View Javadoc

1   /*
2    wsmo4j - a WSMO API and Reference Implementation
3   
4    Copyright (c) 2004-2005, OntoText Lab. / SIRMA
5   
6    This library is free software; you can redistribute it and/or modify it under
7    the terms of the GNU Lesser General Public License as published by the Free
8    Software Foundation; either version 2.1 of the License, or (at your option)
9    any later version.
10   This library is distributed in the hope that it will be useful, but WITHOUT
11   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12   FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
13   details.
14   You should have received a copy of the GNU Lesser General Public License along
15   with this library; if not, write to the Free Software Foundation, Inc.,
16   59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17   */
18  
19  /**
20   * <p>Title: WSMO4J</p>
21   * <p>Description: WSMO API and a Reference Implementation</p>
22   * <p>Copyright:  Copyright (c) 2004-2005</p>
23   * <p>Company: OntoText Lab. / SIRMA </p>
24   */
25  
26  package org.wsmo.factory;
27  
28  import java.io.*;
29  import java.lang.reflect.*;
30  import java.util.*;
31  
32  import org.wsmo.datastore.*;
33  import org.wsmo.locator.*;
34  import org.wsmo.validator.WsmlValidator;
35  import org.wsmo.wsml.*;
36  
37  /**
38   * Factory interface
39   * The Factory is both a factory (creates objects) and a meta-factory (creates factories)
40   * Factory is <b>final</b>
41   * @author not attributable
42   * @version $Revision: 1946 $ $Date: 2007-04-02 15:13:28 +0300 (Mon, 02 Apr 2007) $
43   */
44  
45  /**
46   * @stereotype factory*/
47  public final class Factory {
48  
49      public final static String PROVIDER_CLASS = "provider";
50  
51      public static final String WSMO_PARSER = "wsmo_parser";
52      public static final String WSMO_SERIALIZER = "wsmo_serializer";
53      public static final String WSML_VALIDATOR = "wsml_validator";
54      public static final String LE_FACTORY = "le_factory";
55      public static final String WSMO_FACTORY = "wsmo_factory";
56      public static final String DATA_FACTORY = "data_factory";
57  
58      private static LocatorManager locManager;
59  
60      private static boolean cachingEnabled;
61  
62      private static Map <Map <String, Object>, Object> objectCache;
63  
64      private static Properties defaultImplMap;
65      private static final String propertiesFile = "wsmo4j.properties";
66  
67      static {
68          locManager = new LocatorManager();
69  
70          //cache by default; we may add setCaching(boolean) later
71          cachingEnabled = true;
72  
73          //DON'T use weak refs
74          objectCache = new HashMap <Map <String, Object>, Object>();
75  
76          defaultImplMap = new Properties();
77                  
78          InputStream inProps = Thread.currentThread().getContextClassLoader()
79                                        .getResourceAsStream(propertiesFile);
80          if (inProps == null) {
81  	        inProps = Factory.class.getClassLoader().getResourceAsStream(propertiesFile);
82          }
83          
84          if (inProps == null){
85              throw new RuntimeException("Error loading config file "+propertiesFile+" from class path");
86          }
87          try {
88              defaultImplMap.load(inProps);
89          }
90          catch(IOException ioe) {
91              throw new RuntimeException("Error loading config file ", ioe);
92          }
93      }
94  
95      //singleton
96      private Factory(){
97      }
98  
99      /**
100      * Creates a datastore based on the supplied preferences.
101      * At least one preference should be supplied - the provider class
102      * @see #PROVIDER_CLASS
103      * @param properties the preferences for the datastore. Such preferences
104      * should provide all the necessary information for the data store
105      * initialisation (e.g. provider class, connection URL,...,
106      * etc.)
107      * @return a reference to a datastore
108      */
109     public static DataStore createDatastore(Map properties) {
110 
111         //0. preconditions
112         if (null == properties || false == properties.containsKey(Factory.PROVIDER_CLASS)) {
113             throw new IllegalArgumentException("Datastore class was not specified. There is NO default datastore implementation...");
114         }
115 
116         Object result = _createObject(properties);
117 
118         assert null != result;
119 
120         //post-conditions
121         if (false == result instanceof DataStore) {
122             throw new RuntimeException(properties.get(Factory.PROVIDER_CLASS) + " does not implement the org.wsmo.datastore.Datastore interface");
123         }
124 
125         return (DataStore)result;
126     }
127 
128     /**
129      * Creates a WsmlValidator based on the supplied preferences.
130      * The properties map can contain the factories to be used as Strings or as
131      * instances. The WsmlValidator Constructor needs to check this and
132      * needs to create an instance of a given factory, if only the String
133      * is supplied.
134      * At least one preference should be supplied - the provider class.
135      * 
136      * The validator can either only check a given TopEntity for validity, 
137      * or it can also check all imported ontologies. By default, the validator 
138      * does not check the imported ontologies. 
139      * This feature can be 
140      * enabled by adding a property to the properties map when creating the 
141      * WsmlValidator. Another preference can be set, which references a map 
142      * containing a mapping from logical URIs to physical locations:
143 	 *	 HashMap prefs = new HashMap();
144 	 *	 prefs.put(WsmlValidator.VALIDATE_IMPORTS, new Boolean(true));
145 	 *	 prefs.put(Locator.URI_MAPPING, mapping);
146      * 
147      * @see #PROVIDER_CLASS
148      * @param properties the preferences for the validator.
149      * @return a wsmlValidator
150      */
151     public static WsmlValidator createWsmlValidator(Map <String, Object> properties) {
152 
153         //preconditions
154         if (null == properties) {
155             properties = new HashMap <String, Object>();
156         }
157 
158         //check provider
159         if (!properties.containsKey(Factory.PROVIDER_CLASS)) {
160             //set default Wsml Validator
161             properties.put(Factory.PROVIDER_CLASS,
162                     defaultImplMap.getProperty(Factory.WSML_VALIDATOR));
163         }
164 
165         // check LE factory
166         if (!properties.containsKey(Factory.LE_FACTORY)) {
167             //set default LogExpr factory
168             properties.put(Factory.LE_FACTORY,
169                     defaultImplMap.getProperty(Factory.LE_FACTORY));
170         }
171 
172         Object result = _createObject(properties);
173 
174         assert null != result;
175 
176         //post-conditions
177         if (false == result instanceof WsmlValidator) {
178             throw new RuntimeException(properties.get(Factory.PROVIDER_CLASS) +
179                     " does not implement the org.wsmo.validator.WsmlValidator interface");
180         }
181 
182         return (WsmlValidator) result;
183     }
184 
185     /**
186      * Creates a parser based on the supplied preferences.
187      * The properties map can contain the factories to be used as Strings or as
188      * instances. The Parser Constructor needs to check this and
189      * needs to create an instance of a given factory, if only the String
190      * is supplied.
191      * At least one preference should be supplied - the provider class
192      * @see #PROVIDER_CLASS
193      * @see #PARSER_FACTORY
194      * @param properties the preferences for the parser. Such preferences
195      * should provide all the necessary information for the parser
196      * initialisation (e.g. provider class, factory to be used, file type, grammar version,
197      * etc.)
198      * @return a Parser
199      */
200     public static Parser createParser(Map <String, Object> properties) {
201 
202         //preconditions
203         if (null == properties) {
204             properties = new HashMap <String, Object>();
205         }
206 
207         //check provider
208         if (false == properties.containsKey(Factory.PROVIDER_CLASS)) {
209             //set default parser
210             properties.put(Factory.PROVIDER_CLASS,
211                            defaultImplMap.getProperty(Factory.WSMO_PARSER));
212         }
213 
214         //check WSMO factory
215         if (false == properties.containsKey(Factory.WSMO_FACTORY)) {
216             //set default WSMO factory
217             properties.put(Factory.WSMO_FACTORY,
218                            defaultImplMap.getProperty(Factory.WSMO_FACTORY));
219         }
220 
221         //check LE factory
222         if (false == properties.containsKey(Factory.LE_FACTORY)) {
223             //set default LogExpr factory
224             properties.put(Factory.LE_FACTORY,
225                            defaultImplMap.getProperty(Factory.LE_FACTORY));
226         }
227 
228         Object result = _createObject(properties);
229 
230         assert null != result;
231 
232         //post-conditions
233         if (false == result instanceof Parser) {
234             throw new RuntimeException(properties.get(Factory.PROVIDER_CLASS) + " does not implement the org.wsmo.wsml.Parser interface");
235         }
236 
237         return (Parser)result;
238     }
239 
240     /**
241      * Creates a serialiser based on the supplied preferences.
242      * At least one preference should be supplied - the provider class
243      * @see #PROVIDER_CLASS
244      * @param properties the preferences for the parser. Such preferences
245      * should provide all the necessary information for the parser
246      * initialisation (e.g. provider class, factory to be used, file type, grammar version,
247      * etc.)
248      * @return a Parser
249      */
250     public static Serializer createSerializer(Map <String, Object> properties) {
251 
252         //preconditions
253         if (null == properties) {
254             properties = new HashMap <String, Object>();
255         }
256 
257         //check provider
258         if (false == properties.containsKey(Factory.PROVIDER_CLASS)) {
259             //set default parser
260             properties.put(Factory.PROVIDER_CLASS,
261                     defaultImplMap.getProperty(Factory.WSMO_SERIALIZER));
262         }
263 
264         Object result = _createObject(properties);
265 
266         assert null != result;
267 
268         //post-conditions
269         if (false == result instanceof Serializer) {
270             throw new RuntimeException(properties.get(Factory.PROVIDER_CLASS) + " does not implement the org.wsmo.wsml.Serialiser interface");
271         }
272 
273         return (Serializer)result;
274     }
275 
276     /**
277      * Creates a WsmoFactory based on the supplied preferences.
278      * At least one preference should be supplied - the provider class
279      * @see #PROVIDER_CLASS
280      * @param properties the preferences for the WSMO factory. Such preferences
281      * should provide all the necessary information for the factory
282      * initialisation (e.g. provider class, etc.)
283      * @return a WsmoFactory
284      */
285     public static WsmoFactory createWsmoFactory(Map <String, Object> properties) {
286 
287         //preconditions
288         if (null == properties) {
289             properties = new HashMap <String, Object>();
290         }
291 
292         //check provider
293         if (false == properties.containsKey(Factory.PROVIDER_CLASS)) {
294             //use default WSMO factory
295             properties.put(Factory.PROVIDER_CLASS,
296                     defaultImplMap.getProperty(Factory.WSMO_FACTORY));
297         }
298 
299         Object result = _createFactory(properties);
300 
301         assert null != result;
302 
303         //post-conditions
304         if (false == result instanceof WsmoFactory) {
305             throw new RuntimeException(properties.get(Factory.PROVIDER_CLASS) + " does not implement the org.wsmo.factory.WsmoFactory interface");
306         }
307 
308         return (WsmoFactory)result;
309     }
310 
311 
312     /**
313      * Creates a DataFactory based on the supplied preferences.
314      * The properties map can contain the factories to be used as Strings or as
315      * instances. The DataFactory Constructor needs to check this and
316      * needs to create an instance of a given factory, if only the String
317      * is supplied.
318      * At least one preference should be supplied - the provider class
319      * @see #PROVIDER_CLASS
320      * @param properties the preferences for the Data factory. Such preferences
321      * should provide all the necessary information for the factory
322      * initialisation (e.g. provider class, etc.)
323      * @return a DataFactory
324      */
325     public static DataFactory createDataFactory(Map <String, Object> properties) {
326 
327         //preconditions
328         if (null == properties) {
329             properties = new HashMap <String, Object> ();
330         }
331 
332         //check provider
333         if (false == properties.containsKey(Factory.PROVIDER_CLASS)) {
334             //use default data factory
335             properties.put(Factory.PROVIDER_CLASS,
336                     defaultImplMap.getProperty(Factory.DATA_FACTORY));
337         }
338 
339         Object result = _createFactory(properties);
340 
341         assert null != result;
342 
343         //post-conditions
344         if (false == result instanceof DataFactory) {
345             throw new RuntimeException(properties.get(Factory.PROVIDER_CLASS) + " does not implement the org.wsmo.factory.DataFactory interface");
346         }
347 
348         return (DataFactory)result;
349     }
350 
351     /**
352      * Creates a LogicalExpressionFactory based on the supplied preferences.
353      * The properties map can contain the factories to be used as Strings or as
354      * instances. The LogicalExpressionFactory Constructor needs to check this and
355      * needs to create an instance of a given factory, if only the String
356      * is supplied.
357      * At least one preference should be supplied - the provider class
358      * @see #PROVIDER_CLASS
359      * @param properties the preferences for the LogicalExpression factory. Such preferences
360      * should provide all the necessary information for the factory
361      * initialisation (e.g. provider class, etc.)
362      * @return a LogicalExpressionFactory
363      */
364     public static LogicalExpressionFactory createLogicalExpressionFactory(Map <String, Object> properties) {
365         //preconditions
366         if (null == properties) {
367             properties = new HashMap <String, Object> ();
368         }
369 
370         //check provider
371         if (false == properties.containsKey(Factory.PROVIDER_CLASS)) {
372             //use default WSMO factory
373             properties.put(Factory.PROVIDER_CLASS,
374                     defaultImplMap.getProperty(Factory.LE_FACTORY));
375         }
376 
377         Object result = _createFactory(properties);
378 
379         assert null != result;
380 
381         //post-conditions
382         if (false == result instanceof LogicalExpressionFactory) {
383             throw new RuntimeException(properties.get(Factory.PROVIDER_CLASS) + " does not implement the org.wsmo.factory.LogicalExpressionFactory interface");
384         }
385 
386         return (LogicalExpressionFactory)result;
387     }
388     
389     /**
390      * Returns a LocatorManager. This LocatorManager is used to create a Locator, 
391      * which then can be added to / removed from the LocatorManager. The locator 
392      * is used to lookup wsmo entities based on their IRI. The default locator does 
393      * also accept a mapping from logical URIs to physical locations, that can be 
394      * used to locate ontologies:<br /><br />
395      *   prefs.put(Locator.URI_MAPPING, mapping);<br />
396      *   Locator locator = LocatorManager.createLocator(prefs); 	
397      * 
398      * @return a LocatorManager
399      * @see Locator
400      */
401     public static LocatorManager getLocatorManager() {
402     	return locManager;
403     }
404 
405     private static Object _createObject(Map properties) {
406 
407         Object result = null;
408 
409         //0. preconditions
410         assert properties != null;
411         assert properties.containsKey(Factory.PROVIDER_CLASS);
412 
413         String clazzName;
414         clazzName = (String)properties.get(Factory.PROVIDER_CLASS);
415         Class providerClass = null;
416 
417         try {
418             providerClass = Class.forName(clazzName);
419         }
420         catch (ClassNotFoundException e) {
421             try {
422                 providerClass = Class.forName(clazzName,
423                 							  true,
424                 							  Thread.currentThread().getContextClassLoader());
425             }
426             catch (ClassNotFoundException ne) {
427             	throw new RuntimeException("Provider's class not found in classpath..."+clazzName, ne);
428             }
429         }
430 
431         Constructor providerConstructor = null;
432 
433         try {
434             Class[] param = new Class[] {java.util.Map.class};
435             providerConstructor = providerClass.getConstructor(param);
436         }
437         catch (NoSuchMethodException nsme) {
438             throw new RuntimeException(
439                     "The provider class should have a constuctor which takes a single java.util.Map argument...",
440                     nsme);
441         }
442 
443         try {
444             result = providerConstructor.newInstance(new Object[] {properties});
445         }
446         catch (InvocationTargetException ite) {
447             throw new RuntimeException("cannot invoke the constructor a DataStore!", ite);
448         }
449         catch (IllegalAccessException ile) {
450             throw new RuntimeException("cannot access the constructor!", ile);
451         }
452         catch (InstantiationException inse) {
453             throw new RuntimeException("cannot instantiate a DataStore!", inse);
454         }
455 
456         return result;
457     }
458 
459 
460     private static Object _createFactory(Map <String, Object> properties) {
461 
462         //0. preconditions
463         assert properties != null;
464         assert properties.containsKey(Factory.PROVIDER_CLASS);
465 
466         Object result = null;
467 
468         if (Factory.cachingEnabled) {
469             //check cache
470             synchronized (Factory.objectCache) {
471 
472                 result = Factory.objectCache.get(properties);
473 
474                 if (null == result) {
475                     //NOT FOUND, create new instance and add to cache
476                     result = _createObject(properties);
477                     Factory.objectCache.put(new HashMap <String, Object> (properties), result);
478                 }
479             }
480         }
481         else {
482             //directly create a new instance
483             result = _createObject(properties);
484         }
485 
486         assert null != result;
487         return result;
488     }
489 
490 }
491 
492 /*
493  * $Log$
494  * Revision 1.31  2007/04/02 12:13:15  morcen
495  * Generics support added to wsmo-api, wsmo4j and wsmo-test
496  *
497  * Revision 1.30  2006/11/27 11:36:08  nathaliest
498  * changed the validator to not import ontologies on its own and added documentation how to use the default locator to import ontologies
499  *
500  * Revision 1.29  2006/02/13 02:19:54  haselwanter
501  * The resource loading of the properties file consulted only the context classloader, which a less likely place than the current classloader.
502  *
503  * Revision 1.28  2006/02/06 01:44:21  haselwanter
504  * Added a fallback to the metafactory to retrieve classes via the context classloader if the current classloader is unable to deliver. Fixes #1314733
505  *
506  * Revision 1.27  2006/01/31 09:18:39  nathaliest
507  * small change at documentation
508  *
509  * Revision 1.26  2006/01/11 13:01:17  marin_dimitrov
510  * common constants moved to Factory
511  *
512  * Revision 1.25  2006/01/09 14:18:43  nathaliest
513  * javadoc added
514  *
515  * Revision 1.24  2006/01/05 14:57:48  nathaliest
516  * Validator uses leFactory taken in constructor from properties map
517  *
518  * Revision 1.23  2005/11/18 14:36:28  nathaliest
519  * added Factory.createWsmlValidator(Map properties) method for creating the validator
520  *
521  * Revision 1.22  2005/09/23 07:09:50  holgerlausen
522  * moved constanttransformer from API to implementation, removed dublicated constants in logicalexpression.constants
523  *
524  * Revision 1.21  2005/09/16 12:31:13  marin_dimitrov
525  * DataFactory can now be created from the meta factory
526  *
527  * Revision 1.20  2005/09/16 12:07:05  marin_dimitrov
528  * wsmo4j.properties moved
529  *
530  * Revision 1.19  2005/09/15 13:04:12  alex_simov
531  * 'config.ini' renamed to 'wsmo4j.properties'
532  *
533  * Revision 1.18  2005/09/15 11:23:24  alex_simov
534  * Factory's implementations info fields extracted in an external config file
535  *
536  * Revision 1.17  2005/09/06 18:19:23  holgerlausen
537  * better error message
538  *
539  * Revision 1.16  2005/09/02 15:25:33  alex_simov
540  * default log.expr. factory class relocated
541  *
542  * Revision 1.15  2005/07/11 10:19:26  vassil_momtchev
543  * createLocator method moved to LocatarManager class
544  *
545  * Revision 1.14  2005/07/06 11:43:06  marin_dimitrov
546  * factory caching
547  *
548  * Revision 1.13  2005/07/06 10:56:36  marin_dimitrov
549  * static constructor
550  *
551  * Revision 1.12  2005/07/06 07:10:13  vassil_momtchev
552  * Locators now are managed by LocatorManager (attribute of the Factory)
553  *
554  * Revision 1.11  2005/06/30 12:37:00  alex_simov
555  * Implementation class split: WSMLParserImpl/WSMLSerializerImpl
556  *
557  * Revision 1.10  2005/06/30 12:24:23  alex_simov
558  * Rename: Serialiser -> Serializer
559  *
560  * Revision 1.9  2005/06/30 12:21:07  alex_simov
561  * Rename: Serialiser -> Serializer
562  *
563  * Revision 1.8  2005/06/30 09:56:46  marin_dimitrov
564  * createSerialiser added
565  *
566  * Revision 1.7  2005/06/30 09:32:55  alex_simov
567  * refactoring: org.wsmo.parser -> org.wsmo.wsml.*
568  *
569  * Revision 1.6  2005/06/27 14:09:32  alex_simov
570  * refactoring: *.io.locator -> *.locator
571  * refactoring: *.io.parser -> *.parser
572  * refactoring: *.io.datastore -> *.datastore
573  *
574  * Revision 1.5  2005/06/27 08:51:49  alex_simov
575  * refactoring: *.io.locator -> *.locator
576  * refactoring: *.io.parser -> *.parser
577  * refactoring: *.io.datastore -> *.datastore
578  *
579  * Revision 1.4  2005/06/22 14:40:48  alex_simov
580  * Copyright header added/updated
581  *
582  * Revision 1.3  2005/06/02 14:22:47  alex_simov
583  * Default parser implementation fix
584  *
585  * Revision 1.2  2005/06/01 16:39:11  marin_dimitrov
586  * Datastore --> DataStore
587  *
588  * Revision 1.1  2005/06/01 10:34:43  marin_dimitrov
589  * v0.4.0
590  *
591  * Revision 1.10  2005/05/31 14:42:00  damian
592  * detDefault was not implemented
593  *
594  * Revision 1.9  2005/05/31 13:13:16  damian
595  * get/setDefaultLocator added
596  *
597  * Revision 1.8  2005/05/19 12:53:54  marin
598  * fixed factory package
599  *
600  * Revision 1.7  2005/05/18 14:30:31  marin
601  * implementation + javadoc comments
602  *
603  */