View Javadoc

1   /* 
2    * Copyright (c) 2007, Fraunhofer-Gesellschaft
3    * All rights reserved.
4    * 
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions are
7    * met:
8    * 
9    * (1) Redistributions of source code must retain the above copyright
10   *     notice, this list of conditions and the disclaimer at the end.
11   *     Redistributions in binary form must reproduce the above copyright
12   *     notice, this list of conditions and the following disclaimer in
13   *     the documentation and/or other materials provided with the
14   *     distribution.
15   * 
16   * (2) Neither the name of Fraunhofer nor the names of its
17   *     contributors may be used to endorse or promote products derived
18   *     from this software without specific prior written permission.
19   * 
20   * DISCLAIMER
21   * 
22   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33   *  
34   */
35  package org.ogf.graap.wsag.server.monitoring;
36  
37  import java.text.MessageFormat;
38  import java.text.ParseException;
39  import java.util.Arrays;
40  import java.util.Date;
41  import java.util.Iterator;
42  import java.util.List;
43  import java.util.Map;
44  import java.util.Observable;
45  import java.util.Observer;
46  import java.util.Vector;
47  
48  import org.apache.log4j.Logger;
49  import org.apache.xmlbeans.XmlBoolean;
50  import org.apache.xmlbeans.XmlInt;
51  import org.apache.xmlbeans.XmlObject;
52  import org.apache.xmlbeans.XmlString;
53  import org.ogf.graap.wsag.api.Agreement;
54  import org.ogf.graap.wsag.api.logging.LogMessage;
55  import org.ogf.graap.wsag.api.types.AbstractAgreementType;
56  import org.ogf.graap.wsag.server.accounting.IAccountingSystem;
57  import org.ogf.graap.wsag.server.accounting.SimpleAccountingSystemLogger;
58  import org.ogf.graap.wsag.server.api.IAgreementContext;
59  import org.ogf.graap.wsag.server.api.impl.AgreementContext;
60  import org.ogf.graap.wsag.server.persistence.impl.PersistentAgreementContainer;
61  import org.ogf.schemas.graap.wsAgreement.AgreementContextType;
62  import org.ogf.schemas.graap.wsAgreement.AgreementStateType;
63  import org.ogf.schemas.graap.wsAgreement.GuaranteeTermStateType;
64  import org.ogf.schemas.graap.wsAgreement.ServiceTermStateType;
65  import org.ogf.schemas.graap.wsAgreement.TermTreeType;
66  import org.ogf.schemas.graap.wsAgreement.TerminateInputType;
67  import org.quartz.CronExpression;
68  import org.quartz.CronTrigger;
69  import org.quartz.JobDetail;
70  import org.quartz.Scheduler;
71  import org.quartz.SchedulerException;
72  import org.quartz.SchedulerFactory;
73  import org.quartz.Trigger;
74  import org.quartz.impl.StdSchedulerFactory;
75  
76  /**
77   * MonitorableAgreement
78   * 
79   * Supports monitoring of service terms, agreement state and automatic evaluation of guarantee terms.
80   * 
81   * @author Oliver Waeldrich
82   * 
83   */
84  public class MonitorableAgreement extends Observable
85      implements Agreement, Observer
86  {
87  
88      private static final Logger LOG = Logger.getLogger( MonitorableAgreement.class );
89  
90      //
91      // definition of constants set in the execution properties
92      //
93  
94      /**
95       * Key to resolve if monitoring was started for a particular agreement implementation from the agreement
96       * execution context. It refers a {@link XmlBoolean}. If the boolean value is true monitoring was started
97       * using the {@link MonitorableAgreement}, if false or not present monitoring was not used.
98       * 
99       * Used for loading persisted agreements.
100      * 
101      * @see #getAgreementInstance()
102      * @see AbstractAgreementType#getExecutionContext()
103      */
104     public static final String MONITORING_ACTIVE = "org.wsag4j.monitoring.isActive";
105 
106     /**
107      * Key to resolve the monitoring interval for a particular agreement implementation from the agreement
108      * execution context. It refers a {@link XmlString} value.
109      * 
110      * Used for loading persisted agreements.
111      * 
112      * @see #getAgreementInstance()
113      * @see AbstractAgreementType#getExecutionContext()
114      */
115     public static final String MONITORING_CRON = "org.wsag4j.monitoring.cron";
116 
117     /**
118      * Key to resolve the class names of the monitoring handler for a particular agreement implementation from
119      * the agreement execution context. It refers a {@link XmlString}. The monitoring handler class names are
120      * stored in the agreement execution context with the following strategy:
121      * 
122      * <code>MONITORING_HANDLER + "." + handler[i].getClass().getName()</code>
123      * 
124      * Used for loading persisted agreements.
125      * 
126      * @see #getAgreementInstance()
127      * @see AbstractAgreementType#getExecutionContext()
128      */
129     public static final String MONITORING_HANDLER = "org.wsag4j.monitoring.handler";
130 
131     /**
132      * Key to resolve the number of the monitoring handler for a particular agreement implementation from the
133      * agreement execution context. It refers a {@link XmlInt}.
134      * 
135      * Used for loading persisted agreements.
136      * 
137      * @see #getAgreementInstance()
138      * @see AbstractAgreementType#getExecutionContext()
139      */
140     public static final String MONITORING_HANDLER_COUNT = "org.wsag4j.monitoring.handler.count";
141 
142     //
143     // private variable definitions
144     //
145     private AbstractAgreementType agreementInstance;
146 
147     private IAgreementContext executionContext = new AgreementContext( this );
148 
149     private final List<IServiceTermMonitoringHandler> monitoringHandler =
150         new Vector<IServiceTermMonitoringHandler>();
151 
152     private Scheduler scheduler;
153 
154     private String jobName;
155 
156     private static final String JOB_GROUP = "WSAG4J";
157 
158     private IAccountingSystem accountingSystem = new SimpleAccountingSystemLogger();
159 
160     private boolean monitoring = false;
161 
162     /**
163      * @return the monitoring
164      */
165     public boolean isMonitoring()
166     {
167         return monitoring;
168     }
169 
170     //
171     // default schedule for monitoring that fires each minute
172     //
173     private static final String DEFAULT_SCHEDULE = "0 0/1 * * * ?";
174 
175     private String cronExpression = DEFAULT_SCHEDULE;
176 
177     /**
178      * Creates a new instance of a monitorable agreement. The agreement object, for which this
179      * MonitorableAgreement is created, implements the methods to store the terms and the state of the
180      * agreement, and to terminate the agreement.
181      * 
182      * @param agreement
183      *            the agreement object, which should be monitored.
184      */
185     public MonitorableAgreement( AbstractAgreementType agreement )
186     {
187         this.agreementInstance = agreement;
188 
189         //
190         // register this instance as observer to state change events of the agreement instance
191         //
192         agreement.addObserver( this );
193 
194         //
195         // update the execution context
196         //
197         executionContext.getExecutionProperties().putAll( agreement.getExecutionContext() );
198         executionContext.getTransientExecutionProperties().putAll( agreement.getTransientExecutionContext() );
199 
200         initializeScheduler();
201     }
202 
203     /**
204      * Recreates an instance of a monitorable agreement. The agreement object, for which this
205      * MonitorableAgreement is created, implements the methods to store the terms and the state of the
206      * agreement, and to terminate the agreement.
207      * 
208      * @param persistentAgreementContainer
209      *            the persisted agreement object, which should be monitored.
210      */
211     public MonitorableAgreement( PersistentAgreementContainer persistentAgreementContainer )
212     {
213         // agreement.addObserver(this);
214         throw new UnsupportedOperationException( "Not supported yet." );
215     }
216 
217     private void initializeScheduler()
218     {
219         //
220         // Initialize the quartz scheduler
221         //
222         synchronized ( SchedulerFactory.class )
223         {
224 
225             SchedulerFactory factory = new StdSchedulerFactory();
226 
227             try
228             {
229                 scheduler = factory.getScheduler();
230 
231                 if ( !scheduler.isStarted() )
232                 {
233                     scheduler.start();
234                 }
235             }
236             catch ( SchedulerException e )
237             {
238                 throw new IllegalStateException( "Failed to instantiate Quartz scheduler.", e );
239             }
240 
241         }
242 
243     }
244 
245     private IMonitoringContext initializeMonitoringContext()
246     {
247 
248         IMonitoringContext monitoringContext = new MonitoringContext();
249 
250         //
251         // add the execution context properties to the monitoring context
252         //
253         monitoringContext.setProperties( executionContext.getExecutionProperties() );
254 
255         //
256         // add the transient execution context properties to the monitoring context
257         //
258         monitoringContext.setTransientProperties( executionContext.getTransientExecutionProperties() );
259 
260         // deprecated
261         // //
262         // // add the agreement execution context
263         // //
264         // monitoringContext.getProperties().putAll(executionContext.getExecutionProperties());
265 
266         //
267         // add monitoring handler to monitoring context
268         //
269         monitoringContext.setMonitoringHandler( new IServiceTermMonitoringHandler[0] );
270 
271         for ( int i = 0; i < monitoringHandler.size(); i++ )
272         {
273             monitoringContext.addMonitoringHandler( monitoringHandler.get( i ) );
274         }
275 
276         monitoringContext.setAccountingSystem( accountingSystem );
277 
278         //
279         // put the agreement context into the transient properties
280         //
281         monitoringContext.getTransientProperties().put(
282             IMonitoringContext.WSAG4J_AGREEMENT_EXECUTION_CONTEXT, getExecutionContext() );
283 
284         return monitoringContext;
285     }
286 
287     private synchronized void scheduleMonitoringJobs( IMonitoringContext monitoringContext ) throws Exception
288     {
289 
290         //
291         // TODO: set properties isMonitoring in the execution context
292         // this allows us to restart monitoring if an agreement
293         // was reloaded
294         //
295 
296         jobName = initializeJobName();
297 
298         Trigger agreementMonitoringTrigger = createCronTrigger( jobName );
299 
300         //
301         // create job details
302         //
303         JobDetail agreementMonitoringDetail = new JobDetail( jobName, JOB_GROUP, AgreementMonitorJob.class );
304 
305         agreementMonitoringDetail.getJobDataMap().put( AgreementMonitorJob.WSAG4J_AGREEMENT_INSTANCE,
306             agreementInstance );
307         agreementMonitoringDetail.getJobDataMap().put( AgreementMonitorJob.WSAG4J_MONITORING_CONTEXT,
308             monitoringContext );
309 
310         scheduler.scheduleJob( agreementMonitoringDetail, agreementMonitoringTrigger );
311 
312         //
313         // TODO: schedule job for terminating the monitoring process
314         // if AgreementState is completed
315         //
316     }
317 
318     private String initializeJobName() throws SchedulerException
319     {
320         List<String> names = Arrays.asList( scheduler.getJobNames( JOB_GROUP ) );
321 
322         String name =
323             MessageFormat.format( "WSAG4J_MONITORING_JOB_{0}", new Object[] { new Date().getTime() } );
324 
325         while ( names.contains( name ) )
326         {
327             name = MessageFormat.format( "WSAG4J_MONITORING_JOB_{0}", new Object[] { new Date().getTime() } );
328             try
329             {
330                 wait( 10 );
331             }
332             catch ( InterruptedException e )
333             {
334                 // do nothing, just continue
335             }
336         }
337 
338         return name;
339     }
340 
341     /**
342      * Stores the number and class names of the monitoring handler in the execution properties.
343      */
344     private void saveHandlerToExecutionContext()
345     {
346         int handlerCount = 0;
347         Iterator<IServiceTermMonitoringHandler> handler = monitoringHandler.iterator();
348 
349         while ( handler.hasNext() )
350         {
351 
352             String handlerClass = handler.next().getClass().getName();
353 
354             String key = MONITORING_HANDLER + "." + handlerCount;
355             XmlString value = XmlString.Factory.newValue( handlerClass );
356 
357             getExecutionContext().getExecutionProperties().put( key, value );
358 
359             handlerCount++;
360         }
361 
362         XmlInt value = XmlInt.Factory.newValue( Integer.valueOf( handlerCount ) );
363         getExecutionContext().getExecutionProperties().put( MONITORING_HANDLER_COUNT, value );
364     }
365 
366     /**
367      * Initializes the monitoring handler based on the handler count and names stored in the execution
368      * context.
369      */
370     private void initializeHandlerFromExecutionContext()
371     {
372         int handlerCount = 0;
373         monitoringHandler.clear();
374 
375         XmlInt count = (XmlInt) getExecutionContext().getExecutionProperties().get( MONITORING_HANDLER_COUNT );
376         if ( count != null )
377         {
378             handlerCount = count.getIntValue();
379         }
380 
381         while ( handlerCount > 0 )
382         {
383             handlerCount--;
384 
385             String key = MONITORING_HANDLER + "." + handlerCount;
386             XmlString value = (XmlString) getExecutionContext().getExecutionProperties().get( key );
387 
388             LOG.debug( "initialize agreement monitoring handler" );
389 
390             //
391             // load the agreement monitoring handler
392             //
393             try
394             {
395                 String className = value.getStringValue();
396                 LOG.debug( LogMessage.getMessage( "instantiate monitoring handler ''{0}''", className ) );
397 
398                 Class<IServiceTermMonitoringHandler> clazz;
399                 try
400                 {
401                     //
402                     // check if the class to instantiate implements our handler interface
403                     //
404                     @SuppressWarnings( "unchecked" )
405                     Class<IServiceTermMonitoringHandler> convert =
406                         (Class<IServiceTermMonitoringHandler>) this.getClass().getClassLoader()
407                                                                    .loadClass( className );
408 
409                     clazz = convert;
410                 }
411                 catch ( ClassCastException e )
412                 {
413                     final String msgNotRequiredInterface =
414                         "monitoring handler must implement the 'IServiceTermMonitoringHandler' interface.";
415                     throw new Exception( msgNotRequiredInterface, e );
416                 }
417 
418                 //
419                 // instantiate and add the monitoring handler
420                 //
421                 addMonitoringHandler( clazz.newInstance() );
422 
423                 LOG.debug( LogMessage.getMessage( "successfully instantiated monitoring handler ''{0}''",
424                     className ) );
425             }
426             catch ( Exception e )
427             {
428                 String msgText = "re-initializing monitorable agreement failed: {0}";
429                 LogMessage message = LogMessage.getMessage( msgText, e.getMessage() );
430                 LOG.error( message, e );
431             }
432         }
433 
434     }
435 
436     /**
437      * @return the executionContext
438      */
439     public IAgreementContext getExecutionContext()
440     {
441         return executionContext;
442     }
443 
444     /**
445      * @param executionContext
446      *            the executionContext to set
447      */
448     public void setExecutionContext( IAgreementContext executionContext )
449     {
450         this.executionContext = executionContext;
451     }
452 
453     /**
454      * 
455      * @param handler
456      *            monitoring handler
457      */
458     public void addMonitoringHandler( IServiceTermMonitoringHandler handler )
459     {
460         monitoringHandler.add( handler );
461     }
462 
463     /**
464      * Returns the list of registered monitoring handler.
465      * 
466      * @return the monitoringHandler
467      */
468     public IServiceTermMonitoringHandler[] getMonitoringHandler()
469     {
470         return monitoringHandler.toArray( new IServiceTermMonitoringHandler[monitoringHandler.size()] );
471     }
472 
473     /**
474      * @return the cronExpression
475      */
476     public String getCronExpression()
477     {
478         return cronExpression;
479     }
480 
481     /**
482      * @param cronExpression
483      *            the cronExpression to set
484      */
485     public void setCronExpression( String cronExpression )
486     {
487         this.cronExpression = cronExpression;
488     }
489 
490     private Trigger createCronTrigger( String name ) throws Exception
491     {
492         //
493         // create the cron trigger for job monitoring
494         //
495         CronTrigger trigger = new CronTrigger();
496 
497         try
498         {
499             if ( CronExpression.isValidExpression( cronExpression ) )
500             {
501                 trigger.setCronExpression( cronExpression );
502             }
503             else
504             {
505                 LOG.error( LogMessage.getMessage(
506                     "Invalid cron expression ({0}). Using default monitoring schedule ({1}).",
507                     cronExpression, DEFAULT_SCHEDULE ) );
508                 trigger.setCronExpression( DEFAULT_SCHEDULE );
509             }
510         }
511         catch ( ParseException e )
512         {
513             String msgText = "Invalid default schedule <{0}>. Monitoring not scheduled.";
514             String message = LogMessage.format( msgText, DEFAULT_SCHEDULE );
515             throw new Exception( message, e );
516         }
517 
518         trigger.setGroup( JOB_GROUP );
519         trigger.setName( name );
520 
521         return trigger;
522     }
523 
524     /**
525      * Starts the agreement monitoring process.
526      * 
527      * @throws Exception
528      *             failed to start monitoring
529      */
530     public void startMonitoring() throws Exception
531     {
532         //
533         // set flag that the monitoring process has started
534         //
535         XmlBoolean isMonitoring = XmlBoolean.Factory.newValue( true );
536         XmlString cron = XmlString.Factory.newValue( cronExpression );
537         getExecutionContext().getExecutionProperties().put( MONITORING_ACTIVE, isMonitoring );
538         getExecutionContext().getExecutionProperties().put( MONITORING_CRON, cron );
539 
540         //
541         // save the monitoring handler in the execution context
542         //
543         saveHandlerToExecutionContext();
544 
545         //
546         // initialize the monitoring context
547         //
548         IMonitoringContext monitoringContext = initializeMonitoringContext();
549 
550         //
551         // schedule the monitoring jobs
552         //
553         try
554         {
555             scheduleMonitoringJobs( monitoringContext );
556         }
557         catch ( Exception e )
558         {
559             final String msgText = "Error scheduling monitoring jobs. Reason: {0}";
560             String message = LogMessage.format( msgText, e.getMessage() );
561             LOG.error( message, e );
562 
563             throw new Exception( message, e );
564         }
565 
566         this.monitoring = true;
567     }
568 
569     /**
570      * Stops the agreement monitoring.
571      * 
572      * @throws Exception
573      *             error while stopping the agreement monitor scheduler
574      */
575     public void stopMonitoring() throws Exception
576     {
577         try
578         {
579             XmlBoolean isMonitoring = XmlBoolean.Factory.newValue( false );
580             getExecutionContext().getExecutionProperties().put( MONITORING_ACTIVE, isMonitoring );
581             getAgreementInstance().getAgreementInstance().getExecutionContext()
582                                   .put( MONITORING_ACTIVE, isMonitoring );
583 
584             //
585             // TODO: unset properties isMonitoring in the execution context
586             // when an agreement is reloaded, the monitoring is started
587             // if isMonitoring property is set in the execution properties
588             //
589 
590             scheduler.unscheduleJob( jobName, JOB_GROUP );
591         }
592         catch ( SchedulerException e )
593         {
594             String message = "Error stoping the agreement monitoring. Reason: " + e.getMessage();
595             LOG.error( message );
596 
597             throw new Exception( message, e );
598         }
599 
600         this.monitoring = false;
601     }
602 
603     /**
604      * {@inheritDoc}
605      */
606     public void terminate( TerminateInputType reason )
607     {
608         try
609         {
610             stopMonitoring();
611         }
612         catch ( Exception ex )
613         {
614             LOG.error( "The agreement monitoring scheduler was not stoped" );
615 
616             if ( LOG.isDebugEnabled() )
617             {
618                 LOG.debug( ex );
619             }
620         }
621 
622         try
623         {
624             agreementInstance.terminate( reason );
625         }
626         catch ( Exception ex )
627         {
628             LOG.error( "The agreement could not be terminated." );
629 
630             if ( LOG.isDebugEnabled() )
631             {
632                 LOG.debug( ex );
633             }
634         }
635 
636     }
637 
638     /**
639      * This method notifies a concrete agreement instance that the monitored agreement instance was reloaded.
640      * This essentially implies that the {@link AbstractAgreementType#notifyReload(java.util.Map)} method is
641      * invoked. Implementations of the {@link AbstractAgreementType} can override the
642      * {@link AbstractAgreementType#notifyReinitialized(java.util.Map)} in order to implement domain specific
643      * re-initialization logic.
644      * 
645      * @throws Exception
646      *             indicates an error during the agreement reload process
647      */
648     public void notifyReload() throws Exception
649     {
650         agreementInstance.notifyReload( executionContext.getExecutionProperties() );
651 
652         //
653         // re-initialize monitoring handler and restart agreement monitoring
654         //
655         initializeHandlerFromExecutionContext();
656 
657         Map<String, XmlObject> executionProperties = getExecutionContext().getExecutionProperties();
658         XmlString cron = (XmlString) executionProperties.get( MonitorableAgreement.MONITORING_CRON );
659 
660         if ( cron != null )
661         {
662             cronExpression = cron.getStringValue();
663         }
664         else
665         {
666             cronExpression = DEFAULT_SCHEDULE;
667         }
668 
669         boolean isActive = false;
670         if ( executionProperties.containsKey( MONITORING_ACTIVE ) )
671         {
672             isActive =
673                 ( (XmlBoolean) executionProperties.get( MonitorableAgreement.MONITORING_ACTIVE ) ).getBooleanValue();
674         }
675 
676         if ( isActive )
677         {
678             startMonitoring();
679         }
680     }
681 
682     /**
683      * @return the agreement id
684      * @see org.ogf.graap.wsag.api.Agreement#getAgreementId()
685      */
686     public String getAgreementId()
687     {
688         return agreementInstance.getAgreementId();
689     }
690 
691     /**
692      * @return the agreement context
693      * @see org.ogf.graap.wsag.api.Agreement#getContext()
694      */
695     public AgreementContextType getContext()
696     {
697         return agreementInstance.getContext();
698     }
699 
700     /**
701      * @return the guarantee term states
702      * @see org.ogf.graap.wsag.api.Agreement#getGuaranteeTermStates()
703      */
704     public GuaranteeTermStateType[] getGuaranteeTermStates()
705     {
706         return agreementInstance.getGuaranteeTermStates();
707     }
708 
709     /**
710      * @return the agreement name
711      * @see org.ogf.graap.wsag.api.Agreement#getName()
712      */
713     public String getName()
714     {
715         return agreementInstance.getName();
716     }
717 
718     /**
719      * @return the service term states
720      * @see org.ogf.graap.wsag.api.Agreement#getServiceTermStates()
721      */
722     public ServiceTermStateType[] getServiceTermStates()
723     {
724         return agreementInstance.getServiceTermStates();
725     }
726 
727     /**
728      * @return the agreement state
729      * @see org.ogf.graap.wsag.api.Agreement#getState()
730      */
731     public AgreementStateType getState()
732     {
733         return agreementInstance.getState();
734     }
735 
736     /**
737      * @return the terms of the agreement
738      * @see org.ogf.graap.wsag.api.Agreement#getTerms()
739      */
740     public TermTreeType getTerms()
741     {
742         return agreementInstance.getTerms();
743     }
744 
745     /**
746      * {@inheritDoc}
747      */
748     public AbstractAgreementType getAgreementInstance()
749     {
750         return agreementInstance;
751     }
752 
753     /**
754      * @param accountingSystem
755      *            the accountingSystem to set
756      */
757     public void setAccountingSystem( IAccountingSystem accountingSystem )
758     {
759         if ( accountingSystem != null )
760         {
761             this.accountingSystem = accountingSystem;
762         }
763     }
764 
765     /**
766      * @return the accountingSystem
767      */
768     public IAccountingSystem getAccountingSystem()
769     {
770         return accountingSystem;
771     }
772 
773     /**
774      * If the monitored agreement receives a state change notification of the concrete agreement
775      * implementation (@link {@link AbstractAgreementType#notifyObservers()}) all observer registered to this
776      * monitorable agreement will be notified of the state change ass well.
777      * 
778      * {@inheritDoc}
779      * 
780      * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
781      */
782     public void update( Observable o, Object arg )
783     {
784         if ( o == agreementInstance )
785         {
786             setChanged();
787             notifyObservers();
788         }
789     }
790 }