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.AsyncRequestProcessor;
22 import org.simantics.db.ReadGraph;
23 import org.simantics.db.RequestProcessor;
24 import org.simantics.db.Resource;
25 import org.simantics.db.Statement;
26 import org.simantics.db.WriteGraph;
27 import org.simantics.db.WriteOnlyGraph;
28 import org.simantics.db.common.request.DelayedWriteRequest;
29 import org.simantics.db.exception.AdaptionException;
30 import org.simantics.db.exception.BindingException;
31 import org.simantics.db.exception.CancelTransactionException;
32 import org.simantics.db.exception.DatabaseException;
33 import org.simantics.db.exception.DoesNotContainValueException;
34 import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;
35 import org.simantics.db.exception.NoInverseException;
36 import org.simantics.db.exception.NoSingleResultException;
37 import org.simantics.db.exception.ResourceNotFoundException;
38 import org.simantics.db.exception.RuntimeDatabaseException;
39 import org.simantics.db.exception.ServiceException;
40 import org.simantics.db.exception.ValidationException;
41 import org.simantics.db.procedure.Procedure;
42 import org.simantics.db.request.DelayedWrite;
43 import org.simantics.db.request.Read;
44 import org.simantics.db.request.Write;
47 * Synchronous Transaction. <p>
49 * Hint: Import all methods as static.
50 * import static org.simantics.db.Transaction.*;
52 * Remember also to change Eclipse Preferences:
53 * Organize Imports: number of static imports needed for .* on vakiona 99, siihen vaikka 3
58 * startTransaction(session, true);
71 * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
73 public class Transaction {
75 public static enum Type {
81 /** Thread local transactions */
82 private static ThreadLocal<TransactionInfo> transactions = new ThreadLocal<TransactionInfo>();
84 static private class TransactionInfo {
88 /** Semaphore that is released when the transaction is complete */
91 /** Semaphore that is release after transaction ended */
95 DatabaseException error;
98 boolean commit = false;
103 TransactionInfo(Object graph) {
104 if (graph instanceof WriteGraph) {
105 wg = (WriteGraph) graph;
106 rg = (ReadGraph) graph;
107 } else if (graph instanceof ReadGraph) {
109 rg = (ReadGraph) graph;
111 throw new RuntimeDatabaseException("Not a sync graph");
116 public static ReadGraph readGraph() {
117 TransactionInfo t = transactions.get();
118 return t == null ? null : t.rg;
121 public static WriteGraph writeGraph() {
122 TransactionInfo t = transactions.get();
123 return t == null ? null : t.wg;
126 public static Object setGraph(Object graph) {
128 transactions.set(null);
133 Object oldGraph = null;
134 TransactionInfo t = transactions.get();
137 if (graph instanceof WriteGraph) {
138 t.wg = (WriteGraph) graph;
139 t.rg = (ReadGraph) graph;
140 } else if (graph instanceof ReadGraph) {
142 t.rg = (ReadGraph) graph;
144 throw new RuntimeDatabaseException("Not a sync graph");
147 t = new TransactionInfo(graph);
154 public static void startTransaction(AsyncRequestProcessor processor, boolean write) throws DatabaseException {
155 startTransaction(processor, write ? Type.WRITE : Type.READ);
158 public static void startTransaction(AsyncRequestProcessor processor, Type type) throws DatabaseException {
162 if (transactions.get()!=null) throw new RuntimeDatabaseException("There is already a transaction.");
163 final Semaphore started = new Semaphore(0);
164 final TransactionInfo t = new TransactionInfo();
165 t.es = new Semaphore(0);
166 t.ts = new Semaphore(0);
169 Read<Object> request = new Read<Object>() {
171 public Object perform(ReadGraph g) throws DatabaseException {
177 } catch (InterruptedException e) {
182 Procedure<Object> procedure = new Procedure<Object>() {
184 public void execute(Object result) {
188 public void exception(Throwable ex) {
189 if (ex instanceof DatabaseException)
190 t.error = (DatabaseException) ex;
192 t.error = new DatabaseException(ex);
198 processor.asyncRequest(request, procedure);
200 // Wait until transaction has started
202 // Sleep this thread until transaction has started
204 } catch (InterruptedException e) {
205 throw new DatabaseException("Thread was interrupted.");
213 if (transactions.get()!=null) throw new RuntimeDatabaseException("There is already a transaction.");
214 final Semaphore started = new Semaphore(0);
215 final TransactionInfo t = new TransactionInfo();
216 t.es = new Semaphore(0);
217 t.ts = new Semaphore(0);
220 Consumer<DatabaseException> callback = parameter -> {
225 Write request = new Write() {
227 public void perform(WriteGraph g) throws DatabaseException {
233 } catch (InterruptedException e) {
235 if (!t.commit) throw new CancelTransactionException();
239 processor.asyncRequest( request, callback );
241 // Wait until transaction has started
243 // Sleep this thread until transaction has started
245 } catch (InterruptedException e) {
246 throw new DatabaseException("Thread was interrupted.");
254 if (transactions.get()!=null) throw new RuntimeDatabaseException("There is already a transaction.");
255 final Semaphore started = new Semaphore(0);
256 final TransactionInfo t = new TransactionInfo();
257 t.es = new Semaphore(0);
258 t.ts = new Semaphore(0);
261 Consumer<DatabaseException> callback = parameter -> {
266 DelayedWrite request = new DelayedWriteRequest() {
268 public void perform(WriteGraph g) throws DatabaseException {
274 } catch (InterruptedException e) {
276 if (!t.commit) throw new CancelTransactionException();
280 processor.asyncRequest( request, callback );
282 // Wait until transaction has started
284 // Sleep this thread until transaction has started
286 } catch (InterruptedException e) {
287 throw new DatabaseException("Thread was interrupted.");
296 * Commits transaction if no error occurred
298 * @throws DatabaseException
300 public static void endTransaction() throws DatabaseException {
301 TransactionInfo t = transactions.get();
302 if (t == null) return; //throw new RuntimeDatabaseException("There is no transaction to commit.");
308 } catch (InterruptedException e) {
309 throw new DatabaseException(e);
313 if (t.error instanceof CancelTransactionException==false) throw t.error;
315 transactions.set(null);
319 * Commits transaction
321 * @throws DatabaseException
323 public static void commit() throws DatabaseException {
324 TransactionInfo t = transactions.get();
325 if (t == null) throw new RuntimeDatabaseException("There is not transaction to commit.");
330 public static String getURI(Resource resource) throws ResourceNotFoundException, ValidationException, ServiceException {
331 return readGraph().getPossibleURI(resource);
334 public static String getPossibleURI(Resource resource) throws ResourceNotFoundException, ValidationException, ServiceException {
335 return readGraph().getPossibleURI(resource);
338 public static Resource getResource(String uri) throws ResourceNotFoundException, ValidationException, ServiceException
340 return readGraph().getResource(uri);
343 public static Resource getPossibleResource(String uri) throws ResourceNotFoundException, ValidationException, ServiceException
345 return readGraph().getPossibleResource(uri);
348 public static Resource getBuiltin(String id) throws ResourceNotFoundException, ServiceException
350 return readGraph().getBuiltin(id);
353 public static Collection<Statement> getStatements(Resource subject, Resource relation) throws ManyObjectsForFunctionalRelationException, ServiceException
355 return readGraph().getStatements(subject, relation);
358 public static Collection<Statement> getAssertedStatements(Resource subject, Resource relation) throws ManyObjectsForFunctionalRelationException, ServiceException
360 return readGraph().getAssertedStatements(subject, relation);
363 public static Collection<Resource> getPredicates(Resource subject) throws ServiceException
365 return readGraph().getPredicates(subject);
368 public static Collection<Resource> getPrincipalTypes(Resource subject) throws ServiceException
370 return readGraph().getPrincipalTypes(subject);
373 public static Set<Resource> getTypes(Resource subject) throws ServiceException
375 return readGraph().getTypes(subject);
378 public static Set<Resource> getSupertypes(Resource subject) throws ServiceException
380 return readGraph().getSupertypes(subject);
383 public static Set<Resource> getSuperrelations(Resource subject) throws ServiceException
385 return readGraph().getSuperrelations(subject);
388 public static Collection<Resource> getObjects(Resource subject, Resource relation) throws ManyObjectsForFunctionalRelationException, ServiceException
390 return readGraph().getObjects(subject, relation);
393 public static Collection<Resource> getAssertedObjects(Resource subject, Resource relation) throws ManyObjectsForFunctionalRelationException, ServiceException
395 return readGraph().getAssertedObjects(subject, relation);
398 public static Resource getInverse(Resource relation) throws NoInverseException, ManyObjectsForFunctionalRelationException, ServiceException
400 return readGraph().getInverse(relation);
403 public static Resource getSingleObject(Resource subject, Resource relation) throws NoSingleResultException, ManyObjectsForFunctionalRelationException, ServiceException
405 return readGraph().getSingleObject(subject, relation);
408 public static Statement getSingleStatement(Resource subject, Resource relation) throws NoSingleResultException, ManyObjectsForFunctionalRelationException, ServiceException
410 return readGraph().getSingleStatement(subject, relation);
413 public static Resource getSingleType(Resource subject) throws NoSingleResultException, ServiceException
415 return readGraph().getSingleType(subject);
418 public static Resource getSingleType(Resource subject, Resource baseType) throws NoSingleResultException, ServiceException
420 return readGraph().getSingleType(subject, baseType);
423 public static <T> T getValue(Resource subject) throws DoesNotContainValueException, ServiceException
425 return readGraph().<T>getValue(subject);
428 public static <T> T getValue(Resource subject, Binding binding) throws DoesNotContainValueException, BindingException, ServiceException
430 return readGraph().<T>getValue(subject, binding);
433 public static <T> T getRelatedValue(Resource subject, Resource relation) throws NoSingleResultException, DoesNotContainValueException, ServiceException
435 return readGraph().<T>getRelatedValue(subject, relation);
438 public static <T> T getRelatedValue(Resource subject, Resource relation, Binding binding) throws NoSingleResultException, DoesNotContainValueException, BindingException, ServiceException
440 return readGraph().<T>getRelatedValue(subject, relation, binding);
443 public static <T> T adapt(Resource resource, Class<T> clazz) throws AdaptionException, ValidationException, ServiceException
445 return readGraph().adapt(resource, clazz);
448 public static <T> T adaptUnique(Resource resource, Class<T> clazz) throws AdaptionException, ValidationException, ServiceException
450 return readGraph().adaptUnique(resource, clazz);
453 public static Resource getPossibleInverse(Resource relation) throws ManyObjectsForFunctionalRelationException, ServiceException
455 return readGraph().getPossibleInverse(relation);
458 public static Resource getPossibleObject(Resource subject, Resource relation) throws ManyObjectsForFunctionalRelationException, ServiceException
460 return readGraph().getPossibleObject(subject, relation);
463 public static Statement getPossibleStatement(Resource subject, Resource relation) throws ManyObjectsForFunctionalRelationException, ServiceException
465 return readGraph().getPossibleStatement(subject, relation);
468 public static Resource getPossibleType(Resource subject, Resource baseType) throws ServiceException
470 return readGraph().getPossibleType(subject, baseType);
473 public static <T> T getPossibleValue(Resource subject) throws ServiceException
475 return readGraph().<T>getPossibleValue(subject);
478 public static <T> T getPossibleValue(Resource subject, Binding binding) throws BindingException, ServiceException
480 return readGraph().<T>getPossibleValue(subject, binding);
483 public static <T> T getPossibleRelatedValue(Resource subject, Resource relation) throws ManyObjectsForFunctionalRelationException, ServiceException
485 return readGraph().<T>getPossibleRelatedValue(subject, relation);
488 public static <T> T getPossibleRelatedValue(Resource subject, Resource relation, Binding binding) throws ManyObjectsForFunctionalRelationException, BindingException, ServiceException
490 return readGraph().<T>getPossibleRelatedValue(subject, relation, binding);
493 public static <T> T getPossibleAdapter(Resource resource, Class<T> clazz) throws ValidationException, ServiceException
495 return readGraph().<T>getPossibleAdapter(resource, clazz);
498 public static <T> T getPossibleUniqueAdapter(Resource resource, Class<T> clazz) throws ValidationException, ServiceException
500 return readGraph().<T>getPossibleUniqueAdapter(resource, clazz);
503 public static boolean isInstanceOf(Resource resource, Resource type) throws ServiceException
505 return readGraph().isInstanceOf(resource, type);
508 public static boolean isInheritedFrom(Resource resource, Resource type) throws ServiceException
510 return readGraph().isInheritedFrom(resource, type);
513 public static boolean isSubrelationOf(Resource resource, Resource relation) throws ServiceException
515 return readGraph().isSubrelationOf(resource, relation);
518 public static boolean hasStatement(Resource subject) throws ServiceException
520 return readGraph().hasStatement(subject);
523 public static boolean hasStatement(Resource subject, Resource relation) throws ServiceException
525 return readGraph().hasStatement(subject, relation);
528 public static boolean hasStatement(Resource subject, Resource relation, Resource object) throws ServiceException
530 return readGraph().hasStatement(subject, relation, object);
533 public static boolean hasValue(Resource subject) throws ServiceException
535 return readGraph().hasValue(subject);
538 public static Datatype getDataType(Resource subject) throws DatabaseException
540 return readGraph().getDataType(subject);
543 public static <T extends Accessor> T getAccessor(Resource subject) throws DatabaseException
545 return readGraph().<T>getAccessor(subject);
550 * Makes sure that the statements (s,p,o) and (o,p',s) are found in the
551 * graph, where p' is the inverse predicate of p. Contrary to
552 * {@link WriteOnlyGraph#claim(Resource, Resource, Resource, Resource)} this
553 * method assures that the the statement and its inverse are semantically
554 * valid after the invocation of this method.
556 * @param subject subject, i.e. source resource of the statement to be
558 * @param predicate predicate resource of the statement to be claimed
559 * @param object object, i.e. target resource of the statement to be claimed
560 * @throws ServiceException
562 public static void claim(Resource subject, Resource predicate, Resource object) throws ServiceException {
563 writeGraph().claim(subject, predicate, object);
567 * Sets literal value related to the specified resource with the specified
568 * predicate. If such value exists (s,p), the value is overridden with the
569 * new specified value.
573 * @param value Value of the literal (boxed primitive/String or
574 * primitive/String array)
575 * @throws ManyObjectsForFunctionalRelationException
577 public static void claimValue(Resource resource, Resource predicate, Object value)
578 throws ManyObjectsForFunctionalRelationException, ServiceException, DatabaseException {
579 writeGraph().claimLiteral(resource, predicate, value);
581 public static void claimValue(Resource resource, Resource predicate, Object value, Binding binding)
582 throws BindingException, ManyObjectsForFunctionalRelationException, ServiceException, DatabaseException {
583 writeGraph().claimValue(resource, value, binding);
585 public static void claimValue(Resource resource, Resource predicate, Resource inverse, Resource type, Object value, Binding binding)
586 throws BindingException, ManyObjectsForFunctionalRelationException, ServiceException, DatabaseException {
587 writeGraph().claimLiteral(resource, predicate, inverse, type, value, binding);
591 * Makes sure that no statements matching the patterns (s,?p,?o) and
592 * (?o,?p',s), where ?p' is the inverse predicate of ?p, exist in the graph.
593 * In other words, removes all statements outgoing from the specified
594 * resource along with the inverses of those statements.
597 * @throws ServiceException
599 public static void deny(Resource subject) throws ServiceException {
600 writeGraph().deny(subject);
604 * Makes sure that no statements matching the patterns (s,p,?o) and
605 * (?o,p',s), where p' is the inverse predicate of p, exist in the graph.
606 * Also statements where <code>isSubrelationOf(p, predicate)</code> returns
607 * <code>true</code> shall be removed. In other words, removes all
608 * statements outgoing from the specified resource with the specified
609 * predicate or any of its subrelations, along with the inverses of those
613 * @throws ServiceException
615 public static void deny(Resource subject, Resource predicate) throws ServiceException {
616 writeGraph().deny(subject, predicate);
620 * Makes sure that no statements matching the patterns (s,p,o) and (o,p',s),
621 * where p' is the inverse predicate of p, exist in the graph. Contrary to
622 * {@link #denyStatement(Resource, Resource, Resource)}, all statements
623 * where <code>isSubrelationOf(p, predicate)</code> returns
624 * <code>true</code> shall be removed. In other words, removes all
625 * statements between the specified subject and object with the specified
626 * predicate or any of its subrelations, along with the inverses of those
632 * @throws ServiceException
634 public static void deny(Resource subject, Resource predicate, Resource object) throws ServiceException {
635 writeGraph().deny(subject, predicate, object);
639 * Makes sure that no statements matching the patterns (s,p,o) and (o,p',s),
640 * where p' is the inverse predicate of p, exist in the graph. In other
641 * words, removes the specified statement and its possible inverse.
644 * This method behaves exactly like {@link #deny(Statement)}, it just takes
645 * the arguments as resources instead of a statement.
648 * @throws ServiceException
650 * @see {@link #deny(Statement)}
652 public static void denyStatement(Resource subject, Resource predicate, Resource object) throws ServiceException {
653 writeGraph().denyStatement(subject, predicate, object);
657 * Makes sure that the specified statements (s,p,o) and its inverse
658 * statements (o,p',s), where p' is the inverse predicate of p, do not exist
662 * This method behaves exactly like
663 * {@link #denyStatement(Resource, Resource, Resource)}, it just takes the
664 * arguments as a statement instead of 3 resources.
668 * @see #denyStatement(Resource, Resource, Resource)
670 public static void deny(Statement statement) throws ServiceException {
671 writeGraph().deny(statement);
675 * Removes all statements (resource,predicate,?o) and literal contained by
680 * @throws ManyObjectsForFunctionalRelationException
682 public static void denyValue(Resource resource, Resource predicate) throws ManyObjectsForFunctionalRelationException, ServiceException {
683 writeGraph().denyValue(resource, predicate);