1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.db.impl.graph;
14 import java.io.IOException;
15 import java.io.PrintWriter;
16 import java.io.StringWriter;
17 import java.util.TreeMap;
19 import org.simantics.databoard.Bindings;
20 import org.simantics.databoard.accessor.Accessor;
21 import org.simantics.databoard.binding.Binding;
22 import org.simantics.databoard.binding.error.BindingConstructionException;
23 import org.simantics.databoard.binding.mutable.Variant;
24 import org.simantics.databoard.primitives.MutableBoolean;
25 import org.simantics.databoard.primitives.MutableByte;
26 import org.simantics.databoard.primitives.MutableDouble;
27 import org.simantics.databoard.primitives.MutableFloat;
28 import org.simantics.databoard.primitives.MutableInteger;
29 import org.simantics.databoard.primitives.MutableLong;
30 import org.simantics.databoard.primitives.MutableString;
31 import org.simantics.databoard.serialization.SerializationException;
32 import org.simantics.databoard.serialization.Serializer;
33 import org.simantics.databoard.type.Datatype;
34 import org.simantics.databoard.util.binary.RandomAccessBinary;
35 import org.simantics.db.DevelopmentKeys;
36 import org.simantics.db.ExternalValueSupport;
37 import org.simantics.db.Metadata;
38 import org.simantics.db.Resource;
39 import org.simantics.db.Statement;
40 import org.simantics.db.VirtualGraph;
41 import org.simantics.db.WriteGraph;
42 import org.simantics.db.WriteOnlyGraph;
43 import org.simantics.db.common.request.WriteOnlyRequest;
44 import org.simantics.db.common.utils.Literals;
45 import org.simantics.db.common.utils.Logger;
46 import org.simantics.db.exception.ArgumentException;
47 import org.simantics.db.exception.DatabaseException;
48 import org.simantics.db.exception.InternalException;
49 import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;
50 import org.simantics.db.exception.ServiceException;
51 import org.simantics.db.impl.DatabaseUtils;
52 import org.simantics.db.impl.MemWatch;
53 import org.simantics.db.impl.ResourceImpl;
54 import org.simantics.db.impl.internal.RandomAccessValueSupport;
55 import org.simantics.db.impl.internal.ResourceData;
56 import org.simantics.db.impl.query.CacheEntry;
57 import org.simantics.db.impl.query.QueryProcessor;
58 import org.simantics.db.impl.support.WriteRequestScheduleSupport;
59 import org.simantics.db.procedure.Procedure;
60 import org.simantics.db.request.DelayedWrite;
61 import org.simantics.db.request.DelayedWriteResult;
62 import org.simantics.db.request.Write;
63 import org.simantics.db.request.WriteOnly;
64 import org.simantics.db.request.WriteOnlyResult;
65 import org.simantics.db.request.WriteResult;
66 import org.simantics.db.request.WriteTraits;
67 import org.simantics.layer0.Layer0;
68 import org.simantics.utils.Development;
69 import org.simantics.utils.datastructures.Callback;
70 import org.simantics.utils.datastructures.Pair;
72 import gnu.trove.map.hash.THashMap;
75 final public class WriteGraphImpl extends ReadGraphImpl implements WriteGraph {
77 final public static Binding DATA_TYPE_BINDING = Bindings.getBindingUnchecked(Datatype.class);
79 final public WriteSupport writeSupport;
80 final public VirtualGraph provider;
82 private String resourceName(Resource resource) throws DatabaseException {
83 if(Development.DEVELOPMENT) {
84 Boolean names = Development.getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG_NAMES, Bindings.BOOLEAN);
85 if(names && !writeSupport.writeOnly()) return DatabaseUtils.getReadableName(this, resource);
86 else return resource.toString();
88 throw new IllegalStateException();
91 private Layer0 getBuiltins() {
92 return getService(Layer0.class);
95 private WriteRequestScheduleSupport getWriteRequestScheduler() {
96 return (WriteRequestScheduleSupport) getSession();
99 private WriteGraphImpl(CacheEntry parent2, QueryProcessor readSupport,
100 WriteSupport writeSupport, VirtualGraph provider) {
101 super(parent2, readSupport);
102 this.writeSupport = writeSupport;
103 this.provider = provider;
106 public final static WriteGraphImpl create(QueryProcessor support, WriteSupport writeSupport, VirtualGraph provider) {
108 WriteGraphImpl impl = new WriteGraphImpl(null, support, writeSupport, provider);
111 writeSupport.setDefaultClusterSet(null);
112 } catch (ServiceException e) {
113 Logger.defaultLogError(e);
120 final public WriteGraphImpl newAsync() {
124 public WriteGraphImpl newSync(final VirtualGraph provider) {
125 return new WriteGraphImpl(parent, processor, writeSupport, provider);
127 final public WriteGraphImpl newSync(final CacheEntry parent) {
128 return new WriteGraphImpl(parent, processor, writeSupport, provider);
132 final public ReadGraphImpl withAsyncParent(CacheEntry parent2) {
133 return new WriteGraphImpl(parent2, processor, writeSupport, provider);
137 public ReadGraphImpl newRestart(ReadGraphImpl impl) {
139 WriteGraphImpl write = processor.getSession().getService(WriteGraphImpl.class);
146 final public Resource newResource() throws ServiceException {
150 Resource result = writeSupport.createResource(provider);
152 if(Development.DEVELOPMENT) {
153 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITELOGGER_LOG, Bindings.BOOLEAN))
154 WriteLogger.logNewResource(this, result);
159 } catch (DatabaseException e) {
160 throw new ServiceException(e);
166 final public Resource newResource(long clusterId) throws ServiceException {
170 Resource result = writeSupport.createResource(provider, clusterId);
172 if(Development.DEVELOPMENT) {
173 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITELOGGER_LOG, Bindings.BOOLEAN))
174 WriteLogger.logNewResource(this, result);
179 } catch (DatabaseException e) {
180 throw new ServiceException(e);
186 public Resource newResource(Resource clusterSet) throws ServiceException {
189 if (provider != null)
190 result = writeSupport.createResource(provider);
192 result = writeSupport.createResource(provider, clusterSet);
193 if(Development.DEVELOPMENT) {
194 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITELOGGER_LOG, Bindings.BOOLEAN))
195 WriteLogger.logNewResource(this, result);
198 } catch (ServiceException e) {
200 } catch (DatabaseException e) {
201 throw new ServiceException(e);
206 public void newClusterSet(Resource clusterSet) throws ServiceException {
208 if (provider == null)
209 writeSupport.createClusterSet(provider, clusterSet);
210 if(Development.DEVELOPMENT) {
211 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITELOGGER_LOG, Bindings.BOOLEAN))
212 WriteLogger.logNewResource(this, clusterSet);
214 } catch (ServiceException e) {
216 } catch (DatabaseException e) {
217 throw new ServiceException(e);
222 public Resource setClusterSet4NewResource(Resource clusterSet)
223 throws ServiceException {
224 return writeSupport.setDefaultClusterSet(clusterSet);
227 * Compares two object for equality, allowing null objects also.
231 * @return true if both arguments are <code>null</code> or equal
233 static boolean safeEquals(Object o1, Object o2) {
236 if (o1 == null && o2 == null)
238 if (o1 == null || o2 == null)
240 return o1.equals(o2);
244 public void asyncRequest(DelayedWrite request) {
245 assert (request != null);
246 getWriteRequestScheduler().scheduleRequest(request, new Callback<DatabaseException>() {
249 public void run(DatabaseException parameter) {
250 if(parameter != null)
251 Logger.defaultLogError(parameter);
254 }, null, Boolean.TRUE);
258 public void asyncRequest(DelayedWrite request, Callback<DatabaseException> callback) {
259 assert (request != null);
260 getWriteRequestScheduler().scheduleRequest(request, callback, null, Boolean.TRUE);
264 public <T> void asyncRequest(DelayedWriteResult<T> request, Procedure<T> procedure) {
265 assert (request != null);
266 getWriteRequestScheduler().scheduleRequest(request, procedure, null, Boolean.TRUE);
270 public void asyncRequest(final Write r) {
272 getWriteRequestScheduler().scheduleRequest(r, new Callback<DatabaseException>() {
275 public void run(DatabaseException parameter) {
276 if(parameter != null)
277 Logger.defaultLogError(parameter);
280 }, null, Boolean.TRUE);
284 public void asyncRequest(Write request, Callback<DatabaseException> callback) {
285 assert (request != null);
286 getWriteRequestScheduler().scheduleRequest(request, callback, null, Boolean.TRUE);
290 public void asyncRequest(WriteOnly request) {
291 assert (request != null);
292 getWriteRequestScheduler().scheduleRequest(request, new Callback<DatabaseException>() {
295 public void run(DatabaseException parameter) {
296 if(parameter != null)
297 Logger.defaultLogError(parameter);
300 }, null, Boolean.TRUE);
304 public void asyncRequest(WriteOnly request, Callback<DatabaseException> callback) {
305 assert (request != null);
306 getWriteRequestScheduler().scheduleRequest(request, callback, null, Boolean.TRUE);
310 public <T> void asyncRequest(WriteOnlyResult<T> request, Procedure<T> procedure) {
311 assert (request != null);
312 getWriteRequestScheduler().scheduleRequest(request, procedure, null, Boolean.TRUE);
316 public <T> void asyncRequest(WriteResult<T> request, Procedure<T> procedure) {
317 assert (request != null);
318 getWriteRequestScheduler().scheduleRequest(request, procedure, null, Boolean.TRUE);
322 public void syncRequest(Write request) throws DatabaseException {
324 Resource defaultClusterSet = setClusterSet4NewResource(null);
326 WriteGraphImpl graph = (WriteGraphImpl)newSync(request.getProvider());
328 writeSupport.performWriteRequest(graph, request);
329 } catch (DatabaseException e) {
331 } catch (Throwable t) {
332 throw new DatabaseException(t);
334 setClusterSet4NewResource(defaultClusterSet);
341 public <T> T syncRequest(WriteResult<T> request) throws DatabaseException {
343 Resource defaultClusterSet = setClusterSet4NewResource(null);
345 WriteGraphImpl graph = (WriteGraphImpl)newSync(request.getProvider());
347 return writeSupport.performWriteRequest(graph, request);
348 } catch (DatabaseException e) {
350 } catch (Throwable t) {
351 throw new DatabaseException(t);
353 setClusterSet4NewResource(defaultClusterSet);
358 public void syncRequest(final DelayedWrite request) throws DatabaseException {
362 final DelayedWriteGraph dwg = new DelayedWriteGraph(this);
363 request.perform(dwg);
365 syncRequest(new WriteOnlyRequest() {
368 public void perform(WriteOnlyGraph graph) throws DatabaseException {
369 dwg.commit(graph, request);
374 } catch (DatabaseException e) {
378 } catch (Throwable e) {
380 throw new DatabaseException(e);
389 public void syncRequest(WriteOnly request) throws DatabaseException {
391 Resource defaultClusterSet = setClusterSet4NewResource(null);
394 writeSupport.performWriteRequest(this, request);
395 } catch (DatabaseException e) {
397 } catch (Throwable t) {
398 throw new DatabaseException(t);
400 setClusterSet4NewResource(defaultClusterSet);
406 public void claim(Resource subject, Resource predicate, Resource object) throws ServiceException {
408 if(subject == null || predicate == null || object == null) {
409 throw new ServiceException("Claim does not accept null arguments (subject=" + subject + ",predicate=" + predicate + ",object=" + object + ").");
412 if(processor.isImmutable(object)) {
413 claim(subject, predicate, null, object);
415 claim(subject, predicate, getPossibleInverse(predicate), object);
421 public void claim(Resource subject, Resource predicate, Resource inverse, Resource object) throws ServiceException {
423 if (MemWatch.isLowOnMemory())
426 if(subject == null) throw new ServiceException("Claim does not accept null arguments (subject).");
427 if(predicate == null) throw new ServiceException("Claim does not accept null arguments (predicate).");
428 if(object == null) throw new ServiceException("Claim does not accept null arguments (object).");
429 if(provider == null && subject.isPersistent() && !object.isPersistent())
430 throw new ServiceException("Cannot claim persistent statements where subject is persistent and object is virtual. Persistent database cannot contain statements that refer to virtual graphs.");
433 if(Development.DEVELOPMENT) {
435 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG, Bindings.BOOLEAN)) {
436 String text = "claim(" + resourceName(subject) + ":" + subject + ", " + resourceName(predicate) + ":" + predicate + ", " + resourceName(object) + ":" + object + ")";
437 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG_STACK, Bindings.BOOLEAN)) {
438 StringWriter writer = new StringWriter();
439 PrintWriter out = new PrintWriter(writer);
440 new Exception(text).printStackTrace(out);
441 Development.dispatchEvent(new ClaimEventImpl(this, provider, subject, predicate, object, writer.toString()));
443 Development.dispatchEvent(new ClaimEventImpl(this, provider, subject, predicate, object, text));
446 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITELOGGER_LOG, Bindings.BOOLEAN))
447 WriteLogger.logClaim(this, subject, predicate, inverse, object);
448 } catch (DatabaseException e) {
449 Logger.defaultLogError(e);
452 writeSupport.claim(provider, subject, predicate, object);
453 } catch(RuntimeException e) {
454 throw new ServiceException(e);
457 if(inverse == null) return;
458 if(subject.equals(object) && predicate.equals(inverse)) {
462 // Do as claim(s,p,o) already works -
463 // don't write inverse relations if object is immutable.
464 if(processor.isImmutable(object))
468 writeSupport.claim(provider, object, inverse, subject);
469 } catch(RuntimeException e) {
470 throw new ServiceException(e);
476 public void deny(Resource subject) throws ServiceException {
478 assert(subject != null);
482 for(Statement stm : getStatements(subject, getBuiltins().IsWeaklyRelatedTo)) {
483 if(subject.equals(stm.getSubject())) {
484 Resource inverse = getPossibleInverse(stm.getPredicate());
485 // if(inverse == null) {
487 // String name = adapt(stm.getPredicate(), String.class);
488 // throw new ResourceDoesNotSatisfyAssumptionException("Resource '" + name + "' does not have an inverse.");
489 // } catch (AdaptionException e) {
490 // throw new ResourceDoesNotSatisfyAssumptionException("Resource '" + stm.getPredicate() + "' does not have an inverse.");
493 deny(stm.getSubject(), stm.getPredicate(), inverse, stm.getObject());
497 } catch(DatabaseException e) {
499 throw new ServiceException(INTERNAL_ERROR_STRING, e);
506 public void deny(Resource subject, Resource predicate) throws ServiceException {
508 assert(subject != null);
509 assert(predicate != null);
513 for (Statement stm : getStatements(subject, predicate)) {
514 if (subject.equals(stm.getSubject())) {
515 Resource inverse = getPossibleInverse(stm.getPredicate());
516 // if(inverse == null) {
518 // String name = adapt(stm.getPredicate(), String.class);
519 // throw new ResourceDoesNotSatisfyAssumptionException("Resource '" + name + "' does not have an inverse.");
520 // } catch (AdaptionException e) {
521 // throw new ResourceDoesNotSatisfyAssumptionException("Resource '" + stm.getPredicate() + "' does not have an inverse.");
524 deny(stm.getSubject(), stm.getPredicate(), inverse, stm.getObject());
528 } catch(DatabaseException e) {
530 throw new ServiceException(INTERNAL_ERROR_STRING, e);
537 public void deny(Resource subject, Resource predicate, Resource object) throws ServiceException {
539 assert(subject != null);
540 assert(predicate != null);
541 assert(object != null);
544 for (Statement stm : getStatements(subject, predicate)) {
545 if (subject.equals(stm.getSubject()) && object.equals(stm.getObject())) {
546 Resource inverse = getPossibleInverse(stm.getPredicate());
547 deny(stm.getSubject(), stm.getPredicate(), inverse, stm.getObject());
550 } catch (DatabaseException e) {
551 throw new ServiceException(INTERNAL_ERROR_STRING, e);
557 public void denyStatement(Resource subject, Resource predicate, Resource object) throws ServiceException {
559 assert(subject != null);
560 assert(predicate != null);
561 assert(object != null);
563 Resource inverse = getPossibleInverse(predicate);
564 // if(inverse == null) {
566 // String name = adapt(predicate, String.class);
567 // throw new ResourceDoesNotSatisfyAssumptionException("Resource '" + name + "' does not have an inverse.");
568 // } catch (AdaptionException e) {
569 // throw new ResourceDoesNotSatisfyAssumptionException("Resource '" + predicate + "' does not have an inverse.");
572 deny(subject, predicate, inverse, object);
577 public void deny(Statement statement) throws ServiceException {
578 assert(statement != null);
579 denyStatement(statement.getSubject(), statement.getPredicate(), statement.getObject());
583 public void deny(Resource subject, Resource predicate, Resource inverse, Resource object) throws ServiceException {
585 assert(subject != null);
586 assert(predicate != null);
587 assert(object != null);
589 VirtualGraph provider = processor.getProvider(subject, predicate, object);
591 deny(subject, predicate, inverse, object, provider);
596 * Note: We assume here that all inverse pairs of statements are stored in the same virtual graph.
599 public void deny(Resource subject, Resource predicate, Resource inverse, Resource object, VirtualGraph provider) throws ServiceException {
601 assert(subject != null);
602 assert(predicate != null);
603 assert(object != null);
605 if(Development.DEVELOPMENT) {
607 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG, Bindings.BOOLEAN)) {
608 String text = "deny(" + resourceName(subject) + ":" + subject + ", " + resourceName(predicate) + ":" + predicate + ", " + resourceName(object) + ":" + object + ")";
609 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG_STACK, Bindings.BOOLEAN)) {
610 StringWriter writer = new StringWriter();
611 PrintWriter out = new PrintWriter(writer);
612 new Exception(text).printStackTrace(out);
613 Development.dispatchEvent(new DenyEventImpl(this, provider, subject, predicate, object, writer.toString()));
615 Development.dispatchEvent(new DenyEventImpl(this, provider, subject, predicate, object, text));
618 } catch (DatabaseException e) {
619 Logger.defaultLogError(e);
624 writeSupport.removeStatement(provider, subject, predicate, object);
625 } catch(Throwable e) {
626 throw new InternalException("bug in deny(s,p,i,o)", e);
629 if(inverse == null || (subject.equals(object) && predicate.equals(inverse))) return;
631 // don't deny inverse relations if object is immutable.
632 if(processor.isImmutable(object))
636 writeSupport.removeStatement(provider, object, inverse, subject);
637 } catch(Throwable e) {
638 throw new InternalException("bug in deny(s,p,i,o)", e);
644 public void claimValue(Resource resource, Object value) throws ServiceException {
647 Binding b = Bindings.getBinding(value.getClass());
648 claimValue(resource, value, b);
649 } catch(BindingConstructionException e) {
650 throw new IllegalArgumentException(e);
656 public void claimValue(Resource resource, Object value, Binding binding) throws ServiceException {
658 if(value == null) throw new ServiceException("claimValue does not accept null value");
659 if(binding == null) throw new ServiceException("claimValue does not accept null binding");
661 if(Development.DEVELOPMENT) {
663 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG, Bindings.BOOLEAN)) {
664 String valueText = Literals.shortString(value.toString());
665 String text = "claimValue(" + resourceName(resource) + ", " + valueText + ")";
666 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG_STACK, Bindings.BOOLEAN)) {
667 StringWriter writer = new StringWriter();
668 PrintWriter out = new PrintWriter(writer);
669 new Exception(text).printStackTrace(out);
670 Development.dispatchEvent(new ClaimValueEventImpl(this, provider, resource, value, binding, writer.toString()));
672 Development.dispatchEvent(new ClaimValueEventImpl(this, provider, resource, value, binding, text));
675 } catch (DatabaseException e) {
676 Logger.defaultLogError(e);
681 Serializer serializer = getSerializer(binding);
682 //Serializer serializer = binding.serializer();
683 byte[] data = serializer.serialize(value);
685 if(Development.DEVELOPMENT) {
687 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITELOGGER_LOG, Bindings.BOOLEAN))
688 WriteLogger.logValue(this, resource, data);
689 } catch (DatabaseException e) {
690 Logger.defaultLogError(e);
694 writeSupport.claimValue(provider, resource, data);
696 } catch (DatabaseException e) {
697 throw new ServiceException(e);
698 } catch (SerializationException e) {
699 throw new ServiceException(e);
700 } catch (IOException e) {
701 throw new ServiceException(e);
706 THashMap<Class<?>, Resource> builtinValues = new THashMap<Class<?>, Resource>(32);
708 private void initBuiltinValues(Layer0 b) {
710 if(!builtinValues.isEmpty()) return;
712 builtinValues.put(String.class, b.String);
713 builtinValues.put(Double.class, b.Double);
714 builtinValues.put(Float.class, b.Float);
715 builtinValues.put(Long.class, b.Long);
716 builtinValues.put(Integer.class, b.Integer);
717 builtinValues.put(Byte.class, b.Byte);
718 builtinValues.put(Boolean.class, b.Boolean);
719 builtinValues.put(Variant.class, b.Variant);
721 builtinValues.put(String[].class, b.StringArray);
722 builtinValues.put(double[].class, b.DoubleArray);
723 builtinValues.put(float[].class, b.FloatArray);
724 builtinValues.put(long[].class, b.LongArray);
725 builtinValues.put(int[].class, b.IntegerArray);
726 builtinValues.put(byte[].class, b.ByteArray);
727 builtinValues.put(boolean[].class, b.BooleanArray);
729 builtinValues.put(MutableString.class, b.String);
730 builtinValues.put(MutableDouble.class, b.Double);
731 builtinValues.put(MutableFloat.class, b.Float);
732 builtinValues.put(MutableLong.class, b.Long);
733 builtinValues.put(MutableInteger.class, b.Integer);
734 builtinValues.put(MutableByte.class, b.Byte);
735 builtinValues.put(MutableBoolean.class, b.Boolean);
740 public void addLiteral(Resource resource, Resource predicate, Resource inverse, Resource type, Object value, Binding binding) throws ManyObjectsForFunctionalRelationException, ServiceException {
742 Layer0 b = getBuiltins();
743 Resource valueResource = newResource();
744 claim(valueResource, b.InstanceOf, null, type);
745 claim(resource, predicate, inverse, valueResource);
746 claimValue(valueResource, value, binding);
751 public void addLiteral(Resource resource, Resource predicate, Resource inverse, Object value, Binding binding) throws ManyObjectsForFunctionalRelationException, ServiceException {
753 Layer0 b = getBuiltins();
754 initBuiltinValues(b);
755 Resource literal = newResource();
757 Class<?> clazz = value.getClass();
758 Resource type = builtinValues.get(clazz);
761 Resource dataType = newResource();
762 claim(dataType, b.InstanceOf, null, b.DataType);
763 claimValue(dataType, binding.type(), DATA_TYPE_BINDING);
764 claim(literal, b.HasDataType, b.HasDataType_Inverse, dataType);
767 claim(literal, b.InstanceOf, null, type);
768 claim(resource, predicate, inverse, literal);
769 claimValue(literal, value, binding);
774 public <T extends Accessor> T newLiteral(Resource resource, Resource predicate, Datatype datatype, Object initialValue)
775 throws DatabaseException {
776 Layer0 b = getBuiltins();
777 initBuiltinValues(b);
778 Resource literal = newResource();
779 claim(literal, b.InstanceOf, null, b.Literal);
780 Resource dataType = newResource();
781 claim(dataType, b.InstanceOf, null, b.DataType);
782 claimValue(dataType, datatype, DATA_TYPE_BINDING);
783 claim(literal, b.HasDataType, dataType);
784 claim(resource, predicate, literal);
785 return createAccessor(literal, datatype, initialValue);
788 public RandomAccessBinary createRandomAccessBinary
789 (Resource resource, Resource predicate, Datatype datatype, Object initiaValue)
790 throws DatabaseException {
791 Layer0 b = getBuiltins();
792 initBuiltinValues(b);
793 Resource literal = newResource();
794 claim(literal, b.InstanceOf, null, b.Literal);
795 Resource dataType = newResource();
796 claim(dataType, b.InstanceOf, null, b.DataType);
797 claimValue(dataType, datatype, DATA_TYPE_BINDING);
798 claim(literal, b.HasDataType, dataType);
799 claim(resource, predicate, literal);
800 return createRandomAccessBinary(literal, datatype, initiaValue);
803 public void claimLiteral(Resource resource, Resource predicate, Object value) throws ManyObjectsForFunctionalRelationException, ServiceException {
806 Binding binding = Bindings.getBinding(value.getClass());
807 claimLiteral(resource, predicate, value, binding);
808 } catch(BindingConstructionException e) {
809 throw new IllegalArgumentException(e);
815 public void claimLiteral(Resource resource, Resource predicate, Object value, Binding binding) throws ManyObjectsForFunctionalRelationException, ServiceException {
817 Layer0 b = getBuiltins();
818 initBuiltinValues(b);
820 Statement literalStatement = getPossibleStatement(resource, predicate);
822 if(literalStatement != null && resource.equals(literalStatement.getSubject())) {
824 claimValue(literalStatement.getObject(), value, binding);
828 Class<?> clazz = value.getClass();
829 Resource type = builtinValues.get(clazz);
830 Resource literal = newResource();
833 Resource dataType = newResource();
834 claim(dataType, b.InstanceOf, null, b.DataType);
835 claimValue(dataType, binding.type(), DATA_TYPE_BINDING);
836 claim(literal, b.HasDataType, null, dataType);
838 claim(literal, b.InstanceOf, null, type);
839 claimValue(literal, value, binding);
840 claim(resource, predicate, literal);
844 if(Development.DEVELOPMENT) {
846 getPossibleStatement(resource, predicate);
847 } catch (ManyObjectsForFunctionalRelationException e) {
848 System.err.println("err " + ((ResourceImpl)resource).id + " " + ((ResourceImpl)predicate).id);
849 getPossibleStatement(resource, predicate);
856 public void claimLiteral(Resource resource, Resource predicate, Resource type, Object value)
857 throws org.simantics.db.exception.BindingException, ManyObjectsForFunctionalRelationException, ServiceException {
860 Binding binding = Bindings.getBinding(value.getClass());
861 claimLiteral(resource, predicate, type, value, binding);
862 } catch(BindingConstructionException e) {
863 throw new IllegalArgumentException(e);
869 public void claimLiteral(Resource resource, Resource predicate, Resource type, Object value, Binding binding)
870 throws org.simantics.db.exception.BindingException, ManyObjectsForFunctionalRelationException, ServiceException {
872 Layer0 b = getBuiltins();
874 Statement literalStatement = getPossibleStatement(resource, predicate);
876 if(literalStatement != null && resource.equals(literalStatement.getSubject())) {
878 claimValue(literalStatement.getObject(), value, binding);
882 Resource literal = newResource();
883 claim(literal, b.InstanceOf, null, type);
884 claimValue(literal, value, binding);
885 claim(resource, predicate, literal);
892 public void claimLiteral(Resource resource, Resource predicate, Resource inverse, Resource type, Object value)
893 throws org.simantics.db.exception.BindingException, ManyObjectsForFunctionalRelationException, ServiceException {
896 Binding binding = Bindings.getBinding(value.getClass());
897 claimLiteral(resource, predicate, inverse, type, value, binding);
898 } catch(BindingConstructionException e) {
899 throw new IllegalArgumentException(e);
905 public void claimLiteral(Resource resource, Resource predicate, Resource inverse, Resource type, Object value, Binding binding)
906 throws org.simantics.db.exception.BindingException, ManyObjectsForFunctionalRelationException, ServiceException {
908 Layer0 b = getBuiltins();
910 Statement literalStatement = getPossibleStatement(resource, predicate);
912 if(literalStatement != null && resource.equals(literalStatement.getSubject())) {
914 claimValue(literalStatement.getObject(), value, binding);
918 Resource literal = newResource();
919 claim(literal, b.InstanceOf, null, type);
920 claimValue(literal, value, binding);
921 claim(resource, predicate, inverse, literal);
929 public void denyValue(Resource resource) throws ServiceException {
931 denyValue0(resource, null);
936 public void denyValue(Resource resource, VirtualGraph valueProvider) throws ServiceException {
938 denyValue0(resource, valueProvider);
943 * @param resource resource to remove value from
944 * @param valueProvider <code>null</code> means the caller doesn't know and
945 * this method must find out
946 * @throws ServiceException
948 private void denyValue0(Resource resource, VirtualGraph valueProvider) throws ServiceException {
950 if(Development.DEVELOPMENT) {
952 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG, Bindings.BOOLEAN)) {
953 Object oldValue = getPossibleValue(resource);
954 String valueText = oldValue == null ? "<no value>" : oldValue.toString();
955 String text = "denyValue(" + resourceName(resource) + ", " + valueText + ")";
956 if (oldValue != null) {
957 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG_STACK, Bindings.BOOLEAN)) {
958 StringWriter writer = new StringWriter();
959 PrintWriter out = new PrintWriter(writer);
960 new Exception(text).printStackTrace(out);
961 Development.dispatchEvent(new DenyValueEventImpl(this, provider, resource, oldValue, writer.toString()));
963 Development.dispatchEvent(new DenyValueEventImpl(this, provider, resource, oldValue, text));
967 } catch (DatabaseException e) {
968 Logger.defaultLogError(e);
972 if (provider != null) {
974 // Can only remove from the specified VirtualGraph
975 if (resource.isPersistent())
976 throw new ArgumentException("Tried to remove literal value from persistent resource " + resource
977 + " using virtual graph '" + provider.getIdentifier() + "'");
978 writeSupport.denyValue(provider, resource);
982 // Can remove from any provider
983 if (resource.isPersistent()) {
984 // A persistent resource cannot have a virtual literal
985 // so this should be safe.
986 writeSupport.denyValue(provider, resource);
988 // A virtual resource cannot have a persistent literal.
989 // Must look for a virtual graph for resource.
990 Layer0 L0 = getBuiltins();
991 if (valueProvider == null) {
992 if (hasStatement(resource, L0.InstanceOf)) {
993 valueProvider = processor.getProvider(resource, L0.InstanceOf);
994 } else if (hasStatement(resource, L0.Inherits)) {
995 valueProvider = processor.getProvider(resource, L0.Inherits);
996 } else if (hasStatement(resource, L0.SubrelationOf)) {
997 valueProvider = processor.getProvider(resource, L0.SubrelationOf);
1000 if (valueProvider != null)
1001 writeSupport.denyValue(valueProvider, resource);
1009 public void denyValue(Resource resource, Resource predicate) throws ManyObjectsForFunctionalRelationException, ServiceException {
1011 Statement valueStatement = getPossibleStatement(resource, predicate);
1013 if (valueStatement != null && !valueStatement.isAsserted(resource)) {
1015 Resource value = valueStatement.getObject();
1016 Resource inverse = getPossibleInverse(predicate);
1018 if (provider != null) {
1020 // Can only remove from the specified provider
1021 deny(resource, predicate, inverse, value, provider);
1022 writeSupport.denyValue(provider, value);
1026 // Can remove from any provider
1027 VirtualGraph statementProvider = processor.getProvider(resource, valueStatement.getPredicate(), value);
1028 deny(resource, predicate, inverse, value, statementProvider);
1029 denyValue0(resource, statementProvider);
1038 public void flushCluster() {
1040 writeSupport.flushCluster();
1045 public void flushCluster(Resource r) {
1046 writeSupport.flushCluster(r);
1049 Object serialize(Object value) {
1051 Class<?> clazz = value.getClass();
1053 if(clazz.isArray()) return value;
1055 if(Double.class == clazz) return new double[] { (Double)value };
1056 else if(String.class == clazz) return new String[] { (String)value };
1057 else if(Integer.class == clazz) return new int[] { (Integer)value };
1058 else if(Boolean.class == clazz) return new boolean[] { (Boolean)value };
1059 else if(Long.class == clazz) return new long[] { (Long)value };
1060 else if(Byte.class == clazz) return new byte[] { (Byte)value };
1061 else if(Float.class == clazz) return new float[] { (Float)value };
1067 public <T> void addMetadata(Metadata data) throws ServiceException {
1068 writeSupport.addMetadata(data);
1072 public <T extends Metadata> T getMetadata(Class<T> clazz) throws ServiceException {
1073 return writeSupport.getMetadata(clazz);
1077 public TreeMap<String, byte[]> getMetadata() {
1078 return writeSupport.getMetadata();
1082 public String toString() {
1083 return "WriteGraphImpl[thread=" + Thread.currentThread() + "]";
1086 public void commitAccessorChanges(WriteTraits writeTraits) {
1088 RandomAccessValueSupport ravs = getSession().peekService(RandomAccessValueSupport.class);
1092 for(Pair<Resource, ResourceData> entry : ravs.entries()) {
1093 ResourceData rd = entry.second;
1094 if(!rd.isChanged()) continue;
1095 Resource resource = entry.first;
1097 ExternalValueSupport evs = getService(ExternalValueSupport.class);
1098 long vsize = rd.oldExternalValue ? evs.getValueSize(this, resource) : -1;
1099 long bsize = rd.binaryFile.length();
1100 final int N = 1<<20;
1101 final int LIMIT = 10 * 1000 * 1000;
1104 byte[] bytes = new byte[N];
1105 rd.binaryFile.reset();
1106 rd.binaryFile.position(0);
1108 // if (LIMIT < left)
1109 // evs.moveValue(this, resource);
1111 int length = N < left ? N : (int)left;
1112 rd.binaryFile.readFully(bytes, 0, length);
1113 evs.writeValue(this, resource, offset, length, bytes);
1117 if (count > LIMIT) {
1119 // evs.commitAndContinue(this, writeTraits, resource);
1120 // evs.moveValue(this, resource);
1121 // This is needed so we don't create too many requests and run out of heap.
1122 evs.wait4RequestsLess(1);
1125 if (bsize < vsize) // truncate
1126 evs.writeValue(this, resource, bsize, 0, new byte[0]);
1127 } catch (DatabaseException e) {
1128 Logger.defaultLogError(e);
1131 } catch(IOException e) {
1132 Logger.defaultLogError(e);
1133 } catch (RuntimeException e) {
1134 Logger.defaultLogError(e);
1139 public VirtualGraph getProvider() {
1144 public void clearUndoList(WriteTraits writeTraits) {
1145 writeSupport.clearUndoList(writeTraits);
1148 public void markUndoPoint() {
1149 writeSupport.startUndo();