1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 package org.openrdf.elmo.sesame;
30
31 import java.util.Collections;
32 import java.util.HashSet;
33 import java.util.Iterator;
34 import java.util.Locale;
35 import java.util.Set;
36
37 import javax.persistence.EntityManager;
38 import javax.persistence.EntityTransaction;
39 import javax.persistence.FlushModeType;
40 import javax.persistence.LockModeType;
41 import javax.persistence.Query;
42 import javax.persistence.TransactionRequiredException;
43 import javax.xml.namespace.QName;
44
45 import org.openrdf.elmo.ElmoEntityResolver;
46 import org.openrdf.elmo.ElmoManager;
47 import org.openrdf.elmo.Entity;
48 import org.openrdf.elmo.LiteralManager;
49 import org.openrdf.elmo.Memento;
50 import org.openrdf.elmo.Mergeable;
51 import org.openrdf.elmo.Refreshable;
52 import org.openrdf.elmo.ResourceManager;
53 import org.openrdf.elmo.RoleMapper;
54 import org.openrdf.elmo.exceptions.ElmoCompositionException;
55 import org.openrdf.elmo.exceptions.ElmoIOException;
56 import org.openrdf.elmo.exceptions.ElmoMementoException;
57 import org.openrdf.elmo.exceptions.ElmoPersistException;
58 import org.openrdf.elmo.sesame.iterators.ElmoIteration;
59 import org.openrdf.elmo.sesame.roles.SesameEntity;
60 import org.openrdf.elmo.sesame.roles.SesameManagerAware;
61 import org.openrdf.model.Literal;
62 import org.openrdf.model.Resource;
63 import org.openrdf.model.URI;
64 import org.openrdf.model.Value;
65 import org.openrdf.query.MalformedQueryException;
66 import org.openrdf.query.QueryLanguage;
67 import org.openrdf.query.TupleQuery;
68 import org.openrdf.repository.DelegatingRepositoryConnection;
69 import org.openrdf.repository.RepositoryConnection;
70 import org.openrdf.repository.RepositoryException;
71 import org.openrdf.repository.contextaware.ContextAwareConnection;
72 import org.openrdf.repository.flushable.FlushableConnection;
73 import org.slf4j.Logger;
74 import org.slf4j.LoggerFactory;
75
76
77
78
79
80
81
82 public class SesameManager implements ElmoManager, EntityManager {
83
84 final Logger logger = LoggerFactory.getLogger(SesameManager.class);
85
86 private ContextAwareConnection conn;
87
88 private SesameTransaction trans;
89
90 private Locale locale;
91
92 private String language;
93
94 private ResourceManager<Resource> resources;
95
96 private LiteralManager<URI, Literal> lm;
97
98 private ElmoEntityResolver resolver;
99
100 private RoleMapper<URI> mapper;
101
102 public ContextAwareConnection getConnection() {
103 if (!isOpen())
104 throw new IllegalStateException("Connection has been closed");
105 return conn;
106 }
107
108 public void setConnection(ContextAwareConnection connection) {
109 this.conn = connection;
110 this.trans = new SesameTransaction(conn);
111 }
112
113 public EntityTransaction getTransaction() {
114 return trans;
115 }
116
117 public void joinTransaction() {
118 if (!isOpen())
119 throw new TransactionRequiredException();
120 }
121
122 public Locale getLocale() {
123 return locale;
124 }
125
126 public void setLocale(Locale locale) {
127 this.locale = locale;
128 if (locale != null) {
129 String lang = locale.toString().replace('_', '-');
130 language = lang.toLowerCase();
131 }
132 }
133
134 public String getLanguage() {
135 return language;
136 }
137
138 public void setResourceManager(ResourceManager<Resource> manager) {
139 this.resources = manager;
140 }
141
142 public void setLiteralManager(LiteralManager<URI, Literal> manager) {
143 this.lm = manager;
144 }
145
146 public void setElmoClassResolver(ElmoEntityResolver resolver) {
147 this.resolver = resolver;
148 }
149
150 public void setRoleMapper(RoleMapper<URI> mapper) {
151 this.mapper = mapper;
152 }
153
154 public boolean isOpen() {
155 try {
156 return conn != null && conn.isOpen();
157 } catch (RepositoryException e) {
158 throw new ElmoIOException(e);
159 }
160 }
161
162 public void close() {
163 try {
164 if (conn != null && !trans.isActive())
165 conn.close();
166 conn = null;
167 } catch (RepositoryException e) {
168 throw new ElmoPersistException(e);
169 }
170 }
171
172 public void flush() {
173 try {
174 FlushableConnection flusher;
175 flusher = findFlushableConnection(getConnection());
176 if (flusher != null) {
177 flusher.flush();
178 }
179 } catch (RepositoryException e) {
180 throw new ElmoPersistException(e);
181 }
182 }
183
184 public void clear() {
185 try {
186 FlushableConnection flusher;
187 flusher = findFlushableConnection(getConnection());
188 if (flusher != null) {
189 flusher.clear();
190 }
191 } catch (RepositoryException e) {
192 throw new ElmoPersistException(e);
193 }
194 }
195
196 public FlushModeType getFlushMode() {
197 try {
198 FlushableConnection flusher;
199 flusher = findFlushableConnection(getConnection());
200 if (flusher == null || flusher.isAutoFlush())
201 return FlushModeType.AUTO;
202 return FlushModeType.COMMIT;
203 } catch (RepositoryException e) {
204 throw new ElmoIOException(e);
205 }
206 }
207
208 public void setFlushMode(FlushModeType mode) {
209 try {
210 FlushableConnection flusher;
211 flusher = findFlushableConnection(getConnection());
212 if (flusher != null) {
213 flusher.setAutoFlush(mode.equals(FlushModeType.AUTO));
214 }
215 } catch (RepositoryException e) {
216 throw new ElmoPersistException(e);
217 }
218 }
219
220 public Object getDelegate() {
221 return this;
222 }
223
224 public Memento createMemento() {
225 try {
226 return new SesameMemento(getConnection());
227 } catch (RepositoryException e) {
228 throw new ElmoMementoException(e);
229 } catch (IllegalArgumentException e) {
230 throw new UnsupportedOperationException(e);
231 }
232 }
233
234 public void undoMemento(Memento memento) {
235 if (!(memento instanceof SesameMemento))
236 throw new IllegalArgumentException();
237 SesameMemento m = (SesameMemento) memento;
238 try {
239 m.undo(getConnection());
240 } catch (RepositoryException e) {
241 throw new ElmoMementoException(e);
242 }
243 }
244
245 public void redoMemento(Memento memento) {
246 if (!(memento instanceof SesameMemento))
247 throw new IllegalArgumentException();
248 SesameMemento m = (SesameMemento) memento;
249 try {
250 m.redo(getConnection());
251 } catch (RepositoryException e) {
252 throw new ElmoMementoException(e);
253 }
254 }
255
256 public Object getInstance(Value value) {
257 if (value instanceof Resource) {
258 SesameEntity bean = this.find((Resource) value);
259 if (logger.isDebugEnabled()) {
260 try {
261 if (!getConnection().hasStatement((Resource) value, null,
262 null))
263 logger.debug("Warning: Unknown entity: " + value);
264 } catch (RepositoryException e) {
265 throw new ElmoIOException(e);
266 }
267 }
268 return bean;
269 }
270 return lm.getObject((Literal) value);
271 }
272
273 public Value getValue(Object instance) {
274 if (instance instanceof SesameEntity) {
275 return ((SesameEntity) instance).getSesameResource();
276 } else if (instance instanceof Entity) {
277 return getValue(merge(instance));
278 }
279 Class<?> type = instance.getClass();
280 if (lm.isTypeOfLiteral(type))
281 return lm.getLiteral(instance);
282
283 Class<?>[] interfaces = type.getInterfaces();
284 if (interfaces.length > 0) {
285 for (Class<?> face : interfaces) {
286 if (mapper.findType(face) != null)
287 return getValue(merge(instance));
288 }
289 }
290
291 return lm.getLiteral(instance);
292 }
293
294 public Value getLocalizedValue(Object instance) {
295 return lm.getLiteral(instance.toString(), language);
296 }
297
298 public boolean contains(Object entity) {
299 if (entity instanceof SesameEntity) {
300 SesameEntity se = (SesameEntity) entity;
301 return this.equals(se.getSesameManager());
302 }
303 return false;
304 }
305
306
307
308
309 public <T> T create(Class<T> concept) {
310 return designate(concept);
311 }
312
313
314
315
316 public <T> T create(Class<T> concept, QName qname) {
317 return designate(concept, qname);
318 }
319
320
321
322
323 @SuppressWarnings("unchecked")
324 public <T> T create(Resource resource, Class<T> concept) {
325 return designate(resource, concept);
326 }
327
328 public <T> T designate(Class<T> concept) {
329 Resource resource = resources.createResource(null);
330 return designate(resource, concept);
331 }
332
333 public <T> T designate(Class<T> concept, QName qname) {
334 Resource resource = resources.createResource(qname);
335 return designate(resource, concept);
336 }
337
338 @SuppressWarnings("unchecked")
339 public <T> T designate(Resource resource, Class<T> concept) {
340 Class[] roles = resources.mergeRole(resource, concept);
341 Entity bean = createBean(resource, roles);
342 assert !concept.isInterface()
343 || concept.isAssignableFrom(bean.getClass()) : "Concept has not bean recorded: "
344 + concept.getSimpleName();
345 return (T) bean;
346 }
347
348 public <T> T designateEntity(Class<T> concept, Object entity) {
349 assert entity instanceof SesameEntity : entity;
350 Resource resource = ((SesameEntity) entity).getSesameResource();
351 return designate(resource, concept);
352 }
353
354 public Entity removeDesignation(Class<?> concept, Object entity) {
355 assert entity instanceof SesameEntity : entity;
356 Resource resource = ((SesameEntity) entity).getSesameResource();
357 Class[] roles = resources.removeRole(resource, concept);
358 return createBean(resource, roles);
359 }
360
361 public <T> T rename(T bean, QName qname) {
362 Resource after = resources.createResource(qname);
363 return rename(bean, after);
364 }
365
366 @SuppressWarnings("unchecked")
367 public <T> T rename(T bean, Resource destination) {
368 assert bean instanceof SesameEntity;
369 Resource before = ((SesameEntity) bean).getSesameResource();
370 Class[] roles = resources.getRoles(before);
371 resources.renameResource(before, destination);
372 return (T) createBean(destination, roles);
373 }
374
375 public SesameEntity find(QName qname) {
376 return find(resources.createResource(qname));
377 }
378
379 public QName getSesameBeanQName(SesameEntity bean) {
380 Resource resource = bean.getSesameResource();
381 return resources.createQName(resource);
382 }
383
384 public SesameEntity find(Resource resource) {
385 Class<?>[] roles = resources.getRoles(resource);
386 return createBean(resource, roles);
387 }
388
389 public <T> T find(Class<T> concept, Object qname) {
390 assert qname instanceof QName : qname;
391 SesameEntity entity = find((QName) qname);
392 if (concept.isInstance(entity))
393 return concept.cast(entity);
394 return null;
395 }
396
397 public <T> T getReference(Class<T> concept, Object qname) {
398 return find(concept, qname);
399 }
400
401 public void refresh(Object entity) {
402 if (entity instanceof Refreshable) {
403 ((Refreshable) entity).refresh();
404 }
405 }
406
407 public <T> T merge(T bean) {
408 Object result;
409 if (bean instanceof Entity) {
410 Entity eb = (Entity) bean;
411 QName name = eb.getQName();
412 result = designate(bean.getClass(), name);
413 } else {
414 result = designate(bean.getClass());
415 }
416 assert result instanceof Mergeable;
417 ((Mergeable) result).merge(bean);
418 return (T) result;
419 }
420
421 public void persist(Object bean) {
422 merge(bean);
423 }
424
425 public SesameQuery createQuery(String query) {
426 try {
427 TupleQuery qry = getConnection().prepareTupleQueryWithinContext(
428 query);
429 return new SesameQuery(this, qry);
430 } catch (MalformedQueryException e) {
431 throw new ElmoIOException(e);
432 } catch (RepositoryException e) {
433 throw new ElmoIOException(e);
434 }
435 }
436
437 public SesameQuery createNativeQuery(String serql) {
438 try {
439 TupleQuery qry = getConnection().prepareTupleQueryWithinContext(
440 QueryLanguage.SERQL, serql, "");
441 return new SesameQuery(this, qry);
442 } catch (MalformedQueryException e) {
443 throw new ElmoIOException(e);
444 } catch (RepositoryException e) {
445 throw new ElmoIOException(e);
446 }
447 }
448
449 public SesameQuery createNativeQuery(String serql, Class concept) {
450 try {
451 TupleQuery qry = getConnection().prepareTupleQueryWithinContext(
452 QueryLanguage.SERQL, serql, "");
453 return new SesameQuery(this, qry);
454 } catch (MalformedQueryException e) {
455 throw new ElmoIOException(e);
456 } catch (RepositoryException e) {
457 throw new ElmoIOException(e);
458 }
459 }
460
461 public SesameQuery createNativeQuery(String serql, String nil) {
462 try {
463 TupleQuery qry = getConnection().prepareTupleQueryWithinContext(
464 QueryLanguage.SERQL, serql, "");
465 return new SesameQuery(this, qry);
466 } catch (MalformedQueryException e) {
467 throw new ElmoIOException(e);
468 } catch (RepositoryException e) {
469 throw new ElmoIOException(e);
470 }
471 }
472
473 public Query createNamedQuery(String name) {
474 throw new UnsupportedOperationException(
475 "Named queries are not supported");
476 }
477
478 public <T> Set<T> findAll(final Class<T> javaClass) {
479 Set<T> set = new HashSet<T>();
480 Iterator<Resource> iter = resources.createRoleQuery(javaClass);
481 try {
482 for (int count = 0; iter.hasNext(); count++) {
483 set.add(javaClass.cast(find(iter.next())));
484 }
485 return Collections.unmodifiableSet(set);
486 } finally {
487 ElmoIteration.close(iter);
488 }
489 }
490
491 public void remove(Object entity) {
492 assert entity instanceof SesameEntity : entity;
493 Resource resource = ((SesameEntity) entity).getSesameResource();
494 resources.removeResource(resource);
495 }
496
497 Value createResource(QName qname) {
498 return resources.createResource(qname);
499 }
500
501 private SesameEntity createBean(Resource resource, Class<?>[] roles) {
502 Class<?> type = resolver.resolveRoles(roles);
503 try {
504 Object obj = type.newInstance();
505 assert obj instanceof SesameManagerAware : "core roles are not registered, check your deployed classpath";
506 SesameManagerAware bean = (SesameManagerAware) obj;
507 bean.initSesameManager(this);
508 bean.initSesameResource(resource);
509 return bean;
510 } catch (InstantiationException e) {
511 throw new ElmoCompositionException(e);
512 } catch (IllegalAccessException e) {
513 throw new ElmoCompositionException(e);
514 }
515 }
516
517 private FlushableConnection findFlushableConnection(
518 RepositoryConnection conn) throws RepositoryException {
519 if (conn instanceof FlushableConnection)
520 return (FlushableConnection) conn;
521 if (conn instanceof DelegatingRepositoryConnection) {
522 DelegatingRepositoryConnection dconn = (DelegatingRepositoryConnection) conn;
523 return findFlushableConnection((dconn).getDelegate());
524 }
525 return null;
526 }
527
528 public void lock(Object entity, LockModeType mode) {
529 throw new UnsupportedOperationException("locking is not supported");
530 }
531
532 }