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;
18 import java.util.function.Consumer;
20 import org.simantics.databoard.Bindings;
21 import org.simantics.databoard.accessor.Accessor;
22 import org.simantics.databoard.binding.Binding;
23 import org.simantics.databoard.binding.error.BindingConstructionException;
24 import org.simantics.databoard.binding.mutable.Variant;
25 import org.simantics.databoard.primitives.MutableBoolean;
26 import org.simantics.databoard.primitives.MutableByte;
27 import org.simantics.databoard.primitives.MutableDouble;
28 import org.simantics.databoard.primitives.MutableFloat;
29 import org.simantics.databoard.primitives.MutableInteger;
30 import org.simantics.databoard.primitives.MutableLong;
31 import org.simantics.databoard.primitives.MutableString;
32 import org.simantics.databoard.serialization.SerializationException;
33 import org.simantics.databoard.serialization.Serializer;
34 import org.simantics.databoard.type.Datatype;
35 import org.simantics.databoard.util.binary.RandomAccessBinary;
36 import org.simantics.db.DevelopmentKeys;
37 import org.simantics.db.ExternalValueSupport;
38 import org.simantics.db.Metadata;
39 import org.simantics.db.Resource;
40 import org.simantics.db.Statement;
41 import org.simantics.db.VirtualGraph;
42 import org.simantics.db.WriteGraph;
43 import org.simantics.db.WriteOnlyGraph;
44 import org.simantics.db.common.request.WriteOnlyRequest;
45 import org.simantics.db.common.utils.Literals;
46 import org.simantics.db.common.utils.Logger;
47 import org.simantics.db.exception.ArgumentException;
48 import org.simantics.db.exception.DatabaseException;
49 import org.simantics.db.exception.InternalException;
50 import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;
51 import org.simantics.db.exception.ServiceException;
52 import org.simantics.db.impl.DatabaseUtils;
53 import org.simantics.db.impl.MemWatch;
54 import org.simantics.db.impl.ResourceImpl;
55 import org.simantics.db.impl.internal.RandomAccessValueSupport;
56 import org.simantics.db.impl.internal.ResourceData;
57 import org.simantics.db.impl.query.CacheEntry;
58 import org.simantics.db.impl.query.QueryProcessor;
59 import org.simantics.db.impl.support.WriteRequestScheduleSupport;
60 import org.simantics.db.procedure.Procedure;
61 import org.simantics.db.request.DelayedWrite;
62 import org.simantics.db.request.DelayedWriteResult;
63 import org.simantics.db.request.Write;
64 import org.simantics.db.request.WriteOnly;
65 import org.simantics.db.request.WriteOnlyResult;
66 import org.simantics.db.request.WriteResult;
67 import org.simantics.db.request.WriteTraits;
68 import org.simantics.layer0.Layer0;
69 import org.simantics.utils.Development;
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 public ReadGraphImpl newRestart(ReadGraphImpl impl) {
134 WriteGraphImpl write = processor.getSession().getService(WriteGraphImpl.class);
141 final public Resource newResource() throws ServiceException {
145 Resource result = writeSupport.createResource(provider);
147 if(Development.DEVELOPMENT) {
148 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITELOGGER_LOG, Bindings.BOOLEAN))
149 WriteLogger.logNewResource(this, result);
154 } catch (DatabaseException e) {
155 throw new ServiceException(e);
161 final public Resource newResource(long clusterId) throws ServiceException {
165 Resource result = writeSupport.createResource(provider, clusterId);
167 if(Development.DEVELOPMENT) {
168 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITELOGGER_LOG, Bindings.BOOLEAN))
169 WriteLogger.logNewResource(this, result);
174 } catch (DatabaseException e) {
175 throw new ServiceException(e);
181 public Resource newResource(Resource clusterSet) throws ServiceException {
184 if (provider != null)
185 result = writeSupport.createResource(provider);
187 result = writeSupport.createResource(provider, clusterSet);
188 if(Development.DEVELOPMENT) {
189 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITELOGGER_LOG, Bindings.BOOLEAN))
190 WriteLogger.logNewResource(this, result);
193 } catch (ServiceException e) {
195 } catch (DatabaseException e) {
196 throw new ServiceException(e);
201 public void newClusterSet(Resource clusterSet) throws ServiceException {
203 if (provider == null)
204 writeSupport.createClusterSet(provider, clusterSet);
205 if(Development.DEVELOPMENT) {
206 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITELOGGER_LOG, Bindings.BOOLEAN))
207 WriteLogger.logNewResource(this, clusterSet);
209 } catch (ServiceException e) {
211 } catch (DatabaseException e) {
212 throw new ServiceException(e);
217 public Resource setClusterSet4NewResource(Resource clusterSet)
218 throws ServiceException {
219 return writeSupport.setDefaultClusterSet(clusterSet);
222 * Compares two object for equality, allowing null objects also.
226 * @return true if both arguments are <code>null</code> or equal
228 static boolean safeEquals(Object o1, Object o2) {
231 if (o1 == null && o2 == null)
233 if (o1 == null || o2 == null)
235 return o1.equals(o2);
239 public void asyncRequest(DelayedWrite request) {
240 assert (request != null);
241 getWriteRequestScheduler().scheduleRequest(request, e -> {
243 Logger.defaultLogError(e);
244 }, null, Boolean.TRUE);
248 public void asyncRequest(DelayedWrite request, Consumer<DatabaseException> callback) {
249 assert (request != null);
250 getWriteRequestScheduler().scheduleRequest(request, callback, null, Boolean.TRUE);
254 public <T> void asyncRequest(DelayedWriteResult<T> request, Procedure<T> procedure) {
255 assert (request != null);
256 getWriteRequestScheduler().scheduleRequest(request, procedure, null, Boolean.TRUE);
260 public void asyncRequest(final Write r) {
262 getWriteRequestScheduler().scheduleRequest(r, e -> {
264 Logger.defaultLogError(e);
265 }, null, Boolean.TRUE);
269 public void asyncRequest(Write request, Consumer<DatabaseException> callback) {
270 assert (request != null);
271 getWriteRequestScheduler().scheduleRequest(request, callback, null, Boolean.TRUE);
275 public void asyncRequest(WriteOnly request) {
276 assert (request != null);
277 getWriteRequestScheduler().scheduleRequest(request, e -> {
279 Logger.defaultLogError(e);
280 }, null, Boolean.TRUE);
284 public void asyncRequest(WriteOnly request, Consumer<DatabaseException> callback) {
285 assert (request != null);
286 getWriteRequestScheduler().scheduleRequest(request, callback, null, Boolean.TRUE);
290 public <T> void asyncRequest(WriteOnlyResult<T> request, Procedure<T> procedure) {
291 assert (request != null);
292 getWriteRequestScheduler().scheduleRequest(request, procedure, null, Boolean.TRUE);
296 public <T> void asyncRequest(WriteResult<T> request, Procedure<T> procedure) {
297 assert (request != null);
298 getWriteRequestScheduler().scheduleRequest(request, procedure, null, Boolean.TRUE);
302 public void syncRequest(Write request) throws DatabaseException {
304 Resource defaultClusterSet = setClusterSet4NewResource(null);
306 WriteGraphImpl graph = (WriteGraphImpl)newSync(request.getProvider());
308 writeSupport.performWriteRequest(graph, request);
309 } catch (DatabaseException e) {
311 } catch (Throwable t) {
312 throw new DatabaseException(t);
314 setClusterSet4NewResource(defaultClusterSet);
321 public <T> T syncRequest(WriteResult<T> request) throws DatabaseException {
323 Resource defaultClusterSet = setClusterSet4NewResource(null);
325 WriteGraphImpl graph = (WriteGraphImpl)newSync(request.getProvider());
327 return writeSupport.performWriteRequest(graph, request);
328 } catch (DatabaseException e) {
330 } catch (Throwable t) {
331 throw new DatabaseException(t);
333 setClusterSet4NewResource(defaultClusterSet);
338 public void syncRequest(final DelayedWrite request) throws DatabaseException {
342 final DelayedWriteGraph dwg = new DelayedWriteGraph(this);
343 request.perform(dwg);
345 syncRequest(new WriteOnlyRequest() {
348 public void perform(WriteOnlyGraph graph) throws DatabaseException {
349 dwg.commit(graph, request);
354 } catch (DatabaseException e) {
358 } catch (Throwable e) {
360 throw new DatabaseException(e);
369 public void syncRequest(WriteOnly request) throws DatabaseException {
371 Resource defaultClusterSet = setClusterSet4NewResource(null);
374 writeSupport.performWriteRequest(this, request);
375 } catch (DatabaseException e) {
377 } catch (Throwable t) {
378 throw new DatabaseException(t);
380 setClusterSet4NewResource(defaultClusterSet);
386 public void claim(Resource subject, Resource predicate, Resource object) throws ServiceException {
388 if(subject == null || predicate == null || object == null) {
389 throw new ServiceException("Claim does not accept null arguments (subject=" + subject + ",predicate=" + predicate + ",object=" + object + ").");
392 if(processor.isImmutable(object)) {
393 claim(subject, predicate, null, object);
395 claim(subject, predicate, getPossibleInverse(predicate), object);
401 public void claim(Resource subject, Resource predicate, Resource inverse, Resource object) throws ServiceException {
403 if (MemWatch.isLowOnMemory())
406 if(subject == null) throw new ServiceException("Claim does not accept null arguments (subject).");
407 if(predicate == null) throw new ServiceException("Claim does not accept null arguments (predicate).");
408 if(object == null) throw new ServiceException("Claim does not accept null arguments (object).");
409 if(provider == null && subject.isPersistent() && !object.isPersistent())
410 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.");
413 if(Development.DEVELOPMENT) {
415 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG, Bindings.BOOLEAN)) {
416 String text = "claim(" + resourceName(subject) + ":" + subject + ", " + resourceName(predicate) + ":" + predicate + ", " + resourceName(object) + ":" + object + ")";
417 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG_STACK, Bindings.BOOLEAN)) {
418 StringWriter writer = new StringWriter();
419 PrintWriter out = new PrintWriter(writer);
420 new Exception(text).printStackTrace(out);
421 Development.dispatchEvent(new ClaimEventImpl(this, provider, subject, predicate, object, writer.toString()));
423 Development.dispatchEvent(new ClaimEventImpl(this, provider, subject, predicate, object, text));
426 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITELOGGER_LOG, Bindings.BOOLEAN))
427 WriteLogger.logClaim(this, subject, predicate, inverse, object);
428 } catch (DatabaseException e) {
429 Logger.defaultLogError(e);
432 writeSupport.claim(provider, subject, predicate, object);
433 } catch(RuntimeException e) {
434 throw new ServiceException(e);
437 if(inverse == null) return;
438 if(subject.equals(object) && predicate.equals(inverse)) {
442 // Do as claim(s,p,o) already works -
443 // don't write inverse relations if object is immutable.
444 if(processor.isImmutable(object))
448 writeSupport.claim(provider, object, inverse, subject);
449 } catch(RuntimeException e) {
450 throw new ServiceException(e);
456 public void deny(Resource subject) throws ServiceException {
458 assert(subject != null);
462 for(Statement stm : getStatements(subject, getBuiltins().IsWeaklyRelatedTo)) {
463 if(subject.equals(stm.getSubject())) {
464 Resource inverse = getPossibleInverse(stm.getPredicate());
465 // if(inverse == null) {
467 // String name = adapt(stm.getPredicate(), String.class);
468 // throw new ResourceDoesNotSatisfyAssumptionException("Resource '" + name + "' does not have an inverse.");
469 // } catch (AdaptionException e) {
470 // throw new ResourceDoesNotSatisfyAssumptionException("Resource '" + stm.getPredicate() + "' does not have an inverse.");
473 deny(stm.getSubject(), stm.getPredicate(), inverse, stm.getObject());
477 } catch(DatabaseException e) {
479 throw new ServiceException(INTERNAL_ERROR_STRING, e);
486 public void deny(Resource subject, Resource predicate) throws ServiceException {
488 assert(subject != null);
489 assert(predicate != null);
493 for (Statement stm : getStatements(subject, predicate)) {
494 if (subject.equals(stm.getSubject())) {
495 Resource inverse = getPossibleInverse(stm.getPredicate());
496 // if(inverse == null) {
498 // String name = adapt(stm.getPredicate(), String.class);
499 // throw new ResourceDoesNotSatisfyAssumptionException("Resource '" + name + "' does not have an inverse.");
500 // } catch (AdaptionException e) {
501 // throw new ResourceDoesNotSatisfyAssumptionException("Resource '" + stm.getPredicate() + "' does not have an inverse.");
504 deny(stm.getSubject(), stm.getPredicate(), inverse, stm.getObject());
508 } catch(DatabaseException e) {
510 throw new ServiceException(INTERNAL_ERROR_STRING, e);
517 public void deny(Resource subject, Resource predicate, Resource object) throws ServiceException {
519 assert(subject != null);
520 assert(predicate != null);
521 assert(object != null);
524 for (Statement stm : getStatements(subject, predicate)) {
525 if (subject.equals(stm.getSubject()) && object.equals(stm.getObject())) {
526 Resource inverse = getPossibleInverse(stm.getPredicate());
527 deny(stm.getSubject(), stm.getPredicate(), inverse, stm.getObject());
530 } catch (DatabaseException e) {
531 throw new ServiceException(INTERNAL_ERROR_STRING, e);
537 public void denyStatement(Resource subject, Resource predicate, Resource object) throws ServiceException {
539 assert(subject != null);
540 assert(predicate != null);
541 assert(object != null);
543 Resource inverse = getPossibleInverse(predicate);
544 // if(inverse == null) {
546 // String name = adapt(predicate, String.class);
547 // throw new ResourceDoesNotSatisfyAssumptionException("Resource '" + name + "' does not have an inverse.");
548 // } catch (AdaptionException e) {
549 // throw new ResourceDoesNotSatisfyAssumptionException("Resource '" + predicate + "' does not have an inverse.");
552 deny(subject, predicate, inverse, object);
557 public void deny(Statement statement) throws ServiceException {
558 assert(statement != null);
559 denyStatement(statement.getSubject(), statement.getPredicate(), statement.getObject());
563 public void deny(Resource subject, Resource predicate, Resource inverse, Resource object) throws ServiceException {
565 assert(subject != null);
566 assert(predicate != null);
567 assert(object != null);
569 VirtualGraph provider = processor.getProvider(subject, predicate, object);
571 deny(subject, predicate, inverse, object, provider);
576 * Note: We assume here that all inverse pairs of statements are stored in the same virtual graph.
579 public void deny(Resource subject, Resource predicate, Resource inverse, Resource object, VirtualGraph provider) throws ServiceException {
581 assert(subject != null);
582 assert(predicate != null);
583 assert(object != null);
585 if(Development.DEVELOPMENT) {
587 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG, Bindings.BOOLEAN)) {
588 String text = "deny(" + resourceName(subject) + ":" + subject + ", " + resourceName(predicate) + ":" + predicate + ", " + resourceName(object) + ":" + object + ")";
589 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG_STACK, Bindings.BOOLEAN)) {
590 StringWriter writer = new StringWriter();
591 PrintWriter out = new PrintWriter(writer);
592 new Exception(text).printStackTrace(out);
593 Development.dispatchEvent(new DenyEventImpl(this, provider, subject, predicate, object, writer.toString()));
595 Development.dispatchEvent(new DenyEventImpl(this, provider, subject, predicate, object, text));
598 } catch (DatabaseException e) {
599 Logger.defaultLogError(e);
604 writeSupport.removeStatement(provider, subject, predicate, object);
605 } catch(Throwable e) {
606 throw new InternalException("bug in deny(s,p,i,o)", e);
609 if(inverse == null || (subject.equals(object) && predicate.equals(inverse))) return;
611 // don't deny inverse relations if object is immutable.
612 if(processor.isImmutable(object))
616 writeSupport.removeStatement(provider, object, inverse, subject);
617 } catch(Throwable e) {
618 throw new InternalException("bug in deny(s,p,i,o)", e);
624 public void claimValue(Resource resource, Object value) throws ServiceException {
627 Binding b = Bindings.getBinding(value.getClass());
628 claimValue(resource, value, b);
629 } catch(BindingConstructionException e) {
630 throw new IllegalArgumentException(e);
636 public void claimValue(Resource resource, Object value, Binding binding) throws ServiceException {
638 if(value == null) throw new ServiceException("claimValue does not accept null value");
639 if(binding == null) throw new ServiceException("claimValue does not accept null binding");
641 if(Development.DEVELOPMENT) {
643 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG, Bindings.BOOLEAN)) {
644 String valueText = Literals.shortString(value.toString());
645 String text = "claimValue(" + resourceName(resource) + ", " + valueText + ")";
646 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG_STACK, Bindings.BOOLEAN)) {
647 StringWriter writer = new StringWriter();
648 PrintWriter out = new PrintWriter(writer);
649 new Exception(text).printStackTrace(out);
650 Development.dispatchEvent(new ClaimValueEventImpl(this, provider, resource, value, binding, writer.toString()));
652 Development.dispatchEvent(new ClaimValueEventImpl(this, provider, resource, value, binding, text));
655 } catch (DatabaseException e) {
656 Logger.defaultLogError(e);
661 Serializer serializer = getSerializer(binding);
662 //Serializer serializer = binding.serializer();
663 byte[] data = serializer.serialize(value);
665 if(Development.DEVELOPMENT) {
667 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITELOGGER_LOG, Bindings.BOOLEAN))
668 WriteLogger.logValue(this, resource, data);
669 } catch (DatabaseException e) {
670 Logger.defaultLogError(e);
674 writeSupport.claimValue(provider, resource, data);
676 } catch (DatabaseException e) {
677 throw new ServiceException(e);
678 } catch (SerializationException e) {
679 throw new ServiceException(e);
680 } catch (IOException e) {
681 throw new ServiceException(e);
686 THashMap<Class<?>, Resource> builtinValues = new THashMap<Class<?>, Resource>(32);
688 private void initBuiltinValues(Layer0 b) {
690 if(!builtinValues.isEmpty()) return;
692 builtinValues.put(String.class, b.String);
693 builtinValues.put(Double.class, b.Double);
694 builtinValues.put(Float.class, b.Float);
695 builtinValues.put(Long.class, b.Long);
696 builtinValues.put(Integer.class, b.Integer);
697 builtinValues.put(Byte.class, b.Byte);
698 builtinValues.put(Boolean.class, b.Boolean);
699 builtinValues.put(Variant.class, b.Variant);
701 builtinValues.put(String[].class, b.StringArray);
702 builtinValues.put(double[].class, b.DoubleArray);
703 builtinValues.put(float[].class, b.FloatArray);
704 builtinValues.put(long[].class, b.LongArray);
705 builtinValues.put(int[].class, b.IntegerArray);
706 builtinValues.put(byte[].class, b.ByteArray);
707 builtinValues.put(boolean[].class, b.BooleanArray);
709 builtinValues.put(MutableString.class, b.String);
710 builtinValues.put(MutableDouble.class, b.Double);
711 builtinValues.put(MutableFloat.class, b.Float);
712 builtinValues.put(MutableLong.class, b.Long);
713 builtinValues.put(MutableInteger.class, b.Integer);
714 builtinValues.put(MutableByte.class, b.Byte);
715 builtinValues.put(MutableBoolean.class, b.Boolean);
720 public void addLiteral(Resource resource, Resource predicate, Resource inverse, Resource type, Object value, Binding binding) throws ManyObjectsForFunctionalRelationException, ServiceException {
722 Layer0 b = getBuiltins();
723 Resource valueResource = newResource();
724 claim(valueResource, b.InstanceOf, null, type);
725 claim(resource, predicate, inverse, valueResource);
726 claimValue(valueResource, value, binding);
731 public void addLiteral(Resource resource, Resource predicate, Resource inverse, Object value, Binding binding) throws ManyObjectsForFunctionalRelationException, ServiceException {
733 Layer0 b = getBuiltins();
734 initBuiltinValues(b);
735 Resource literal = newResource();
737 Class<?> clazz = value.getClass();
738 Resource type = builtinValues.get(clazz);
741 Resource dataType = newResource();
742 claim(dataType, b.InstanceOf, null, b.DataType);
743 claimValue(dataType, binding.type(), DATA_TYPE_BINDING);
744 claim(literal, b.HasDataType, b.HasDataType_Inverse, dataType);
747 claim(literal, b.InstanceOf, null, type);
748 claim(resource, predicate, inverse, literal);
749 claimValue(literal, value, binding);
754 public <T extends Accessor> T newLiteral(Resource resource, Resource predicate, Datatype datatype, Object initialValue)
755 throws DatabaseException {
756 Layer0 b = getBuiltins();
757 initBuiltinValues(b);
758 Resource literal = newResource();
759 claim(literal, b.InstanceOf, null, b.Literal);
760 Resource dataType = newResource();
761 claim(dataType, b.InstanceOf, null, b.DataType);
762 claimValue(dataType, datatype, DATA_TYPE_BINDING);
763 claim(literal, b.HasDataType, dataType);
764 claim(resource, predicate, literal);
765 return createAccessor(literal, datatype, initialValue);
768 public RandomAccessBinary createRandomAccessBinary
769 (Resource resource, Resource predicate, Datatype datatype, Object initiaValue)
770 throws DatabaseException {
771 Layer0 b = getBuiltins();
772 initBuiltinValues(b);
773 Resource literal = newResource();
774 claim(literal, b.InstanceOf, null, b.Literal);
775 Resource dataType = newResource();
776 claim(dataType, b.InstanceOf, null, b.DataType);
777 claimValue(dataType, datatype, DATA_TYPE_BINDING);
778 claim(literal, b.HasDataType, dataType);
779 claim(resource, predicate, literal);
780 return createRandomAccessBinary(literal, datatype, initiaValue);
783 public void claimLiteral(Resource resource, Resource predicate, Object value) throws ManyObjectsForFunctionalRelationException, ServiceException {
786 Binding binding = Bindings.getBinding(value.getClass());
787 claimLiteral(resource, predicate, value, binding);
788 } catch(BindingConstructionException e) {
789 throw new IllegalArgumentException(e);
795 public void claimLiteral(Resource resource, Resource predicate, Object value, Binding binding) throws ManyObjectsForFunctionalRelationException, ServiceException {
797 Layer0 b = getBuiltins();
798 initBuiltinValues(b);
800 if(resource.toString().equals("[id=$319492]") && predicate.toString().equals("[id=$235477]"))
801 System.err.println("foobar2");
804 Statement literalStatement = getPossibleStatement(resource, predicate);
806 if(literalStatement != null && resource.equals(literalStatement.getSubject())) {
808 claimValue(literalStatement.getObject(), value, binding);
812 Class<?> clazz = value.getClass();
813 Resource type = builtinValues.get(clazz);
814 Resource literal = newResource();
817 Resource dataType = newResource();
818 claim(dataType, b.InstanceOf, null, b.DataType);
819 claimValue(dataType, binding.type(), DATA_TYPE_BINDING);
820 claim(literal, b.HasDataType, null, dataType);
822 claim(literal, b.InstanceOf, null, type);
823 claimValue(literal, value, binding);
824 claim(resource, predicate, literal);
828 if(Development.DEVELOPMENT) {
830 getPossibleStatement(resource, predicate);
831 } catch (ManyObjectsForFunctionalRelationException e) {
832 System.err.println("err " + ((ResourceImpl)resource).id + " " + ((ResourceImpl)predicate).id);
833 getPossibleStatement(resource, predicate);
840 public void claimLiteral(Resource resource, Resource predicate, Resource type, Object value)
841 throws org.simantics.db.exception.BindingException, ManyObjectsForFunctionalRelationException, ServiceException {
844 Binding binding = Bindings.getBinding(value.getClass());
845 claimLiteral(resource, predicate, type, value, binding);
846 } catch(BindingConstructionException e) {
847 throw new IllegalArgumentException(e);
853 public void claimLiteral(Resource resource, Resource predicate, Resource type, Object value, Binding binding)
854 throws org.simantics.db.exception.BindingException, ManyObjectsForFunctionalRelationException, ServiceException {
856 Layer0 b = getBuiltins();
858 Statement literalStatement = getPossibleStatement(resource, predicate);
860 if(literalStatement != null && resource.equals(literalStatement.getSubject())) {
862 claimValue(literalStatement.getObject(), value, binding);
866 Resource literal = newResource();
867 claim(literal, b.InstanceOf, null, type);
868 claimValue(literal, value, binding);
869 claim(resource, predicate, literal);
876 public void claimLiteral(Resource resource, Resource predicate, Resource inverse, Resource type, Object value)
877 throws org.simantics.db.exception.BindingException, ManyObjectsForFunctionalRelationException, ServiceException {
880 Binding binding = Bindings.getBinding(value.getClass());
881 claimLiteral(resource, predicate, inverse, type, value, binding);
882 } catch(BindingConstructionException e) {
883 throw new IllegalArgumentException(e);
889 public void claimLiteral(Resource resource, Resource predicate, Resource inverse, Resource type, Object value, Binding binding)
890 throws org.simantics.db.exception.BindingException, ManyObjectsForFunctionalRelationException, ServiceException {
892 Layer0 b = getBuiltins();
894 Statement literalStatement = getPossibleStatement(resource, predicate);
896 if(literalStatement != null && resource.equals(literalStatement.getSubject())) {
898 claimValue(literalStatement.getObject(), value, binding);
902 Resource literal = newResource();
903 claim(literal, b.InstanceOf, null, type);
904 claimValue(literal, value, binding);
905 claim(resource, predicate, inverse, literal);
913 public void denyValue(Resource resource) throws ServiceException {
915 denyValue0(resource, null);
920 public void denyValue(Resource resource, VirtualGraph valueProvider) throws ServiceException {
922 denyValue0(resource, valueProvider);
927 * @param resource resource to remove value from
928 * @param valueProvider <code>null</code> means the caller doesn't know and
929 * this method must find out
930 * @throws ServiceException
932 private void denyValue0(Resource resource, VirtualGraph valueProvider) throws ServiceException {
934 if(Development.DEVELOPMENT) {
936 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG, Bindings.BOOLEAN)) {
937 Object oldValue = getPossibleValue(resource);
938 String valueText = oldValue == null ? "<no value>" : oldValue.toString();
939 String text = "denyValue(" + resourceName(resource) + ", " + valueText + ")";
940 if (oldValue != null) {
941 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG_STACK, Bindings.BOOLEAN)) {
942 StringWriter writer = new StringWriter();
943 PrintWriter out = new PrintWriter(writer);
944 new Exception(text).printStackTrace(out);
945 Development.dispatchEvent(new DenyValueEventImpl(this, provider, resource, oldValue, writer.toString()));
947 Development.dispatchEvent(new DenyValueEventImpl(this, provider, resource, oldValue, text));
951 } catch (DatabaseException e) {
952 Logger.defaultLogError(e);
956 if (provider != null) {
958 // Can only remove from the specified VirtualGraph
959 if (resource.isPersistent())
960 throw new ArgumentException("Tried to remove literal value from persistent resource " + resource
961 + " using virtual graph '" + provider.getIdentifier() + "'");
962 writeSupport.denyValue(provider, resource);
966 // Can remove from any provider
967 if (resource.isPersistent()) {
968 // A persistent resource cannot have a virtual literal
969 // so this should be safe.
970 writeSupport.denyValue(provider, resource);
972 // A virtual resource cannot have a persistent literal.
973 // Must look for a virtual graph for resource.
974 Layer0 L0 = getBuiltins();
975 if (valueProvider == null) {
976 if (hasStatement(resource, L0.InstanceOf)) {
977 valueProvider = processor.getProvider(resource, L0.InstanceOf);
978 } else if (hasStatement(resource, L0.Inherits)) {
979 valueProvider = processor.getProvider(resource, L0.Inherits);
980 } else if (hasStatement(resource, L0.SubrelationOf)) {
981 valueProvider = processor.getProvider(resource, L0.SubrelationOf);
984 if (valueProvider != null)
985 writeSupport.denyValue(valueProvider, resource);
993 public void denyValue(Resource resource, Resource predicate) throws ManyObjectsForFunctionalRelationException, ServiceException {
995 Statement valueStatement = getPossibleStatement(resource, predicate);
997 if (valueStatement != null && !valueStatement.isAsserted(resource)) {
999 Resource value = valueStatement.getObject();
1000 Resource inverse = getPossibleInverse(predicate);
1002 if (provider != null) {
1004 // Can only remove from the specified provider
1005 deny(resource, predicate, inverse, value, provider);
1006 writeSupport.denyValue(provider, value);
1010 // Can remove from any provider
1011 VirtualGraph statementProvider = processor.getProvider(resource, valueStatement.getPredicate(), value);
1012 deny(resource, predicate, inverse, value, statementProvider);
1013 denyValue0(resource, statementProvider);
1022 public void flushCluster() {
1024 writeSupport.flushCluster();
1029 public void flushCluster(Resource r) {
1030 writeSupport.flushCluster(r);
1033 Object serialize(Object value) {
1035 Class<?> clazz = value.getClass();
1037 if(clazz.isArray()) return value;
1039 if(Double.class == clazz) return new double[] { (Double)value };
1040 else if(String.class == clazz) return new String[] { (String)value };
1041 else if(Integer.class == clazz) return new int[] { (Integer)value };
1042 else if(Boolean.class == clazz) return new boolean[] { (Boolean)value };
1043 else if(Long.class == clazz) return new long[] { (Long)value };
1044 else if(Byte.class == clazz) return new byte[] { (Byte)value };
1045 else if(Float.class == clazz) return new float[] { (Float)value };
1051 public <T> void addMetadata(Metadata data) throws ServiceException {
1052 writeSupport.addMetadata(data);
1056 public <T extends Metadata> T getMetadata(Class<T> clazz) throws ServiceException {
1057 return writeSupport.getMetadata(clazz);
1061 public TreeMap<String, byte[]> getMetadata() {
1062 return writeSupport.getMetadata();
1066 public String toString() {
1067 return "WriteGraphImpl[thread=" + Thread.currentThread() + "]";
1070 public void commitAccessorChanges(WriteTraits writeTraits) {
1072 RandomAccessValueSupport ravs = getSession().peekService(RandomAccessValueSupport.class);
1076 for(Pair<Resource, ResourceData> entry : ravs.entries()) {
1077 ResourceData rd = entry.second;
1078 if(!rd.isChanged()) continue;
1079 Resource resource = entry.first;
1081 ExternalValueSupport evs = getService(ExternalValueSupport.class);
1082 long vsize = rd.oldExternalValue ? evs.getValueSize(this, resource) : -1;
1083 long bsize = rd.binaryFile.length();
1084 final int N = 1<<20;
1085 final int LIMIT = 10 * 1000 * 1000;
1088 byte[] bytes = new byte[N];
1089 rd.binaryFile.reset();
1090 rd.binaryFile.position(0);
1092 // if (LIMIT < left)
1093 // evs.moveValue(this, resource);
1095 int length = N < left ? N : (int)left;
1096 rd.binaryFile.readFully(bytes, 0, length);
1097 evs.writeValue(this, resource, offset, length, bytes);
1101 if (count > LIMIT) {
1103 // evs.commitAndContinue(this, writeTraits, resource);
1104 // evs.moveValue(this, resource);
1105 // This is needed so we don't create too many requests and run out of heap.
1106 evs.wait4RequestsLess(1);
1109 if (bsize < vsize) // truncate
1110 evs.writeValue(this, resource, bsize, 0, new byte[0]);
1111 } catch (DatabaseException e) {
1112 Logger.defaultLogError(e);
1115 } catch(IOException e) {
1116 Logger.defaultLogError(e);
1117 } catch (RuntimeException e) {
1118 Logger.defaultLogError(e);
1123 public VirtualGraph getProvider() {
1128 public void clearUndoList(WriteTraits writeTraits) {
1129 writeSupport.clearUndoList(writeTraits);
1132 public void markUndoPoint() {
1133 writeSupport.startUndo();