]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.common/src/org/simantics/db/common/utils/Transaction.java
75020215d686d00c79fd72a870c00e3184c7be60
[simantics/platform.git] / bundles / org.simantics.db.common / src / org / simantics / db / common / utils / Transaction.java
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
7  *
8  * Contributors:
9  *     VTT Technical Research Centre of Finland - initial API and implementation
10  *******************************************************************************/
11 package org.simantics.db.common.utils;
12
13 import java.util.Collection;
14 import java.util.Set;
15 import java.util.concurrent.Semaphore;
16
17 import org.simantics.databoard.accessor.Accessor;
18 import org.simantics.databoard.binding.Binding;
19 import org.simantics.databoard.type.Datatype;
20 import org.simantics.db.ReadGraph;
21 import org.simantics.db.RequestProcessor;
22 import org.simantics.db.Resource;
23 import org.simantics.db.Statement;
24 import org.simantics.db.VirtualGraph;
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.UndoTraits;
44 import org.simantics.db.request.Write;
45 import org.simantics.utils.datastructures.Callback;
46
47 /**
48  * Synchronous Transaction. <p>
49  * 
50  * Hint: Import all methods as static.
51  * import static org.simantics.db.Transaction.*; 
52  * 
53  * Remember also to change Eclipse Preferences:
54  *   Organize Imports: number of static imports needed for .* on vakiona 99, siihen vaikka 3
55  *
56  * 
57  * Usage A:
58  * 
59  * startTransaction(session, true);
60  * try {
61  *  ...
62  *    commit();
63  * } finally {
64  *    endTransaction();
65  * }
66  * 
67  * Usage B:
68  * setGraph(g);
69  * ...
70  * setGraph(null);
71  *
72  * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
73  */
74 public class Transaction {
75
76         public static enum Type {
77                 READ,
78                 WRITE,
79                 DELAYED_WRITE
80         }
81         
82         /** Thread local transactions */
83         private static ThreadLocal<TransactionInfo> transactions = new ThreadLocal<TransactionInfo>();
84         
85         static private class TransactionInfo {
86                 WriteGraph wg;
87                 ReadGraph rg;
88                 
89                 /** Semaphore that is released when the transaction is complete */
90                 Semaphore ts;
91                 
92                 /** Semaphore that is release after transaction ended */
93                 Semaphore es;
94                 
95                 /** Error */
96                 DatabaseException error;
97                 
98                 /** */
99                 boolean commit = false;
100                 
101                 TransactionInfo() {
102                 }
103                 
104                 TransactionInfo(Object graph) {
105                         if (graph instanceof WriteGraph) {
106                                 wg = (WriteGraph) graph;
107                                 rg = (ReadGraph) graph;
108                         } else if (graph instanceof ReadGraph) {
109                                 wg = null;
110                                 rg = (ReadGraph) graph;
111                         } else {
112                                 throw new RuntimeDatabaseException("Not a sync graph");
113                         }                       
114                 }
115         }
116         
117         public static ReadGraph readGraph() {
118                 TransactionInfo t = transactions.get();
119                 return t == null ? null : t.rg;
120         }
121         
122         public static WriteGraph writeGraph() {
123                 TransactionInfo t = transactions.get();
124                 return t == null ? null : t.wg;
125         }
126                 
127         public static Object setGraph(Object graph) {
128                 if (graph==null) {
129                         transactions.set(null);
130                         return null;
131                 }
132                 
133                 {
134                         Object oldGraph = null;
135                         TransactionInfo t = transactions.get();
136                         if (t!=null) {                          
137                                 oldGraph = t.rg;
138                                 if (graph instanceof WriteGraph) {
139                                         t.wg = (WriteGraph) graph;
140                                         t.rg = (ReadGraph) graph;
141                                 } else if (graph instanceof ReadGraph) {
142                                         t.wg = null;
143                                         t.rg = (ReadGraph) graph;
144                                 } else {
145                                         throw new RuntimeDatabaseException("Not a sync graph");
146                                 }                                                       
147                         } else {
148                                 t = new TransactionInfo(graph);
149                         }
150                         transactions.set(t);
151                         return oldGraph;
152                 }
153         }
154         
155         public static void startTransaction(RequestProcessor processor, boolean write) throws DatabaseException {
156                 startTransaction(processor, write ? Type.WRITE : Type.READ);
157         }
158         
159         public static void startTransaction(RequestProcessor processor, Type type) throws DatabaseException {
160                 switch (type) {
161                         case READ:
162                         {
163                                 if (transactions.get()!=null) throw new RuntimeDatabaseException("There is already a transaction.");
164                                 final Semaphore started = new Semaphore(0);
165                                 final TransactionInfo t = new TransactionInfo();
166                                 t.es = new Semaphore(0);
167                                 t.ts = new Semaphore(0);
168                                 transactions.set(t);
169
170                                 Read<Object> request = new Read<Object>() {
171                                         @Override
172                                         public Object perform(ReadGraph g) throws DatabaseException {
173                                                 t.wg = null;
174                                                 t.rg = g;
175                                                 started.release();
176                                                 try {
177                                                         t.ts.acquire();
178                                                 } catch (InterruptedException e) {
179                                                 }
180                                                 return null;
181                                         }
182                                 };
183                                 Procedure<Object> procedure = new Procedure<Object>() {
184                                     @Override
185                                     public void execute(Object result) {
186                                         t.es.release(9999);
187                                     }
188                                     @Override
189                                     public void exception(Throwable ex) {
190                                         if (ex instanceof DatabaseException)
191                                             t.error = (DatabaseException) ex;
192                                         else {
193                                             t.error = new DatabaseException(ex);
194                                         }
195                                         t.es.release(9999);
196                                     }
197                                 };
198
199                                 processor.asyncRequest(request, procedure);
200
201                                 // Wait until transaction has started
202                                 try {
203                                         // Sleep this thread until transaction has started
204                                         started.acquire(1);
205                                 } catch (InterruptedException e) {
206                                         throw new DatabaseException("Thread was interrupted.");
207                                 } finally {
208                                 }
209                         }
210                         break;
211
212                         case WRITE:
213                         {
214                                 if (transactions.get()!=null) throw new RuntimeDatabaseException("There is already a transaction.");
215                                 final Semaphore started = new Semaphore(0);
216                                 final TransactionInfo t = new TransactionInfo();
217                                 t.es = new Semaphore(0);
218                                 t.ts = new Semaphore(0);
219                                 transactions.set(t);
220
221                                 Callback<DatabaseException> callback = new Callback<DatabaseException>() {
222                                         @Override
223                                         public void run(DatabaseException parameter) {
224                                                 t.error = parameter;
225                                                 t.es.release(9999);
226                                         }
227                                 };
228
229                                 Write request =  new Write() { 
230                                         @Override
231                                         public void perform(WriteGraph g) throws DatabaseException {
232                                                 t.wg = g;
233                                                 t.rg = g;
234                                                 started.release();
235                                                 try {
236                                                         t.ts.acquire();
237                                                 } catch (InterruptedException e) {
238                                                 }
239                                                 if (!t.commit) throw new CancelTransactionException();
240                                         }
241                                         @Override
242                                         public UndoTraits getUndoTraits() {
243                                                 return null;
244                                         }
245                                         @Override
246                                         public VirtualGraph getProvider() {
247                                                 return null;
248                                         }
249                                 };
250
251                                 processor.asyncRequest( request, callback );
252
253                                 // Wait until transaction has started
254                                 try {
255                                         // Sleep this thread until transaction has started
256                                         started.acquire(1);
257                                 } catch (InterruptedException e) {
258                                         throw new DatabaseException("Thread was interrupted.");
259                                 } finally {
260                                 }
261                         }
262                         break;
263
264                         case DELAYED_WRITE:
265                         {
266                                 if (transactions.get()!=null) throw new RuntimeDatabaseException("There is already a transaction.");
267                                 final Semaphore started = new Semaphore(0);
268                                 final TransactionInfo t = new TransactionInfo();
269                                 t.es = new Semaphore(0);
270                                 t.ts = new Semaphore(0);
271                                 transactions.set(t);
272
273                                 Callback<DatabaseException> callback = new Callback<DatabaseException>() {
274                                         @Override
275                                         public void run(DatabaseException parameter) {
276                                                 t.error = parameter;
277                                                 t.es.release(9999);
278                                         }
279                                 };
280
281                                 DelayedWrite request =  new DelayedWriteRequest() { 
282                                         @Override
283                                         public void perform(WriteGraph g) throws DatabaseException {
284                                                 t.wg = g;
285                                                 t.rg = g;
286                                                 started.release();
287                                                 try {
288                                                         t.ts.acquire();
289                                                 } catch (InterruptedException e) {
290                                                 }
291                                                 if (!t.commit) throw new CancelTransactionException();
292                                         }
293                                 };
294
295                                 processor.asyncRequest( request, callback );
296
297                                 // Wait until transaction has started
298                                 try {
299                                         // Sleep this thread until transaction has started
300                                         started.acquire(1);
301                                 } catch (InterruptedException e) {
302                                         throw new DatabaseException("Thread was interrupted.");
303                                 } finally {
304                                 }
305                         }
306                         break;
307                 }
308         }
309         
310         /**
311          * Commits transaction if no error occurred 
312          * 
313          * @throws DatabaseException
314          */
315         public static void endTransaction() throws DatabaseException {
316                 TransactionInfo t = transactions.get();
317                 if (t == null) return; //throw new RuntimeDatabaseException("There is no transaction to commit.");
318                 
319                 t.ts.release(9999);
320                 
321                 try {
322                         t.es.acquire();
323                 } catch (InterruptedException e) {
324                         throw new DatabaseException(e);
325                 }                               
326                 
327                 if (t.error!=null) {
328                         if (t.error instanceof CancelTransactionException==false) throw t.error;                
329                 }
330                 transactions.set(null);
331         }
332
333         /**
334          * Commits transaction  
335          * 
336          * @throws DatabaseException
337          */
338         public static void commit() throws DatabaseException {
339                 TransactionInfo t = transactions.get();
340                 if (t == null) throw new RuntimeDatabaseException("There is not transaction to commit.");
341                 t.commit = true;
342                 endTransaction();
343         }
344         
345     public static String getURI(Resource resource) throws ResourceNotFoundException, ValidationException, ServiceException {
346         return readGraph().getPossibleURI(resource);
347     }
348     
349     public static String getPossibleURI(Resource resource) throws ResourceNotFoundException, ValidationException, ServiceException {
350         return readGraph().getPossibleURI(resource);
351     }
352         
353     public static Resource getResource(String uri) throws ResourceNotFoundException, ValidationException, ServiceException 
354     {
355         return readGraph().getResource(uri);
356     }
357
358     public static Resource getPossibleResource(String uri) throws ResourceNotFoundException, ValidationException, ServiceException
359     {
360         return readGraph().getPossibleResource(uri);
361     }
362     
363     public static Resource getBuiltin(String id) throws ResourceNotFoundException, ServiceException
364     {
365         return readGraph().getBuiltin(id);
366     }
367
368     public static Collection<Statement> getStatements(Resource subject, Resource relation) throws ManyObjectsForFunctionalRelationException, ServiceException
369     {
370         return readGraph().getStatements(subject, relation);
371     }
372
373     public static Collection<Statement> getAssertedStatements(Resource subject, Resource relation) throws ManyObjectsForFunctionalRelationException, ServiceException
374     {
375         return readGraph().getAssertedStatements(subject, relation);            
376     }    
377     
378     public static Collection<Resource> getPredicates(Resource subject) throws ServiceException
379     {
380         return readGraph().getPredicates(subject);      
381     }
382
383     public static Collection<Resource> getPrincipalTypes(Resource subject) throws ServiceException
384     {
385         return readGraph().getPrincipalTypes(subject);
386     }
387
388     public static Set<Resource> getTypes(Resource subject) throws ServiceException
389     {
390         return readGraph().getTypes(subject);
391     }
392
393     public static Set<Resource> getSupertypes(Resource subject) throws ServiceException
394     {
395         return readGraph().getSupertypes(subject);
396     }
397
398     public static Set<Resource> getSuperrelations(Resource subject) throws ServiceException
399     {
400         return readGraph().getSuperrelations(subject);
401     }
402
403     public static Collection<Resource> getObjects(Resource subject, Resource relation) throws ManyObjectsForFunctionalRelationException, ServiceException
404     {
405         return readGraph().getObjects(subject, relation);
406     }
407
408     public static Collection<Resource> getAssertedObjects(Resource subject, Resource relation) throws ManyObjectsForFunctionalRelationException, ServiceException
409     {
410         return readGraph().getAssertedObjects(subject, relation);
411     }
412     
413     public static Resource getInverse(Resource relation) throws NoInverseException, ManyObjectsForFunctionalRelationException, ServiceException
414     {
415         return readGraph().getInverse(relation);
416     }
417     
418     public static Resource getSingleObject(Resource subject, Resource relation) throws NoSingleResultException, ManyObjectsForFunctionalRelationException, ServiceException
419     {
420         return readGraph().getSingleObject(subject, relation);
421     }
422     
423     public static Statement getSingleStatement(Resource subject, Resource relation) throws NoSingleResultException, ManyObjectsForFunctionalRelationException, ServiceException
424     {
425         return readGraph().getSingleStatement(subject, relation);
426     }
427
428     public static Resource getSingleType(Resource subject) throws NoSingleResultException, ServiceException
429     {
430         return readGraph().getSingleType(subject);
431     }
432     
433     public static Resource getSingleType(Resource subject, Resource baseType) throws NoSingleResultException, ServiceException
434     {
435         return readGraph().getSingleType(subject, baseType);
436     }
437
438     public static <T> T getValue(Resource subject) throws DoesNotContainValueException, ServiceException
439     {
440         return readGraph().<T>getValue(subject);
441     }
442
443     public static <T> T getValue(Resource subject, Binding binding) throws DoesNotContainValueException, BindingException, ServiceException
444     {
445         return readGraph().<T>getValue(subject, binding);
446     }
447
448     public static <T> T getRelatedValue(Resource subject, Resource relation) throws NoSingleResultException, DoesNotContainValueException, ServiceException
449     {
450         return readGraph().<T>getRelatedValue(subject, relation);
451     }
452
453     public static <T> T getRelatedValue(Resource subject, Resource relation, Binding binding) throws NoSingleResultException, DoesNotContainValueException, BindingException, ServiceException
454     {
455         return readGraph().<T>getRelatedValue(subject, relation, binding);
456     }
457
458     public static <T> T adapt(Resource resource, Class<T> clazz) throws AdaptionException, ValidationException, ServiceException
459     {
460         return readGraph().adapt(resource, clazz);
461     }
462
463     public static <T> T adaptUnique(Resource resource, Class<T> clazz) throws AdaptionException, ValidationException, ServiceException
464     {
465         return readGraph().adaptUnique(resource, clazz);
466     }
467     
468     public static Resource getPossibleInverse(Resource relation) throws ManyObjectsForFunctionalRelationException, ServiceException
469     {
470         return readGraph().getPossibleInverse(relation);
471     }
472     
473     public static Resource getPossibleObject(Resource subject, Resource relation) throws ManyObjectsForFunctionalRelationException, ServiceException
474     {
475         return readGraph().getPossibleObject(subject, relation);
476     }
477     
478     public static Statement getPossibleStatement(Resource subject, Resource relation) throws ManyObjectsForFunctionalRelationException, ServiceException
479     {
480         return readGraph().getPossibleStatement(subject, relation);
481     }
482     
483     public static Resource getPossibleType(Resource subject, Resource baseType) throws ServiceException
484     {
485         return readGraph().getPossibleType(subject, baseType);
486     }
487     
488     public static <T> T getPossibleValue(Resource subject) throws ServiceException
489     {
490         return readGraph().<T>getPossibleValue(subject);
491     }
492     
493     public static <T> T getPossibleValue(Resource subject, Binding binding) throws BindingException, ServiceException
494     {
495         return readGraph().<T>getPossibleValue(subject, binding);
496     }
497
498     public static <T> T getPossibleRelatedValue(Resource subject, Resource relation) throws ManyObjectsForFunctionalRelationException, ServiceException
499     {
500         return readGraph().<T>getPossibleRelatedValue(subject, relation);
501     }
502     
503     public static <T> T getPossibleRelatedValue(Resource subject, Resource relation, Binding binding) throws ManyObjectsForFunctionalRelationException, BindingException, ServiceException
504     {
505         return readGraph().<T>getPossibleRelatedValue(subject, relation, binding);
506     }
507     
508     public static <T> T getPossibleAdapter(Resource resource, Class<T> clazz) throws ValidationException, ServiceException
509     {
510         return readGraph().<T>getPossibleAdapter(resource, clazz);
511     }
512     
513     public static <T> T getPossibleUniqueAdapter(Resource resource, Class<T> clazz) throws ValidationException, ServiceException
514     {
515         return readGraph().<T>getPossibleUniqueAdapter(resource, clazz);
516     }
517     
518     public static boolean isInstanceOf(Resource resource, Resource type) throws ServiceException
519     {
520         return readGraph().isInstanceOf(resource, type);
521     }
522     
523     public static boolean isInheritedFrom(Resource resource, Resource type) throws ServiceException
524     {
525         return readGraph().isInheritedFrom(resource, type);
526     }
527     
528     public static boolean isSubrelationOf(Resource resource, Resource relation) throws ServiceException
529     {
530         return readGraph().isSubrelationOf(resource, relation);
531     }
532     
533     public static boolean hasStatement(Resource subject) throws ServiceException
534     {
535         return readGraph().hasStatement(subject);
536     }
537     
538     public static boolean hasStatement(Resource subject, Resource relation) throws ServiceException
539     {
540         return readGraph().hasStatement(subject, relation);
541     }
542     
543     public static boolean hasStatement(Resource subject, Resource relation, Resource object) throws ServiceException
544     {
545         return readGraph().hasStatement(subject, relation, object);
546     }
547     
548     public static boolean hasValue(Resource subject) throws ServiceException
549     {
550         return readGraph().hasValue(subject);
551     }
552     
553     public static Datatype getDataType(Resource subject) throws DatabaseException
554     {
555         return readGraph().getDataType(subject);
556     }
557     
558     public static <T extends Accessor> T getAccessor(Resource subject) throws DatabaseException
559     {
560         return readGraph().<T>getAccessor(subject);
561     }
562     
563     
564     /**
565      * Makes sure that the statements (s,p,o) and (o,p',s) are found in the
566      * graph, where p' is the inverse predicate of p. Contrary to
567      * {@link WriteOnlyGraph#claim(Resource, Resource, Resource, Resource)} this
568      * method assures that the the statement and its inverse are semantically
569      * valid after the invocation of this method.
570      * 
571      * @param subject subject, i.e. source resource of the statement to be
572      *        claimed
573      * @param predicate predicate resource of the statement to be claimed
574      * @param object object, i.e. target resource of the statement to be claimed
575      * @throws ServiceException
576      */
577     public static void claim(Resource subject, Resource predicate, Resource object) throws ServiceException {
578         writeGraph().claim(subject, predicate, object);
579     }
580
581     /**
582      * Sets literal value related to the specified resource with the specified
583      * predicate. If such value exists (s,p), the value is overridden with the
584      * new specified value.
585      * 
586      * @param resource
587      * @param predicate
588      * @param value Value of the literal (boxed primitive/String or
589      *        primitive/String array)
590      * @throws ManyObjectsForFunctionalRelationException
591      */
592     public static void claimValue(Resource resource, Resource predicate, Object value)
593     throws ManyObjectsForFunctionalRelationException, ServiceException, DatabaseException {
594         writeGraph().claimLiteral(resource, predicate, value);
595     }
596     public static void claimValue(Resource resource, Resource predicate, Object value, Binding binding)
597     throws BindingException, ManyObjectsForFunctionalRelationException, ServiceException, DatabaseException {
598         writeGraph().claimValue(resource, value, binding);
599     }
600     public static void claimValue(Resource resource, Resource predicate, Resource inverse, Resource type, Object value, Binding binding)
601     throws BindingException, ManyObjectsForFunctionalRelationException, ServiceException, DatabaseException {
602         writeGraph().claimLiteral(resource, predicate, inverse, type, value, binding);
603     }
604
605     /**
606      * Makes sure that no statements matching the patterns (s,?p,?o) and
607      * (?o,?p',s), where ?p' is the inverse predicate of ?p, exist in the graph.
608      * In other words, removes all statements outgoing from the specified
609      * resource along with the inverses of those statements.
610      * 
611      * @param subject
612      * @throws ServiceException
613      */
614     public static void deny(Resource subject) throws ServiceException {
615         writeGraph().deny(subject);
616     }
617
618     /**
619      * Makes sure that no statements matching the patterns (s,p,?o) and
620      * (?o,p',s), where p' is the inverse predicate of p, exist in the graph.
621      * Also statements where <code>isSubrelationOf(p, predicate)</code> returns
622      * <code>true</code> shall be removed. In other words, removes all
623      * statements outgoing from the specified resource with the specified
624      * predicate or any of its subrelations, along with the inverses of those
625      * statements.
626      * 
627      * @param subject
628      * @throws ServiceException
629      */
630     public static void deny(Resource subject, Resource predicate) throws ServiceException {
631         writeGraph().deny(subject, predicate);
632     }
633
634     /**
635      * Makes sure that no statements matching the patterns (s,p,o) and (o,p',s),
636      * where p' is the inverse predicate of p, exist in the graph. Contrary to
637      * {@link #denyStatement(Resource, Resource, Resource)}, all statements
638      * where <code>isSubrelationOf(p, predicate)</code> returns
639      * <code>true</code> shall be removed. In other words, removes all
640      * statements between the specified subject and object with the specified
641      * predicate or any of its subrelations, along with the inverses of those
642      * statements.
643      * 
644      * @param subject
645      * @param predicate
646      * @param object
647      * @throws ServiceException
648      */
649     public static void deny(Resource subject, Resource predicate, Resource object) throws ServiceException {
650         writeGraph().deny(subject, predicate, object);
651     }
652
653     /**
654      * Makes sure that no statements matching the patterns (s,p,o) and (o,p',s),
655      * where p' is the inverse predicate of p, exist in the graph. In other
656      * words, removes the specified statement and its possible inverse.
657      * 
658      * <p>
659      * This method behaves exactly like {@link #deny(Statement)}, it just takes
660      * the arguments as resources instead of a statement.
661      * 
662      * @param subject
663      * @throws ServiceException
664      * 
665      * @see {@link #deny(Statement)}
666      */
667     public static void denyStatement(Resource subject, Resource predicate, Resource object) throws ServiceException {
668         writeGraph().denyStatement(subject, predicate, object);
669     }
670
671     /**
672      * Makes sure that the specified statements (s,p,o) and its inverse
673      * statements (o,p',s), where p' is the inverse predicate of p, do not exist
674      * in the graph.
675      * 
676      * <p>
677      * This method behaves exactly like
678      * {@link #denyStatement(Resource, Resource, Resource)}, it just takes the
679      * arguments as a statement instead of 3 resources.
680      * 
681      * @param statement
682      * 
683      * @see #denyStatement(Resource, Resource, Resource)
684      */
685     public static void deny(Statement statement) throws ServiceException {
686         writeGraph().deny(statement);
687     }
688
689     /**
690      * Removes all statements (resource,predicate,?o) and literal contained by
691      * ?o.
692      * 
693      * @param resource
694      * @param predicate
695      * @throws ManyObjectsForFunctionalRelationException
696      */
697     public static void denyValue(Resource resource, Resource predicate) throws ManyObjectsForFunctionalRelationException, ServiceException {
698         writeGraph().denyValue(resource, predicate);
699     }
700     
701 }
702