package org.simantics.db.layer0.variable; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; import org.simantics.databoard.Bindings; import org.simantics.databoard.accessor.reference.ChildReference; import org.simantics.databoard.binding.Binding; import org.simantics.databoard.binding.impl.ObjectVariantBinding; import org.simantics.databoard.type.Datatype; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.WriteGraph; import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener; import org.simantics.db.common.validation.L0Validations; import org.simantics.db.exception.DatabaseException; import org.simantics.db.exception.ValidationException; import org.simantics.db.layer0.exception.MissingVariableValueException; import org.simantics.db.layer0.exception.PendingVariableException; import org.simantics.db.layer0.exception.VariableException; import org.simantics.db.layer0.function.All; import org.simantics.db.layer0.request.PropertyInfo; import org.simantics.db.layer0.request.PropertyInfoRequest; import org.simantics.db.layer0.scl.SCLDatabaseException; import org.simantics.db.layer0.util.Layer0Utils; import org.simantics.layer0.Layer0; import org.simantics.utils.Development; import org.simantics.utils.datastructures.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class StandardGraphPropertyVariable extends AbstractPropertyVariable { private static final Logger LOGGER = LoggerFactory.getLogger(StandardGraphPropertyVariable.class); protected static final PropertyInfo NO_PROPERTY = new PropertyInfo(null, null, false, Collections. emptySet(), null, null, null, null, null, null, Collections.> emptyMap(), null, false); final public Variable parent; final public Resource parentResource; final public PropertyInfo property; final public Resource represents; transient private int hash = 0; public StandardGraphPropertyVariable(ReadGraph graph, Variable parent, VariableNode node, Resource property) throws DatabaseException { this(graph, parent, node, (Resource)parent.getPossibleRepresents(graph), getPropertyInfo(graph, property)); } public StandardGraphPropertyVariable(ReadGraph graph, Variable parent, VariableNode node, Resource parentResource, Resource property) throws DatabaseException { this(graph, parent, node, parentResource, getPropertyInfo(graph, property)); } public StandardGraphPropertyVariable(ReadGraph graph, Variable parent, Resource property) throws DatabaseException { this(graph, parent, null, (Resource)parent.getPossibleRepresents(graph), getPropertyInfo(graph, property)); } public StandardGraphPropertyVariable(ReadGraph graph, Variable parent, Resource parentResource, PropertyInfo property) throws DatabaseException { this(parent, null, parentResource, property, getPossibleRepresents(graph, parentResource, property.predicate)); } public StandardGraphPropertyVariable(ReadGraph graph, Variable parent, VariableNode node, Resource parentResource, PropertyInfo property) throws DatabaseException { this(parent, node, parentResource, property, getPossibleRepresents(graph, parentResource, property.predicate)); } private static PropertyInfo getPropertyInfo(ReadGraph graph, Resource property) throws DatabaseException { return property != null ? graph.syncRequest(new PropertyInfoRequest(property), TransientCacheAsyncListener.instance()) : NO_PROPERTY; } private static Resource getPossibleRepresents(ReadGraph graph, Resource parentResource, Resource predicate) throws DatabaseException { if(parentResource == null || predicate == null) return null; return graph.getPossibleObject(parentResource, predicate); } public boolean isAsserted() { return false; } public StandardGraphPropertyVariable(Variable parent, VariableNode node, Resource parentResource, PropertyInfo property, Resource represents) throws DatabaseException { super(node); assert parent != null; this.parent = parent; this.property = property; this.parentResource = parentResource; this.represents = represents; } @Override public String getName(ReadGraph graph) throws DatabaseException { if(node != null) return node.support.manager.getName(node.node); return property.name; } @Override public String getPossibleLabel(ReadGraph graph) throws DatabaseException { return graph.getPossibleRelatedValue2(property.predicate, graph.getService(Layer0.class).HasLabel, parent, Bindings.STRING); } @Override public String getLabel(ReadGraph graph) throws DatabaseException { return graph.getRelatedValue2(property.predicate, graph.getService(Layer0.class).HasLabel, parent, Bindings.STRING); } @Override public Variable getParent(ReadGraph graph) throws DatabaseException { return parent; } @Override public PropertyInfo getPropertyInfo(ReadGraph graph) throws DatabaseException { return property; } @SuppressWarnings("unchecked") @Override public T getValue(ReadGraph graph) throws DatabaseException { if(Development.DEVELOPMENT) { String error = L0Validations.checkValueType(graph, parentResource, property.predicate); if(error != null) { LOGGER.error(error); //throw new ValidationException(error); } } return (T)getValueAccessor(graph).getValue(graph, this); } @SuppressWarnings("unchecked") @Override public T getValue(ReadGraph graph, Binding binding) throws DatabaseException { // Fall back to the bindingless method, if the expected output is a Java object if (binding instanceof ObjectVariantBinding) return getValue(graph); if(Development.DEVELOPMENT) { String error = L0Validations.checkValueType(graph, parentResource, property.predicate); if(error != null) { LOGGER.error(error); throw new ValidationException(error); } } try { return (T) getValueAccessor(graph).getValue(graph, this, binding); } catch (SCLDatabaseException e) { // these can be thrown when compiling e.g. derived properties throw e; } catch (MissingVariableValueException | PendingVariableException e) { throw e; } catch (Throwable t) { throw new MissingVariableValueException(t); } } @Override public Resource getRepresents(ReadGraph graph) throws DatabaseException { if(represents == null) throw new VariableException("Variable is not represented by any resource (URI=" + getPossibleURI(graph) + ")."); return represents; // return graph.getSingleObject(parentResource, property.predicate); } @Override public Resource getPossibleRepresents(ReadGraph graph) throws DatabaseException { // if(parentResource == null) return null; // return graph.getPossibleObject(parentResource, property.predicate); return represents; } @Override public void setValue(WriteGraph graph, Object value, Binding binding) throws DatabaseException { if(Development.DEVELOPMENT) { String error = L0Validations.checkValueType(graph, parentResource, property.predicate); if(error != null) { LOGGER.error(error); //throw new ValidationException(error); } } getValueAccessor(graph).setValue(graph, this, value, binding); } @Override public void setValue(WriteGraph graph, Object value) throws DatabaseException { if(Development.DEVELOPMENT) { String error = L0Validations.checkValueType(graph, parentResource, property.predicate); if(error != null) { LOGGER.error(error); throw new ValidationException(error); } } getValueAccessor(graph).setValue(graph, this, value); } @Override public Binding getDefaultBinding(ReadGraph graph) throws DatabaseException { return Layer0Utils.getDefaultBinding(graph, this); } @Override public Binding getPossibleDefaultBinding(ReadGraph graph) throws DatabaseException { return Layer0Utils.getPossibleDefaultBinding(graph, this); } @Override public Datatype getDatatype(ReadGraph graph) throws DatabaseException { //<<<<<<< .mine // // Binding binding = getPossibleDefaultBinding(graph); // if(binding != null) return binding.type(); // // Variant vt = getVariantValue(graph); // binding = vt.getBinding(); // if(binding == null) throw new DatabaseException("No binding in Variant with value " + vt.getValue()); // return binding.type(); //======= Datatype type; try { type = getValueAccessor(graph).getDatatype(graph, this); } catch (Throwable t) { throw new MissingVariableValueException(t); } if (type == null) { String uri = this.getPossibleURI(graph); if (uri != null) throw new DatabaseException("No data type for " + uri); else throw new DatabaseException("No data type for " + this.getIdentifier()); } return type; //>>>>>>> .r30794 } @Override public Datatype getPossibleDatatype(ReadGraph graph) throws DatabaseException { try { return getDatatype(graph); } catch (DatabaseException e) { return null; } } @Override public String getUnit(ReadGraph graph) throws DatabaseException { try { return Layer0Utils.getUnit(graph, this); } catch (DatabaseException e) { return null; } } @Override public Resource getPropertyResource(ReadGraph graph) { return property.predicate; } @Override public Resource getContainerResource(ReadGraph graph) throws DatabaseException { return parentResource; } @Override public Collection getChildren(ReadGraph graph) throws DatabaseException { Map result = new HashMap(); VariableMap map = getPossibleChildVariableMap(graph); if(map != null) map.getVariables(graph, this, result); return result.values(); } @Override public Variable getPossibleChild(ReadGraph graph, String name) throws DatabaseException { VariableMap map = getPossibleChildVariableMap(graph); if(map == null) return null; try { return map.getVariable(graph, this, name); } catch (DatabaseException e) { return null; } } @Override protected Variable getPossibleDomainProperty(ReadGraph graph, String name) throws DatabaseException { VariableMap valueMap = getPossiblePropertyVariableMap(graph); if(valueMap == null) return null; try { return valueMap.getVariable(graph, this, name); } catch (DatabaseException e) { return null; } catch (Exception t) { LOGGER.error("getPossibleDomainProperty is implemented incorrectly, but returns null on Exception for backward compatibility. URI="+getURI(graph)+", name="+name+".", t); return null; } } @Override public Map collectDomainProperties(ReadGraph graph, Map properties) throws DatabaseException { VariableMap valueMap = getPossiblePropertyVariableMap(graph); if(valueMap == null) return properties; return valueMap.getVariables(graph, this, properties); } @Override public Variable getPredicate(ReadGraph graph) throws DatabaseException { return Variables.getVariable(graph, graph.getURI(property.predicate)); } @Override public Resource getPredicateResource(ReadGraph graph) throws DatabaseException { return property.predicate; } @Override public Resource getPossiblePredicateResource(ReadGraph graph) throws DatabaseException { return property.predicate; } @Override public int hashCode() { if(hash == 0) { final int prime = 31; int result = 1; result = prime * result + (parent != null ? parent.hashCode() : 0); result = prime * result + (node != null ? node.hashCode() : 0); result = prime * result + (property.predicate != null ? property.predicate.hashCode() : 0); result = prime * result + (parentResource != null ? parentResource.hashCode() : 0); result = prime * result + (represents != null ? represents.hashCode() : 0); hash =result; } return hash; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; StandardGraphPropertyVariable other = (StandardGraphPropertyVariable) obj; if(node != null) { if(!node.equals(other.node)) return false; } else if (other.node != null) return false; if(property.predicate != null) { if(!property.predicate.equals(other.property.predicate)) return false; } else if (other.property.predicate != null) return false; if(parentResource != null) { if(!parentResource.equals(other.parentResource)) return false; } else if (other.parentResource != null) return false; if(parent != null) { if(!parent.equals(other.parent)) return false; } else if (other.parent != null) return false; if(represents != null) { if(!represents.equals(other.represents)) return false; } else if (other.represents != null) return false; return true; } @Override protected Variable getNameVariable(ReadGraph graph) throws DatabaseException { throw new UnsupportedOperationException(); } protected ValueAccessor getValueAccessor(ReadGraph graph) throws DatabaseException { if((property == null || property == NO_PROPERTY) && parentResource == null) return All.standardValueAccessor; ValueAccessor accessor = property.valueAccessor; if(accessor != null) return accessor; else { System.err.println("No value accessor for " + getURI(graph)); return All.standardValueAccessor; } } protected VariableMap getPossibleChildVariableMap(ReadGraph graph) throws DatabaseException { if(represents == null) return All.standardPropertyDomainChildren; Resource domainChildren = Layer0.getInstance(graph).domainChildren; return graph.getPossibleRelatedValue2(represents, domainChildren, new StandardGraphPropertyVariable(graph, this, domainChildren)); } protected VariableMap getPossiblePropertyVariableMap(ReadGraph graph) throws DatabaseException { if(property == null) return All.standardPropertyDomainProperties; if(property.predicate == null) return null; return graph.syncRequest(new PropertyVariableMapRequest(property.predicate), TransientCacheAsyncListener.instance()); } public Set getClassifications(ReadGraph graph) throws DatabaseException { return property.classifications; } @Override public Map collectDomainProperties(ReadGraph graph, String classification, Map properties) throws DatabaseException { VariableMap valueMap = getPossiblePropertyVariableMap(graph); if(valueMap == null) return properties; return valueMap.getVariables(graph, this, classification, properties); } public Collection getProperties(ReadGraph graph, String classification) throws DatabaseException { VariableMap valueMap = getPossiblePropertyVariableMap(graph); if(valueMap == null) return Collections.emptyList(); Map propertyMap = valueMap.getVariables(graph, this, classification, null); if(propertyMap == null || propertyMap.isEmpty()) return Collections.emptyList(); else return propertyMap.values(); } }