package org.simantics.db.layer0.variable; import java.text.Format; import org.simantics.databoard.Bindings; import org.simantics.databoard.Datatypes; import org.simantics.databoard.accessor.reference.ChildReference; import org.simantics.databoard.accessor.reference.IndexReference; import org.simantics.databoard.adapter.AdaptException; import org.simantics.databoard.binding.ArrayBinding; import org.simantics.databoard.binding.Binding; import org.simantics.databoard.binding.error.BindingException; import org.simantics.databoard.binding.mutable.Variant; import org.simantics.databoard.binding.reflection.GenericArrayBinding; import org.simantics.databoard.type.ArrayType; 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.exception.DatabaseException; import org.simantics.db.exception.RuntimeDatabaseException; import org.simantics.db.layer0.variable.RVI.RVIPart; import org.simantics.db.layer0.variable.RVI.StringRVIPart; import org.simantics.db.layer0.variable.Variables.Role; import org.simantics.operation.Layer0X; public class SubliteralPropertyVariableDeprecated extends AbstractPropertyVariable { private final Variable parent; private final ChildReference reference; public SubliteralPropertyVariableDeprecated(Variable parent, ChildReference reference) { this.parent = parent; this.reference = reference; } @Override public Variable getPredicate(ReadGraph graph) throws DatabaseException { return parent.getPredicate(graph); } @Override public Resource getPropertyResource(ReadGraph graph) throws DatabaseException { if (parent instanceof AbstractPropertyVariable) { return ((AbstractPropertyVariable) parent).getPropertyResource(graph); } throw new RuntimeDatabaseException("not supported for parent " + parent); } @Override public Resource getContainerResource(ReadGraph graph) throws DatabaseException { if (parent instanceof AbstractPropertyVariable) { return ((AbstractPropertyVariable) parent).getContainerResource(graph); } throw new RuntimeDatabaseException("not supported for parent " + parent); } static class DisplayPropertyVariable extends ValueProxyVariable { private String suffix; public DisplayPropertyVariable(Variable proxy, Variable parent, String suffix) { super(proxy, parent); assert suffix != null; this.suffix = suffix; } public boolean equals(Object obj) { if (this == obj) return true; if (!(obj instanceof DisplayPropertyVariable)) return false; DisplayPropertyVariable other = (DisplayPropertyVariable) obj; return proxy.equals(other.proxy) && suffix.equals(suffix); } @Override public int hashCode() { return proxy.hashCode() * 31 + suffix.hashCode(); } @Override public String getURI(ReadGraph graph) throws DatabaseException { return parent.getURI(graph) + Role.PROPERTY.getIdentifier() + getName(graph); } @Override public String getName(ReadGraph graph) throws DatabaseException { return Variables.DISPLAY_PROPERTY; } @Override public Datatype getDatatype(ReadGraph graph) throws DatabaseException { return Datatypes.STRING; } @Override public RVI getRVI(ReadGraph graph) throws DatabaseException { return new RVIBuilder(parent.getRVI(graph)) .append(new StringRVIPart(Role.PROPERTY, getName(graph))) .toRVI(); } @Override public T getPossibleValue(ReadGraph graph) throws DatabaseException { return getPossibleValue(graph, Bindings.STRING); } @SuppressWarnings("unchecked") @Override public T getPossibleValue(ReadGraph graph, Binding binding) throws DatabaseException { String str = proxy.getPossiblePropertyValue(graph, Variables.DISPLAY_PROPERTY, Bindings.STRING); return (T) (str != null ? str + " " + suffix : null); } @Override public T getValue(ReadGraph graph) throws DatabaseException { return getValue(graph, Bindings.STRING); } @SuppressWarnings("unchecked") @Override public T getValue(ReadGraph graph, Binding binding) throws DatabaseException { return (T) (proxy.getPropertyValue(graph, Variables.DISPLAY_PROPERTY, binding) + " " + suffix); } public Variant getVariantValue(ReadGraph graph) throws DatabaseException { return new Variant(Bindings.STRING, getValue(graph, Bindings.STRING)); } } static class DisplayUnitVariable extends ValueProxyVariable { public DisplayUnitVariable(Variable proxy, Variable parent) { super(proxy, parent); } public boolean equals(Object obj) { if (this == obj) return true; if (!(obj instanceof DisplayUnitVariable)) return false; DisplayUnitVariable other = (DisplayUnitVariable) obj; return proxy.equals(other.proxy); } @Override public int hashCode() { return proxy.hashCode() * 53; } @Override public String getURI(ReadGraph graph) throws DatabaseException { return parent.getURI(graph) + Role.PROPERTY.getIdentifier() + getName(graph); } @Override public String getName(ReadGraph graph) throws DatabaseException { return Variables.DISPLAY_UNIT; } @Override public Datatype getDatatype(ReadGraph graph) throws DatabaseException { return Datatypes.STRING; } @Override public RVI getRVI(ReadGraph graph) throws DatabaseException { return new RVIBuilder(parent.getRVI(graph)) .append(new StringRVIPart(Role.PROPERTY, getName(graph))) .toRVI(); } @Override public T getPossibleValue(ReadGraph graph) throws DatabaseException { return getPossibleValue(graph, Bindings.STRING); } @Override public T getPossibleValue(ReadGraph graph, Binding binding) throws DatabaseException { return proxy.getPossiblePropertyValue(graph, Variables.DISPLAY_UNIT, Bindings.STRING); } @Override public T getValue(ReadGraph graph) throws DatabaseException { return getValue(graph, Bindings.STRING); } @Override public T getValue(ReadGraph graph, Binding binding) throws DatabaseException { return proxy.getPropertyValue(graph, Variables.DISPLAY_UNIT, binding); } public Variant getVariantValue(ReadGraph graph) throws DatabaseException { return new Variant(Bindings.STRING, getValue(graph, Bindings.STRING)); } } protected String getReferenceString(ReadGraph graph) throws DatabaseException { Layer0X L0X = Layer0X.getInstance(graph); Format formatter = parent.getPossiblePropertyValue(graph, L0X.HasChildReferenceFormatter); if (formatter != null) { try { String format = formatter.format(reference); if (format != null) return format; } catch (IllegalArgumentException e) { // Ignore it this, use default formatting. } } if (reference instanceof IndexReference) { // Fallback logic [i] where 0 <= i <= N-1, N = sizeof(array) IndexReference index = (IndexReference) reference; return "[" + index.getIndex() + "]"; } return reference.toString(); } public Variable getPossibleExtraProperty(ReadGraph graph, String name) throws DatabaseException { if (Variables.DISPLAY_PROPERTY.equals(name)) { return new DisplayPropertyVariable(parent, this, getReferenceString(graph)); } else if (Variables.DISPLAY_UNIT.equals(name)) { return new DisplayUnitVariable(parent, this); } /*else if (Variables.DATATYPE.equals(name)) { Object value = getPossibleDatatype(graph); if (value != null) return new ConstantPropertyVariable(this, name, value, datatype_binding); } else if (Variables.UNIT.equals(name)) { Object value = parent.getPossiblePropertyValue(graph, name); if (value != null) return new ConstantPropertyVariable(this, name, value, Bindings.STRING); } else if (Variables.PREDICATE.equals(name)) { Object value = getPossiblePredicate(graph); if (value != null) return new ConstantPropertyVariable(this, name, value, null); } */ return null; } @Override public Datatype getDatatype(ReadGraph graph) throws DatabaseException { Datatype parentType = parent.getDatatype(graph); if(parentType instanceof ArrayType) { ArrayType at = (ArrayType)parentType; return at.getComponentType(0); } return null; } @SuppressWarnings("unchecked") @Override public T getValue(ReadGraph graph) throws DatabaseException { Object parentValue = parent.getValue(graph); Datatype parentType = parent.getDatatype(graph); Binding parentBinding = Bindings.getBinding(parentType); if (parentType instanceof ArrayType) { ArrayBinding ab = (ArrayBinding)parentBinding; IndexReference ref = (IndexReference)reference; try { return (T)ab.get(parentValue, ref.index); } catch (IndexOutOfBoundsException e) { throw new RuntimeDatabaseException(e); } catch (BindingException e) { throw new RuntimeDatabaseException(e); } } throw new RuntimeDatabaseException("parent variable data type " + parentType + " is not an ArrayType"); } @SuppressWarnings("unchecked") @Override public T getValue(ReadGraph graph, Binding binding) throws DatabaseException { Object parentValue = parent.getValue(graph); Datatype parentType = parent.getDatatype(graph); Binding parentBinding = Bindings.getBinding(parentType); if (parentType instanceof ArrayType) { ArrayBinding ab = (ArrayBinding)parentBinding; IndexReference ref = (IndexReference)reference; try { Object indexValue = ab.get(parentValue, ref.index); return (T) Bindings.adapt(indexValue, ab.getComponentBinding(), binding); } catch (IndexOutOfBoundsException e) { throw new RuntimeDatabaseException(e); } catch (BindingException e) { throw new RuntimeDatabaseException(e); } catch (AdaptException e) { throw new RuntimeDatabaseException(e); } } throw new RuntimeDatabaseException("parent variable data type " + parentType + " is not an ArrayType"); } @Override public void setValue(WriteGraph graph, Object value, Binding binding) throws DatabaseException { Object parentValue = parent.getValue(graph); Datatype parentType = parent.getDatatype(graph); if(parentType instanceof ArrayType) { Binding parentBinding = Bindings.getBinding(parentType); ArrayBinding ab = (ArrayBinding)parentBinding; IndexReference ref = (IndexReference)reference; try { Object indexValue = adaptValueForArray(parentValue, value, binding, ab.getComponentBinding()); if (indexValue == value) { // Adaption was passthrough, trust specified binding and // create a generic array binding out of it. ab = resolveArrayBinding(parentValue.getClass(), binding); } ab.set(parentValue, ref.index, indexValue); parent.setValue(graph, parentValue, ab); } catch (IndexOutOfBoundsException e) { throw new RuntimeDatabaseException(e); } catch (BindingException e) { throw new RuntimeDatabaseException(e); } catch (AdaptException e) { throw new RuntimeDatabaseException(e); } } } private ArrayBinding resolveArrayBinding(Class arrayClass, Binding binding) { Class componentClass = arrayClass.getComponentType(); if (componentClass.isPrimitive()) { if (componentClass == boolean.class) return Bindings.BOOLEAN_ARRAY; if (componentClass == byte.class) return Bindings.BYTE_ARRAY; if (componentClass == int.class) return Bindings.INT_ARRAY; if (componentClass == long.class) return Bindings.LONG_ARRAY; if (componentClass == float.class) return Bindings.FLOAT_ARRAY; if (componentClass == double.class) return Bindings.DOUBLE_ARRAY; } if (componentClass.equals(String.class)) return Bindings.STRING_ARRAY; return new GenericArrayBinding(arrayClass, new ArrayType(binding.type()), binding); } private Object adaptValueForArray(Object array, Object indexValue, Binding from, Binding to) throws AdaptException { Class arrayType = array.getClass(); if (!arrayType.isArray()) throw new AdaptException("array " + array + " is not of an array class"); Class arrayComponentType = arrayType.getComponentType(); if (arrayComponentType.isAssignableFrom(indexValue.getClass())) { // Type match, be happy. return indexValue; } // Only adapt if necessary. return Bindings.adapt(indexValue, from, to); } @Override public String getName(ReadGraph graph) throws DatabaseException { return reference.toString(false); } // @Override // public Object getSerialized(ReadGraph graph) throws DatabaseException { // return reference.toString(false); // } @Override public Variable getParent(ReadGraph graph) throws DatabaseException { return parent; } @Override public Role getRole(ReadGraph graph) throws DatabaseException { return Role.CHILD; } @Override public RVIPart getRVIPart(ReadGraph graph) throws DatabaseException { return new StringRVIPart(Role.CHILD, reference.toString(false)); } @Override public boolean equals(Object obj) { if (!super.equals(obj)) return false; if (!(obj instanceof SubliteralPropertyVariableDeprecated)) return false; SubliteralPropertyVariableDeprecated other = (SubliteralPropertyVariableDeprecated) obj; return reference.equals(other.reference); } @Override public int hashCode() { return super.hashCode() * 31 + reference.hashCode(); } }