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 Statement literalStatement = getPossibleStatement(resource, predicate);
807 if(literalStatement != null && resource.equals(literalStatement.getSubject())) {
809 claimValue(literalStatement.getObject(), value, binding);
813 Class<?> clazz = value.getClass();
814 Resource type = builtinValues.get(clazz);
815 Resource literal = newResource();
818 Resource dataType = newResource();
819 claim(dataType, b.InstanceOf, null, b.DataType);
820 claimValue(dataType, binding.type(), DATA_TYPE_BINDING);
821 claim(literal, b.HasDataType, null, dataType);
823 claim(literal, b.InstanceOf, null, type);
824 claimValue(literal, value, binding);
825 claim(resource, predicate, literal);
829 if(Development.DEVELOPMENT) {
831 getPossibleStatement(resource, predicate);
832 } catch (ManyObjectsForFunctionalRelationException e) {
833 System.err.println("err " + ((ResourceImpl)resource).id + " " + ((ResourceImpl)predicate).id);
834 getPossibleStatement(resource, predicate);
841 public void claimLiteral(Resource resource, Resource predicate, Resource type, Object value)
842 throws org.simantics.db.exception.BindingException, ManyObjectsForFunctionalRelationException, ServiceException {
845 Binding binding = Bindings.getBinding(value.getClass());
846 claimLiteral(resource, predicate, type, value, binding);
847 } catch(BindingConstructionException e) {
848 throw new IllegalArgumentException(e);
854 public void claimLiteral(Resource resource, Resource predicate, Resource type, Object value, Binding binding)
855 throws org.simantics.db.exception.BindingException, ManyObjectsForFunctionalRelationException, ServiceException {
857 Layer0 b = getBuiltins();
859 Statement literalStatement = getPossibleStatement(resource, predicate);
861 if(literalStatement != null && resource.equals(literalStatement.getSubject())) {
863 claimValue(literalStatement.getObject(), value, binding);
867 Resource literal = newResource();
868 claim(literal, b.InstanceOf, null, type);
869 claimValue(literal, value, binding);
870 claim(resource, predicate, literal);
877 public void claimLiteral(Resource resource, Resource predicate, Resource inverse, Resource type, Object value)
878 throws org.simantics.db.exception.BindingException, ManyObjectsForFunctionalRelationException, ServiceException {
881 Binding binding = Bindings.getBinding(value.getClass());
882 claimLiteral(resource, predicate, inverse, type, value, binding);
883 } catch(BindingConstructionException e) {
884 throw new IllegalArgumentException(e);
890 public void claimLiteral(Resource resource, Resource predicate, Resource inverse, Resource type, Object value, Binding binding)
891 throws org.simantics.db.exception.BindingException, ManyObjectsForFunctionalRelationException, ServiceException {
893 Layer0 b = getBuiltins();
895 Statement literalStatement = getPossibleStatement(resource, predicate);
897 if(literalStatement != null && resource.equals(literalStatement.getSubject())) {
899 claimValue(literalStatement.getObject(), value, binding);
903 Resource literal = newResource();
904 claim(literal, b.InstanceOf, null, type);
905 claimValue(literal, value, binding);
906 claim(resource, predicate, inverse, literal);
914 public void denyValue(Resource resource) throws ServiceException {
916 denyValue0(resource, null);
921 public void denyValue(Resource resource, VirtualGraph valueProvider) throws ServiceException {
923 denyValue0(resource, valueProvider);
928 * @param resource resource to remove value from
929 * @param valueProvider <code>null</code> means the caller doesn't know and
930 * this method must find out
931 * @throws ServiceException
933 private void denyValue0(Resource resource, VirtualGraph valueProvider) throws ServiceException {
935 if(Development.DEVELOPMENT) {
937 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG, Bindings.BOOLEAN)) {
938 Object oldValue = getPossibleValue(resource);
939 String valueText = oldValue == null ? "<no value>" : oldValue.toString();
940 String text = "denyValue(" + resourceName(resource) + ", " + valueText + ")";
941 if (oldValue != null) {
942 if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG_STACK, Bindings.BOOLEAN)) {
943 StringWriter writer = new StringWriter();
944 PrintWriter out = new PrintWriter(writer);
945 new Exception(text).printStackTrace(out);
946 Development.dispatchEvent(new DenyValueEventImpl(this, provider, resource, oldValue, writer.toString()));
948 Development.dispatchEvent(new DenyValueEventImpl(this, provider, resource, oldValue, text));
952 } catch (DatabaseException e) {
953 Logger.defaultLogError(e);
957 if (provider != null) {
959 // Can only remove from the specified VirtualGraph
960 if (resource.isPersistent())
961 throw new ArgumentException("Tried to remove literal value from persistent resource " + resource
962 + " using virtual graph '" + provider.getIdentifier() + "'");
963 writeSupport.denyValue(provider, resource);
967 // Can remove from any provider
968 if (resource.isPersistent()) {
969 // A persistent resource cannot have a virtual literal
970 // so this should be safe.
971 writeSupport.denyValue(provider, resource);
973 // A virtual resource cannot have a persistent literal.
974 // Must look for a virtual graph for resource.
975 Layer0 L0 = getBuiltins();
976 if (valueProvider == null) {
977 if (hasStatement(resource, L0.InstanceOf)) {
978 valueProvider = processor.getProvider(resource, L0.InstanceOf);
979 } else if (hasStatement(resource, L0.Inherits)) {
980 valueProvider = processor.getProvider(resource, L0.Inherits);
981 } else if (hasStatement(resource, L0.SubrelationOf)) {
982 valueProvider = processor.getProvider(resource, L0.SubrelationOf);
985 if (valueProvider != null)
986 writeSupport.denyValue(valueProvider, resource);
994 public void denyValue(Resource resource, Resource predicate) throws ManyObjectsForFunctionalRelationException, ServiceException {
996 Statement valueStatement = getPossibleStatement(resource, predicate);
998 if (valueStatement != null && !valueStatement.isAsserted(resource)) {
1000 Resource value = valueStatement.getObject();
1001 Resource inverse = getPossibleInverse(predicate);
1003 if (provider != null) {
1005 // Can only remove from the specified provider
1006 deny(resource, predicate, inverse, value, provider);
1007 writeSupport.denyValue(provider, value);
1011 // Can remove from any provider
1012 VirtualGraph statementProvider = processor.getProvider(resource, valueStatement.getPredicate(), value);
1013 deny(resource, predicate, inverse, value, statementProvider);
1014 denyValue0(resource, statementProvider);
1023 public void flushCluster() {
1025 writeSupport.flushCluster();
1030 public void flushCluster(Resource r) {
1031 writeSupport.flushCluster(r);
1034 Object serialize(Object value) {
1036 Class<?> clazz = value.getClass();
1038 if(clazz.isArray()) return value;
1040 if(Double.class == clazz) return new double[] { (Double)value };
1041 else if(String.class == clazz) return new String[] { (String)value };
1042 else if(Integer.class == clazz) return new int[] { (Integer)value };
1043 else if(Boolean.class == clazz) return new boolean[] { (Boolean)value };
1044 else if(Long.class == clazz) return new long[] { (Long)value };
1045 else if(Byte.class == clazz) return new byte[] { (Byte)value };
1046 else if(Float.class == clazz) return new float[] { (Float)value };
1052 public <T> void addMetadata(Metadata data) throws ServiceException {
1053 writeSupport.addMetadata(data);
1057 public <T extends Metadata> T getMetadata(Class<T> clazz) throws ServiceException {
1058 return writeSupport.getMetadata(clazz);
1062 public TreeMap<String, byte[]> getMetadata() {
1063 return writeSupport.getMetadata();
1067 public String toString() {
1068 return "WriteGraphImpl[thread=" + Thread.currentThread() + "]";
1071 public void commitAccessorChanges(WriteTraits writeTraits) {
1073 RandomAccessValueSupport ravs = getSession().peekService(RandomAccessValueSupport.class);
1077 for(Pair<Resource, ResourceData> entry : ravs.entries()) {
1078 ResourceData rd = entry.second;
1079 if(!rd.isChanged()) continue;
1080 Resource resource = entry.first;
1082 ExternalValueSupport evs = getService(ExternalValueSupport.class);
1083 long vsize = rd.oldExternalValue ? evs.getValueSize(this, resource) : -1;
1084 long bsize = rd.binaryFile.length();
1085 final int N = 1<<20;
1086 final int LIMIT = 10 * 1000 * 1000;
1089 byte[] bytes = new byte[N];
1090 rd.binaryFile.reset();
1091 rd.binaryFile.position(0);
1093 // if (LIMIT < left)
1094 // evs.moveValue(this, resource);
1096 int length = N < left ? N : (int)left;
1097 rd.binaryFile.readFully(bytes, 0, length);
1098 evs.writeValue(this, resource, offset, length, bytes);
1102 if (count > LIMIT) {
1104 // evs.commitAndContinue(this, writeTraits, resource);
1105 // evs.moveValue(this, resource);
1106 // This is needed so we don't create too many requests and run out of heap.
1107 evs.wait4RequestsLess(1);
1110 if (bsize < vsize) // truncate
1111 evs.writeValue(this, resource, bsize, 0, new byte[0]);
1112 } catch (DatabaseException e) {
1113 Logger.defaultLogError(e);
1116 } catch(IOException e) {
1117 Logger.defaultLogError(e);
1118 } catch (RuntimeException e) {
1119 Logger.defaultLogError(e);
1124 public VirtualGraph getProvider() {
1129 public void clearUndoList(WriteTraits writeTraits) {
1130 writeSupport.clearUndoList(writeTraits);
1133 public void markUndoPoint() {
1134 writeSupport.startUndo();