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.engine;
36  
37  import java.io.InputStream;
38  import java.text.MessageFormat;
39  import java.util.HashMap;
40  import java.util.List;
41  import java.util.Map;
42  import java.util.UUID;
43  import java.util.Vector;
44  
45  import org.apache.log4j.Logger;
46  import org.apache.xml.resolver.tools.CatalogResolver;
47  import org.apache.xmlbeans.XmlObject;
48  import org.ogf.graap.wsag.api.AgreementFactory;
49  import org.ogf.graap.wsag.api.WsagConstants;
50  import org.ogf.graap.wsag.api.logging.LogMessage;
51  import org.ogf.graap.wsag.server.api.IAgreementFactory;
52  import org.ogf.graap.wsag.server.api.impl.FactoryContext;
53  import org.ogf.graap.wsag.server.api.impl.AgreementFactoryFacade;
54  import org.ogf.graap.wsag.server.persistence.EmfRegistry;
55  import org.ogf.graap.wsag.server.persistence.IAgreementFactoryHome;
56  import org.ogf.graap.wsag.server.persistence.PersistentAgreementFactory;
57  import org.ogf.graap.wsag.server.persistence.impl.AbstractWSAG4JPersistence;
58  import org.ogf.graap.wsag4j.types.configuration.FactoryConfigurationType;
59  import org.ogf.graap.wsag4j.types.configuration.ImplementationConfigurationType;
60  import org.ogf.graap.wsag4j.types.configuration.WSAG4JEngineConfigurationDocument;
61  import org.ogf.graap.wsag4j.types.configuration.WSAG4JEngineConfigurationType;
62  import org.quartz.Scheduler;
63  import org.quartz.SchedulerException;
64  import org.quartz.SchedulerFactory;
65  import org.quartz.impl.StdSchedulerFactory;
66  
67  /**
68   * The WSAGEngine provides access to all agreement factories configured for this engine. The available
69   * factories can be retrieved via the agreement factory home interface. The agreement factory home is
70   * retrieved by the {@link #getAgreementFactoryHome()} method. Before the engine can be used it must be
71   * initialized. Engine initialization is triggered by the {@link #initializeEngine(String)} method.
72   * 
73   * @author Oliver Waeldrich
74   * 
75   */
76  public class WsagEngine
77      implements IAgreementFactoryHome
78  {
79  
80      private static final Logger LOG = Logger.getLogger( WsagEngine.class );
81  
82      /**
83       * Configuration of this engine instance.
84       */
85      private WSAG4JEngineConfigurationType engineConfiguration = null;
86  
87      /**
88       * The persistence layer configured for this instance.
89       */
90      private AbstractWSAG4JPersistence persistenceLayer;
91  
92      /**
93       * A map that contains the available persistent agreement factory which are identified by their factory
94       * id.
95       */
96      protected Map<String, PersistentAgreementFactory> persistentFactories =
97          new HashMap<String, PersistentAgreementFactory>();
98  
99      /**
100      * An ordered list with the available agreement factories. The factories are stored in the order they were
101      * retrieved from the persistence layer.
102      */
103     protected List<PersistentAgreementFactory> factoriesOL = new Vector<PersistentAgreementFactory>();
104 
105     /**
106      * Returns a new WSAG engine instance.
107      * 
108      * @param configuration
109      *            engine configuration as input stream
110      * 
111      * @return the new created engine instance
112      * 
113      * @throws EngineInstantiationException
114      *             failed to instantiate the engine
115      */
116     public static WsagEngine getInstance( InputStream configuration ) throws EngineInstantiationException
117     {
118         WSAG4JEngineConfigurationDocument config = null;
119         try
120         {
121             config = (WSAG4JEngineConfigurationDocument) XmlObject.Factory.parse( configuration );
122         }
123         catch ( Exception e )
124         {
125             String message =
126                 MessageFormat.format( "Failed to read WSAG4J engine configuration. Reason: {0}",
127                     e.getMessage() );
128             throw new EngineInstantiationException( message, e );
129         }
130 
131         return getInstance( config.getWSAG4JEngineConfiguration() );
132     }
133 
134     /**
135      * Returns a new WSAG engine instance.
136      * 
137      * @param configFile
138      *            engine configuration as file name (must be available in the class path)
139      * 
140      * @return the new created engine instance
141      * 
142      * @throws EngineInstantiationException
143      *             failed to instantiate the engine
144      */
145     public static WsagEngine getInstance( String configFile ) throws EngineInstantiationException
146     {
147         InputStream in = WsagEngine.class.getResourceAsStream( configFile );
148         return getInstance( in );
149     }
150 
151     /**
152      * Returns a new WSAG engine instance.
153      * 
154      * @param engineConfiguration
155      *            engine configuration
156      * 
157      * @return the new created engine instance
158      * 
159      * @throws EngineInstantiationException
160      *             failed to instantiate the engine
161      */
162     public static WsagEngine getInstance( WSAG4JEngineConfigurationType engineConfiguration )
163         throws EngineInstantiationException
164     {
165 
166         if ( engineConfiguration == null )
167         {
168             throw new EngineInstantiationException( "WSAG4J engine configuration must not be null." );
169         }
170 
171         try
172         {
173             WsagEngine wsagEngine = new WsagEngine( engineConfiguration );
174             wsagEngine.initialize();
175 
176             return wsagEngine;
177         }
178         catch ( Exception e )
179         {
180             String message =
181                 MessageFormat.format( "failed to instantiate WSAG4J engine. Reason: {0}", e.getMessage() );
182             throw new EngineInstantiationException( message, e );
183         }
184     }
185 
186     /**
187      * Creates a new WSAG4J engine instance.
188      * 
189      * @param engineConfiguration
190      *            engine configuration file
191      * 
192      */
193     private WsagEngine( WSAG4JEngineConfigurationType engineConfiguration )
194     {
195         this.engineConfiguration = engineConfiguration;
196     }
197 
198     /**
199      * looks up a factory with the given id.
200      * 
201      * @param factoryId
202      *            the id of the factory to find
203      * 
204      * @return the factory
205      * 
206      * @throws Exception
207      *             an error occurred while looking up the factory.
208      * 
209      * @see IAgreementFactoryHome#find(String)
210      */
211     public PersistentAgreementFactory find( String factoryId ) throws Exception
212     {
213         if ( persistentFactories.containsKey( factoryId ) )
214         {
215             return persistentFactories.get( factoryId );
216         }
217 
218         return null;
219     }
220 
221     /**
222      * Instantiates a new agreement factory instance based on the engine configuration.
223      * 
224      * @param configuration
225      *            Configuration of the wsag4j engine.
226      * 
227      * @return Agreement factory prototype based on the wsag4j configuration.
228      * 
229      * @throws Exception
230      *             failed to initialize the configured factory
231      */
232     public IAgreementFactory getAgreementFactoryPrototype() throws Exception
233     {
234         String implementationClass = null;
235 
236         try
237         {
238             implementationClass =
239                 engineConfiguration.getFactory().getFactoryImplementation().getImplementationClass();
240 
241             if ( implementationClass == null )
242             {
243                 throw new Exception();
244             }
245         }
246         catch ( Exception ex )
247         {
248             String message =
249                 "Error in WSAG4J configuration: "
250                     + "Could not load agreement factory implementation from configuration file.";
251             throw new Exception( message, ex );
252         }
253 
254         try
255         {
256 
257             Object instance = Class.forName( implementationClass ).newInstance();
258 
259             if ( instance instanceof AgreementFactory )
260             {
261                 AgreementFactory impl = (AgreementFactory) instance;
262 
263                 IAgreementFactory factory = null;
264 
265                 //
266                 // if the implementation is not an instance of
267                 // IWSAG4JAgreementFactory, return a facade for
268                 // the implementation.
269                 //
270                 if ( impl instanceof IAgreementFactory )
271                 {
272                     factory = (IAgreementFactory) impl;
273                 }
274                 else
275                 {
276                     factory = new AgreementFactoryFacade( impl );
277                 }
278 
279                 //
280                 // explicitly initialize the factory context
281                 // and set the engine configuration
282                 //
283                 factory.setFactoryContext( new FactoryContext( factory ) );
284 
285                 factory.initialize( this );
286 
287                 //
288                 // also populate the factory context with the factory
289                 // configuration, so that action implementations may
290                 // look up the factory configuration
291                 //
292                 factory.getFactoryContext().put( WsagConstants.WSAG4J_FACTORY_CONFIGURATION,
293                     engineConfiguration );
294 
295                 return factory;
296 
297             }
298             else
299             {
300                 Object[] filler = new Object[] { implementationClass, IAgreementFactoryHome.class.getName() };
301                 String msgLoadPersistenceLayerError =
302                     "Error loading WSAG4J persistence layer. Class [{0}] does not implement interface [{1}].";
303                 String message = MessageFormat.format( msgLoadPersistenceLayerError, filler );
304                 throw new Exception( message );
305             }
306 
307         }
308         catch ( ClassNotFoundException e )
309         {
310             String message =
311                 MessageFormat.format(
312                     "Error loading WSAG4J persistence layer. Class [{0}] not found. Error: {1}",
313                     implementationClass, e.getMessage() );
314             throw new Exception( message );
315         }
316         catch ( InstantiationException e )
317         {
318             String message =
319                 MessageFormat.format( "Error loading WSAG4J persistence layer. "
320                     + "Class [{0}] could not be instantiated. Error: {1}", implementationClass,
321                     e.getMessage() );
322             throw new Exception( message );
323         }
324         catch ( IllegalAccessException e )
325         {
326             String message =
327                 MessageFormat.format( "Error loading WSAG4J persistence layer. "
328                     + "Class [{0}] could not be accessed. Error: {1}", implementationClass, e.getMessage() );
329             throw new Exception( message );
330         }
331     }
332 
333     /**
334      * Returns the configuration for this engine instance.
335      * 
336      * @return the wsag4jConfiguration
337      */
338     public WSAG4JEngineConfigurationType getConfiguration()
339     {
340         return engineConfiguration;
341     }
342 
343     /**
344      * Returns the resource id configured for this engine instance or the a generated UUID if not set.
345      * 
346      * @return the default resource id
347      */
348     public String getDefaultResourceId()
349     {
350         if ( getConfiguration().isSetResourceId() )
351         {
352             return getConfiguration().getResourceId();
353         }
354         else
355         {
356             LOG.error( "agreement factory id not set in configuration file" );
357             LOG.error( "generate random agreement factory id " );
358             LOG.error( "agreement persistence will be disabled" );
359             return UUID.randomUUID().toString();
360         }
361     }
362 
363     /**
364      * Returns the name of the persistence layer implementation class from the engine configuration.
365      * 
366      * @param configuration
367      *            the engine configuration
368      * 
369      * @return the name of the persistence layer implementation class
370      * 
371      * @throws Exception
372      *             failed to resolve the implementation class
373      */
374     private String getPersistenceImplementationClass( WSAG4JEngineConfigurationType configuration )
375         throws Exception
376     {
377         String implementationClass;
378         try
379         {
380             FactoryConfigurationType factoryConfig = configuration.getFactory();
381             ImplementationConfigurationType persistenceConfig = factoryConfig.getPersistenceImplementation();
382             implementationClass = persistenceConfig.getImplementationClass();
383 
384             LOG.debug( LogMessage.getMessage( "Create ''{0}'' instance as persistence layer.",
385                 implementationClass ) );
386         }
387         catch ( Exception e )
388         {
389             throw new Exception( "failed to read WSAG4J engine configuration", e );
390         }
391         return implementationClass;
392     }
393 
394     /**
395      * Returns the persistence layer for this engine.
396      * 
397      * @return the persistence layer for this engine
398      */
399     public IAgreementFactoryHome getPersistenceLayer()
400     {
401         return persistenceLayer;
402     }
403 
404     /**
405      * Initializes the WSAG4J Engine with the local configuration.
406      * 
407      * @throws Exception
408      *             indicates an error during engine initialization
409      */
410     private void initialize() throws Exception
411     {
412         try
413         {
414             LOG.info( "start initialization process for new WSAG4J engine instance" );
415 
416             //
417             // set the CatalogResolver as default entity resolver for XmlBeans
418             //
419             System.setProperty( "xmlbean.entityResolver", CatalogResolver.class.getName() );
420 
421             LOG.info( "load WSAG4J engine configuration" );
422 
423             LOG.info( "initialize WSAG4J persistence layer" );
424             initializePersistenceLayer();
425 
426             LOG.info( "WSAG4J engine initialized successfully" );
427         }
428         catch ( Exception e )
429         {
430             throw new Exception( "failed to initialize WSAG4J engine", e );
431         }
432     }
433 
434     /**
435      * Initializes the WSAG4J persistence layer.
436      */
437     private void initializePersistenceLayer() throws Exception
438     {
439 
440         try
441         {
442             LOG.info( "WsagEngine -> initialize PersistenceLayer" );
443 
444             // build and initialise agreement factory home
445             try
446             {
447                 persistenceLayer = loadPersistenceLayer( engineConfiguration );
448                 persistenceLayer.initialize( this );
449 
450                 PersistentAgreementFactory[] factories = getPersistenceLayer().list();
451                 for ( int j = 0; j < factories.length; j++ )
452                 {
453                     if ( persistentFactories.containsKey( factories[j].getResourceId() ) )
454                     {
455                         String message1 =
456                             "[duplicated resource id] "
457                                 + "the agreement factory resource id must be unique in a WSAG4J engine.";
458                         LOG.error( message1 );
459 
460                         String message2 =
461                             "[duplicated resource id] the factory with resource id ''{0}'' was not loaded.";
462                         LOG.error( MessageFormat.format( message2,
463                             new Object[] { factories[j].getResourceId() } ) );
464                     }
465                     else
466                     {
467                         persistentFactories.put( factories[j].getResourceId(), factories[j] );
468                         factoriesOL.add( factories[j] );
469                     }
470                 }
471             }
472             catch ( Exception e )
473             {
474                 LOG.error( "error loading persistence layer", e );
475             }
476 
477             LOG.info( "WsagEngine -> Persistence Layer initialized" );
478         }
479         catch ( Exception e )
480         {
481             LOG.error( "WsagEngine -> failed to initialize Persistence Layer", e );
482             throw new Exception( "Failed to initialize persistence layer.", e );
483         }
484     }
485 
486     /**
487      * @return all available persistent factories
488      * 
489      * @throws Exception
490      *             indicates an error while generating the factory list
491      * 
492      * @see org.ogf.graap.wsag.server.persistence.IAgreementFactoryHome#list()
493      */
494     public PersistentAgreementFactory[] list() throws Exception
495     {
496         return factoriesOL.toArray( new PersistentAgreementFactory[persistentFactories.size()] );
497     }
498 
499     private AbstractWSAG4JPersistence loadPersistenceLayer( WSAG4JEngineConfigurationType configuration )
500         throws Exception
501     {
502         String implementationClass = getPersistenceImplementationClass( configuration );
503 
504         try
505         {
506             Object instance = Class.forName( implementationClass ).newInstance();
507 
508             if ( instance instanceof AbstractWSAG4JPersistence )
509             {
510                 LOG.debug( "Persistence layer instance created and loaded." );
511                 return (AbstractWSAG4JPersistence) instance;
512             }
513             else
514             {
515                 String text =
516                     "Error loading WSAG4J persistence layer. Class {0} does not implement interface {1}.";
517                 String message =
518                     MessageFormat.format( text, implementationClass, IAgreementFactoryHome.class.getName() );
519 
520                 throw new Exception( message );
521             }
522         }
523         catch ( ClassNotFoundException e )
524         {
525             String text = "Error loading WSAG4J persistence layer. Class [{0}] not found. Error: {1}";
526             String message = MessageFormat.format( text, implementationClass, e.getMessage() );
527 
528             throw new Exception( message );
529         }
530         catch ( InstantiationException e )
531         {
532             throw new Exception( MessageFormat.format(
533                 "Error loading WSAG4J persistence layer. Class [{0}] could not be instantiated. Error: {1}",
534                 implementationClass, e.getMessage() ) );
535         }
536         catch ( IllegalAccessException e )
537         {
538             throw new Exception( MessageFormat.format(
539                 "Error loading WSAG4J persistence layer. Class [{0}] could not be accessed. Error: {1}",
540                 implementationClass, e.getMessage() ) );
541         }
542     }
543 
544     /**
545      * @param factoryId
546      *            removes the factory with the given id from the persistence layer
547      * 
548      * @throws Exception
549      *             an error occurred while removing the factory
550      * 
551      * @see org.ogf.graap.wsag.server.persistence.IAgreementFactoryHome#remove(java.lang.String)
552      */
553     public void remove( String factoryId ) throws Exception
554     {
555         if ( persistentFactories.containsKey( factoryId ) )
556         {
557             factoriesOL.remove( persistentFactories.get( factoryId ) );
558             persistentFactories.remove( factoryId );
559         }
560     }
561 
562     /**
563      * Saves all factories.
564      * 
565      * @throws Exception
566      *             indicates an error while saving the factories
567      */
568     public void save() throws Exception
569     {
570         PersistentAgreementFactory[] factories = list();
571         for ( int i = 0; i < factories.length; i++ )
572         {
573             factories[i].save();
574         }
575     }
576 
577     /**
578      * @param factories
579      *            the factories to save
580      * 
581      * @throws Exception
582      *             indicates an error while saving the factories
583      * 
584      * @see org.ogf.graap.wsag.server.persistence.IAgreementFactoryHome#saveAgreementFactories(org.ogf.graap.wsag.server.persistence.PersistentAgreementFactory[])
585      */
586     public void saveAgreementFactories( PersistentAgreementFactory[] factories ) throws Exception
587     {
588         for ( int i = 0; i < factories.length; i++ )
589         {
590             factories[i].save();
591         }
592     }
593 
594     /**
595      * Shutdown of the WSAG4J engine instance.
596      * 
597      * @throws Exception
598      *             indicates an error during engine shutdown
599      */
600     public void shutdown() throws Exception
601     {
602         LOG.info( "start shutdown process for WSAG4J engine instance" );
603 
604         try
605         {
606             LOG.info( "shutdown Quarz scheduler" );
607 
608             SchedulerFactory factory = new StdSchedulerFactory();
609             Scheduler scheduler = factory.getScheduler();
610 
611             if ( scheduler.isStarted() )
612             {
613                 scheduler.shutdown();
614             }
615         }
616         catch ( SchedulerException e )
617         {
618             LOG.error( "Failed to shutdown quartz scheduler.", e );
619         }
620 
621         LOG.info( "shutdown WSAG4J engine persistence layer" );
622         shutdownPersistenceLayer();
623 
624         LOG.info( "shutdown of WSAG4J engine persistence layer completed" );
625 
626         LOG.info( "WSAG4J engine shutdown completed" );
627     }
628 
629     /**
630      * Shutdown the persistence layer and persist all agreements that are currently managed by the
631      * implementation.
632      * 
633      * TODO: Save current agreement states.
634      */
635     private void shutdownPersistenceLayer() throws Exception
636     {
637         // load all agreements
638         PersistentAgreementFactory[] factories = getPersistenceLayer().list();
639         for ( int i = 0; i < factories.length; i++ )
640         {
641             try
642             {
643                 final String msgDoSave = "Save agreement factory ''{0}''.";
644                 LOG.debug( LogMessage.getMessage( msgDoSave, factories[i].getResourceId() ) );
645 
646                 factories[i].save();
647 
648                 final String msgSaved = "Agreement factory ''{0}'' saved.";
649                 LOG.debug( LogMessage.getMessage( msgSaved, factories[i].getResourceId() ) );
650             }
651             catch ( Exception e )
652             {
653                 String message = "Failed to save agreement factory ''{0}''.";
654                 LOG.error( MessageFormat.format( message, new Object[] { factories[i].getResourceId() } ), e );
655             }
656         }
657 
658         // remove references to agreement (factory) home
659         persistentFactories.clear();
660         factoriesOL.clear();
661 
662         persistenceLayer = null;
663 
664         // close the entity manager factory
665         EmfRegistry.finalizeEmfRegistry();
666     }
667 
668 }