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