1 /*******************************************************************************
2 * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
9 * VTT Technical Research Centre of Finland - initial API and implementation
10 *******************************************************************************/
11 package org.simantics.db.common.utils;
13 import java.util.Collection;
15 import java.util.concurrent.Semaphore;
16 import java.util.function.Consumer;
18 import org.simantics.databoard.accessor.Accessor;
19 import org.simantics.databoard.binding.Binding;
20 import org.simantics.databoard.type.Datatype;
21 import org.simantics.db.ReadGraph;
22 import org.simantics.db.RequestProcessor;
23 import org.simantics.db.Resource;
24 import org.simantics.db.Statement;
25 import org.simantics.db.WriteGraph;
26 import org.simantics.db.WriteOnlyGraph;
27 import org.simantics.db.common.request.DelayedWriteRequest;
28 import org.simantics.db.exception.AdaptionException;
29 import org.simantics.db.exception.BindingException;
30 import org.simantics.db.exception.CancelTransactionException;
31 import org.simantics.db.exception.DatabaseException;
32 import org.simantics.db.exception.DoesNotContainValueException;
33 import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;
34 import org.simantics.db.exception.NoInverseException;
35 import org.simantics.db.exception.NoSingleResultException;
36 import org.simantics.db.exception.ResourceNotFoundException;
37 import org.simantics.db.exception.RuntimeDatabaseException;
38 import org.simantics.db.exception.ServiceException;
39 import org.simantics.db.exception.ValidationException;
40 import org.simantics.db.procedure.Procedure;
41 import org.simantics.db.request.DelayedWrite;
42 import org.simantics.db.request.Read;
43 import org.simantics.db.request.Write;
46 * Synchronous Transaction. <p>
48 * Hint: Import all methods as static.
49 * import static org.simantics.db.Transaction.*;
51 * Remember also to change Eclipse Preferences:
52 * Organize Imports: number of static imports needed for .* on vakiona 99, siihen vaikka 3
57 * startTransaction(session, true);
70 * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
72 public class Transaction {
74 public static enum Type {
80 /** Thread local transactions */
81 private static ThreadLocal<TransactionInfo> transactions = new ThreadLocal<TransactionInfo>();
83 static private class TransactionInfo {
87 /** Semaphore that is released when the transaction is complete */
90 /** Semaphore that is release after transaction ended */
94 DatabaseException error;
97 boolean commit = false;
102 TransactionInfo(Object graph) {
103 if (graph instanceof WriteGraph) {
104 wg = (WriteGraph) graph;
105 rg = (ReadGraph) graph;
106 } else if (graph instanceof ReadGraph) {
108 rg = (ReadGraph) graph;
110 throw new RuntimeDatabaseException("Not a sync graph");
115 public static ReadGraph readGraph() {
116 TransactionInfo t = transactions.get();
117 return t == null ? null : t.rg;
120 public static WriteGraph writeGraph() {
121 TransactionInfo t = transactions.get();
122 return t == null ? null : t.wg;
125 public static Object setGraph(Object graph) {
127 transactions.set(null);
132 Object oldGraph = null;
133 TransactionInfo t = transactions.get();
136 if (graph instanceof WriteGraph) {
137 t.wg = (WriteGraph) graph;
138 t.rg = (ReadGraph) graph;
139 } else if (graph instanceof ReadGraph) {
141 t.rg = (ReadGraph) graph;
143 throw new RuntimeDatabaseException("Not a sync graph");
146 t = new TransactionInfo(graph);
153 public static void startTransaction(RequestProcessor processor, boolean write) throws DatabaseException {
154 startTransaction(processor, write ? Type.WRITE : Type.READ);
157 public static void startTransaction(RequestProcessor processor, Type type) throws DatabaseException {
161 if (transactions.get()!=null) throw new RuntimeDatabaseException("There is already a transaction.");
162 final Semaphore started = new Semaphore(0);
163 final TransactionInfo t = new TransactionInfo();
164 t.es = new Semaphore(0);
165 t.ts = new Semaphore(0);
168 Read<Object> request = new Read<Object>() {
170 public Object perform(ReadGraph g) throws DatabaseException {
176 } catch (InterruptedException e) {
181 Procedure<Object> procedure = new Procedure<Object>() {
183 public void execute(Object result) {
187 public void exception(Throwable ex) {
188 if (ex instanceof DatabaseException)
189 t.error = (DatabaseException) ex;
191 t.error = new DatabaseException(ex);
197 processor.asyncRequest(request, procedure);
199 // Wait until transaction has started
201 // Sleep this thread until transaction has started
203 } catch (InterruptedException e) {
204 throw new DatabaseException("Thread was interrupted.");
212 if (transactions.get()!=null) throw new RuntimeDatabaseException("There is already a transaction.");
213 final Semaphore started = new Semaphore(0);
214 final TransactionInfo t = new TransactionInfo();
215 t.es = new Semaphore(0);
216 t.ts = new Semaphore(0);
219 Consumer<DatabaseException> callback = parameter -> {
224 Write request = new Write() {
226 public void perform(WriteGraph g) throws DatabaseException {
232 } catch (InterruptedException e) {
234 if (!t.commit) throw new CancelTransactionException();
238 processor.asyncRequest( request, callback );
240 // Wait until transaction has started
242 // Sleep this thread until transaction has started
244 } catch (InterruptedException e) {
245 throw new DatabaseException("Thread was interrupted.");
253 if (transactions.get()!=null) throw new RuntimeDatabaseException("There is already a transaction.");
254 final Semaphore started = new Semaphore(0);
255 final TransactionInfo t = new TransactionInfo();
256 t.es = new Semaphore(0);
257 t.ts = new Semaphore(0);
260 Consumer<DatabaseException> callback = parameter -> {
265 DelayedWrite request = new DelayedWriteRequest() {
267 public void perform(WriteGraph g) throws DatabaseException {
273 } catch (InterruptedException e) {
275 if (!t.commit) throw new CancelTransactionException();
279 processor.asyncRequest( request, callback );
281 // Wait until transaction has started
283 // Sleep this thread until transaction has started
285 } catch (InterruptedException e) {
286 throw new DatabaseException("Thread was interrupted.");
295 * Commits transaction if no error occurred
297 * @throws DatabaseException
299 public static void endTransaction() throws DatabaseException {
300 TransactionInfo t = transactions.get();
301 if (t == null) return; //throw new RuntimeDatabaseException("There is no transaction to commit.");
307 } catch (InterruptedException e) {
308 throw new DatabaseException(e);
312 if (t.error instanceof CancelTransactionException==false) throw t.error;
314 transactions.set(null);
318 * Commits transaction
320 * @throws DatabaseException
322 public static void commit() throws DatabaseException {
323 TransactionInfo t = transactions.get();
324 if (t == null) throw new RuntimeDatabaseException("There is not transaction to commit.");
329 public static String getURI(Resource resource) throws ResourceNotFoundException, ValidationException, ServiceException {
330 return readGraph().getPossibleURI(resource);
333 public static String getPossibleURI(Resource resource) throws ResourceNotFoundException, ValidationException, ServiceException {
334 return readGraph().getPossibleURI(resource);
337 public static Resource getResource(String uri) throws ResourceNotFoundException, ValidationException, ServiceException
339 return readGraph().getResource(uri);
342 public static Resource getPossibleResource(String uri) throws ResourceNotFoundException, ValidationException, ServiceException
344 return readGraph().getPossibleResource(uri);
347 public static Resource getBuiltin(String id) throws ResourceNotFoundException, ServiceException
349 return readGraph().getBuiltin(id);
352 public static Collection<Statement> getStatements(Resource subject, Resource relation) throws ManyObjectsForFunctionalRelationException, ServiceException
354 return readGraph().getStatements(subject, relation);
357 public static Collection<Statement> getAssertedStatements(Resource subject, Resource relation) throws ManyObjectsForFunctionalRelationException, ServiceException
359 return readGraph().getAssertedStatements(subject, relation);
362 public static Collection<Resource> getPredicates(Resource subject) throws ServiceException
364 return readGraph().getPredicates(subject);
367 public static Collection<Resource> getPrincipalTypes(Resource subject) throws ServiceException
369 return readGraph().getPrincipalTypes(subject);
372 public static Set<Resource> getTypes(Resource subject) throws ServiceException
374 return readGraph().getTypes(subject);
377 public static Set<Resource> getSupertypes(Resource subject) throws ServiceException
379 return readGraph().getSupertypes(subject);
382 public static Set<Resource> getSuperrelations(Resource subject) throws ServiceException
384 return readGraph().getSuperrelations(subject);
387 public static Collection<Resource> getObjects(Resource subject, Resource relation) throws ManyObjectsForFunctionalRelationException, ServiceException
389 return readGraph().getObjects(subject, relation);
392 public static Collection<Resource> getAssertedObjects(Resource subject, Resource relation) throws ManyObjectsForFunctionalRelationException, ServiceException
394 return readGraph().getAssertedObjects(subject, relation);
397 public static Resource getInverse(Resource relation) throws NoInverseException, ManyObjectsForFunctionalRelationException, ServiceException
399 return readGraph().getInverse(relation);
402 public static Resource getSingleObject(Resource subject, Resource relation) throws NoSingleResultException, ManyObjectsForFunctionalRelationException, ServiceException
404 return readGraph().getSingleObject(subject, relation);
407 public static Statement getSingleStatement(Resource subject, Resource relation) throws NoSingleResultException, ManyObjectsForFunctionalRelationException, ServiceException
409 return readGraph().getSingleStatement(subject, relation);
412 public static Resource getSingleType(Resource subject) throws NoSingleResultException, ServiceException
414 return readGraph().getSingleType(subject);
417 public static Resource getSingleType(Resource subject, Resource baseType) throws NoSingleResultException, ServiceException
419 return readGraph().getSingleType(subject, baseType);
422 public static <T> T getValue(Resource subject) throws DoesNotContainValueException, ServiceException
424 return readGraph().<T>getValue(subject);
427 public static <T> T getValue(Resource subject, Binding binding) throws DoesNotContainValueException, BindingException, ServiceException
429 return readGraph().<T>getValue(subject, binding);
432 public static <T> T getRelatedValue(Resource subject, Resource relation) throws NoSingleResultException, DoesNotContainValueException, ServiceException
434 return readGraph().<T>getRelatedValue(subject, relation);
437 public static <T> T getRelatedValue(Resource subject, Resource relation, Binding binding) throws NoSingleResultException, DoesNotContainValueException, BindingException, ServiceException
439 return readGraph().<T>getRelatedValue(subject, relation, binding);
442 public static <T> T adapt(Resource resource, Class<T> clazz) throws AdaptionException, ValidationException, ServiceException
444 return readGraph().adapt(resource, clazz);
447 public static <T> T adaptUnique(Resource resource, Class<T> clazz) throws AdaptionException, ValidationException, ServiceException
449 return readGraph().adaptUnique(resource, clazz);
452 public static Resource getPossibleInverse(Resource relation) throws ManyObjectsForFunctionalRelationException, ServiceException
454 return readGraph().getPossibleInverse(relation);
457 public static Resource getPossibleObject(Resource subject, Resource relation) throws ManyObjectsForFunctionalRelationException, ServiceException
459 return readGraph().getPossibleObject(subject, relation);
462 public static Statement getPossibleStatement(Resource subject, Resource relation) throws ManyObjectsForFunctionalRelationException, ServiceException
464 return readGraph().getPossibleStatement(subject, relation);
467 public static Resource getPossibleType(Resource subject, Resource baseType) throws ServiceException
469 return readGraph().getPossibleType(subject, baseType);
472 public static <T> T getPossibleValue(Resource subject) throws ServiceException
474 return readGraph().<T>getPossibleValue(subject);
477 public static <T> T getPossibleValue(Resource subject, Binding binding) throws BindingException, ServiceException
479 return readGraph().<T>getPossibleValue(subject, binding);
482 public static <T> T getPossibleRelatedValue(Resource subject, Resource relation) throws ManyObjectsForFunctionalRelationException, ServiceException
484 return readGraph().<T>getPossibleRelatedValue(subject, relation);
487 public static <T> T getPossibleRelatedValue(Resource subject, Resource relation, Binding binding) throws ManyObjectsForFunctionalRelationException, BindingException, ServiceException
489 return readGraph().<T>getPossibleRelatedValue(subject, relation, binding);
492 public static <T> T getPossibleAdapter(Resource resource, Class<T> clazz) throws ValidationException, ServiceException
494 return readGraph().<T>getPossibleAdapter(resource, clazz);
497 public static <T> T getPossibleUniqueAdapter(Resource resource, Class<T> clazz) throws ValidationException, ServiceException
499 return readGraph().<T>getPossibleUniqueAdapter(resource, clazz);
502 public static boolean isInstanceOf(Resource resource, Resource type) throws ServiceException
504 return readGraph().isInstanceOf(resource, type);
507 public static boolean isInheritedFrom(Resource resource, Resource type) throws ServiceException
509 return readGraph().isInheritedFrom(resource, type);
512 public static boolean isSubrelationOf(Resource resource, Resource relation) throws ServiceException
514 return readGraph().isSubrelationOf(resource, relation);
517 public static boolean hasStatement(Resource subject) throws ServiceException
519 return readGraph().hasStatement(subject);
522 public static boolean hasStatement(Resource subject, Resource relation) throws ServiceException
524 return readGraph().hasStatement(subject, relation);
527 public static boolean hasStatement(Resource subject, Resource relation, Resource object) throws ServiceException
529 return readGraph().hasStatement(subject, relation, object);
532 public static boolean hasValue(Resource subject) throws ServiceException
534 return readGraph().hasValue(subject);
537 public static Datatype getDataType(Resource subject) throws DatabaseException
539 return readGraph().getDataType(subject);
542 public static <T extends Accessor> T getAccessor(Resource subject) throws DatabaseException
544 return readGraph().<T>getAccessor(subject);
549 * Makes sure that the statements (s,p,o) and (o,p',s) are found in the
550 * graph, where p' is the inverse predicate of p. Contrary to
551 * {@link WriteOnlyGraph#claim(Resource, Resource, Resource, Resource)} this
552 * method assures that the the statement and its inverse are semantically
553 * valid after the invocation of this method.
555 * @param subject subject, i.e. source resource of the statement to be
557 * @param predicate predicate resource of the statement to be claimed
558 * @param object object, i.e. target resource of the statement to be claimed
559 * @throws ServiceException
561 public static void claim(Resource subject, Resource predicate, Resource object) throws ServiceException {
562 writeGraph().claim(subject, predicate, object);
566 * Sets literal value related to the specified resource with the specified
567 * predicate. If such value exists (s,p), the value is overridden with the
568 * new specified value.
572 * @param value Value of the literal (boxed primitive/String or
573 * primitive/String array)
574 * @throws ManyObjectsForFunctionalRelationException
576 public static void claimValue(Resource resource, Resource predicate, Object value)
577 throws ManyObjectsForFunctionalRelationException, ServiceException, DatabaseException {
578 writeGraph().claimLiteral(resource, predicate, value);
580 public static void claimValue(Resource resource, Resource predicate, Object value, Binding binding)
581 throws BindingException, ManyObjectsForFunctionalRelationException, ServiceException, DatabaseException {
582 writeGraph().claimValue(resource, value, binding);
584 public static void claimValue(Resource resource, Resource predicate, Resource inverse, Resource type, Object value, Binding binding)
585 throws BindingException, ManyObjectsForFunctionalRelationException, ServiceException, DatabaseException {
586 writeGraph().claimLiteral(resource, predicate, inverse, type, value, binding);
590 * Makes sure that no statements matching the patterns (s,?p,?o) and
591 * (?o,?p',s), where ?p' is the inverse predicate of ?p, exist in the graph.
592 * In other words, removes all statements outgoing from the specified
593 * resource along with the inverses of those statements.
596 * @throws ServiceException
598 public static void deny(Resource subject) throws ServiceException {
599 writeGraph().deny(subject);
603 * Makes sure that no statements matching the patterns (s,p,?o) and
604 * (?o,p',s), where p' is the inverse predicate of p, exist in the graph.
605 * Also statements where <code>isSubrelationOf(p, predicate)</code> returns
606 * <code>true</code> shall be removed. In other words, removes all
607 * statements outgoing from the specified resource with the specified
608 * predicate or any of its subrelations, along with the inverses of those
612 * @throws ServiceException
614 public static void deny(Resource subject, Resource predicate) throws ServiceException {
615 writeGraph().deny(subject, predicate);
619 * Makes sure that no statements matching the patterns (s,p,o) and (o,p',s),
620 * where p' is the inverse predicate of p, exist in the graph. Contrary to
621 * {@link #denyStatement(Resource, Resource, Resource)}, all statements
622 * where <code>isSubrelationOf(p, predicate)</code> returns
623 * <code>true</code> shall be removed. In other words, removes all
624 * statements between the specified subject and object with the specified
625 * predicate or any of its subrelations, along with the inverses of those
631 * @throws ServiceException
633 public static void deny(Resource subject, Resource predicate, Resource object) throws ServiceException {
634 writeGraph().deny(subject, predicate, object);
638 * Makes sure that no statements matching the patterns (s,p,o) and (o,p',s),
639 * where p' is the inverse predicate of p, exist in the graph. In other
640 * words, removes the specified statement and its possible inverse.
643 * This method behaves exactly like {@link #deny(Statement)}, it just takes
644 * the arguments as resources instead of a statement.
647 * @throws ServiceException
649 * @see {@link #deny(Statement)}
651 public static void denyStatement(Resource subject, Resource predicate, Resource object) throws ServiceException {
652 writeGraph().denyStatement(subject, predicate, object);
656 * Makes sure that the specified statements (s,p,o) and its inverse
657 * statements (o,p',s), where p' is the inverse predicate of p, do not exist
661 * This method behaves exactly like
662 * {@link #denyStatement(Resource, Resource, Resource)}, it just takes the
663 * arguments as a statement instead of 3 resources.
667 * @see #denyStatement(Resource, Resource, Resource)
669 public static void deny(Statement statement) throws ServiceException {
670 writeGraph().deny(statement);
674 * Removes all statements (resource,predicate,?o) and literal contained by
679 * @throws ManyObjectsForFunctionalRelationException
681 public static void denyValue(Resource resource, Resource predicate) throws ManyObjectsForFunctionalRelationException, ServiceException {
682 writeGraph().denyValue(resource, predicate);