View Javadoc

1   /*
2    * Copyright (c) 2007, James Leigh All rights reserved.
3    * 
4    * Redistribution and use in source and binary forms, with or without
5    * modification, are permitted provided that the following conditions are met:
6    * 
7    * - Redistributions of source code must retain the above copyright notice, this
8    *   list of conditions and the following disclaimer.
9    * - Redistributions in binary form must reproduce the above copyright notice,
10   *   this list of conditions and the following disclaimer in the documentation
11   *   and/or other materials provided with the distribution. 
12   * - Neither the name of the openrdf.org nor the names of its contributors may
13   *   be used to endorse or promote products derived from this software without
14   *   specific prior written permission.
15   * 
16   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26   * POSSIBILITY OF SUCH DAMAGE.
27   * 
28   */
29  package org.openrdf.elmo.sesame;
30  
31  import info.aduna.platform.Platform;
32  import info.aduna.platform.PlatformFactory;
33  
34  import java.io.File;
35  import java.io.IOException;
36  import java.lang.ref.WeakReference;
37  import java.net.URL;
38  import java.util.Locale;
39  import java.util.Map;
40  import java.util.WeakHashMap;
41  
42  import javax.persistence.EntityManagerFactory;
43  import javax.xml.namespace.QName;
44  
45  import org.openrdf.elmo.ElmoBehaviourFactory;
46  import org.openrdf.elmo.ElmoManagerFactory;
47  import org.openrdf.elmo.ElmoModule;
48  import org.openrdf.elmo.Entity;
49  import org.openrdf.elmo.LiteralManager;
50  import org.openrdf.elmo.RoleMapper;
51  import org.openrdf.elmo.dynacode.ClassFactory;
52  import org.openrdf.elmo.exceptions.ElmoIOException;
53  import org.openrdf.elmo.exceptions.ElmoInitializationException;
54  import org.openrdf.elmo.impl.ElmoEntityCompositor;
55  import org.openrdf.elmo.impl.ElmoMapperClassFactory;
56  import org.openrdf.elmo.impl.InstanceBehaviourFactory;
57  import org.openrdf.model.Literal;
58  import org.openrdf.model.Resource;
59  import org.openrdf.model.URI;
60  import org.openrdf.model.ValueFactory;
61  import org.openrdf.query.QueryLanguage;
62  import org.openrdf.repository.Repository;
63  import org.openrdf.repository.RepositoryException;
64  import org.openrdf.repository.config.RepositoryConfigException;
65  import org.openrdf.repository.contextaware.ContextAwareConnection;
66  import org.openrdf.repository.flushable.FlushableRepository;
67  import org.openrdf.repository.loader.LoaderRepository;
68  import org.openrdf.repository.loader.LoaderRepositoryFactory;
69  import org.openrdf.repository.sail.SailRepository;
70  import org.openrdf.rio.RDFParseException;
71  import org.openrdf.sail.memory.MemoryStore;
72  
73  /**
74   * Creates SesameBeanManagers.
75   * 
76   * @author James Leigh
77   * 
78   */
79  public class SesameManagerFactory implements ElmoManagerFactory, EntityManagerFactory {
80  	private static Map<ClassLoader, WeakReference<ClassFactory>> definers = new WeakHashMap<ClassLoader, WeakReference<ClassFactory>>();
81  
82  	private static Map<ClassLoader, WeakReference<ClassFactory>> inferencingDefiners = new WeakHashMap<ClassLoader, WeakReference<ClassFactory>>();
83  
84  	private boolean sharedDefiner = true;
85  
86  	private ClassFactory definer;
87  
88  	private ElmoEntityCompositor resolver;
89  
90  	private LoaderRepository repository;
91  
92  	private QName[] context;
93  
94  	private LiteralManager<URI, Literal> literalManager;
95  
96  	private QueryLanguage ql = QueryLanguage.SPARQL;
97  
98  	private boolean openned = true;
99  
100 	private boolean inferencing = false;
101 
102 	private ElmoMapperClassFactory propertyMapper;
103 
104 	private RoleMapper<URI> mapper;
105 
106 	private boolean shutDownRepositoryOnClose = false;
107 
108 	/**
109 	 * @deprecated Use {@link #SesameManagerFactory(ElmoModule,Repository)} instead
110 	 */
111 	@Deprecated
112 	public SesameManagerFactory(Repository repository) {
113 		this(new ElmoModule(), repository);
114 	}
115 
116 	public SesameManagerFactory(ElmoModule module) {
117 		try {
118 			Repository repository = new SailRepository(new MemoryStore());
119 			repository.initialize();
120 			shutDownRepositoryOnClose = true;
121 			setRepository(new LoaderRepository(repository));
122 			setElmoModule(module);
123 		} catch (RepositoryException e) {
124 			throw new ElmoInitializationException(e);
125 		}
126 	}
127 
128 	public SesameManagerFactory(ElmoModule module, Repository repository) {
129 		setRepository(new LoaderRepository(repository));
130 		if (module != null) {
131 			setElmoModule(module);
132 		} else {
133 			new NullPointerException("ElmoModule is null").printStackTrace();
134 		}
135 	}
136 
137 	public SesameManagerFactory(ElmoModule module, URL server, String repositoryId) {
138 		try {
139 			LoaderRepositoryFactory loader = new LoaderRepositoryFactory(server);
140 			LoaderRepository repository = loader.createRepository(repositoryId);
141 			shutDownRepositoryOnClose = true;
142 			setRepository(repository);
143 			setElmoModule(module);
144 		} catch (RepositoryConfigException e) {
145 			throw new ElmoInitializationException(e);
146 		} catch (RepositoryException e) {
147 			throw new ElmoInitializationException(e);
148 		}
149 	}
150 
151 	public SesameManagerFactory(ElmoModule module, File dataDir, String repositoryId) {
152 		try {
153 			LoaderRepositoryFactory loader = new LoaderRepositoryFactory(dataDir);
154 			LoaderRepository repository = loader.createRepository(repositoryId);
155 			shutDownRepositoryOnClose = true;
156 			setRepository(repository);
157 			setElmoModule(module);
158 		} catch (RepositoryConfigException e) {
159 			throw new ElmoInitializationException(e);
160 		} catch (RepositoryException e) {
161 			throw new ElmoInitializationException(e);
162 		}
163 	}
164 
165 	public SesameManagerFactory(ElmoModule module, String appId,
166 			String repositoryId) {
167 		this(module, getDataDir(appId), repositoryId);
168 	}
169 
170 	public Repository getRepository() {
171 		return repository;
172 	}
173 
174 	public QueryLanguage getQueryLanguage() {
175 		return ql;
176 	}
177 
178 	public void setQueryLanguage(QueryLanguage ql) {
179 		this.ql = ql;
180 	}
181 
182 	public void setInferencingEnabled(boolean enabled) {
183 		inferencing = enabled;
184 		if (enabled) {
185 			propertyMapper
186 					.setElmoPropertyFactoryClass(InferencingPropertyFactory.class);
187 		} else {
188 			propertyMapper
189 					.setElmoPropertyFactoryClass(SesamePropertyFactory.class);
190 		}
191 		if (sharedDefiner) {
192 			setClassDefiner(getSharedDefiner(definer.getParent()));
193 		} else {
194 			setClassDefiner(new ClassFactory(definer.getParent()));
195 		}
196 	}
197 
198 	public RoleMapper<URI> getRoleMapper() {
199 		return mapper;
200 	}
201 
202 	public LiteralManager<URI, Literal> getLiteralManager() {
203 		return literalManager;
204 	}
205 
206 	public boolean isOpen() {
207 		return openned;
208 	}
209 
210 	public void close() {
211 		try {
212 			if (shutDownRepositoryOnClose) {
213 				repository.shutDown();
214 			} else {
215 				repository.clearLoadedContexts();
216 			}
217 		} catch (RepositoryException e) {
218 			throw new ElmoIOException(e);
219 		}
220 		openned = false;
221 	}
222 
223 	public SesameManager createEntityManager() {
224 		return createElmoManager();
225 	}
226 
227 	public SesameManager createEntityManager(Map properties) {
228 		return createElmoManager();
229 	}
230 
231 	public SesameManager createElmoManager() {
232 		return createElmoManager(null);
233 	}
234 
235 	public SesameManager createElmoManager(Locale locale) {
236 		if (!openned)
237 			throw new IllegalStateException("SesameManagerFactory is closed");
238 		SesameResourceManager rolesManager;
239 		ContextAwareConnection conn;
240 		try {
241 			conn = new ContextAwareConnection(new FlushableRepository(repository));
242 			conn.setQueryLanguage(ql);
243 			rolesManager = new SesameResourceManager();
244 			rolesManager.setConnection(conn);
245 			rolesManager.setValueFactory(repository.getValueFactory());
246 			rolesManager.setRoleMapper(mapper);
247 			if (context != null && context.length > 0) {
248 				Resource[] resources = createResource(rolesManager, context);
249 				conn.setAddContexts(resources[0]);
250 				conn.setRemoveContexts(resources[0]);
251 				conn.setReadContexts(resources);
252 			}
253 		} catch (RepositoryException e) {
254 			throw new ElmoInitializationException(e);
255 		}
256 		SesameManager manager = new SesameManager();
257 		manager.setConnection(conn);
258 		manager.setLocale(locale);
259 		manager.setElmoClassResolver(resolver);
260 		manager.setLiteralManager(literalManager);
261 		manager.setRoleMapper(mapper);
262 		manager.setResourceManager(rolesManager);
263 		return manager;
264 	}
265 
266 	private static File getDataDir(String appId) {
267 		Platform platform = PlatformFactory.getPlatform();
268 		return platform.getApplicationDataDir(appId);
269 	}
270 
271 	private void setRepository(LoaderRepository repository) {
272 		ClassLoader cl = Thread.currentThread().getContextClassLoader();
273 		if (cl == null)
274 			cl = getClass().getClassLoader();
275 		this.repository = repository;
276 		ValueFactory vf = repository.getValueFactory();
277 		literalManager = new SesameLiteralManager(vf);
278 		propertyMapper = new ElmoMapperClassFactory();
279 		propertyMapper.setElmoPropertyFactoryClass(SesamePropertyFactory.class);
280 		resolver = new ElmoEntityCompositor();
281 		resolver.setBehaviourClassResolver(propertyMapper);
282 		resolver.addFactoryClass(InstanceBehaviourFactory.class);
283 		resolver.addFactoryClass(InstanceBehaviourFactory.class, Entity.class);
284 		setClassLoader(cl);
285 		if (sharedDefiner) {
286 			setClassDefiner(getSharedDefiner(cl));
287 		} else {
288 			setClassDefiner(new ClassFactory(cl));
289 		}
290 	}
291 
292 	private void setClassLoader(ClassLoader cl) {
293 		literalManager.setClassLoader(cl);
294 		ValueFactory vf = repository.getValueFactory();
295 		SesameRoleMapperFactory factory = new SesameRoleMapperFactory(vf);
296 		factory.setClassLoader(cl);
297 		mapper = factory.createRoleMapper();
298 		mapper.recordRole(SesameEntitySupport.class);
299 	}
300 
301 	private void setElmoModule(ElmoModule module) {
302 		for (ElmoModule.Association e : module.getLiterals()) {
303 			literalManager.recordType(e.getJavaClass(), e.getRdfType());
304 		}
305 		for (ElmoModule.Association e : module.getRoles()) {
306 			if (e.getRdfType() == null) {
307 				mapper.recordRole(e.getJavaClass());
308 			} else {
309 				mapper.recordRole(e.getJavaClass(), e.getRdfType());
310 			}
311 		}
312 		for (ElmoModule.Association e : module.getFactories()) {
313 			if (e.getRdfType() == null) {
314 				mapper.recordFactory(e.getJavaClass());
315 			} else {
316 				mapper.recordFactory(e.getJavaClass(), e.getRdfType());
317 			}
318 		}
319 		for (ElmoBehaviourFactory<?> f : module.getRecordedFactoryInstances()) {
320 			if (sharedDefiner) {
321 				sharedDefiner = false;
322 				setClassDefiner(new ClassFactory(definer.getParent()));
323 			}
324 			resolver.addBehaviourFactory(f);
325 		}
326 		if (module.getContext() != null) {
327 			context = new QName[1 + module.getContexts().size()];
328 			context[0] = module.getContext();
329 			for (int i=1; i<context.length; i++) {
330 				context[i] = module.getContexts().get(i-1);
331 			}
332 		}
333 		for (Map.Entry<URL, String> e : module.getDatasets().entrySet()) {
334 			loadContext(e.getKey(), e.getValue());
335 		}
336 		for (String path : module.getResources()) {
337 			loadResources(path);
338 		}
339 	}
340 
341 	private Resource[] createResource(SesameResourceManager rolesManager,
342 			QName... context) {
343 		Resource[] result = new Resource[context.length];
344 		for (int i = 0; i < result.length; i++) {
345 			result[i] = rolesManager.createResource(context[i]);
346 		}
347 		return result;
348 	}
349 
350 	private void loadResources(String path) throws ElmoInitializationException {
351 		try {
352 			repository.loadResources(path);
353 		} catch (RepositoryException e) {
354 			throw new ElmoInitializationException(e);
355 		} catch (RDFParseException e) {
356 			throw new ElmoInitializationException(e);
357 		} catch (IOException e) {
358 			throw new ElmoInitializationException(e);
359 		}
360 	}
361 
362 	private void loadContext(URL dataset, String context)
363 			throws ElmoInitializationException {
364 		try {
365 			ValueFactory vf = repository.getValueFactory();
366 			repository.loadContext(dataset, vf.createURI(context));
367 		} catch (RepositoryException e) {
368 			throw new ElmoInitializationException(e);
369 		} catch (RDFParseException e) {
370 			throw new ElmoInitializationException(e);
371 		} catch (IOException e) {
372 			throw new ElmoInitializationException(e);
373 		}
374 	}
375 
376 	private ClassFactory getSharedDefiner(ClassLoader cl) {
377 		ClassFactory definer = null;
378 		if (inferencing) {
379 			synchronized (inferencingDefiners) {
380 				WeakReference<ClassFactory> ref = inferencingDefiners.get(cl);
381 				if (ref != null) {
382 					definer = ref.get();
383 				}
384 				if (definer == null) {
385 					definer = new ClassFactory(cl);
386 					inferencingDefiners.put(cl,
387 							new WeakReference<ClassFactory>(definer));
388 				}
389 			}
390 		} else {
391 			synchronized (definers) {
392 				WeakReference<ClassFactory> ref = definers.get(cl);
393 				if (ref != null) {
394 					definer = ref.get();
395 				}
396 				if (definer == null) {
397 					definer = new ClassFactory(cl);
398 					definers.put(cl, new WeakReference<ClassFactory>(definer));
399 				}
400 			}
401 		}
402 		return definer;
403 	}
404 
405 	private void setClassDefiner(ClassFactory definer) {
406 		this.definer = definer;
407 		propertyMapper.setClassDefiner(definer);
408 		resolver.setClassDefiner(definer);
409 	}
410 }