View Javadoc

1   /*
2    ORDI - Ontology Repository and Data Integration
3   
4    Copyright (c) 2004-2007, 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  package com.ontotext.ordi;
19  
20  import java.io.InputStream;
21  import java.lang.reflect.Constructor;
22  import java.lang.reflect.InvocationTargetException;
23  import java.util.HashMap;
24  import java.util.Iterator;
25  import java.util.Map;
26  import java.util.Properties;
27  import java.util.WeakHashMap;
28  import java.util.Map.Entry;
29  
30  import org.apache.log4j.Logger;
31  
32  import com.ontotext.ordi.exception.ORDIRuntimeException;
33  import com.ontotext.ordi.tripleset.TSource;
34  
35  /**
36   * This class contains methods to instantiate instances of ORDI data model or
37   * domain specific models as WSMO4J layered on top of it.
38   * 
39   * Default settings are supported in the optional file "ordi.properties".
40   * 
41   * The class cannot be instantiated it has only static method.
42   * 
43   * @author vassil
44   * 
45   */
46  public final class Factory {
47  
48      public static final String ORDI_MODEL_DEAULT_PROPERTIES = "ordi.properties";
49      public static final String ORDI_MODEL_IMPLEMENTATION = TSource.class
50              .getName();
51      private static Properties defaultSettings = null;
52      private static Logger logger = Logger.getLogger(Factory.class);
53  
54      /**
55       * Creates a new instance of ORDI data model, based on the default settings.
56       * The class to instantiate is defined by ordi_model_implementation. All
57       * properties described in the file are supplied to the constructor of class
58       * to instantiate.
59       * 
60       * @return object to implement ORDI data model
61       */
62      public static TSource createDefaultTSource() {
63          return createTSource(mergeWithDefaultProperties(null));
64      }
65  
66      /**
67       * Creates a new instance of ORDI data model, based on the default and
68       * runtime settings. The runtime settings have higher priority than the
69       * default settings. The class to instantiate is defined by
70       * ordi_model_implementation. All properties described in the file are
71       * supplied to the constructor of class to instantiate.
72       * 
73       * @param map
74       *            runtime settings
75       * 
76       * @return object to implement ORDI data model
77       */
78      public static TSource createTSource(Map<Object, Object> map) {
79          map = mergeWithDefaultProperties(map);
80          if (logger.isInfoEnabled()) {
81              Iterator<Map.Entry<Object, Object>> iterator = map.entrySet()
82                      .iterator();
83              logger.info("Properties used by factory:");
84              while (iterator.hasNext()) {
85                  Entry<Object, Object> entry = iterator.next();
86                  logger.info(String.format("%s=%s", entry.getKey(), entry
87                          .getValue()));
88              }
89          }
90          if (map.containsKey(ORDI_MODEL_IMPLEMENTATION) == false) {
91              throw new ORDIRuntimeException(String.format(
92                      "Default properties do not specify %s key!",
93                      ORDI_MODEL_IMPLEMENTATION));
94          }
95          Object result = instantiateObject(map.get(ORDI_MODEL_IMPLEMENTATION)
96                  .toString(), map);
97          if (result instanceof TSource == false) {
98              throw new ORDIRuntimeException(
99                      String
100                             .format(
101                                     "The provided class %s do not implements TSource interface!",
102                                     map.get(ORDI_MODEL_IMPLEMENTATION)));
103         }
104         return (TSource) result;
105     }
106 
107     /**
108      * Creates a new instance of the supplied class type. This method is useful
109      * for creation of domain specific models layered on top of ORDI data model
110      * like wsmo4rdf. The method reuses also the configuration in the default
111      * settings.
112      * 
113      * @param type
114      *            is interface or class to be created
115      * @param map
116      *            is runtime configuration to be used
117      * @return instance of class type
118      */
119     @SuppressWarnings("unchecked")
120     public static <X> X create(Class<X> type, Map<Object, Object> map) {
121         map = mergeWithDefaultProperties(map);
122         if (logger.isInfoEnabled()) {
123             Iterator<Map.Entry<Object, Object>> iterator = map.entrySet()
124                     .iterator();
125             logger.info("Properties used by factory:");
126             while (iterator.hasNext()) {
127                 Entry<Object, Object> entry = iterator.next();
128                 logger.info(String.format("%s=%s", entry.getKey(), entry
129                         .getValue()));
130             }
131         }
132         Object typeName = map.get(type.getName());
133         if (typeName instanceof Class<?>) {
134             typeName = ((Class) typeName).getName();
135         } else if (typeName == null || typeName instanceof String == false) {
136             logger.info(String.format(
137                     "No implementation is specified for type %s", type
138                             .getName()));
139             typeName = type.getName();
140         }
141         return (X) instantiateObject((String) typeName, map);
142     }
143 
144     private static Map<String, WeakHashMap<String, Object>> instances =
145         new HashMap<String, WeakHashMap<String, Object>>();
146 
147     /**
148      * This method instantiate type to implements DataSource which has 1)
149      * default constructor OR 2) constructor to get Map.
150      * 
151      * @param typeName
152      *            is class to be instantiated
153      * @param map
154      *            is the parameters to be used
155      * @return
156      */
157     private synchronized static Object instantiateObject(String typeName,
158             Map<Object, Object> map) {
159         Object result = null;
160         Class<?> providerClass = null;
161         Constructor<?> providerConstructor = null;
162         String mapParameters = map.toString();
163 
164         // Check whether the requested implementation is already constructed
165         if (instances.containsKey(typeName)) {
166             WeakHashMap<String, Object> weak = instances.get(typeName);
167             result = weak.get(mapParameters);
168         }
169         if (result instanceof TSource && ((TSource) result).isShutdown() == false) {
170             return result;
171         }
172 
173         // Try to construct DataSource
174         try {
175             providerClass = Class.forName(typeName);
176         } catch (ClassNotFoundException e) {
177             try {
178                 providerClass = Class.forName(typeName, true, Thread
179                         .currentThread().getContextClassLoader());
180             } catch (ClassNotFoundException ne) {
181                 throw new ORDIRuntimeException(String.format(
182                         "Provider's class %s is not found in classpath!",
183                         typeName), ne);
184             }
185         }
186         Object[] contructorParams = new Object[] {
187                 new Class[] { java.util.Map.class }, new Class[0] };
188         try {
189             for (int i = 0; i < contructorParams.length; i++) {
190                 providerConstructor = providerClass
191                         .getConstructor((Class[]) contructorParams[i]);
192             }
193         } catch (NoSuchMethodException nsme) {
194         }
195         if (providerConstructor == null) {
196             throw new ORDIRuntimeException(
197                     String
198                             .format(
199                                     "Provider's class %s has no suitable constructor to invoke!",
200                                     typeName));
201         }
202         try {
203             result = providerConstructor.newInstance(new Object[] { map });
204         } catch (InvocationTargetException ite) {
205             throw new ORDIRuntimeException(String.format(
206                     "Cannot construct object of type %s! ", typeName), ite);
207         } catch (IllegalAccessException ile) {
208             throw new ORDIRuntimeException("Cannot access the constructor!",
209                     ile);
210         } catch (InstantiationException inse) {
211             throw new ORDIRuntimeException(String.format(
212                     "Cannot instantiate %s!", typeName), inse);
213         }
214 
215         // Register the object as constructed
216         WeakHashMap<String, Object> weak = instances.get(typeName);
217         if (weak == null) {
218             weak = new WeakHashMap<String, Object>();
219             instances.put(typeName, weak);
220         }
221         weak.put(mapParameters, result);
222 
223         return result;
224     }
225 
226     private synchronized static void loadDeaultProperties() {
227         if (defaultSettings != null) {
228             return;
229         }
230         defaultSettings = new Properties();
231         InputStream inProps = Thread.currentThread().getContextClassLoader()
232                 .getResourceAsStream(ORDI_MODEL_DEAULT_PROPERTIES);
233         if (inProps == null) {
234             inProps = Factory.class.getClassLoader().getResourceAsStream(
235                     ORDI_MODEL_DEAULT_PROPERTIES);
236         }
237         if (inProps == null) {
238             defaultSettings = new Properties();
239             return;
240         }
241         try {
242             defaultSettings.load(inProps);
243         } catch (Exception e) {
244             throw new ORDIRuntimeException(String.format(
245                     "The file %s could not be read or has invalid format!",
246                     ORDI_MODEL_DEAULT_PROPERTIES), e);
247         }
248     }
249 
250     private static Map<Object, Object> mergeWithDefaultProperties(
251             Map<Object, Object> map) {
252         loadDeaultProperties();
253         Map<Object, Object> result = new HashMap<Object, Object>();
254         Iterator<Map.Entry<Object, Object>> iteratorProp = defaultSettings
255                 .entrySet().iterator();
256         while (iteratorProp.hasNext()) {
257             Map.Entry<Object, Object> entry = iteratorProp.next();
258             result.put(entry.getKey().toString(), entry.getValue());
259         }
260         if (map != null) {
261             Iterator<Map.Entry<Object, Object>> iteratorMap = map.entrySet()
262                     .iterator();
263             while (iteratorMap.hasNext()) {
264                 Map.Entry<Object, Object> entry = iteratorMap.next();
265                 result.put(entry.getKey(), entry.getValue());
266             }
267         }
268         return result;
269     }
270 }