-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.db.impl.graph;\r
-\r
-import java.io.IOException;\r
-import java.io.PrintWriter;\r
-import java.io.StringWriter;\r
-import java.util.TreeMap;\r
-\r
-import org.simantics.databoard.Bindings;\r
-import org.simantics.databoard.accessor.Accessor;\r
-import org.simantics.databoard.binding.Binding;\r
-import org.simantics.databoard.binding.error.BindingConstructionException;\r
-import org.simantics.databoard.binding.mutable.Variant;\r
-import org.simantics.databoard.primitives.MutableBoolean;\r
-import org.simantics.databoard.primitives.MutableByte;\r
-import org.simantics.databoard.primitives.MutableDouble;\r
-import org.simantics.databoard.primitives.MutableFloat;\r
-import org.simantics.databoard.primitives.MutableInteger;\r
-import org.simantics.databoard.primitives.MutableLong;\r
-import org.simantics.databoard.primitives.MutableString;\r
-import org.simantics.databoard.serialization.SerializationException;\r
-import org.simantics.databoard.serialization.Serializer;\r
-import org.simantics.databoard.type.Datatype;\r
-import org.simantics.databoard.util.binary.RandomAccessBinary;\r
-import org.simantics.db.DevelopmentKeys;\r
-import org.simantics.db.ExternalValueSupport;\r
-import org.simantics.db.Metadata;\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.Statement;\r
-import org.simantics.db.VirtualGraph;\r
-import org.simantics.db.WriteGraph;\r
-import org.simantics.db.WriteOnlyGraph;\r
-import org.simantics.db.common.request.WriteOnlyRequest;\r
-import org.simantics.db.common.utils.Literals;\r
-import org.simantics.db.common.utils.Logger;\r
-import org.simantics.db.exception.ArgumentException;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.exception.InternalException;\r
-import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;\r
-import org.simantics.db.exception.ServiceException;\r
-import org.simantics.db.impl.DatabaseUtils;\r
-import org.simantics.db.impl.MemWatch;\r
-import org.simantics.db.impl.ResourceImpl;\r
-import org.simantics.db.impl.internal.RandomAccessValueSupport;\r
-import org.simantics.db.impl.internal.ResourceData;\r
-import org.simantics.db.impl.query.CacheEntry;\r
-import org.simantics.db.impl.query.QueryProcessor;\r
-import org.simantics.db.impl.support.WriteRequestScheduleSupport;\r
-import org.simantics.db.procedure.Procedure;\r
-import org.simantics.db.request.DelayedWrite;\r
-import org.simantics.db.request.DelayedWriteResult;\r
-import org.simantics.db.request.Write;\r
-import org.simantics.db.request.WriteOnly;\r
-import org.simantics.db.request.WriteOnlyResult;\r
-import org.simantics.db.request.WriteResult;\r
-import org.simantics.db.request.WriteTraits;\r
-import org.simantics.layer0.Layer0;\r
-import org.simantics.utils.Development;\r
-import org.simantics.utils.datastructures.Callback;\r
-import org.simantics.utils.datastructures.Pair;\r
-\r
-import gnu.trove.map.hash.THashMap;\r
-\r
-\r
-final public class WriteGraphImpl extends ReadGraphImpl implements WriteGraph {\r
-\r
- final public static Binding DATA_TYPE_BINDING = Bindings.getBindingUnchecked(Datatype.class);\r
- \r
- final public WriteSupport writeSupport;\r
- final public VirtualGraph provider;\r
- \r
- private String resourceName(Resource resource) throws DatabaseException {\r
- if(Development.DEVELOPMENT) {\r
- Boolean names = Development.getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG_NAMES, Bindings.BOOLEAN); \r
- if(names && !writeSupport.writeOnly()) return DatabaseUtils.getReadableName(this, resource);\r
- else return resource.toString();\r
- }\r
- throw new IllegalStateException();\r
- }\r
- \r
- private Layer0 getBuiltins() {\r
- return getService(Layer0.class);\r
- }\r
-\r
- private WriteRequestScheduleSupport getWriteRequestScheduler() {\r
- return (WriteRequestScheduleSupport) getSession();\r
- }\r
-\r
- private WriteGraphImpl(CacheEntry parent2, QueryProcessor readSupport,\r
- WriteSupport writeSupport, VirtualGraph provider) {\r
- super(parent2, readSupport);\r
- this.writeSupport = writeSupport;\r
- this.provider = provider;\r
- }\r
-\r
- public final static WriteGraphImpl create(QueryProcessor support, WriteSupport writeSupport, VirtualGraph provider) {\r
-\r
- WriteGraphImpl impl = new WriteGraphImpl(null, support, writeSupport, provider); \r
- \r
- try {\r
- writeSupport.setDefaultClusterSet(null);\r
- } catch (ServiceException e) {\r
- Logger.defaultLogError(e);\r
- }\r
- \r
- return impl;\r
- \r
- }\r
-\r
- final public WriteGraphImpl newAsync() {\r
- return this;\r
- }\r
- \r
- public WriteGraphImpl newSync(final VirtualGraph provider) {\r
- return new WriteGraphImpl(parent, processor, writeSupport, provider);\r
- }\r
- final public WriteGraphImpl newSync(final CacheEntry parent) {\r
- return new WriteGraphImpl(parent, processor, writeSupport, provider);\r
- }\r
-\r
- @Override\r
- final public ReadGraphImpl withAsyncParent(CacheEntry parent2) {\r
- return new WriteGraphImpl(parent2, processor, writeSupport, provider);\r
- }\r
-\r
- @Override\r
- public ReadGraphImpl newRestart(ReadGraphImpl impl) {\r
-\r
- WriteGraphImpl write = processor.getSession().getService(WriteGraphImpl.class);\r
-\r
- return write;\r
- \r
- }\r
-\r
- @Override\r
- final public Resource newResource() throws ServiceException {\r
- \r
- try {\r
- \r
- Resource result = writeSupport.createResource(provider); \r
-\r
- if(Development.DEVELOPMENT) {\r
- if(Development.<Boolean>getProperty(DevelopmentKeys.WRITELOGGER_LOG, Bindings.BOOLEAN))\r
- WriteLogger.logNewResource(this, result);\r
- }\r
- \r
- return result;\r
- \r
- } catch (DatabaseException e) {\r
- throw new ServiceException(e);\r
- }\r
- \r
- }\r
-\r
- @Override\r
- final public Resource newResource(long clusterId) throws ServiceException {\r
- \r
- try {\r
- \r
- Resource result = writeSupport.createResource(provider, clusterId); \r
-\r
- if(Development.DEVELOPMENT) {\r
- if(Development.<Boolean>getProperty(DevelopmentKeys.WRITELOGGER_LOG, Bindings.BOOLEAN))\r
- WriteLogger.logNewResource(this, result);\r
- }\r
- \r
- return result;\r
- \r
- } catch (DatabaseException e) {\r
- throw new ServiceException(e);\r
- }\r
- \r
- }\r
-\r
- @Override\r
- public Resource newResource(Resource clusterSet) throws ServiceException {\r
- try {\r
- Resource result;\r
- if (provider != null)\r
- result = writeSupport.createResource(provider);\r
- else\r
- result = writeSupport.createResource(provider, clusterSet); \r
- if(Development.DEVELOPMENT) {\r
- if(Development.<Boolean>getProperty(DevelopmentKeys.WRITELOGGER_LOG, Bindings.BOOLEAN))\r
- WriteLogger.logNewResource(this, result);\r
- }\r
- return result;\r
- } catch (ServiceException e) {\r
- throw e;\r
- } catch (DatabaseException e) {\r
- throw new ServiceException(e);\r
- }\r
- }\r
-\r
- @Override\r
- public void newClusterSet(Resource clusterSet) throws ServiceException {\r
- try {\r
- if (provider == null)\r
- writeSupport.createClusterSet(provider, clusterSet); \r
- if(Development.DEVELOPMENT) {\r
- if(Development.<Boolean>getProperty(DevelopmentKeys.WRITELOGGER_LOG, Bindings.BOOLEAN))\r
- WriteLogger.logNewResource(this, clusterSet);\r
- }\r
- } catch (ServiceException e) {\r
- throw e;\r
- } catch (DatabaseException e) {\r
- throw new ServiceException(e);\r
- }\r
- }\r
-\r
- @Override\r
- public Resource setClusterSet4NewResource(Resource clusterSet)\r
- throws ServiceException {\r
- return writeSupport.setDefaultClusterSet(clusterSet);\r
- }\r
- /**\r
- * Compares two object for equality, allowing null objects also.\r
- * \r
- * @param o1 obj1\r
- * @param o2 obj2\r
- * @return true if both arguments are <code>null</code> or equal\r
- */\r
- static boolean safeEquals(Object o1, Object o2) {\r
- if (o1 == o2)\r
- return true;\r
- if (o1 == null && o2 == null)\r
- return true;\r
- if (o1 == null || o2 == null)\r
- return false;\r
- return o1.equals(o2);\r
- }\r
-\r
- @Override\r
- public void asyncRequest(DelayedWrite request) {\r
- assert (request != null);\r
- getWriteRequestScheduler().scheduleRequest(request, new Callback<DatabaseException>() {\r
-\r
- @Override\r
- public void run(DatabaseException parameter) {\r
- if(parameter != null)\r
- Logger.defaultLogError(parameter);\r
- }\r
- \r
- }, null, Boolean.TRUE);\r
- }\r
-\r
- @Override\r
- public void asyncRequest(DelayedWrite request, Callback<DatabaseException> callback) {\r
- assert (request != null);\r
- getWriteRequestScheduler().scheduleRequest(request, callback, null, Boolean.TRUE);\r
- }\r
-\r
- @Override\r
- public <T> void asyncRequest(DelayedWriteResult<T> request, Procedure<T> procedure) {\r
- assert (request != null);\r
- getWriteRequestScheduler().scheduleRequest(request, procedure, null, Boolean.TRUE);\r
- }\r
-\r
- @Override\r
- public void asyncRequest(final Write r) {\r
- assert (r != null);\r
- getWriteRequestScheduler().scheduleRequest(r, new Callback<DatabaseException>() {\r
-\r
- @Override\r
- public void run(DatabaseException parameter) {\r
- if(parameter != null)\r
- Logger.defaultLogError(parameter);\r
- }\r
- \r
- }, null, Boolean.TRUE);\r
- }\r
-\r
- @Override\r
- public void asyncRequest(Write request, Callback<DatabaseException> callback) {\r
- assert (request != null);\r
- getWriteRequestScheduler().scheduleRequest(request, callback, null, Boolean.TRUE);\r
- }\r
-\r
- @Override\r
- public void asyncRequest(WriteOnly request) {\r
- assert (request != null);\r
- getWriteRequestScheduler().scheduleRequest(request, new Callback<DatabaseException>() {\r
-\r
- @Override\r
- public void run(DatabaseException parameter) {\r
- if(parameter != null)\r
- Logger.defaultLogError(parameter);\r
- }\r
- \r
- }, null, Boolean.TRUE);\r
- }\r
- \r
- @Override\r
- public void asyncRequest(WriteOnly request, Callback<DatabaseException> callback) {\r
- assert (request != null);\r
- getWriteRequestScheduler().scheduleRequest(request, callback, null, Boolean.TRUE);\r
- }\r
-\r
- @Override\r
- public <T> void asyncRequest(WriteOnlyResult<T> request, Procedure<T> procedure) {\r
- assert (request != null);\r
- getWriteRequestScheduler().scheduleRequest(request, procedure, null, Boolean.TRUE);\r
- }\r
-\r
- @Override\r
- public <T> void asyncRequest(WriteResult<T> request, Procedure<T> procedure) {\r
- assert (request != null);\r
- getWriteRequestScheduler().scheduleRequest(request, procedure, null, Boolean.TRUE);\r
- }\r
-\r
- @Override\r
- public void syncRequest(Write request) throws DatabaseException {\r
- \r
- Resource defaultClusterSet = setClusterSet4NewResource(null);\r
- \r
- WriteGraphImpl graph = (WriteGraphImpl)newSync(request.getProvider()); \r
- try {\r
- writeSupport.performWriteRequest(graph, request);\r
- } catch (DatabaseException e) {\r
- throw e;\r
- } catch (Throwable t) {\r
- throw new DatabaseException(t);\r
- } finally {\r
- setClusterSet4NewResource(defaultClusterSet);\r
- }\r
- \r
- \r
- }\r
- \r
- @Override\r
- public <T> T syncRequest(WriteResult<T> request) throws DatabaseException {\r
-\r
- Resource defaultClusterSet = setClusterSet4NewResource(null);\r
-\r
- WriteGraphImpl graph = (WriteGraphImpl)newSync(request.getProvider()); \r
- try {\r
- return writeSupport.performWriteRequest(graph, request);\r
- } catch (DatabaseException e) {\r
- throw e;\r
- } catch (Throwable t) {\r
- throw new DatabaseException(t);\r
- } finally {\r
- setClusterSet4NewResource(defaultClusterSet);\r
- }\r
- }\r
-\r
- @Override\r
- public void syncRequest(final DelayedWrite request) throws DatabaseException {\r
- \r
- try {\r
-\r
- final DelayedWriteGraph dwg = new DelayedWriteGraph(this);\r
- request.perform(dwg);\r
-\r
- syncRequest(new WriteOnlyRequest() {\r
-\r
- @Override\r
- public void perform(WriteOnlyGraph graph) throws DatabaseException {\r
- dwg.commit(graph, request);\r
- }\r
-\r
- });\r
-\r
- } catch (DatabaseException e) {\r
- \r
- throw e;\r
- \r
- } catch (Throwable e) {\r
- \r
- throw new DatabaseException(e);\r
- \r
- } finally {\r
- \r
- }\r
- \r
- }\r
-\r
- @Override\r
- public void syncRequest(WriteOnly request) throws DatabaseException {\r
- \r
- Resource defaultClusterSet = setClusterSet4NewResource(null);\r
- \r
- try {\r
- writeSupport.performWriteRequest(this, request);\r
- } catch (DatabaseException e) {\r
- throw e;\r
- } catch (Throwable t) {\r
- throw new DatabaseException(t);\r
- } finally {\r
- setClusterSet4NewResource(defaultClusterSet);\r
- }\r
- \r
- }\r
- \r
- @Override\r
- public void claim(Resource subject, Resource predicate, Resource object) throws ServiceException {\r
-\r
- if(subject == null || predicate == null || object == null) {\r
- throw new ServiceException("Claim does not accept null arguments (subject=" + subject + ",predicate=" + predicate + ",object=" + object + ").");\r
- }\r
-\r
- if(processor.isImmutable(object)) {\r
- claim(subject, predicate, null, object); \r
- } else {\r
- claim(subject, predicate, getPossibleInverse(predicate), object); \r
- }\r
-\r
- }\r
-\r
- @Override\r
- public void claim(Resource subject, Resource predicate, Resource inverse, Resource object) throws ServiceException {\r
- \r
- if (MemWatch.isLowOnMemory())\r
- writeSupport.gc();\r
-\r
- if(subject == null) throw new ServiceException("Claim does not accept null arguments (subject).");\r
- if(predicate == null) throw new ServiceException("Claim does not accept null arguments (predicate).");\r
- if(object == null) throw new ServiceException("Claim does not accept null arguments (object).");\r
- if(provider == null && subject.isPersistent() && !object.isPersistent())\r
- 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
-\r
- try {\r
- if(Development.DEVELOPMENT) {\r
- try {\r
- if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG, Bindings.BOOLEAN)) {\r
- String text = "claim(" + resourceName(subject) + ":" + subject + ", " + resourceName(predicate) + ":" + predicate + ", " + resourceName(object) + ":" + object + ")";\r
- if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG_STACK, Bindings.BOOLEAN)) {\r
- StringWriter writer = new StringWriter();\r
- PrintWriter out = new PrintWriter(writer);\r
- new Exception(text).printStackTrace(out);\r
- Development.dispatchEvent(new ClaimEventImpl(this, provider, subject, predicate, object, writer.toString()));\r
- } else {\r
- Development.dispatchEvent(new ClaimEventImpl(this, provider, subject, predicate, object, text));\r
- }\r
- }\r
- if(Development.<Boolean>getProperty(DevelopmentKeys.WRITELOGGER_LOG, Bindings.BOOLEAN))\r
- WriteLogger.logClaim(this, subject, predicate, inverse, object);\r
- } catch (DatabaseException e) {\r
- Logger.defaultLogError(e);\r
- }\r
- }\r
- writeSupport.claim(provider, subject, predicate, object);\r
- } catch(RuntimeException e) {\r
- throw new ServiceException(e);\r
- }\r
- \r
- if(inverse == null) return;\r
- if(subject.equals(object) && predicate.equals(inverse)) {\r
- return;\r
- }\r
-\r
- // Do as claim(s,p,o) already works -\r
- // don't write inverse relations if object is immutable.\r
- if(processor.isImmutable(object))\r
- return;\r
-\r
- try {\r
- writeSupport.claim(provider, object, inverse, subject);\r
- } catch(RuntimeException e) {\r
- throw new ServiceException(e);\r
- }\r
- \r
- }\r
-\r
- @Override\r
- public void deny(Resource subject) throws ServiceException {\r
- \r
- assert(subject != null);\r
-\r
- try {\r
- \r
- for(Statement stm : getStatements(subject, getBuiltins().IsWeaklyRelatedTo)) {\r
- if(subject.equals(stm.getSubject())) {\r
- Resource inverse = getPossibleInverse(stm.getPredicate());\r
-// if(inverse == null) {\r
-// try {\r
-// String name = adapt(stm.getPredicate(), String.class);\r
-// throw new ResourceDoesNotSatisfyAssumptionException("Resource '" + name + "' does not have an inverse.");\r
-// } catch (AdaptionException e) {\r
-// throw new ResourceDoesNotSatisfyAssumptionException("Resource '" + stm.getPredicate() + "' does not have an inverse.");\r
-// }\r
-// }\r
- deny(stm.getSubject(), stm.getPredicate(), inverse, stm.getObject());\r
- }\r
- }\r
- \r
- } catch(DatabaseException e) {\r
- \r
- throw new ServiceException(INTERNAL_ERROR_STRING, e);\r
- \r
- }\r
- \r
- }\r
-\r
- @Override\r
- public void deny(Resource subject, Resource predicate) throws ServiceException {\r
- \r
- assert(subject != null);\r
- assert(predicate != null);\r
-\r
- try {\r
-\r
- for (Statement stm : getStatements(subject, predicate)) {\r
- if (subject.equals(stm.getSubject())) {\r
- Resource inverse = getPossibleInverse(stm.getPredicate());\r
-// if(inverse == null) {\r
-// try {\r
-// String name = adapt(stm.getPredicate(), String.class);\r
-// throw new ResourceDoesNotSatisfyAssumptionException("Resource '" + name + "' does not have an inverse.");\r
-// } catch (AdaptionException e) {\r
-// throw new ResourceDoesNotSatisfyAssumptionException("Resource '" + stm.getPredicate() + "' does not have an inverse.");\r
-// }\r
-// }\r
- deny(stm.getSubject(), stm.getPredicate(), inverse, stm.getObject());\r
- }\r
- }\r
-\r
- } catch(DatabaseException e) {\r
- \r
- throw new ServiceException(INTERNAL_ERROR_STRING, e);\r
- \r
- }\r
-\r
- }\r
-\r
- @Override\r
- public void deny(Resource subject, Resource predicate, Resource object) throws ServiceException {\r
-\r
- assert(subject != null);\r
- assert(predicate != null);\r
- assert(object != null);\r
-\r
- try { \r
- for (Statement stm : getStatements(subject, predicate)) {\r
- if (subject.equals(stm.getSubject()) && object.equals(stm.getObject())) {\r
- Resource inverse = getPossibleInverse(stm.getPredicate());\r
- deny(stm.getSubject(), stm.getPredicate(), inverse, stm.getObject());\r
- }\r
- }\r
- } catch (DatabaseException e) {\r
- throw new ServiceException(INTERNAL_ERROR_STRING, e);\r
- }\r
-\r
- }\r
-\r
- @Override\r
- public void denyStatement(Resource subject, Resource predicate, Resource object) throws ServiceException {\r
- \r
- assert(subject != null);\r
- assert(predicate != null);\r
- assert(object != null);\r
- \r
- Resource inverse = getPossibleInverse(predicate);\r
-// if(inverse == null) {\r
-// try {\r
-// String name = adapt(predicate, String.class);\r
-// throw new ResourceDoesNotSatisfyAssumptionException("Resource '" + name + "' does not have an inverse.");\r
-// } catch (AdaptionException e) {\r
-// throw new ResourceDoesNotSatisfyAssumptionException("Resource '" + predicate + "' does not have an inverse.");\r
-// }\r
-// }\r
- deny(subject, predicate, inverse, object);\r
- \r
- }\r
-\r
- @Override\r
- public void deny(Statement statement) throws ServiceException {\r
- assert(statement != null);\r
- denyStatement(statement.getSubject(), statement.getPredicate(), statement.getObject());\r
- }\r
-\r
- @Override\r
- public void deny(Resource subject, Resource predicate, Resource inverse, Resource object) throws ServiceException {\r
-\r
- assert(subject != null);\r
- assert(predicate != null);\r
- assert(object != null);\r
- \r
- VirtualGraph provider = processor.getProvider(subject, predicate, object);\r
- \r
- deny(subject, predicate, inverse, object, provider);\r
- \r
- }\r
-\r
- /*\r
- * Note: We assume here that all inverse pairs of statements are stored in the same virtual graph.\r
- */\r
- @Override\r
- public void deny(Resource subject, Resource predicate, Resource inverse, Resource object, VirtualGraph provider) throws ServiceException {\r
- \r
- assert(subject != null);\r
- assert(predicate != null);\r
- assert(object != null);\r
-\r
- if(Development.DEVELOPMENT) {\r
- try {\r
- if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG, Bindings.BOOLEAN)) {\r
- String text = "deny(" + resourceName(subject) + ":" + subject + ", " + resourceName(predicate) + ":" + predicate + ", " + resourceName(object) + ":" + object + ")";\r
- if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG_STACK, Bindings.BOOLEAN)) {\r
- StringWriter writer = new StringWriter();\r
- PrintWriter out = new PrintWriter(writer);\r
- new Exception(text).printStackTrace(out);\r
- Development.dispatchEvent(new DenyEventImpl(this, provider, subject, predicate, object, writer.toString()));\r
- } else {\r
- Development.dispatchEvent(new DenyEventImpl(this, provider, subject, predicate, object, text));\r
- }\r
- }\r
- } catch (DatabaseException e) {\r
- Logger.defaultLogError(e);\r
- }\r
- }\r
- \r
- try {\r
- writeSupport.removeStatement(provider, subject, predicate, object);\r
- } catch(Throwable e) {\r
- throw new InternalException("bug in deny(s,p,i,o)", e);\r
- }\r
- \r
- if(inverse == null || (subject.equals(object) && predicate.equals(inverse))) return;\r
-\r
- // don't deny inverse relations if object is immutable.\r
- if(processor.isImmutable(object))\r
- return;\r
- \r
- try {\r
- writeSupport.removeStatement(provider, object, inverse, subject);\r
- } catch(Throwable e) {\r
- throw new InternalException("bug in deny(s,p,i,o)", e);\r
- }\r
- \r
- }\r
- \r
- @Override\r
- public void claimValue(Resource resource, Object value) throws ServiceException {\r
- \r
- try {\r
- Binding b = Bindings.getBinding(value.getClass());\r
- claimValue(resource, value, b);\r
- } catch(BindingConstructionException e) {\r
- throw new IllegalArgumentException(e);\r
- }\r
- \r
- }\r
-\r
- @Override\r
- public void claimValue(Resource resource, Object value, Binding binding) throws ServiceException {\r
- \r
- if(value == null) throw new ServiceException("claimValue does not accept null value");\r
- if(binding == null) throw new ServiceException("claimValue does not accept null binding");\r
- \r
- if(Development.DEVELOPMENT) {\r
- try {\r
- if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG, Bindings.BOOLEAN)) {\r
- String valueText = Literals.shortString(value.toString());\r
- String text = "claimValue(" + resourceName(resource) + ", " + valueText + ")";\r
- if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG_STACK, Bindings.BOOLEAN)) {\r
- StringWriter writer = new StringWriter();\r
- PrintWriter out = new PrintWriter(writer);\r
- new Exception(text).printStackTrace(out);\r
- Development.dispatchEvent(new ClaimValueEventImpl(this, provider, resource, value, binding, writer.toString()));\r
- } else {\r
- Development.dispatchEvent(new ClaimValueEventImpl(this, provider, resource, value, binding, text));\r
- }\r
- }\r
- } catch (DatabaseException e) {\r
- Logger.defaultLogError(e);\r
- }\r
- }\r
- \r
- try {\r
- Serializer serializer = getSerializer(binding);\r
- //Serializer serializer = binding.serializer();\r
- byte[] data = serializer.serialize(value);\r
-\r
- if(Development.DEVELOPMENT) {\r
- try {\r
- if(Development.<Boolean>getProperty(DevelopmentKeys.WRITELOGGER_LOG, Bindings.BOOLEAN))\r
- WriteLogger.logValue(this, resource, data);\r
- } catch (DatabaseException e) {\r
- Logger.defaultLogError(e);\r
- }\r
- }\r
- \r
- writeSupport.claimValue(provider, resource, data);\r
- \r
- } catch (DatabaseException e) {\r
- throw new ServiceException(e);\r
- } catch (SerializationException e) {\r
- throw new ServiceException(e);\r
- } catch (IOException e) {\r
- throw new ServiceException(e);\r
- } \r
- \r
- }\r
-\r
- THashMap<Class<?>, Resource> builtinValues = new THashMap<Class<?>, Resource>(32);\r
-\r
- private void initBuiltinValues(Layer0 b) {\r
-\r
- if(!builtinValues.isEmpty()) return;\r
-\r
- builtinValues.put(String.class, b.String);\r
- builtinValues.put(Double.class, b.Double);\r
- builtinValues.put(Float.class, b.Float);\r
- builtinValues.put(Long.class, b.Long);\r
- builtinValues.put(Integer.class, b.Integer);\r
- builtinValues.put(Byte.class, b.Byte);\r
- builtinValues.put(Boolean.class, b.Boolean);\r
- builtinValues.put(Variant.class, b.Variant);\r
-\r
- builtinValues.put(String[].class, b.StringArray);\r
- builtinValues.put(double[].class, b.DoubleArray);\r
- builtinValues.put(float[].class, b.FloatArray);\r
- builtinValues.put(long[].class, b.LongArray);\r
- builtinValues.put(int[].class, b.IntegerArray);\r
- builtinValues.put(byte[].class, b.ByteArray);\r
- builtinValues.put(boolean[].class, b.BooleanArray);\r
-\r
- builtinValues.put(MutableString.class, b.String);\r
- builtinValues.put(MutableDouble.class, b.Double);\r
- builtinValues.put(MutableFloat.class, b.Float);\r
- builtinValues.put(MutableLong.class, b.Long);\r
- builtinValues.put(MutableInteger.class, b.Integer);\r
- builtinValues.put(MutableByte.class, b.Byte);\r
- builtinValues.put(MutableBoolean.class, b.Boolean);\r
-\r
- }\r
-\r
- @Override\r
- public void addLiteral(Resource resource, Resource predicate, Resource inverse, Resource type, Object value, Binding binding) throws ManyObjectsForFunctionalRelationException, ServiceException {\r
-\r
- Layer0 b = getBuiltins();\r
- Resource valueResource = newResource();\r
- claim(valueResource, b.InstanceOf, null, type);\r
- claim(resource, predicate, inverse, valueResource);\r
- claimValue(valueResource, value, binding);\r
- \r
- }\r
-\r
- @Override\r
- public void addLiteral(Resource resource, Resource predicate, Resource inverse, Object value, Binding binding) throws ManyObjectsForFunctionalRelationException, ServiceException {\r
-\r
- Layer0 b = getBuiltins();\r
- initBuiltinValues(b);\r
- Resource literal = newResource();\r
- \r
- Class<?> clazz = value.getClass();\r
- Resource type = builtinValues.get(clazz);\r
- if (type == null) {\r
- type = b.Literal;\r
- Resource dataType = newResource();\r
- claim(dataType, b.InstanceOf, null, b.DataType);\r
- claimValue(dataType, binding.type(), DATA_TYPE_BINDING);\r
- claim(literal, b.HasDataType, b.HasDataType_Inverse, dataType);\r
- }\r
- \r
- claim(literal, b.InstanceOf, null, type);\r
- claim(resource, predicate, inverse, literal);\r
- claimValue(literal, value, binding);\r
- \r
- }\r
-\r
- @Override\r
- public <T extends Accessor> T newLiteral(Resource resource, Resource predicate, Datatype datatype, Object initialValue)\r
- throws DatabaseException {\r
- Layer0 b = getBuiltins();\r
- initBuiltinValues(b); \r
- Resource literal = newResource();\r
- claim(literal, b.InstanceOf, null, b.Literal);\r
- Resource dataType = newResource();\r
- claim(dataType, b.InstanceOf, null, b.DataType);\r
- claimValue(dataType, datatype, DATA_TYPE_BINDING);\r
- claim(literal, b.HasDataType, dataType);\r
- claim(resource, predicate, literal);\r
- return createAccessor(literal, datatype, initialValue);\r
- }\r
- @Override\r
- public RandomAccessBinary createRandomAccessBinary\r
- (Resource resource, Resource predicate, Datatype datatype, Object initiaValue)\r
- throws DatabaseException {\r
- Layer0 b = getBuiltins();\r
- initBuiltinValues(b); \r
- Resource literal = newResource();\r
- claim(literal, b.InstanceOf, null, b.Literal);\r
- Resource dataType = newResource();\r
- claim(dataType, b.InstanceOf, null, b.DataType);\r
- claimValue(dataType, datatype, DATA_TYPE_BINDING);\r
- claim(literal, b.HasDataType, dataType);\r
- claim(resource, predicate, literal);\r
- return createRandomAccessBinary(literal, datatype, initiaValue);\r
- }\r
- @Override\r
- public void claimLiteral(Resource resource, Resource predicate, Object value) throws ManyObjectsForFunctionalRelationException, ServiceException {\r
-\r
- try {\r
- Binding binding = Bindings.getBinding(value.getClass());\r
- claimLiteral(resource, predicate, value, binding);\r
- } catch(BindingConstructionException e) {\r
- throw new IllegalArgumentException(e);\r
- } \r
-\r
- }\r
-\r
- @Override\r
- public void claimLiteral(Resource resource, Resource predicate, Object value, Binding binding) throws ManyObjectsForFunctionalRelationException, ServiceException {\r
- \r
- Layer0 b = getBuiltins();\r
- initBuiltinValues(b); \r
- \r
- Statement literalStatement = getPossibleStatement(resource, predicate);\r
-\r
- if(literalStatement != null && resource.equals(literalStatement.getSubject())) {\r
-\r
- claimValue(literalStatement.getObject(), value, binding);\r
-\r
- } else {\r
-\r
- Class<?> clazz = value.getClass();\r
- Resource type = builtinValues.get(clazz);\r
- Resource literal = newResource();\r
- if (type == null) {\r
- type = b.Literal;\r
- Resource dataType = newResource();\r
- claim(dataType, b.InstanceOf, null, b.DataType);\r
- claimValue(dataType, binding.type(), DATA_TYPE_BINDING);\r
- claim(literal, b.HasDataType, null, dataType);\r
- }\r
- claim(literal, b.InstanceOf, null, type);\r
- claimValue(literal, value, binding); \r
- claim(resource, predicate, literal);\r
-\r
- }\r
-\r
- if(Development.DEVELOPMENT) {\r
- try {\r
- getPossibleStatement(resource, predicate);\r
- } catch (ManyObjectsForFunctionalRelationException e) {\r
- System.err.println("err " + ((ResourceImpl)resource).id + " " + ((ResourceImpl)predicate).id);\r
- getPossibleStatement(resource, predicate);\r
- }\r
- }\r
- \r
- }\r
- \r
- @Override\r
- public void claimLiteral(Resource resource, Resource predicate, Resource type, Object value)\r
- throws org.simantics.db.exception.BindingException, ManyObjectsForFunctionalRelationException, ServiceException {\r
- \r
- try {\r
- Binding binding = Bindings.getBinding(value.getClass());\r
- claimLiteral(resource, predicate, type, value, binding);\r
- } catch(BindingConstructionException e) {\r
- throw new IllegalArgumentException(e);\r
- } \r
- \r
- }\r
- \r
- @Override\r
- public void claimLiteral(Resource resource, Resource predicate, Resource type, Object value, Binding binding)\r
- throws org.simantics.db.exception.BindingException, ManyObjectsForFunctionalRelationException, ServiceException {\r
- \r
- Layer0 b = getBuiltins();\r
- \r
- Statement literalStatement = getPossibleStatement(resource, predicate);\r
-\r
- if(literalStatement != null && resource.equals(literalStatement.getSubject())) {\r
-\r
- claimValue(literalStatement.getObject(), value, binding);\r
-\r
- } else {\r
-\r
- Resource literal = newResource();\r
- claim(literal, b.InstanceOf, null, type);\r
- claimValue(literal, value, binding); \r
- claim(resource, predicate, literal);\r
-\r
- }\r
- \r
- }\r
- \r
- @Override\r
- public void claimLiteral(Resource resource, Resource predicate, Resource inverse, Resource type, Object value)\r
- throws org.simantics.db.exception.BindingException, ManyObjectsForFunctionalRelationException, ServiceException {\r
-\r
- try {\r
- Binding binding = Bindings.getBinding(value.getClass());\r
- claimLiteral(resource, predicate, inverse, type, value, binding);\r
- } catch(BindingConstructionException e) {\r
- throw new IllegalArgumentException(e);\r
- } \r
- \r
- }\r
- \r
- @Override\r
- public void claimLiteral(Resource resource, Resource predicate, Resource inverse, Resource type, Object value, Binding binding)\r
- throws org.simantics.db.exception.BindingException, ManyObjectsForFunctionalRelationException, ServiceException {\r
- \r
- Layer0 b = getBuiltins();\r
- \r
- Statement literalStatement = getPossibleStatement(resource, predicate);\r
-\r
- if(literalStatement != null && resource.equals(literalStatement.getSubject())) {\r
-\r
- claimValue(literalStatement.getObject(), value, binding);\r
-\r
- } else {\r
-\r
- Resource literal = newResource();\r
- claim(literal, b.InstanceOf, null, type);\r
- claimValue(literal, value, binding); \r
- claim(resource, predicate, inverse, literal);\r
-\r
- }\r
- \r
- }\r
-\r
-\r
- @Override\r
- public void denyValue(Resource resource) throws ServiceException {\r
-\r
- denyValue0(resource, null);\r
-\r
- }\r
-\r
- @Override\r
- public void denyValue(Resource resource, VirtualGraph valueProvider) throws ServiceException {\r
-\r
- denyValue0(resource, valueProvider);\r
-\r
- }\r
- \r
- /**\r
- * @param resource resource to remove value from\r
- * @param valueProvider <code>null</code> means the caller doesn't know and\r
- * this method must find out\r
- * @throws ServiceException\r
- */\r
- private void denyValue0(Resource resource, VirtualGraph valueProvider) throws ServiceException {\r
-\r
- if(Development.DEVELOPMENT) {\r
- try {\r
- if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG, Bindings.BOOLEAN)) {\r
- Object oldValue = getPossibleValue(resource);\r
- String valueText = oldValue == null ? "<no value>" : oldValue.toString();\r
- String text = "denyValue(" + resourceName(resource) + ", " + valueText + ")";\r
- if (oldValue != null) {\r
- if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG_STACK, Bindings.BOOLEAN)) {\r
- StringWriter writer = new StringWriter();\r
- PrintWriter out = new PrintWriter(writer);\r
- new Exception(text).printStackTrace(out);\r
- Development.dispatchEvent(new DenyValueEventImpl(this, provider, resource, oldValue, writer.toString()));\r
- } else {\r
- Development.dispatchEvent(new DenyValueEventImpl(this, provider, resource, oldValue, text));\r
- }\r
- }\r
- }\r
- } catch (DatabaseException e) {\r
- Logger.defaultLogError(e);\r
- }\r
- }\r
- \r
- if (provider != null) {\r
-\r
- // Can only remove from the specified VirtualGraph\r
- if (resource.isPersistent())\r
- throw new ArgumentException("Tried to remove literal value from persistent resource " + resource\r
- + " using virtual graph '" + provider.getIdentifier() + "'");\r
- writeSupport.denyValue(provider, resource);\r
-\r
- } else {\r
-\r
- // Can remove from any provider\r
- if (resource.isPersistent()) {\r
- // A persistent resource cannot have a virtual literal\r
- // so this should be safe.\r
- writeSupport.denyValue(provider, resource);\r
- } else {\r
- // A virtual resource cannot have a persistent literal.\r
- // Must look for a virtual graph for resource.\r
- Layer0 L0 = getBuiltins();\r
- if (valueProvider == null) {\r
- if (hasStatement(resource, L0.InstanceOf)) {\r
- valueProvider = processor.getProvider(resource, L0.InstanceOf);\r
- } else if (hasStatement(resource, L0.Inherits)) {\r
- valueProvider = processor.getProvider(resource, L0.Inherits);\r
- } else if (hasStatement(resource, L0.SubrelationOf)) {\r
- valueProvider = processor.getProvider(resource, L0.SubrelationOf);\r
- }\r
- }\r
- if (valueProvider != null)\r
- writeSupport.denyValue(valueProvider, resource);\r
- }\r
-\r
- }\r
-\r
- }\r
-\r
- @Override\r
- public void denyValue(Resource resource, Resource predicate) throws ManyObjectsForFunctionalRelationException, ServiceException {\r
-\r
- Statement valueStatement = getPossibleStatement(resource, predicate);\r
-\r
- if (valueStatement != null && !valueStatement.isAsserted(resource)) {\r
-\r
- Resource value = valueStatement.getObject();\r
- Resource inverse = getPossibleInverse(predicate);\r
-\r
- if (provider != null) {\r
-\r
- // Can only remove from the specified provider\r
- deny(resource, predicate, inverse, value, provider);\r
- writeSupport.denyValue(provider, value);\r
-\r
- } else {\r
-\r
- // Can remove from any provider\r
- VirtualGraph statementProvider = processor.getProvider(resource, valueStatement.getPredicate(), value);\r
- deny(resource, predicate, inverse, value, statementProvider);\r
- denyValue0(resource, statementProvider);\r
-\r
- }\r
-\r
- }\r
-\r
- }\r
-\r
- @Override\r
- public void flushCluster() {\r
- \r
- writeSupport.flushCluster();\r
- \r
- }\r
-\r
- @Override\r
- public void flushCluster(Resource r) {\r
- writeSupport.flushCluster(r);\r
- }\r
- \r
- Object serialize(Object value) {\r
- \r
- Class<?> clazz = value.getClass();\r
- \r
- if(clazz.isArray()) return value;\r
- \r
- if(Double.class == clazz) return new double[] { (Double)value };\r
- else if(String.class == clazz) return new String[] { (String)value };\r
- else if(Integer.class == clazz) return new int[] { (Integer)value };\r
- else if(Boolean.class == clazz) return new boolean[] { (Boolean)value };\r
- else if(Long.class == clazz) return new long[] { (Long)value };\r
- else if(Byte.class == clazz) return new byte[] { (Byte)value };\r
- else if(Float.class == clazz) return new float[] { (Float)value };\r
- else return value;\r
- \r
- }\r
- \r
- @Override\r
- public <T> void addMetadata(Metadata data) throws ServiceException {\r
- writeSupport.addMetadata(data);\r
- }\r
-\r
- @Override\r
- public <T extends Metadata> T getMetadata(Class<T> clazz) throws ServiceException {\r
- return writeSupport.getMetadata(clazz);\r
- }\r
-\r
- @Override\r
- public TreeMap<String, byte[]> getMetadata() {\r
- return writeSupport.getMetadata();\r
- }\r
-\r
- @Override\r
- public String toString() {\r
- return "WriteGraphImpl[thread=" + Thread.currentThread() + "]";\r
- } \r
-\r
- public void commitAccessorChanges(WriteTraits writeTraits) {\r
- try {\r
- RandomAccessValueSupport ravs = getSession().peekService(RandomAccessValueSupport.class);\r
- if (ravs == null)\r
- return;\r
-\r
- for(Pair<Resource, ResourceData> entry : ravs.entries()) {\r
- ResourceData rd = entry.second;\r
- if(!rd.isChanged()) continue;\r
- Resource resource = entry.first;\r
- try {\r
- ExternalValueSupport evs = getService(ExternalValueSupport.class);\r
- long vsize = rd.oldExternalValue ? evs.getValueSize(this, resource) : -1;\r
- long bsize = rd.binaryFile.length();\r
- final int N = 1<<20;\r
- final int LIMIT = 10 * 1000 * 1000;\r
- long left = bsize;\r
- long offset = 0;\r
- byte[] bytes = new byte[N];\r
- rd.binaryFile.reset();\r
- rd.binaryFile.position(0);\r
- int count = 0;\r
-// if (LIMIT < left)\r
-// evs.moveValue(this, resource);\r
- while (left > 0) {\r
- int length = N < left ? N : (int)left;\r
- rd.binaryFile.readFully(bytes, 0, length);\r
- evs.writeValue(this, resource, offset, length, bytes);\r
- offset += length;\r
- left -= length;\r
- count += length;\r
- if (count > LIMIT) {\r
- count = 0;\r
-// evs.commitAndContinue(this, writeTraits, resource);\r
-// evs.moveValue(this, resource);\r
- // This is needed so we don't create too many requests and run out of heap.\r
- evs.wait4RequestsLess(1);\r
- }\r
- }\r
- if (bsize < vsize) // truncate\r
- evs.writeValue(this, resource, bsize, 0, new byte[0]);\r
- } catch (DatabaseException e) {\r
- Logger.defaultLogError(e);\r
- }\r
- }\r
- } catch(IOException e) {\r
- Logger.defaultLogError(e);\r
- } catch (RuntimeException e) {\r
- Logger.defaultLogError(e);\r
- }\r
- }\r
-\r
- @Override\r
- public VirtualGraph getProvider() {\r
- return provider;\r
- }\r
-\r
- @Override\r
- public void clearUndoList(WriteTraits writeTraits) {\r
- writeSupport.clearUndoList(writeTraits);\r
- }\r
- \r
- public void markUndoPoint() {\r
- writeSupport.startUndo();\r
- }\r
- \r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2018 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.db.impl.graph;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.TreeMap;
+import java.util.function.Consumer;
+
+import org.simantics.databoard.Bindings;
+import org.simantics.databoard.accessor.Accessor;
+import org.simantics.databoard.binding.Binding;
+import org.simantics.databoard.binding.error.BindingConstructionException;
+import org.simantics.databoard.binding.mutable.Variant;
+import org.simantics.databoard.primitives.MutableBoolean;
+import org.simantics.databoard.primitives.MutableByte;
+import org.simantics.databoard.primitives.MutableDouble;
+import org.simantics.databoard.primitives.MutableFloat;
+import org.simantics.databoard.primitives.MutableInteger;
+import org.simantics.databoard.primitives.MutableLong;
+import org.simantics.databoard.primitives.MutableString;
+import org.simantics.databoard.serialization.SerializationException;
+import org.simantics.databoard.serialization.Serializer;
+import org.simantics.databoard.type.Datatype;
+import org.simantics.databoard.util.binary.RandomAccessBinary;
+import org.simantics.db.DevelopmentKeys;
+import org.simantics.db.ExternalValueSupport;
+import org.simantics.db.Metadata;
+import org.simantics.db.Resource;
+import org.simantics.db.Statement;
+import org.simantics.db.VirtualGraph;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.WriteOnlyGraph;
+import org.simantics.db.common.request.WriteOnlyRequest;
+import org.simantics.db.common.utils.Literals;
+import org.simantics.db.common.utils.Logger;
+import org.simantics.db.exception.ArgumentException;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.exception.InternalException;
+import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;
+import org.simantics.db.exception.ServiceException;
+import org.simantics.db.impl.DatabaseUtils;
+import org.simantics.db.impl.MemWatch;
+import org.simantics.db.impl.ResourceImpl;
+import org.simantics.db.impl.internal.RandomAccessValueSupport;
+import org.simantics.db.impl.internal.ResourceData;
+import org.simantics.db.impl.query.CacheEntry;
+import org.simantics.db.impl.query.QueryProcessor;
+import org.simantics.db.impl.support.WriteRequestScheduleSupport;
+import org.simantics.db.procedure.Procedure;
+import org.simantics.db.request.DelayedWrite;
+import org.simantics.db.request.DelayedWriteResult;
+import org.simantics.db.request.Write;
+import org.simantics.db.request.WriteOnly;
+import org.simantics.db.request.WriteOnlyResult;
+import org.simantics.db.request.WriteResult;
+import org.simantics.db.request.WriteTraits;
+import org.simantics.layer0.Layer0;
+import org.simantics.utils.Development;
+import org.simantics.utils.datastructures.Pair;
+
+import gnu.trove.map.hash.THashMap;
+
+
+final public class WriteGraphImpl extends ReadGraphImpl implements WriteGraph {
+
+ final public static Binding DATA_TYPE_BINDING = Bindings.getBindingUnchecked(Datatype.class);
+
+ final public WriteSupport writeSupport;
+ final public VirtualGraph provider;
+
+ private String resourceName(Resource resource) throws DatabaseException {
+ if(Development.DEVELOPMENT) {
+ Boolean names = Development.getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG_NAMES, Bindings.BOOLEAN);
+ if(names && !writeSupport.writeOnly()) return DatabaseUtils.getReadableName(this, resource);
+ else return resource.toString();
+ }
+ throw new IllegalStateException();
+ }
+
+ private Layer0 getBuiltins() {
+ return getService(Layer0.class);
+ }
+
+ private WriteRequestScheduleSupport getWriteRequestScheduler() {
+ return (WriteRequestScheduleSupport) getSession();
+ }
+
+ private WriteGraphImpl(CacheEntry parent2, QueryProcessor readSupport,
+ WriteSupport writeSupport, VirtualGraph provider) {
+ super(null, parent2, readSupport);
+ this.writeSupport = writeSupport;
+ this.provider = provider;
+ }
+
+ public final static WriteGraphImpl create(QueryProcessor support, WriteSupport writeSupport, VirtualGraph provider) {
+
+ WriteGraphImpl impl = new WriteGraphImpl(null, support, writeSupport, provider);
+
+ try {
+ writeSupport.setDefaultClusterSet(null);
+ } catch (ServiceException e) {
+ Logger.defaultLogError(e);
+ }
+
+ return impl;
+
+ }
+
+ final public WriteGraphImpl newAsync() {
+ return this;
+ }
+
+ public WriteGraphImpl newSync(final VirtualGraph provider) {
+ return new WriteGraphImpl(parent, processor, writeSupport, provider);
+ }
+ final public WriteGraphImpl newSync(final CacheEntry parent) {
+ return new WriteGraphImpl(parent, processor, writeSupport, provider);
+ }
+
+ @Override
+ public ReadGraphImpl newRestart(ReadGraphImpl impl) {
+
+ WriteGraphImpl write = processor.getSession().getService(WriteGraphImpl.class);
+
+ return write;
+
+ }
+
+ @Override
+ final public Resource newResource() throws ServiceException {
+
+ try {
+
+ Resource result = writeSupport.createResource(provider);
+
+ if(Development.DEVELOPMENT) {
+ if(Development.<Boolean>getProperty(DevelopmentKeys.WRITELOGGER_LOG, Bindings.BOOLEAN))
+ WriteLogger.logNewResource(this, result);
+ }
+
+ return result;
+
+ } catch (DatabaseException e) {
+ throw new ServiceException(e);
+ }
+
+ }
+
+ @Override
+ final public Resource newResource(long clusterId) throws ServiceException {
+
+ try {
+
+ Resource result = writeSupport.createResource(provider, clusterId);
+
+ if(Development.DEVELOPMENT) {
+ if(Development.<Boolean>getProperty(DevelopmentKeys.WRITELOGGER_LOG, Bindings.BOOLEAN))
+ WriteLogger.logNewResource(this, result);
+ }
+
+ return result;
+
+ } catch (DatabaseException e) {
+ throw new ServiceException(e);
+ }
+
+ }
+
+ @Override
+ public Resource newResource(Resource clusterSet) throws ServiceException {
+ try {
+ Resource result;
+ if (provider != null)
+ result = writeSupport.createResource(provider);
+ else
+ result = writeSupport.createResource(provider, clusterSet);
+ if(Development.DEVELOPMENT) {
+ if(Development.<Boolean>getProperty(DevelopmentKeys.WRITELOGGER_LOG, Bindings.BOOLEAN))
+ WriteLogger.logNewResource(this, result);
+ }
+ return result;
+ } catch (ServiceException e) {
+ throw e;
+ } catch (DatabaseException e) {
+ throw new ServiceException(e);
+ }
+ }
+
+ @Override
+ public void newClusterSet(Resource clusterSet) throws ServiceException {
+ try {
+ if (provider == null)
+ writeSupport.createClusterSet(provider, clusterSet);
+ if(Development.DEVELOPMENT) {
+ if(Development.<Boolean>getProperty(DevelopmentKeys.WRITELOGGER_LOG, Bindings.BOOLEAN))
+ WriteLogger.logNewResource(this, clusterSet);
+ }
+ } catch (ServiceException e) {
+ throw e;
+ } catch (DatabaseException e) {
+ throw new ServiceException(e);
+ }
+ }
+
+ @Override
+ public Resource setClusterSet4NewResource(Resource clusterSet)
+ throws ServiceException {
+ return writeSupport.setDefaultClusterSet(clusterSet);
+ }
+ /**
+ * Compares two object for equality, allowing null objects also.
+ *
+ * @param o1 obj1
+ * @param o2 obj2
+ * @return true if both arguments are <code>null</code> or equal
+ */
+ static boolean safeEquals(Object o1, Object o2) {
+ if (o1 == o2)
+ return true;
+ if (o1 == null && o2 == null)
+ return true;
+ if (o1 == null || o2 == null)
+ return false;
+ return o1.equals(o2);
+ }
+
+ @Override
+ public void asyncRequest(DelayedWrite request) {
+ assert (request != null);
+ getWriteRequestScheduler().scheduleRequest(request, e -> {
+ if(e != null)
+ Logger.defaultLogError(e);
+ }, null, Boolean.TRUE);
+ }
+
+ @Override
+ public void asyncRequest(DelayedWrite request, Consumer<DatabaseException> callback) {
+ assert (request != null);
+ getWriteRequestScheduler().scheduleRequest(request, callback, null, Boolean.TRUE);
+ }
+
+ @Override
+ public <T> void asyncRequest(DelayedWriteResult<T> request, Procedure<T> procedure) {
+ assert (request != null);
+ getWriteRequestScheduler().scheduleRequest(request, procedure, null, Boolean.TRUE);
+ }
+
+ @Override
+ public void asyncRequest(final Write r) {
+ assert (r != null);
+ getWriteRequestScheduler().scheduleRequest(r, e -> {
+ if(e != null)
+ Logger.defaultLogError(e);
+ }, null, Boolean.TRUE);
+ }
+
+ @Override
+ public void asyncRequest(Write request, Consumer<DatabaseException> callback) {
+ assert (request != null);
+ getWriteRequestScheduler().scheduleRequest(request, callback, null, Boolean.TRUE);
+ }
+
+ @Override
+ public void asyncRequest(WriteOnly request) {
+ assert (request != null);
+ getWriteRequestScheduler().scheduleRequest(request, e -> {
+ if(e != null)
+ Logger.defaultLogError(e);
+ }, null, Boolean.TRUE);
+ }
+
+ @Override
+ public void asyncRequest(WriteOnly request, Consumer<DatabaseException> callback) {
+ assert (request != null);
+ getWriteRequestScheduler().scheduleRequest(request, callback, null, Boolean.TRUE);
+ }
+
+ @Override
+ public <T> void asyncRequest(WriteOnlyResult<T> request, Procedure<T> procedure) {
+ assert (request != null);
+ getWriteRequestScheduler().scheduleRequest(request, procedure, null, Boolean.TRUE);
+ }
+
+ @Override
+ public <T> void asyncRequest(WriteResult<T> request, Procedure<T> procedure) {
+ assert (request != null);
+ getWriteRequestScheduler().scheduleRequest(request, procedure, null, Boolean.TRUE);
+ }
+
+ @Override
+ public void syncRequest(Write request) throws DatabaseException {
+
+ Resource defaultClusterSet = setClusterSet4NewResource(null);
+
+ WriteGraphImpl graph = (WriteGraphImpl)newSync(request.getProvider());
+ try {
+ writeSupport.performWriteRequest(graph, request);
+ } catch (DatabaseException e) {
+ throw e;
+ } catch (Throwable t) {
+ throw new DatabaseException(t);
+ } finally {
+ setClusterSet4NewResource(defaultClusterSet);
+ }
+
+
+ }
+
+ @Override
+ public <T> T syncRequest(WriteResult<T> request) throws DatabaseException {
+
+ Resource defaultClusterSet = setClusterSet4NewResource(null);
+
+ WriteGraphImpl graph = (WriteGraphImpl)newSync(request.getProvider());
+ try {
+ return writeSupport.performWriteRequest(graph, request);
+ } catch (DatabaseException e) {
+ throw e;
+ } catch (Throwable t) {
+ throw new DatabaseException(t);
+ } finally {
+ setClusterSet4NewResource(defaultClusterSet);
+ }
+ }
+
+ @Override
+ public void syncRequest(final DelayedWrite request) throws DatabaseException {
+
+ try {
+
+ final DelayedWriteGraph dwg = new DelayedWriteGraph(this);
+ request.perform(dwg);
+
+ syncRequest(new WriteOnlyRequest() {
+
+ @Override
+ public void perform(WriteOnlyGraph graph) throws DatabaseException {
+ dwg.commit(graph, request);
+ }
+
+ });
+
+ } catch (DatabaseException e) {
+
+ throw e;
+
+ } catch (Throwable e) {
+
+ throw new DatabaseException(e);
+
+ } finally {
+
+ }
+
+ }
+
+ @Override
+ public void syncRequest(WriteOnly request) throws DatabaseException {
+
+ Resource defaultClusterSet = setClusterSet4NewResource(null);
+
+ try {
+ writeSupport.performWriteRequest(this, request);
+ } catch (DatabaseException e) {
+ throw e;
+ } catch (Throwable t) {
+ throw new DatabaseException(t);
+ } finally {
+ setClusterSet4NewResource(defaultClusterSet);
+ }
+
+ }
+
+ @Override
+ public void claim(Resource subject, Resource predicate, Resource object) throws ServiceException {
+
+ if(subject == null || predicate == null || object == null) {
+ throw new ServiceException("Claim does not accept null arguments (subject=" + subject + ",predicate=" + predicate + ",object=" + object + ").");
+ }
+
+ if(processor.isImmutable(object)) {
+ claim(subject, predicate, null, object);
+ } else {
+ claim(subject, predicate, getPossibleInverse(predicate), object);
+ }
+
+ }
+
+ @Override
+ public void claim(Resource subject, Resource predicate, Resource inverse, Resource object) throws ServiceException {
+
+ if (MemWatch.isLowOnMemory())
+ writeSupport.gc();
+
+ if(subject == null) throw new ServiceException("Claim does not accept null arguments (subject).");
+ if(predicate == null) throw new ServiceException("Claim does not accept null arguments (predicate).");
+ if(object == null) throw new ServiceException("Claim does not accept null arguments (object).");
+ if(provider == null && subject.isPersistent() && !object.isPersistent())
+ 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.");
+
+ try {
+ if(Development.DEVELOPMENT) {
+ try {
+ if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG, Bindings.BOOLEAN)) {
+ String text = "claim(" + resourceName(subject) + ":" + subject + ", " + resourceName(predicate) + ":" + predicate + ", " + resourceName(object) + ":" + object + ")";
+ if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG_STACK, Bindings.BOOLEAN)) {
+ StringWriter writer = new StringWriter();
+ PrintWriter out = new PrintWriter(writer);
+ new Exception(text).printStackTrace(out);
+ Development.dispatchEvent(new ClaimEventImpl(this, provider, subject, predicate, object, writer.toString()));
+ } else {
+ Development.dispatchEvent(new ClaimEventImpl(this, provider, subject, predicate, object, text));
+ }
+ }
+ if(Development.<Boolean>getProperty(DevelopmentKeys.WRITELOGGER_LOG, Bindings.BOOLEAN))
+ WriteLogger.logClaim(this, subject, predicate, inverse, object);
+ } catch (DatabaseException e) {
+ Logger.defaultLogError(e);
+ }
+ }
+ writeSupport.claim(provider, subject, predicate, object);
+ } catch(RuntimeException e) {
+ throw new ServiceException(e);
+ }
+
+ if(inverse == null) return;
+ if(subject.equals(object) && predicate.equals(inverse)) {
+ return;
+ }
+
+ // Do as claim(s,p,o) already works -
+ // don't write inverse relations if object is immutable.
+ if(processor.isImmutable(object))
+ return;
+
+ try {
+ writeSupport.claim(provider, object, inverse, subject);
+ } catch(RuntimeException e) {
+ throw new ServiceException(e);
+ }
+
+ }
+
+ @Override
+ public void deny(Resource subject) throws ServiceException {
+
+ assert(subject != null);
+
+ try {
+
+ for(Statement stm : getStatements(subject, getBuiltins().IsWeaklyRelatedTo)) {
+ if(subject.equals(stm.getSubject())) {
+ Resource inverse = getPossibleInverse(stm.getPredicate());
+// if(inverse == null) {
+// try {
+// String name = adapt(stm.getPredicate(), String.class);
+// throw new ResourceDoesNotSatisfyAssumptionException("Resource '" + name + "' does not have an inverse.");
+// } catch (AdaptionException e) {
+// throw new ResourceDoesNotSatisfyAssumptionException("Resource '" + stm.getPredicate() + "' does not have an inverse.");
+// }
+// }
+ deny(stm.getSubject(), stm.getPredicate(), inverse, stm.getObject());
+ }
+ }
+
+ } catch(DatabaseException e) {
+
+ throw new ServiceException(INTERNAL_ERROR_STRING, e);
+
+ }
+
+ }
+
+ @Override
+ public void deny(Resource subject, Resource predicate) throws ServiceException {
+
+ assert(subject != null);
+ assert(predicate != null);
+
+ try {
+
+ for (Statement stm : getStatements(subject, predicate)) {
+ if (subject.equals(stm.getSubject())) {
+ Resource inverse = getPossibleInverse(stm.getPredicate());
+// if(inverse == null) {
+// try {
+// String name = adapt(stm.getPredicate(), String.class);
+// throw new ResourceDoesNotSatisfyAssumptionException("Resource '" + name + "' does not have an inverse.");
+// } catch (AdaptionException e) {
+// throw new ResourceDoesNotSatisfyAssumptionException("Resource '" + stm.getPredicate() + "' does not have an inverse.");
+// }
+// }
+ deny(stm.getSubject(), stm.getPredicate(), inverse, stm.getObject());
+ }
+ }
+
+ } catch(DatabaseException e) {
+
+ throw new ServiceException(INTERNAL_ERROR_STRING, e);
+
+ }
+
+ }
+
+ @Override
+ public void deny(Resource subject, Resource predicate, Resource object) throws ServiceException {
+
+ assert(subject != null);
+ assert(predicate != null);
+ assert(object != null);
+
+ try {
+ for (Statement stm : getStatements(subject, predicate)) {
+ if (subject.equals(stm.getSubject()) && object.equals(stm.getObject())) {
+ Resource inverse = getPossibleInverse(stm.getPredicate());
+ deny(stm.getSubject(), stm.getPredicate(), inverse, stm.getObject());
+ }
+ }
+ } catch (DatabaseException e) {
+ throw new ServiceException(INTERNAL_ERROR_STRING, e);
+ }
+
+ }
+
+ @Override
+ public void denyStatement(Resource subject, Resource predicate, Resource object) throws ServiceException {
+
+ assert(subject != null);
+ assert(predicate != null);
+ assert(object != null);
+
+ Resource inverse = getPossibleInverse(predicate);
+// if(inverse == null) {
+// try {
+// String name = adapt(predicate, String.class);
+// throw new ResourceDoesNotSatisfyAssumptionException("Resource '" + name + "' does not have an inverse.");
+// } catch (AdaptionException e) {
+// throw new ResourceDoesNotSatisfyAssumptionException("Resource '" + predicate + "' does not have an inverse.");
+// }
+// }
+ deny(subject, predicate, inverse, object);
+
+ }
+
+ @Override
+ public void deny(Statement statement) throws ServiceException {
+ assert(statement != null);
+ denyStatement(statement.getSubject(), statement.getPredicate(), statement.getObject());
+ }
+
+ @Override
+ public void deny(Resource subject, Resource predicate, Resource inverse, Resource object) throws ServiceException {
+
+ assert(subject != null);
+ assert(predicate != null);
+ assert(object != null);
+
+ VirtualGraph provider = processor.getProvider(subject, predicate, object);
+
+ deny(subject, predicate, inverse, object, provider);
+
+ }
+
+ /*
+ * Note: We assume here that all inverse pairs of statements are stored in the same virtual graph.
+ */
+ @Override
+ public void deny(Resource subject, Resource predicate, Resource inverse, Resource object, VirtualGraph provider) throws ServiceException {
+
+ assert(subject != null);
+ assert(predicate != null);
+ assert(object != null);
+
+ if(Development.DEVELOPMENT) {
+ try {
+ if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG, Bindings.BOOLEAN)) {
+ String text = "deny(" + resourceName(subject) + ":" + subject + ", " + resourceName(predicate) + ":" + predicate + ", " + resourceName(object) + ":" + object + ")";
+ if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG_STACK, Bindings.BOOLEAN)) {
+ StringWriter writer = new StringWriter();
+ PrintWriter out = new PrintWriter(writer);
+ new Exception(text).printStackTrace(out);
+ Development.dispatchEvent(new DenyEventImpl(this, provider, subject, predicate, object, writer.toString()));
+ } else {
+ Development.dispatchEvent(new DenyEventImpl(this, provider, subject, predicate, object, text));
+ }
+ }
+ } catch (DatabaseException e) {
+ Logger.defaultLogError(e);
+ }
+ }
+
+ try {
+ writeSupport.removeStatement(provider, subject, predicate, object);
+ } catch(Throwable e) {
+ throw new InternalException("bug in deny(s,p,i,o)", e);
+ }
+
+ if(inverse == null || (subject.equals(object) && predicate.equals(inverse))) return;
+
+ // don't deny inverse relations if object is immutable.
+ if(processor.isImmutable(object))
+ return;
+
+ try {
+ writeSupport.removeStatement(provider, object, inverse, subject);
+ } catch(Throwable e) {
+ throw new InternalException("bug in deny(s,p,i,o)", e);
+ }
+
+ }
+
+ @Override
+ public void claimValue(Resource resource, Object value) throws ServiceException {
+
+ try {
+ Binding b = Bindings.getBinding(value.getClass());
+ claimValue(resource, value, b);
+ } catch(BindingConstructionException e) {
+ throw new IllegalArgumentException(e);
+ }
+
+ }
+
+ @Override
+ public void claimValue(Resource resource, Object value, Binding binding) throws ServiceException {
+
+ if(value == null) throw new ServiceException("claimValue does not accept null value");
+ if(binding == null) throw new ServiceException("claimValue does not accept null binding");
+
+ if(Development.DEVELOPMENT) {
+ try {
+ if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG, Bindings.BOOLEAN)) {
+ String valueText = Literals.shortString(value.toString());
+ String text = "claimValue(" + resourceName(resource) + ", " + valueText + ")";
+ if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG_STACK, Bindings.BOOLEAN)) {
+ StringWriter writer = new StringWriter();
+ PrintWriter out = new PrintWriter(writer);
+ new Exception(text).printStackTrace(out);
+ Development.dispatchEvent(new ClaimValueEventImpl(this, provider, resource, value, binding, writer.toString()));
+ } else {
+ Development.dispatchEvent(new ClaimValueEventImpl(this, provider, resource, value, binding, text));
+ }
+ }
+ } catch (DatabaseException e) {
+ Logger.defaultLogError(e);
+ }
+ }
+
+ try {
+ Serializer serializer = getSerializer(binding);
+ //Serializer serializer = binding.serializer();
+ byte[] data = serializer.serialize(value);
+
+ if(Development.DEVELOPMENT) {
+ try {
+ if(Development.<Boolean>getProperty(DevelopmentKeys.WRITELOGGER_LOG, Bindings.BOOLEAN))
+ WriteLogger.logValue(this, resource, data);
+ } catch (DatabaseException e) {
+ Logger.defaultLogError(e);
+ }
+ }
+
+ writeSupport.claimValue(provider, resource, data);
+
+ } catch (DatabaseException e) {
+ throw new ServiceException(e);
+ } catch (SerializationException e) {
+ throw new ServiceException(e);
+ } catch (IOException e) {
+ throw new ServiceException(e);
+ }
+
+ }
+
+ THashMap<Class<?>, Resource> builtinValues = new THashMap<Class<?>, Resource>(32);
+
+ private void initBuiltinValues(Layer0 b) {
+
+ if(!builtinValues.isEmpty()) return;
+
+ builtinValues.put(String.class, b.String);
+ builtinValues.put(Double.class, b.Double);
+ builtinValues.put(Float.class, b.Float);
+ builtinValues.put(Long.class, b.Long);
+ builtinValues.put(Integer.class, b.Integer);
+ builtinValues.put(Byte.class, b.Byte);
+ builtinValues.put(Boolean.class, b.Boolean);
+ builtinValues.put(Variant.class, b.Variant);
+
+ builtinValues.put(String[].class, b.StringArray);
+ builtinValues.put(double[].class, b.DoubleArray);
+ builtinValues.put(float[].class, b.FloatArray);
+ builtinValues.put(long[].class, b.LongArray);
+ builtinValues.put(int[].class, b.IntegerArray);
+ builtinValues.put(byte[].class, b.ByteArray);
+ builtinValues.put(boolean[].class, b.BooleanArray);
+
+ builtinValues.put(MutableString.class, b.String);
+ builtinValues.put(MutableDouble.class, b.Double);
+ builtinValues.put(MutableFloat.class, b.Float);
+ builtinValues.put(MutableLong.class, b.Long);
+ builtinValues.put(MutableInteger.class, b.Integer);
+ builtinValues.put(MutableByte.class, b.Byte);
+ builtinValues.put(MutableBoolean.class, b.Boolean);
+
+ }
+
+ @Override
+ public void addLiteral(Resource resource, Resource predicate, Resource inverse, Resource type, Object value, Binding binding) throws ManyObjectsForFunctionalRelationException, ServiceException {
+
+ Layer0 b = getBuiltins();
+ Resource valueResource = newResource();
+ claim(valueResource, b.InstanceOf, null, type);
+ claim(resource, predicate, inverse, valueResource);
+ claimValue(valueResource, value, binding);
+
+ }
+
+ @Override
+ public void addLiteral(Resource resource, Resource predicate, Resource inverse, Object value, Binding binding) throws ManyObjectsForFunctionalRelationException, ServiceException {
+
+ Layer0 b = getBuiltins();
+ initBuiltinValues(b);
+ Resource literal = newResource();
+
+ Class<?> clazz = value.getClass();
+ Resource type = builtinValues.get(clazz);
+ if (type == null) {
+ type = b.Literal;
+ Resource dataType = newResource();
+ claim(dataType, b.InstanceOf, null, b.DataType);
+ claimValue(dataType, binding.type(), DATA_TYPE_BINDING);
+ claim(literal, b.HasDataType, b.HasDataType_Inverse, dataType);
+ }
+
+ claim(literal, b.InstanceOf, null, type);
+ claim(resource, predicate, inverse, literal);
+ claimValue(literal, value, binding);
+
+ }
+
+ @Override
+ public <T extends Accessor> T newLiteral(Resource resource, Resource predicate, Datatype datatype, Object initialValue)
+ throws DatabaseException {
+ Layer0 b = getBuiltins();
+ initBuiltinValues(b);
+ Resource literal = newResource();
+ claim(literal, b.InstanceOf, null, b.Literal);
+ Resource dataType = newResource();
+ claim(dataType, b.InstanceOf, null, b.DataType);
+ claimValue(dataType, datatype, DATA_TYPE_BINDING);
+ claim(literal, b.HasDataType, dataType);
+ claim(resource, predicate, literal);
+ return createAccessor(literal, datatype, initialValue);
+ }
+ @Override
+ public RandomAccessBinary createRandomAccessBinary
+ (Resource resource, Resource predicate, Datatype datatype, Object initiaValue)
+ throws DatabaseException {
+ Layer0 b = getBuiltins();
+ initBuiltinValues(b);
+ Resource literal = newResource();
+ claim(literal, b.InstanceOf, null, b.Literal);
+ Resource dataType = newResource();
+ claim(dataType, b.InstanceOf, null, b.DataType);
+ claimValue(dataType, datatype, DATA_TYPE_BINDING);
+ claim(literal, b.HasDataType, dataType);
+ claim(resource, predicate, literal);
+ return createRandomAccessBinary(literal, datatype, initiaValue);
+ }
+ @Override
+ public void claimLiteral(Resource resource, Resource predicate, Object value) throws ManyObjectsForFunctionalRelationException, ServiceException {
+
+ try {
+ Binding binding = Bindings.getBinding(value.getClass());
+ claimLiteral(resource, predicate, value, binding);
+ } catch(BindingConstructionException e) {
+ throw new IllegalArgumentException(e);
+ }
+
+ }
+
+ @Override
+ public void claimLiteral(Resource resource, Resource predicate, Object value, Binding binding) throws ManyObjectsForFunctionalRelationException, ServiceException {
+
+ Layer0 b = getBuiltins();
+ initBuiltinValues(b);
+
+ Statement literalStatement = getPossibleStatement(resource, predicate);
+
+ if(literalStatement != null && resource.equals(literalStatement.getSubject())) {
+
+ claimValue(literalStatement.getObject(), value, binding);
+
+ } else {
+
+ Class<?> clazz = value.getClass();
+ Resource type = builtinValues.get(clazz);
+ Resource literal = newResource();
+ if (type == null) {
+ type = b.Literal;
+ Resource dataType = newResource();
+ claim(dataType, b.InstanceOf, null, b.DataType);
+ claimValue(dataType, binding.type(), DATA_TYPE_BINDING);
+ claim(literal, b.HasDataType, null, dataType);
+ }
+ claim(literal, b.InstanceOf, null, type);
+ claimValue(literal, value, binding);
+ claim(resource, predicate, literal);
+
+ }
+
+ if(Development.DEVELOPMENT) {
+ try {
+ getPossibleStatement(resource, predicate);
+ } catch (ManyObjectsForFunctionalRelationException e) {
+ System.err.println("err " + ((ResourceImpl)resource).id + " " + ((ResourceImpl)predicate).id);
+ getPossibleStatement(resource, predicate);
+ }
+ }
+
+ }
+
+ @Override
+ public void claimLiteral(Resource resource, Resource predicate, Resource type, Object value)
+ throws org.simantics.db.exception.BindingException, ManyObjectsForFunctionalRelationException, ServiceException {
+
+ try {
+ Binding binding = Bindings.getBinding(value.getClass());
+ claimLiteral(resource, predicate, type, value, binding);
+ } catch(BindingConstructionException e) {
+ throw new IllegalArgumentException(e);
+ }
+
+ }
+
+ @Override
+ public void claimLiteral(Resource resource, Resource predicate, Resource type, Object value, Binding binding)
+ throws org.simantics.db.exception.BindingException, ManyObjectsForFunctionalRelationException, ServiceException {
+
+ Layer0 b = getBuiltins();
+
+ Statement literalStatement = getPossibleStatement(resource, predicate);
+
+ if(literalStatement != null && resource.equals(literalStatement.getSubject())) {
+
+ claimValue(literalStatement.getObject(), value, binding);
+
+ } else {
+
+ Resource literal = newResource();
+ claim(literal, b.InstanceOf, null, type);
+ claimValue(literal, value, binding);
+ claim(resource, predicate, literal);
+
+ }
+
+ }
+
+ @Override
+ public void claimLiteral(Resource resource, Resource predicate, Resource inverse, Resource type, Object value)
+ throws org.simantics.db.exception.BindingException, ManyObjectsForFunctionalRelationException, ServiceException {
+
+ try {
+ Binding binding = Bindings.getBinding(value.getClass());
+ claimLiteral(resource, predicate, inverse, type, value, binding);
+ } catch(BindingConstructionException e) {
+ throw new IllegalArgumentException(e);
+ }
+
+ }
+
+ @Override
+ public void claimLiteral(Resource resource, Resource predicate, Resource inverse, Resource type, Object value, Binding binding)
+ throws org.simantics.db.exception.BindingException, ManyObjectsForFunctionalRelationException, ServiceException {
+
+ Layer0 b = getBuiltins();
+
+ Statement literalStatement = getPossibleStatement(resource, predicate);
+
+ if(literalStatement != null && resource.equals(literalStatement.getSubject())) {
+
+ claimValue(literalStatement.getObject(), value, binding);
+
+ } else {
+
+ Resource literal = newResource();
+ claim(literal, b.InstanceOf, null, type);
+ claimValue(literal, value, binding);
+ claim(resource, predicate, inverse, literal);
+
+ }
+
+ }
+
+
+ @Override
+ public void denyValue(Resource resource) throws ServiceException {
+
+ denyValue0(resource, null);
+
+ }
+
+ @Override
+ public void denyValue(Resource resource, VirtualGraph valueProvider) throws ServiceException {
+
+ denyValue0(resource, valueProvider);
+
+ }
+
+ /**
+ * @param resource resource to remove value from
+ * @param valueProvider <code>null</code> means the caller doesn't know and
+ * this method must find out
+ * @throws ServiceException
+ */
+ private void denyValue0(Resource resource, VirtualGraph valueProvider) throws ServiceException {
+
+ if(Development.DEVELOPMENT) {
+ try {
+ if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG, Bindings.BOOLEAN)) {
+ Object oldValue = getPossibleValue(resource);
+ String valueText = oldValue == null ? "<no value>" : oldValue.toString();
+ String text = "denyValue(" + resourceName(resource) + ", " + valueText + ")";
+ if (oldValue != null) {
+ if(Development.<Boolean>getProperty(DevelopmentKeys.WRITEGRAPH_DEBUG_STACK, Bindings.BOOLEAN)) {
+ StringWriter writer = new StringWriter();
+ PrintWriter out = new PrintWriter(writer);
+ new Exception(text).printStackTrace(out);
+ Development.dispatchEvent(new DenyValueEventImpl(this, provider, resource, oldValue, writer.toString()));
+ } else {
+ Development.dispatchEvent(new DenyValueEventImpl(this, provider, resource, oldValue, text));
+ }
+ }
+ }
+ } catch (DatabaseException e) {
+ Logger.defaultLogError(e);
+ }
+ }
+
+ if (provider != null) {
+
+ // Can only remove from the specified VirtualGraph
+ if (resource.isPersistent())
+ throw new ArgumentException("Tried to remove literal value from persistent resource " + resource
+ + " using virtual graph '" + provider.getIdentifier() + "'");
+ writeSupport.denyValue(provider, resource);
+
+ } else {
+
+ // Can remove from any provider
+ if (resource.isPersistent()) {
+ // A persistent resource cannot have a virtual literal
+ // so this should be safe.
+ writeSupport.denyValue(provider, resource);
+ } else {
+ // A virtual resource cannot have a persistent literal.
+ // Must look for a virtual graph for resource.
+ Layer0 L0 = getBuiltins();
+ if (valueProvider == null) {
+ if (hasStatement(resource, L0.InstanceOf)) {
+ valueProvider = processor.getProvider(resource, L0.InstanceOf);
+ } else if (hasStatement(resource, L0.Inherits)) {
+ valueProvider = processor.getProvider(resource, L0.Inherits);
+ } else if (hasStatement(resource, L0.SubrelationOf)) {
+ valueProvider = processor.getProvider(resource, L0.SubrelationOf);
+ }
+ }
+ if (valueProvider != null)
+ writeSupport.denyValue(valueProvider, resource);
+ }
+
+ }
+
+ }
+
+ @Override
+ public void denyValue(Resource resource, Resource predicate) throws ManyObjectsForFunctionalRelationException, ServiceException {
+
+ Statement valueStatement = getPossibleStatement(resource, predicate);
+
+ if (valueStatement != null && !valueStatement.isAsserted(resource)) {
+
+ Resource value = valueStatement.getObject();
+ Resource inverse = getPossibleInverse(predicate);
+
+ if (provider != null) {
+
+ // Can only remove from the specified provider
+ deny(resource, predicate, inverse, value, provider);
+ writeSupport.denyValue(provider, value);
+
+ } else {
+
+ // Can remove from any provider
+ VirtualGraph statementProvider = processor.getProvider(resource, valueStatement.getPredicate(), value);
+ deny(resource, predicate, inverse, value, statementProvider);
+ denyValue0(resource, statementProvider);
+
+ }
+
+ }
+
+ }
+
+ @Override
+ public void flushCluster() {
+
+ writeSupport.flushCluster();
+
+ }
+
+ @Override
+ public void flushCluster(Resource r) {
+ writeSupport.flushCluster(r);
+ }
+
+ Object serialize(Object value) {
+
+ Class<?> clazz = value.getClass();
+
+ if(clazz.isArray()) return value;
+
+ if(Double.class == clazz) return new double[] { (Double)value };
+ else if(String.class == clazz) return new String[] { (String)value };
+ else if(Integer.class == clazz) return new int[] { (Integer)value };
+ else if(Boolean.class == clazz) return new boolean[] { (Boolean)value };
+ else if(Long.class == clazz) return new long[] { (Long)value };
+ else if(Byte.class == clazz) return new byte[] { (Byte)value };
+ else if(Float.class == clazz) return new float[] { (Float)value };
+ else return value;
+
+ }
+
+ @Override
+ public <T> void addMetadata(Metadata data) throws ServiceException {
+ writeSupport.addMetadata(data);
+ }
+
+ @Override
+ public <T extends Metadata> T getMetadata(Class<T> clazz) throws ServiceException {
+ return writeSupport.getMetadata(clazz);
+ }
+
+ @Override
+ public TreeMap<String, byte[]> getMetadata() {
+ return writeSupport.getMetadata();
+ }
+
+ @Override
+ public String toString() {
+ return "WriteGraphImpl[thread=" + Thread.currentThread() + "]";
+ }
+
+ public void commitAccessorChanges(WriteTraits writeTraits) {
+ try {
+ RandomAccessValueSupport ravs = getSession().peekService(RandomAccessValueSupport.class);
+ if (ravs == null)
+ return;
+
+ for(Pair<Resource, ResourceData> entry : ravs.entries()) {
+ ResourceData rd = entry.second;
+ if(!rd.isChanged()) continue;
+ Resource resource = entry.first;
+ try {
+ ExternalValueSupport evs = getService(ExternalValueSupport.class);
+ long vsize = rd.oldExternalValue ? evs.getValueSize(this, resource) : -1;
+ long bsize = rd.binaryFile.length();
+ final int N = 1<<20;
+ final int LIMIT = 10 * 1000 * 1000;
+ long left = bsize;
+ long offset = 0;
+ byte[] bytes = new byte[N];
+ rd.binaryFile.reset();
+ rd.binaryFile.position(0);
+ int count = 0;
+// if (LIMIT < left)
+// evs.moveValue(this, resource);
+ while (left > 0) {
+ int length = N < left ? N : (int)left;
+ rd.binaryFile.readFully(bytes, 0, length);
+ evs.writeValue(this, resource, offset, length, bytes);
+ offset += length;
+ left -= length;
+ count += length;
+ if (count > LIMIT) {
+ count = 0;
+// evs.commitAndContinue(this, writeTraits, resource);
+// evs.moveValue(this, resource);
+ // This is needed so we don't create too many requests and run out of heap.
+ evs.wait4RequestsLess(1);
+ }
+ }
+ if (bsize < vsize) // truncate
+ evs.writeValue(this, resource, bsize, 0, new byte[0]);
+ } catch (DatabaseException e) {
+ Logger.defaultLogError(e);
+ }
+ }
+ } catch(IOException e) {
+ Logger.defaultLogError(e);
+ } catch (RuntimeException e) {
+ Logger.defaultLogError(e);
+ }
+ }
+
+ @Override
+ public VirtualGraph getProvider() {
+ return provider;
+ }
+
+ @Override
+ public void clearUndoList(WriteTraits writeTraits) {
+ writeSupport.clearUndoList(writeTraits);
+ }
+
+ public void markUndoPoint() {
+ writeSupport.startUndo();
+ }
+
+}