1 /*******************************************************************************
\r
2 * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.
\r
3 * All rights reserved. This program and the accompanying materials
\r
4 * are made available under the terms of the Eclipse Public License v1.0
\r
5 * which accompanies this distribution, and is available at
\r
6 * http://www.eclipse.org/legal/epl-v10.html
\r
9 * VTT Technical Research Centre of Finland - initial API and implementation
\r
10 *******************************************************************************/
\r
11 package org.simantics.db.common.utils;
\r
13 import java.util.Collection;
\r
14 import java.util.Set;
\r
15 import java.util.concurrent.Semaphore;
\r
17 import org.simantics.databoard.accessor.Accessor;
\r
18 import org.simantics.databoard.binding.Binding;
\r
19 import org.simantics.databoard.type.Datatype;
\r
20 import org.simantics.db.ReadGraph;
\r
21 import org.simantics.db.RequestProcessor;
\r
22 import org.simantics.db.Resource;
\r
23 import org.simantics.db.Statement;
\r
24 import org.simantics.db.VirtualGraph;
\r
25 import org.simantics.db.WriteGraph;
\r
26 import org.simantics.db.WriteOnlyGraph;
\r
27 import org.simantics.db.common.request.DelayedWriteRequest;
\r
28 import org.simantics.db.exception.AdaptionException;
\r
29 import org.simantics.db.exception.BindingException;
\r
30 import org.simantics.db.exception.CancelTransactionException;
\r
31 import org.simantics.db.exception.DatabaseException;
\r
32 import org.simantics.db.exception.DoesNotContainValueException;
\r
33 import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;
\r
34 import org.simantics.db.exception.NoInverseException;
\r
35 import org.simantics.db.exception.NoSingleResultException;
\r
36 import org.simantics.db.exception.ResourceNotFoundException;
\r
37 import org.simantics.db.exception.RuntimeDatabaseException;
\r
38 import org.simantics.db.exception.ServiceException;
\r
39 import org.simantics.db.exception.ValidationException;
\r
40 import org.simantics.db.procedure.Procedure;
\r
41 import org.simantics.db.request.DelayedWrite;
\r
42 import org.simantics.db.request.Read;
\r
43 import org.simantics.db.request.UndoTraits;
\r
44 import org.simantics.db.request.Write;
\r
45 import org.simantics.utils.datastructures.Callback;
\r
48 * Synchronous Transaction. <p>
\r
50 * Hint: Import all methods as static.
\r
51 * import static org.simantics.db.Transaction.*;
\r
53 * Remember also to change Eclipse Preferences:
\r
54 * Organize Imports: number of static imports needed for .* on vakiona 99, siihen vaikka 3
\r
59 * startTransaction(session, true);
\r
72 * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
\r
74 public class Transaction {
\r
76 public static enum Type {
\r
82 /** Thread local transactions */
\r
83 private static ThreadLocal<TransactionInfo> transactions = new ThreadLocal<TransactionInfo>();
\r
85 static private class TransactionInfo {
\r
89 /** Semaphore that is released when the transaction is complete */
\r
92 /** Semaphore that is release after transaction ended */
\r
96 DatabaseException error;
\r
99 boolean commit = false;
\r
101 TransactionInfo() {
\r
104 TransactionInfo(Object graph) {
\r
105 if (graph instanceof WriteGraph) {
\r
106 wg = (WriteGraph) graph;
\r
107 rg = (ReadGraph) graph;
\r
108 } else if (graph instanceof ReadGraph) {
\r
110 rg = (ReadGraph) graph;
\r
112 throw new RuntimeDatabaseException("Not a sync graph");
\r
117 public static ReadGraph readGraph() {
\r
118 TransactionInfo t = transactions.get();
\r
119 return t == null ? null : t.rg;
\r
122 public static WriteGraph writeGraph() {
\r
123 TransactionInfo t = transactions.get();
\r
124 return t == null ? null : t.wg;
\r
127 public static Object setGraph(Object graph) {
\r
129 transactions.set(null);
\r
134 Object oldGraph = null;
\r
135 TransactionInfo t = transactions.get();
\r
138 if (graph instanceof WriteGraph) {
\r
139 t.wg = (WriteGraph) graph;
\r
140 t.rg = (ReadGraph) graph;
\r
141 } else if (graph instanceof ReadGraph) {
\r
143 t.rg = (ReadGraph) graph;
\r
145 throw new RuntimeDatabaseException("Not a sync graph");
\r
148 t = new TransactionInfo(graph);
\r
150 transactions.set(t);
\r
155 public static void startTransaction(RequestProcessor processor, boolean write) throws DatabaseException {
\r
156 startTransaction(processor, write ? Type.WRITE : Type.READ);
\r
159 public static void startTransaction(RequestProcessor processor, Type type) throws DatabaseException {
\r
163 if (transactions.get()!=null) throw new RuntimeDatabaseException("There is already a transaction.");
\r
164 final Semaphore started = new Semaphore(0);
\r
165 final TransactionInfo t = new TransactionInfo();
\r
166 t.es = new Semaphore(0);
\r
167 t.ts = new Semaphore(0);
\r
168 transactions.set(t);
\r
170 Read<Object> request = new Read<Object>() {
\r
172 public Object perform(ReadGraph g) throws DatabaseException {
\r
178 } catch (InterruptedException e) {
\r
183 Procedure<Object> procedure = new Procedure<Object>() {
\r
185 public void execute(Object result) {
\r
186 t.es.release(9999);
\r
189 public void exception(Throwable ex) {
\r
190 if (ex instanceof DatabaseException)
\r
191 t.error = (DatabaseException) ex;
\r
193 t.error = new DatabaseException(ex);
\r
195 t.es.release(9999);
\r
199 processor.asyncRequest(request, procedure);
\r
201 // Wait until transaction has started
\r
203 // Sleep this thread until transaction has started
\r
204 started.acquire(1);
\r
205 } catch (InterruptedException e) {
\r
206 throw new DatabaseException("Thread was interrupted.");
\r
214 if (transactions.get()!=null) throw new RuntimeDatabaseException("There is already a transaction.");
\r
215 final Semaphore started = new Semaphore(0);
\r
216 final TransactionInfo t = new TransactionInfo();
\r
217 t.es = new Semaphore(0);
\r
218 t.ts = new Semaphore(0);
\r
219 transactions.set(t);
\r
221 Callback<DatabaseException> callback = new Callback<DatabaseException>() {
\r
223 public void run(DatabaseException parameter) {
\r
224 t.error = parameter;
\r
225 t.es.release(9999);
\r
229 Write request = new Write() {
\r
231 public void perform(WriteGraph g) throws DatabaseException {
\r
237 } catch (InterruptedException e) {
\r
239 if (!t.commit) throw new CancelTransactionException();
\r
242 public UndoTraits getUndoTraits() {
\r
246 public VirtualGraph getProvider() {
\r
251 processor.asyncRequest( request, callback );
\r
253 // Wait until transaction has started
\r
255 // Sleep this thread until transaction has started
\r
256 started.acquire(1);
\r
257 } catch (InterruptedException e) {
\r
258 throw new DatabaseException("Thread was interrupted.");
\r
264 case DELAYED_WRITE:
\r
266 if (transactions.get()!=null) throw new RuntimeDatabaseException("There is already a transaction.");
\r
267 final Semaphore started = new Semaphore(0);
\r
268 final TransactionInfo t = new TransactionInfo();
\r
269 t.es = new Semaphore(0);
\r
270 t.ts = new Semaphore(0);
\r
271 transactions.set(t);
\r
273 Callback<DatabaseException> callback = new Callback<DatabaseException>() {
\r
275 public void run(DatabaseException parameter) {
\r
276 t.error = parameter;
\r
277 t.es.release(9999);
\r
281 DelayedWrite request = new DelayedWriteRequest() {
\r
283 public void perform(WriteGraph g) throws DatabaseException {
\r
289 } catch (InterruptedException e) {
\r
291 if (!t.commit) throw new CancelTransactionException();
\r
295 processor.asyncRequest( request, callback );
\r
297 // Wait until transaction has started
\r
299 // Sleep this thread until transaction has started
\r
300 started.acquire(1);
\r
301 } catch (InterruptedException e) {
\r
302 throw new DatabaseException("Thread was interrupted.");
\r
311 * Commits transaction if no error occurred
\r
313 * @throws DatabaseException
\r
315 public static void endTransaction() throws DatabaseException {
\r
316 TransactionInfo t = transactions.get();
\r
317 if (t == null) return; //throw new RuntimeDatabaseException("There is no transaction to commit.");
\r
319 t.ts.release(9999);
\r
323 } catch (InterruptedException e) {
\r
324 throw new DatabaseException(e);
\r
327 if (t.error!=null) {
\r
328 if (t.error instanceof CancelTransactionException==false) throw t.error;
\r
330 transactions.set(null);
\r
334 * Commits transaction
\r
336 * @throws DatabaseException
\r
338 public static void commit() throws DatabaseException {
\r
339 TransactionInfo t = transactions.get();
\r
340 if (t == null) throw new RuntimeDatabaseException("There is not transaction to commit.");
\r
345 public static String getURI(Resource resource) throws ResourceNotFoundException, ValidationException, ServiceException {
\r
346 return readGraph().getPossibleURI(resource);
\r
349 public static String getPossibleURI(Resource resource) throws ResourceNotFoundException, ValidationException, ServiceException {
\r
350 return readGraph().getPossibleURI(resource);
\r
353 public static Resource getResource(String uri) throws ResourceNotFoundException, ValidationException, ServiceException
\r
355 return readGraph().getResource(uri);
\r
358 public static Resource getPossibleResource(String uri) throws ResourceNotFoundException, ValidationException, ServiceException
\r
360 return readGraph().getPossibleResource(uri);
\r
363 public static Resource getBuiltin(String id) throws ResourceNotFoundException, ServiceException
\r
365 return readGraph().getBuiltin(id);
\r
368 public static Collection<Statement> getStatements(Resource subject, Resource relation) throws ManyObjectsForFunctionalRelationException, ServiceException
\r
370 return readGraph().getStatements(subject, relation);
\r
373 public static Collection<Statement> getAssertedStatements(Resource subject, Resource relation) throws ManyObjectsForFunctionalRelationException, ServiceException
\r
375 return readGraph().getAssertedStatements(subject, relation);
\r
378 public static Collection<Resource> getPredicates(Resource subject) throws ServiceException
\r
380 return readGraph().getPredicates(subject);
\r
383 public static Collection<Resource> getPrincipalTypes(Resource subject) throws ServiceException
\r
385 return readGraph().getPrincipalTypes(subject);
\r
388 public static Set<Resource> getTypes(Resource subject) throws ServiceException
\r
390 return readGraph().getTypes(subject);
\r
393 public static Set<Resource> getSupertypes(Resource subject) throws ServiceException
\r
395 return readGraph().getSupertypes(subject);
\r
398 public static Set<Resource> getSuperrelations(Resource subject) throws ServiceException
\r
400 return readGraph().getSuperrelations(subject);
\r
403 public static Collection<Resource> getObjects(Resource subject, Resource relation) throws ManyObjectsForFunctionalRelationException, ServiceException
\r
405 return readGraph().getObjects(subject, relation);
\r
408 public static Collection<Resource> getAssertedObjects(Resource subject, Resource relation) throws ManyObjectsForFunctionalRelationException, ServiceException
\r
410 return readGraph().getAssertedObjects(subject, relation);
\r
413 public static Resource getInverse(Resource relation) throws NoInverseException, ManyObjectsForFunctionalRelationException, ServiceException
\r
415 return readGraph().getInverse(relation);
\r
418 public static Resource getSingleObject(Resource subject, Resource relation) throws NoSingleResultException, ManyObjectsForFunctionalRelationException, ServiceException
\r
420 return readGraph().getSingleObject(subject, relation);
\r
423 public static Statement getSingleStatement(Resource subject, Resource relation) throws NoSingleResultException, ManyObjectsForFunctionalRelationException, ServiceException
\r
425 return readGraph().getSingleStatement(subject, relation);
\r
428 public static Resource getSingleType(Resource subject) throws NoSingleResultException, ServiceException
\r
430 return readGraph().getSingleType(subject);
\r
433 public static Resource getSingleType(Resource subject, Resource baseType) throws NoSingleResultException, ServiceException
\r
435 return readGraph().getSingleType(subject, baseType);
\r
438 public static <T> T getValue(Resource subject) throws DoesNotContainValueException, ServiceException
\r
440 return readGraph().<T>getValue(subject);
\r
443 public static <T> T getValue(Resource subject, Binding binding) throws DoesNotContainValueException, BindingException, ServiceException
\r
445 return readGraph().<T>getValue(subject, binding);
\r
448 public static <T> T getRelatedValue(Resource subject, Resource relation) throws NoSingleResultException, DoesNotContainValueException, ServiceException
\r
450 return readGraph().<T>getRelatedValue(subject, relation);
\r
453 public static <T> T getRelatedValue(Resource subject, Resource relation, Binding binding) throws NoSingleResultException, DoesNotContainValueException, BindingException, ServiceException
\r
455 return readGraph().<T>getRelatedValue(subject, relation, binding);
\r
458 public static <T> T adapt(Resource resource, Class<T> clazz) throws AdaptionException, ValidationException, ServiceException
\r
460 return readGraph().adapt(resource, clazz);
\r
463 public static <T> T adaptUnique(Resource resource, Class<T> clazz) throws AdaptionException, ValidationException, ServiceException
\r
465 return readGraph().adaptUnique(resource, clazz);
\r
468 public static Resource getPossibleInverse(Resource relation) throws ManyObjectsForFunctionalRelationException, ServiceException
\r
470 return readGraph().getPossibleInverse(relation);
\r
473 public static Resource getPossibleObject(Resource subject, Resource relation) throws ManyObjectsForFunctionalRelationException, ServiceException
\r
475 return readGraph().getPossibleObject(subject, relation);
\r
478 public static Statement getPossibleStatement(Resource subject, Resource relation) throws ManyObjectsForFunctionalRelationException, ServiceException
\r
480 return readGraph().getPossibleStatement(subject, relation);
\r
483 public static Resource getPossibleType(Resource subject, Resource baseType) throws ServiceException
\r
485 return readGraph().getPossibleType(subject, baseType);
\r
488 public static <T> T getPossibleValue(Resource subject) throws ServiceException
\r
490 return readGraph().<T>getPossibleValue(subject);
\r
493 public static <T> T getPossibleValue(Resource subject, Binding binding) throws BindingException, ServiceException
\r
495 return readGraph().<T>getPossibleValue(subject, binding);
\r
498 public static <T> T getPossibleRelatedValue(Resource subject, Resource relation) throws ManyObjectsForFunctionalRelationException, ServiceException
\r
500 return readGraph().<T>getPossibleRelatedValue(subject, relation);
\r
503 public static <T> T getPossibleRelatedValue(Resource subject, Resource relation, Binding binding) throws ManyObjectsForFunctionalRelationException, BindingException, ServiceException
\r
505 return readGraph().<T>getPossibleRelatedValue(subject, relation, binding);
\r
508 public static <T> T getPossibleAdapter(Resource resource, Class<T> clazz) throws ValidationException, ServiceException
\r
510 return readGraph().<T>getPossibleAdapter(resource, clazz);
\r
513 public static <T> T getPossibleUniqueAdapter(Resource resource, Class<T> clazz) throws ValidationException, ServiceException
\r
515 return readGraph().<T>getPossibleUniqueAdapter(resource, clazz);
\r
518 public static boolean isInstanceOf(Resource resource, Resource type) throws ServiceException
\r
520 return readGraph().isInstanceOf(resource, type);
\r
523 public static boolean isInheritedFrom(Resource resource, Resource type) throws ServiceException
\r
525 return readGraph().isInheritedFrom(resource, type);
\r
528 public static boolean isSubrelationOf(Resource resource, Resource relation) throws ServiceException
\r
530 return readGraph().isSubrelationOf(resource, relation);
\r
533 public static boolean hasStatement(Resource subject) throws ServiceException
\r
535 return readGraph().hasStatement(subject);
\r
538 public static boolean hasStatement(Resource subject, Resource relation) throws ServiceException
\r
540 return readGraph().hasStatement(subject, relation);
\r
543 public static boolean hasStatement(Resource subject, Resource relation, Resource object) throws ServiceException
\r
545 return readGraph().hasStatement(subject, relation, object);
\r
548 public static boolean hasValue(Resource subject) throws ServiceException
\r
550 return readGraph().hasValue(subject);
\r
553 public static Datatype getDataType(Resource subject) throws DatabaseException
\r
555 return readGraph().getDataType(subject);
\r
558 public static <T extends Accessor> T getAccessor(Resource subject) throws DatabaseException
\r
560 return readGraph().<T>getAccessor(subject);
\r
565 * Makes sure that the statements (s,p,o) and (o,p',s) are found in the
\r
566 * graph, where p' is the inverse predicate of p. Contrary to
\r
567 * {@link WriteOnlyGraph#claim(Resource, Resource, Resource, Resource)} this
\r
568 * method assures that the the statement and its inverse are semantically
\r
569 * valid after the invocation of this method.
\r
571 * @param subject subject, i.e. source resource of the statement to be
\r
573 * @param predicate predicate resource of the statement to be claimed
\r
574 * @param object object, i.e. target resource of the statement to be claimed
\r
575 * @throws ServiceException
\r
577 public static void claim(Resource subject, Resource predicate, Resource object) throws ServiceException {
\r
578 writeGraph().claim(subject, predicate, object);
\r
582 * Sets literal value related to the specified resource with the specified
\r
583 * predicate. If such value exists (s,p), the value is overridden with the
\r
584 * new specified value.
\r
588 * @param value Value of the literal (boxed primitive/String or
\r
589 * primitive/String array)
\r
590 * @throws ManyObjectsForFunctionalRelationException
\r
592 public static void claimValue(Resource resource, Resource predicate, Object value)
\r
593 throws ManyObjectsForFunctionalRelationException, ServiceException, DatabaseException {
\r
594 writeGraph().claimLiteral(resource, predicate, value);
\r
596 public static void claimValue(Resource resource, Resource predicate, Object value, Binding binding)
\r
597 throws BindingException, ManyObjectsForFunctionalRelationException, ServiceException, DatabaseException {
\r
598 writeGraph().claimValue(resource, value, binding);
\r
600 public static void claimValue(Resource resource, Resource predicate, Resource inverse, Resource type, Object value, Binding binding)
\r
601 throws BindingException, ManyObjectsForFunctionalRelationException, ServiceException, DatabaseException {
\r
602 writeGraph().claimLiteral(resource, predicate, inverse, type, value, binding);
\r
606 * Makes sure that no statements matching the patterns (s,?p,?o) and
\r
607 * (?o,?p',s), where ?p' is the inverse predicate of ?p, exist in the graph.
\r
608 * In other words, removes all statements outgoing from the specified
\r
609 * resource along with the inverses of those statements.
\r
612 * @throws ServiceException
\r
614 public static void deny(Resource subject) throws ServiceException {
\r
615 writeGraph().deny(subject);
\r
619 * Makes sure that no statements matching the patterns (s,p,?o) and
\r
620 * (?o,p',s), where p' is the inverse predicate of p, exist in the graph.
\r
621 * Also statements where <code>isSubrelationOf(p, predicate)</code> returns
\r
622 * <code>true</code> shall be removed. In other words, removes all
\r
623 * statements outgoing from the specified resource with the specified
\r
624 * predicate or any of its subrelations, along with the inverses of those
\r
628 * @throws ServiceException
\r
630 public static void deny(Resource subject, Resource predicate) throws ServiceException {
\r
631 writeGraph().deny(subject, predicate);
\r
635 * Makes sure that no statements matching the patterns (s,p,o) and (o,p',s),
\r
636 * where p' is the inverse predicate of p, exist in the graph. Contrary to
\r
637 * {@link #denyStatement(Resource, Resource, Resource)}, all statements
\r
638 * where <code>isSubrelationOf(p, predicate)</code> returns
\r
639 * <code>true</code> shall be removed. In other words, removes all
\r
640 * statements between the specified subject and object with the specified
\r
641 * predicate or any of its subrelations, along with the inverses of those
\r
647 * @throws ServiceException
\r
649 public static void deny(Resource subject, Resource predicate, Resource object) throws ServiceException {
\r
650 writeGraph().deny(subject, predicate, object);
\r
654 * Makes sure that no statements matching the patterns (s,p,o) and (o,p',s),
\r
655 * where p' is the inverse predicate of p, exist in the graph. In other
\r
656 * words, removes the specified statement and its possible inverse.
\r
659 * This method behaves exactly like {@link #deny(Statement)}, it just takes
\r
660 * the arguments as resources instead of a statement.
\r
663 * @throws ServiceException
\r
665 * @see {@link #deny(Statement)}
\r
667 public static void denyStatement(Resource subject, Resource predicate, Resource object) throws ServiceException {
\r
668 writeGraph().denyStatement(subject, predicate, object);
\r
672 * Makes sure that the specified statements (s,p,o) and its inverse
\r
673 * statements (o,p',s), where p' is the inverse predicate of p, do not exist
\r
677 * This method behaves exactly like
\r
678 * {@link #denyStatement(Resource, Resource, Resource)}, it just takes the
\r
679 * arguments as a statement instead of 3 resources.
\r
683 * @see #denyStatement(Resource, Resource, Resource)
\r
685 public static void deny(Statement statement) throws ServiceException {
\r
686 writeGraph().deny(statement);
\r
690 * Removes all statements (resource,predicate,?o) and literal contained by
\r
695 * @throws ManyObjectsForFunctionalRelationException
\r
697 public static void denyValue(Resource resource, Resource predicate) throws ManyObjectsForFunctionalRelationException, ServiceException {
\r
698 writeGraph().denyValue(resource, predicate);
\r