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 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, e -> {
248 Logger.defaultLogError(e);
249 }, null, Boolean.TRUE);
253 public void asyncRequest(DelayedWrite request, Consumer<DatabaseException> callback) {
254 assert (request != null);
255 getWriteRequestScheduler().scheduleRequest(request, callback, null, Boolean.TRUE);
259 public <T> void asyncRequest(DelayedWriteResult<T> request, Procedure<T> procedure) {
260 assert (request != null);
261 getWriteRequestScheduler().scheduleRequest(request, procedure, null, Boolean.TRUE);
265 public void asyncRequest(final Write r) {
267 getWriteRequestScheduler().scheduleRequest(r, e -> {
269 Logger.defaultLogError(e);
270 }, null, Boolean.TRUE);
274 public void asyncRequest(Write request, Consumer<DatabaseException> callback) {
275 assert (request != null);
276 getWriteRequestScheduler().scheduleRequest(request, callback, null, Boolean.TRUE);
280 public void asyncRequest(WriteOnly request) {
281 assert (request != null);
282 getWriteRequestScheduler().scheduleRequest(request, e -> {
284 Logger.defaultLogError(e);
285 }, null, Boolean.TRUE);
289 public void asyncRequest(WriteOnly request, Consumer<DatabaseException> callback) {
290 assert (request != null);
291 getWriteRequestScheduler().scheduleRequest(request, callback, null, Boolean.TRUE);
295 public <T> void asyncRequest(WriteOnlyResult<T> request, Procedure<T> procedure) {
296 assert (request != null);
297 getWriteRequestScheduler().scheduleRequest(request, procedure, null, Boolean.TRUE);
301 public <T> void asyncRequest(WriteResult<T> request, Procedure<T> procedure) {
302 assert (request != null);
303 getWriteRequestScheduler().scheduleRequest(request, procedure, null, Boolean.TRUE);
307 public void syncRequest(Write request) throws DatabaseException {
309 Resource defaultClusterSet = setClusterSet4NewResource(null);
311 WriteGraphImpl graph = (WriteGraphImpl)newSync(request.getProvider());
313 writeSupport.performWriteRequest(graph, request);
314 } catch (DatabaseException e) {
316 } catch (Throwable t) {
317 throw new DatabaseException(t);
319 setClusterSet4NewResource(defaultClusterSet);
326 public <T> T syncRequest(WriteResult<T> request) throws DatabaseException {
328 Resource defaultClusterSet = setClusterSet4NewResource(null);
330 WriteGraphImpl graph = (WriteGraphImpl)newSync(request.getProvider());
332 return writeSupport.performWriteRequest(graph, request);
333 } catch (DatabaseException e) {
335 } catch (Throwable t) {
336 throw new DatabaseException(t);
338 setClusterSet4NewResource(defaultClusterSet);
343 public void syncRequest(final DelayedWrite request) throws DatabaseException {
347 final DelayedWriteGraph dwg = new DelayedWriteGraph(this);
348 request.perform(dwg);
350 syncRequest(new WriteOnlyRequest() {
353 public void perform(WriteOnlyGraph graph) throws DatabaseException {
354 dwg.commit(graph, request);
359 } catch (DatabaseException e) {
363 } catch (Throwable e) {
365 throw new DatabaseException(e);
374 public void syncRequest(WriteOnly request) throws DatabaseException {
376 Resource defaultClusterSet = setClusterSet4NewResource(null);
379 writeSupport.performWriteRequest(this, request);
380 } catch (DatabaseException e) {
382 } catch (Throwable t) {
383 throw new DatabaseException(t);
385 setClusterSet4NewResource(defaultClusterSet);
391 public void claim(Resource subject, Resource predicate, Resource object) throws ServiceException {
393 if(subject == null || predicate == null || object == null) {
394 throw new ServiceException("Claim does not accept null arguments (subject=" + subject + ",predicate=" + predicate + ",object=" + object + ").");
397 if(processor.isImmutable(object)) {
398 claim(subject, predicate, null, object);
400 claim(subject, predicate, getPossibleInverse(predicate), object);
406 public void claim(Resource subject, Resource predicate, Resource inverse, Resource object) throws ServiceException {
408 if (MemWatch.isLowOnMemory())
411 if(subject == null) throw new ServiceException("Claim does not accept null arguments (subject).");
412 if(predicate == null) throw new ServiceException("Claim does not accept null arguments (predicate).");
413 if(object == null) throw new ServiceException("Claim does not accept null arguments (object).");
414 if(provider == null && subject.isPersistent() && !object.isPersistent())
415 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.");
418 if(Development.DEVELOPMENT) {
420 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG, Bindings.BOOLEAN)) {
421 String text = "claim(" + resourceName(subject) + ":" + subject + ", " + resourceName(predicate) + ":" + predicate + ", " + resourceName(object) + ":" + object + ")";
422 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG_STACK, Bindings.BOOLEAN)) {
423 StringWriter writer = new StringWriter();
424 PrintWriter out = new PrintWriter(writer);
425 new Exception(text).printStackTrace(out);
426 Development.dispatchEvent(new ClaimEventImpl(this, provider, subject, predicate, object, writer.toString()));
428 Development.dispatchEvent(new ClaimEventImpl(this, provider, subject, predicate, object, text));
431 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITELOGGER_LOG, Bindings.BOOLEAN))
432 WriteLogger.logClaim(this, subject, predicate, inverse, object);
433 } catch (DatabaseException e) {
434 Logger.defaultLogError(e);
437 writeSupport.claim(provider, subject, predicate, object);
438 } catch(RuntimeException e) {
439 throw new ServiceException(e);
442 if(inverse == null) return;
443 if(subject.equals(object) && predicate.equals(inverse)) {
447 // Do as claim(s,p,o) already works -
448 // don't write inverse relations if object is immutable.
449 if(processor.isImmutable(object))
453 writeSupport.claim(provider, object, inverse, subject);
454 } catch(RuntimeException e) {
455 throw new ServiceException(e);
461 public void deny(Resource subject) throws ServiceException {
463 assert(subject != null);
467 for(Statement stm : getStatements(subject, getBuiltins().IsWeaklyRelatedTo)) {
468 if(subject.equals(stm.getSubject())) {
469 Resource inverse = getPossibleInverse(stm.getPredicate());
470 // if(inverse == null) {
472 // String name = adapt(stm.getPredicate(), String.class);
473 // throw new ResourceDoesNotSatisfyAssumptionException("Resource '" + name + "' does not have an inverse.");
474 // } catch (AdaptionException e) {
475 // throw new ResourceDoesNotSatisfyAssumptionException("Resource '" + stm.getPredicate() + "' does not have an inverse.");
478 deny(stm.getSubject(), stm.getPredicate(), inverse, stm.getObject());
482 } catch(DatabaseException e) {
484 throw new ServiceException(INTERNAL_ERROR_STRING, e);
491 public void deny(Resource subject, Resource predicate) throws ServiceException {
493 assert(subject != null);
494 assert(predicate != null);
498 for (Statement stm : getStatements(subject, predicate)) {
499 if (subject.equals(stm.getSubject())) {
500 Resource inverse = getPossibleInverse(stm.getPredicate());
501 // if(inverse == null) {
503 // String name = adapt(stm.getPredicate(), String.class);
504 // throw new ResourceDoesNotSatisfyAssumptionException("Resource '" + name + "' does not have an inverse.");
505 // } catch (AdaptionException e) {
506 // throw new ResourceDoesNotSatisfyAssumptionException("Resource '" + stm.getPredicate() + "' does not have an inverse.");
509 deny(stm.getSubject(), stm.getPredicate(), inverse, stm.getObject());
513 } catch(DatabaseException e) {
515 throw new ServiceException(INTERNAL_ERROR_STRING, e);
522 public void deny(Resource subject, Resource predicate, Resource object) throws ServiceException {
524 assert(subject != null);
525 assert(predicate != null);
526 assert(object != null);
529 for (Statement stm : getStatements(subject, predicate)) {
530 if (subject.equals(stm.getSubject()) && object.equals(stm.getObject())) {
531 Resource inverse = getPossibleInverse(stm.getPredicate());
532 deny(stm.getSubject(), stm.getPredicate(), inverse, stm.getObject());
535 } catch (DatabaseException e) {
536 throw new ServiceException(INTERNAL_ERROR_STRING, e);
542 public void denyStatement(Resource subject, Resource predicate, Resource object) throws ServiceException {
544 assert(subject != null);
545 assert(predicate != null);
546 assert(object != null);
548 Resource inverse = getPossibleInverse(predicate);
549 // if(inverse == null) {
551 // String name = adapt(predicate, String.class);
552 // throw new ResourceDoesNotSatisfyAssumptionException("Resource '" + name + "' does not have an inverse.");
553 // } catch (AdaptionException e) {
554 // throw new ResourceDoesNotSatisfyAssumptionException("Resource '" + predicate + "' does not have an inverse.");
557 deny(subject, predicate, inverse, object);
562 public void deny(Statement statement) throws ServiceException {
563 assert(statement != null);
564 denyStatement(statement.getSubject(), statement.getPredicate(), statement.getObject());
568 public void deny(Resource subject, Resource predicate, Resource inverse, Resource object) throws ServiceException {
570 assert(subject != null);
571 assert(predicate != null);
572 assert(object != null);
574 VirtualGraph provider = processor.getProvider(subject, predicate, object);
576 deny(subject, predicate, inverse, object, provider);
581 * Note: We assume here that all inverse pairs of statements are stored in the same virtual graph.
584 public void deny(Resource subject, Resource predicate, Resource inverse, Resource object, VirtualGraph provider) throws ServiceException {
586 assert(subject != null);
587 assert(predicate != null);
588 assert(object != null);
590 if(Development.DEVELOPMENT) {
592 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG, Bindings.BOOLEAN)) {
593 String text = "deny(" + resourceName(subject) + ":" + subject + ", " + resourceName(predicate) + ":" + predicate + ", " + resourceName(object) + ":" + object + ")";
594 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG_STACK, Bindings.BOOLEAN)) {
595 StringWriter writer = new StringWriter();
596 PrintWriter out = new PrintWriter(writer);
597 new Exception(text).printStackTrace(out);
598 Development.dispatchEvent(new DenyEventImpl(this, provider, subject, predicate, object, writer.toString()));
600 Development.dispatchEvent(new DenyEventImpl(this, provider, subject, predicate, object, text));
603 } catch (DatabaseException e) {
604 Logger.defaultLogError(e);
609 writeSupport.removeStatement(provider, subject, predicate, object);
610 } catch(Throwable e) {
611 throw new InternalException("bug in deny(s,p,i,o)", e);
614 if(inverse == null || (subject.equals(object) && predicate.equals(inverse))) return;
616 // don't deny inverse relations if object is immutable.
617 if(processor.isImmutable(object))
621 writeSupport.removeStatement(provider, object, inverse, subject);
622 } catch(Throwable e) {
623 throw new InternalException("bug in deny(s,p,i,o)", e);
629 public void claimValue(Resource resource, Object value) throws ServiceException {
632 Binding b = Bindings.getBinding(value.getClass());
633 claimValue(resource, value, b);
634 } catch(BindingConstructionException e) {
635 throw new IllegalArgumentException(e);
641 public void claimValue(Resource resource, Object value, Binding binding) throws ServiceException {
643 if(value == null) throw new ServiceException("claimValue does not accept null value");
644 if(binding == null) throw new ServiceException("claimValue does not accept null binding");
646 if(Development.DEVELOPMENT) {
648 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG, Bindings.BOOLEAN)) {
649 String valueText = Literals.shortString(value.toString());
650 String text = "claimValue(" + resourceName(resource) + ", " + valueText + ")";
651 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG_STACK, Bindings.BOOLEAN)) {
652 StringWriter writer = new StringWriter();
653 PrintWriter out = new PrintWriter(writer);
654 new Exception(text).printStackTrace(out);
655 Development.dispatchEvent(new ClaimValueEventImpl(this, provider, resource, value, binding, writer.toString()));
657 Development.dispatchEvent(new ClaimValueEventImpl(this, provider, resource, value, binding, text));
660 } catch (DatabaseException e) {
661 Logger.defaultLogError(e);
666 Serializer serializer = getSerializer(binding);
667 //Serializer serializer = binding.serializer();
668 byte[] data = serializer.serialize(value);
670 if(Development.DEVELOPMENT) {
672 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITELOGGER_LOG, Bindings.BOOLEAN))
673 WriteLogger.logValue(this, resource, data);
674 } catch (DatabaseException e) {
675 Logger.defaultLogError(e);
679 writeSupport.claimValue(provider, resource, data);
681 } catch (DatabaseException e) {
682 throw new ServiceException(e);
683 } catch (SerializationException e) {
684 throw new ServiceException(e);
685 } catch (IOException e) {
686 throw new ServiceException(e);
691 THashMap<Class<?>, Resource> builtinValues = new THashMap<Class<?>, Resource>(32);
693 private void initBuiltinValues(Layer0 b) {
695 if(!builtinValues.isEmpty()) return;
697 builtinValues.put(String.class, b.String);
698 builtinValues.put(Double.class, b.Double);
699 builtinValues.put(Float.class, b.Float);
700 builtinValues.put(Long.class, b.Long);
701 builtinValues.put(Integer.class, b.Integer);
702 builtinValues.put(Byte.class, b.Byte);
703 builtinValues.put(Boolean.class, b.Boolean);
704 builtinValues.put(Variant.class, b.Variant);
706 builtinValues.put(String[].class, b.StringArray);
707 builtinValues.put(double[].class, b.DoubleArray);
708 builtinValues.put(float[].class, b.FloatArray);
709 builtinValues.put(long[].class, b.LongArray);
710 builtinValues.put(int[].class, b.IntegerArray);
711 builtinValues.put(byte[].class, b.ByteArray);
712 builtinValues.put(boolean[].class, b.BooleanArray);
714 builtinValues.put(MutableString.class, b.String);
715 builtinValues.put(MutableDouble.class, b.Double);
716 builtinValues.put(MutableFloat.class, b.Float);
717 builtinValues.put(MutableLong.class, b.Long);
718 builtinValues.put(MutableInteger.class, b.Integer);
719 builtinValues.put(MutableByte.class, b.Byte);
720 builtinValues.put(MutableBoolean.class, b.Boolean);
725 public void addLiteral(Resource resource, Resource predicate, Resource inverse, Resource type, Object value, Binding binding) throws ManyObjectsForFunctionalRelationException, ServiceException {
727 Layer0 b = getBuiltins();
728 Resource valueResource = newResource();
729 claim(valueResource, b.InstanceOf, null, type);
730 claim(resource, predicate, inverse, valueResource);
731 claimValue(valueResource, value, binding);
736 public void addLiteral(Resource resource, Resource predicate, Resource inverse, Object value, Binding binding) throws ManyObjectsForFunctionalRelationException, ServiceException {
738 Layer0 b = getBuiltins();
739 initBuiltinValues(b);
740 Resource literal = newResource();
742 Class<?> clazz = value.getClass();
743 Resource type = builtinValues.get(clazz);
746 Resource dataType = newResource();
747 claim(dataType, b.InstanceOf, null, b.DataType);
748 claimValue(dataType, binding.type(), DATA_TYPE_BINDING);
749 claim(literal, b.HasDataType, b.HasDataType_Inverse, dataType);
752 claim(literal, b.InstanceOf, null, type);
753 claim(resource, predicate, inverse, literal);
754 claimValue(literal, value, binding);
759 public <T extends Accessor> T newLiteral(Resource resource, Resource predicate, Datatype datatype, Object initialValue)
760 throws DatabaseException {
761 Layer0 b = getBuiltins();
762 initBuiltinValues(b);
763 Resource literal = newResource();
764 claim(literal, b.InstanceOf, null, b.Literal);
765 Resource dataType = newResource();
766 claim(dataType, b.InstanceOf, null, b.DataType);
767 claimValue(dataType, datatype, DATA_TYPE_BINDING);
768 claim(literal, b.HasDataType, dataType);
769 claim(resource, predicate, literal);
770 return createAccessor(literal, datatype, initialValue);
773 public RandomAccessBinary createRandomAccessBinary
774 (Resource resource, Resource predicate, Datatype datatype, Object initiaValue)
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 createRandomAccessBinary(literal, datatype, initiaValue);
788 public void claimLiteral(Resource resource, Resource predicate, Object value) throws ManyObjectsForFunctionalRelationException, ServiceException {
791 Binding binding = Bindings.getBinding(value.getClass());
792 claimLiteral(resource, predicate, value, binding);
793 } catch(BindingConstructionException e) {
794 throw new IllegalArgumentException(e);
800 public void claimLiteral(Resource resource, Resource predicate, Object value, Binding binding) throws ManyObjectsForFunctionalRelationException, ServiceException {
802 Layer0 b = getBuiltins();
803 initBuiltinValues(b);
805 if(resource.toString().equals("[id=$319492]") && predicate.toString().equals("[id=$235477]"))
806 System.err.println("foobar2");
809 Statement literalStatement = getPossibleStatement(resource, predicate);
811 if(literalStatement != null && resource.equals(literalStatement.getSubject())) {
813 claimValue(literalStatement.getObject(), value, binding);
817 Class<?> clazz = value.getClass();
818 Resource type = builtinValues.get(clazz);
819 Resource literal = newResource();
822 Resource dataType = newResource();
823 claim(dataType, b.InstanceOf, null, b.DataType);
824 claimValue(dataType, binding.type(), DATA_TYPE_BINDING);
825 claim(literal, b.HasDataType, null, dataType);
827 claim(literal, b.InstanceOf, null, type);
828 claimValue(literal, value, binding);
829 claim(resource, predicate, literal);
833 if(Development.DEVELOPMENT) {
835 getPossibleStatement(resource, predicate);
836 } catch (ManyObjectsForFunctionalRelationException e) {
837 System.err.println("err " + ((ResourceImpl)resource).id + " " + ((ResourceImpl)predicate).id);
838 getPossibleStatement(resource, predicate);
845 public void claimLiteral(Resource resource, Resource predicate, Resource type, Object value)
846 throws org.simantics.db.exception.BindingException, ManyObjectsForFunctionalRelationException, ServiceException {
849 Binding binding = Bindings.getBinding(value.getClass());
850 claimLiteral(resource, predicate, type, value, binding);
851 } catch(BindingConstructionException e) {
852 throw new IllegalArgumentException(e);
858 public void claimLiteral(Resource resource, Resource predicate, Resource type, Object value, Binding binding)
859 throws org.simantics.db.exception.BindingException, ManyObjectsForFunctionalRelationException, ServiceException {
861 Layer0 b = getBuiltins();
863 Statement literalStatement = getPossibleStatement(resource, predicate);
865 if(literalStatement != null && resource.equals(literalStatement.getSubject())) {
867 claimValue(literalStatement.getObject(), value, binding);
871 Resource literal = newResource();
872 claim(literal, b.InstanceOf, null, type);
873 claimValue(literal, value, binding);
874 claim(resource, predicate, literal);
881 public void claimLiteral(Resource resource, Resource predicate, Resource inverse, Resource type, Object value)
882 throws org.simantics.db.exception.BindingException, ManyObjectsForFunctionalRelationException, ServiceException {
885 Binding binding = Bindings.getBinding(value.getClass());
886 claimLiteral(resource, predicate, inverse, type, value, binding);
887 } catch(BindingConstructionException e) {
888 throw new IllegalArgumentException(e);
894 public void claimLiteral(Resource resource, Resource predicate, Resource inverse, Resource type, Object value, Binding binding)
895 throws org.simantics.db.exception.BindingException, ManyObjectsForFunctionalRelationException, ServiceException {
897 Layer0 b = getBuiltins();
899 Statement literalStatement = getPossibleStatement(resource, predicate);
901 if(literalStatement != null && resource.equals(literalStatement.getSubject())) {
903 claimValue(literalStatement.getObject(), value, binding);
907 Resource literal = newResource();
908 claim(literal, b.InstanceOf, null, type);
909 claimValue(literal, value, binding);
910 claim(resource, predicate, inverse, literal);
918 public void denyValue(Resource resource) throws ServiceException {
920 denyValue0(resource, null);
925 public void denyValue(Resource resource, VirtualGraph valueProvider) throws ServiceException {
927 denyValue0(resource, valueProvider);
932 * @param resource resource to remove value from
933 * @param valueProvider <code>null</code> means the caller doesn't know and
934 * this method must find out
935 * @throws ServiceException
937 private void denyValue0(Resource resource, VirtualGraph valueProvider) throws ServiceException {
939 if(Development.DEVELOPMENT) {
941 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG, Bindings.BOOLEAN)) {
942 Object oldValue = getPossibleValue(resource);
943 String valueText = oldValue == null ? "<no value>" : oldValue.toString();
944 String text = "denyValue(" + resourceName(resource) + ", " + valueText + ")";
945 if (oldValue != null) {
946 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG_STACK, Bindings.BOOLEAN)) {
947 StringWriter writer = new StringWriter();
948 PrintWriter out = new PrintWriter(writer);
949 new Exception(text).printStackTrace(out);
950 Development.dispatchEvent(new DenyValueEventImpl(this, provider, resource, oldValue, writer.toString()));
952 Development.dispatchEvent(new DenyValueEventImpl(this, provider, resource, oldValue, text));
956 } catch (DatabaseException e) {
957 Logger.defaultLogError(e);
961 if (provider != null) {
963 // Can only remove from the specified VirtualGraph
964 if (resource.isPersistent())
965 throw new ArgumentException("Tried to remove literal value from persistent resource " + resource
966 + " using virtual graph '" + provider.getIdentifier() + "'");
967 writeSupport.denyValue(provider, resource);
971 // Can remove from any provider
972 if (resource.isPersistent()) {
973 // A persistent resource cannot have a virtual literal
974 // so this should be safe.
975 writeSupport.denyValue(provider, resource);
977 // A virtual resource cannot have a persistent literal.
978 // Must look for a virtual graph for resource.
979 Layer0 L0 = getBuiltins();
980 if (valueProvider == null) {
981 if (hasStatement(resource, L0.InstanceOf)) {
982 valueProvider = processor.getProvider(resource, L0.InstanceOf);
983 } else if (hasStatement(resource, L0.Inherits)) {
984 valueProvider = processor.getProvider(resource, L0.Inherits);
985 } else if (hasStatement(resource, L0.SubrelationOf)) {
986 valueProvider = processor.getProvider(resource, L0.SubrelationOf);
989 if (valueProvider != null)
990 writeSupport.denyValue(valueProvider, resource);
998 public void denyValue(Resource resource, Resource predicate) throws ManyObjectsForFunctionalRelationException, ServiceException {
1000 Statement valueStatement = getPossibleStatement(resource, predicate);
1002 if (valueStatement != null && !valueStatement.isAsserted(resource)) {
1004 Resource value = valueStatement.getObject();
1005 Resource inverse = getPossibleInverse(predicate);
1007 if (provider != null) {
1009 // Can only remove from the specified provider
1010 deny(resource, predicate, inverse, value, provider);
1011 writeSupport.denyValue(provider, value);
1015 // Can remove from any provider
1016 VirtualGraph statementProvider = processor.getProvider(resource, valueStatement.getPredicate(), value);
1017 deny(resource, predicate, inverse, value, statementProvider);
1018 denyValue0(resource, statementProvider);
1027 public void flushCluster() {
1029 writeSupport.flushCluster();
1034 public void flushCluster(Resource r) {
1035 writeSupport.flushCluster(r);
1038 Object serialize(Object value) {
1040 Class<?> clazz = value.getClass();
1042 if(clazz.isArray()) return value;
1044 if(Double.class == clazz) return new double[] { (Double)value };
1045 else if(String.class == clazz) return new String[] { (String)value };
1046 else if(Integer.class == clazz) return new int[] { (Integer)value };
1047 else if(Boolean.class == clazz) return new boolean[] { (Boolean)value };
1048 else if(Long.class == clazz) return new long[] { (Long)value };
1049 else if(Byte.class == clazz) return new byte[] { (Byte)value };
1050 else if(Float.class == clazz) return new float[] { (Float)value };
1056 public <T> void addMetadata(Metadata data) throws ServiceException {
1057 writeSupport.addMetadata(data);
1061 public <T extends Metadata> T getMetadata(Class<T> clazz) throws ServiceException {
1062 return writeSupport.getMetadata(clazz);
1066 public TreeMap<String, byte[]> getMetadata() {
1067 return writeSupport.getMetadata();
1071 public String toString() {
1072 return "WriteGraphImpl[thread=" + Thread.currentThread() + "]";
1075 public void commitAccessorChanges(WriteTraits writeTraits) {
1077 RandomAccessValueSupport ravs = getSession().peekService(RandomAccessValueSupport.class);
1081 for(Pair<Resource, ResourceData> entry : ravs.entries()) {
1082 ResourceData rd = entry.second;
1083 if(!rd.isChanged()) continue;
1084 Resource resource = entry.first;
1086 ExternalValueSupport evs = getService(ExternalValueSupport.class);
1087 long vsize = rd.oldExternalValue ? evs.getValueSize(this, resource) : -1;
1088 long bsize = rd.binaryFile.length();
1089 final int N = 1<<20;
1090 final int LIMIT = 10 * 1000 * 1000;
1093 byte[] bytes = new byte[N];
1094 rd.binaryFile.reset();
1095 rd.binaryFile.position(0);
1097 // if (LIMIT < left)
1098 // evs.moveValue(this, resource);
1100 int length = N < left ? N : (int)left;
1101 rd.binaryFile.readFully(bytes, 0, length);
1102 evs.writeValue(this, resource, offset, length, bytes);
1106 if (count > LIMIT) {
1108 // evs.commitAndContinue(this, writeTraits, resource);
1109 // evs.moveValue(this, resource);
1110 // This is needed so we don't create too many requests and run out of heap.
1111 evs.wait4RequestsLess(1);
1114 if (bsize < vsize) // truncate
1115 evs.writeValue(this, resource, bsize, 0, new byte[0]);
1116 } catch (DatabaseException e) {
1117 Logger.defaultLogError(e);
1120 } catch(IOException e) {
1121 Logger.defaultLogError(e);
1122 } catch (RuntimeException e) {
1123 Logger.defaultLogError(e);
1128 public VirtualGraph getProvider() {
1133 public void clearUndoList(WriteTraits writeTraits) {
1134 writeSupport.clearUndoList(writeTraits);
1137 public void markUndoPoint() {
1138 writeSupport.startUndo();