-/*******************************************************************************\r
- * Copyright (c) 2010 Association for Decentralized Information Management in\r
- * 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
+/*******************************************************************************
+ * Copyright (c) 2010 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.databoard.type;
-import java.util.HashSet;\r
-import java.util.List;\r
-import java.util.Set;\r
-import java.util.StringTokenizer;\r
-\r
-import org.simantics.databoard.accessor.error.ReferenceException;\r
-import org.simantics.databoard.accessor.reference.ChildReference;\r
-import org.simantics.databoard.accessor.reference.IndexReference;\r
-import org.simantics.databoard.accessor.reference.LabelReference;\r
-import org.simantics.databoard.accessor.reference.NameReference;\r
-import org.simantics.databoard.annotations.Referable;\r
-import org.simantics.databoard.binding.error.DatatypeConstructionException;\r
-import org.simantics.databoard.util.IdentityPair;\r
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import org.simantics.databoard.accessor.error.ReferenceException;
+import org.simantics.databoard.accessor.reference.ChildReference;
+import org.simantics.databoard.accessor.reference.IndexReference;
+import org.simantics.databoard.accessor.reference.LabelReference;
+import org.simantics.databoard.accessor.reference.NameReference;
+import org.simantics.databoard.annotations.Referable;
+import org.simantics.databoard.binding.error.DatatypeConstructionException;
+import org.simantics.databoard.util.IdentityPair;
public @Referable class RecordType extends Datatype {
- \r
- public static final Datatype VOID_TYPE = new RecordType(false);\r
- \r
- public static final String KEY_REFERABLE = "referable"; // "false"/"true"\r
- \r
- // Key to identifier(s) index\r
- public static final String KEY_IDENTIFIER = "identifier"; // "0" "0,1" "n[,m]"\r
- \r
- public static final Component[] NO_COMPONENTS = new Component[0];\r
- Component[] components = NO_COMPONENTS;\r
- \r
- /** Indices to identifiers of this record. This field is filled on request */\r
- private transient int[] identifiersIndices;\r
- \r
- /** Identifier type */\r
+ public static final Datatype VOID_TYPE = new RecordType(false);
+
+ public static final String KEY_REFERABLE = "referable"; // "false"/"true"
+
+ // Key to identifier(s) index
+ public static final String KEY_IDENTIFIER = "identifier"; // "0" "0,1" "n[,m]"
+
+ public static final Component[] NO_COMPONENTS = new Component[0];
+
+ Component[] components = NO_COMPONENTS;
+
+ /** Indices to identifiers of this record. This field is filled on request */
+ private transient int[] identifiersIndices;
+
+ /** Identifier type */
private transient Datatype identifierType;
public RecordType() {
- setReferable(false);\r
+ setReferable(false);
}
public RecordType(boolean referable, Component...components) {
- this.components = components;\r
- setReferable(referable);\r
+ this.components = components;
+ setReferable(referable);
}
- public boolean isReferable() {\r
+ public boolean isReferable() {
String str = metadata.get( KEY_REFERABLE );
return str!=null && str.equals( Boolean.TRUE.toString() );
- }\r
- \r
- public void setReferable( boolean referable ) {\r
- if ( !referable ) \r
- {\r
- metadata.remove(KEY_REFERABLE); \r
- } else {\r
- metadata.put(KEY_REFERABLE, Boolean.toString(referable));\r
- }\r
+ }
+
+ public void setReferable( boolean referable ) {
+ if ( !referable )
+ {
+ metadata.remove(KEY_REFERABLE);
+ } else {
+ metadata.put(KEY_REFERABLE, Boolean.toString(referable));
+ }
}
@Override
public void setComponents(Component[] components) {
this.components = components;
}
- \r
- public void mergeRecord(RecordType src)\r
- throws DatatypeConstructionException\r
- {\r
- int ci = src.getComponentCount();\r
- for (int i=0; i<ci; i++) {\r
- Component sc = src.components[ i ];\r
- \r
- int li = getComponentIndex2( sc.name );\r
- if ( li<0 ) {\r
- addComponent(sc.name, sc.type);\r
- } else {\r
- Component lc = components[ li ];\r
- if ( sc.type instanceof RecordType && lc.type instanceof RecordType ) {\r
- ((RecordType)lc.type).mergeRecord( (RecordType) sc.type );\r
- } else if ( sc.type.equals( lc.type ) ) {} \r
- else {\r
- throw new DatatypeConstructionException("Cannot merge field \""+sc.name+"\" "+sc.type.getClass().getName()+" and "+lc.getClass().getName());\r
- }\r
- }\r
- \r
- }\r
- }\r
- \r
+
+ public void mergeRecord(RecordType src)
+ throws DatatypeConstructionException
+ {
+ int ci = src.getComponentCount();
+ for (int i=0; i<ci; i++) {
+ Component sc = src.components[ i ];
+
+ int li = getComponentIndex2( sc.name );
+ if ( li<0 ) {
+ addComponent(sc.name, sc.type);
+ } else {
+ Component lc = components[ li ];
+ if ( sc.type instanceof RecordType && lc.type instanceof RecordType ) {
+ ((RecordType)lc.type).mergeRecord( (RecordType) sc.type );
+ } else if ( sc.type.equals( lc.type ) ) {}
+ else {
+ throw new DatatypeConstructionException("Cannot merge field \""+sc.name+"\" "+sc.type.getClass().getName()+" and "+lc.getClass().getName());
+ }
+ }
+
+ }
+ }
+
public void addComponent(String name, Datatype type)
{
Component c = new Component(name, type);
newComponents[ components.length ] = c;
components = newComponents;
}
- }\r
- \r
- public void clear() {\r
- components = new Component[0];\r
- metadata.clear();\r
- }\r
- \r
- public void removeComponent(String name) {\r
- int index = getComponentIndex2(name);\r
- if (index<0) throw new IllegalArgumentException();\r
- Component[] newComponents = new Component[ components.length -1 ];\r
- if (index>0) System.arraycopy(components, 0, newComponents, 0, index);\r
- if (index<newComponents.length) System.arraycopy(components, index+1, newComponents, index, newComponents.length - index);\r
- components = newComponents; \r
- // xxx untested\r
}
- \r
- @Override\r
- public int getComponentCount() {\r
- return components.length;\r
- }\r
- \r
+
+ public void clear() {
+ components = new Component[0];
+ metadata.clear();
+ }
+
+ public void removeComponent(String name) {
+ int index = getComponentIndex2(name);
+ if (index<0) throw new IllegalArgumentException();
+ Component[] newComponents = new Component[ components.length -1 ];
+ if (index>0) System.arraycopy(components, 0, newComponents, 0, index);
+ if (index<newComponents.length) System.arraycopy(components, index+1, newComponents, index, newComponents.length - index);
+ components = newComponents;
+ // xxx untested
+ }
+
+ @Override
+ public int getComponentCount() {
+ return components.length;
+ }
+
@Override
protected boolean deepEquals(Object obj, Set<IdentityPair<Datatype, Datatype>> compareHistory) {
- if ( this==obj ) return true;\r
- if ( !hasEqualMetadata(obj) ) return false;\r
+ if ( this==obj ) return true;
+ if ( !hasEqualMetadata(obj) ) return false;
if (obj instanceof RecordType == false) return false;
RecordType other = (RecordType) obj;
for (Component c : components)
hash = hash*13 + 7 * c.name.hashCode() /*+ 3*c.type.hashCode()*/;
return hash;
- } \r
+ }
@Override
public void accept(Visitor1 v, Object obj) {
if (!getComponent(i).name.equals(Integer.toString(i))) return false;
}
return true;
- }\r
-\r
- /**\r
- * Get component type by index\r
- * @param index index\r
- * @return componenet type or <tt>null</tt> if index was invalid\r
- */\r
- @Override\r
- public Datatype getComponentType(int index) {\r
- if (index<0||index>=components.length) return null;\r
- return components[index].type;\r
- }\r
- \r
- @Override\r
- public Datatype getComponentType(ChildReference path) throws IllegalArgumentException {\r
- if (path==null) return this;\r
- if (path instanceof IndexReference) {\r
- IndexReference ir = (IndexReference) path;\r
- return components[ir.index].type.getComponentType(path.childReference);\r
- }\r
- if (path instanceof NameReference) {\r
- NameReference nr = (NameReference) path;\r
- return getComponent( nr.name ).type.getComponentType(path.childReference);\r
- }\r
- if (path instanceof LabelReference) {\r
- LabelReference lr = (LabelReference) path; \r
- try {\r
- Integer i = new Integer(lr.label);\r
- return getComponent( i ).type.getComponentType(path.childReference);\r
- } catch (NumberFormatException nfe) {\r
- return getComponent( lr.label ).type.getComponentType(path.childReference);\r
- }\r
- }\r
- throw new IllegalArgumentException();\r
- }\r
- \r
- public boolean hasComponent(String fieldName) {\r
- for (int i=0; i<components.length; i++)\r
- if (components[i].name.equals(fieldName)) return true;\r
- return false;\r
- }\r
- \r
- /**\r
- * Get component by name.\r
- * \r
- * @param fieldName component name\r
- * @return component index or <code>null</code> if one does not exist\r
- */\r
- public Integer getComponentIndex(String fieldName) {\r
- for (int i=0; i<components.length; i++)\r
- if (components[i].name.equals(fieldName)) return i;\r
- return null;\r
- }\r
-\r
- /**\r
- * Get component by name.\r
- * \r
- * @param fieldName component name\r
- * @return component index or -1 if one does not exist\r
- */\r
- public int getComponentIndex2(String fieldName) {\r
- for (int i=0; i<components.length; i++)\r
- if (components[i].name.equals(fieldName)) return i;\r
- return -1;\r
- }\r
- \r
- /**\r
- * Get component Datatype by field name\r
- * @param fieldName\r
- * @return datatype or <code>null</code>\r
- */\r
- public Datatype getComponentType(String fieldName) {\r
- int index = getComponentIndex2(fieldName);\r
- if (index<0) return null;\r
- return components[index].type;\r
- }\r
- \r
- /**\r
- * Get component by name.\r
- * \r
- * @param fieldName component name\r
- * @return component or <code>null</code> if one does not exist\r
- */\r
- public Component getComponent(String fieldName) {\r
- for (Component c : components)\r
- if (c.name.equals(fieldName)) return c;\r
- return null;\r
- }\r
-\r
- /**\r
- * Get component by index.\r
- * \r
- * @param index component index\r
- * @return component or <code>null</code> if one does not exist\r
- */\r
- public Component getComponent(int index) {\r
- if (index<0||index>=components.length) return null;\r
- return components[index];\r
- }\r
- \r
- public Component[] getComponents() {\r
- return components;\r
- }\r
-\r
- /**\r
- * Get an array of indices that describe which fields compose the identifier \r
- * of this record \r
- * \r
- * @return indices\r
- */\r
- public int[] getIdentifiers() {\r
- String ids = metadata.get( KEY_IDENTIFIER );\r
- if (ids == null) {\r
- identifiersIndices = new int[0];\r
- } else {\r
- // Parse\r
- StringTokenizer st = new StringTokenizer(ids, ",");\r
- \r
- int[] indices = new int[ st.countTokens() ];\r
- for (int i=0; i<indices.length; i++) {\r
- String token = st.nextToken();\r
- try {\r
- indices[i] = Integer.valueOf(token);\r
- } catch ( NumberFormatException nfe ) {\r
- indices[i] = -1;\r
- }\r
- }\r
- identifiersIndices = indices;\r
- }\r
- return identifiersIndices;\r
- }\r
- \r
- /**\r
- * Set which fields compose the identifier of this record \r
- * \r
- * @param indices\r
- */\r
- public void setIdentifiers(int...indices)\r
- {\r
- if (indices.length==0) {\r
- metadata.remove( KEY_IDENTIFIER );\r
- return;\r
- }\r
- identifiersIndices = indices;\r
- StringBuilder sb = new StringBuilder();\r
- for (int i=0; i<indices.length; i++) {\r
- if (i>0) sb.append(',');\r
- sb.append( Integer.toString(indices[i]) );\r
- }\r
- \r
- String str = sb.toString();\r
- if ( str.isEmpty() ) {\r
- metadata.remove( KEY_IDENTIFIER ); \r
- } else {\r
- metadata.put( KEY_IDENTIFIER, str );\r
- }\r
- }\r
-\r
- /**\r
- * Set which fields compose the identifier of this record\r
- * @param indices\r
- */\r
- public void setIdentifiers(List<Integer> indices)\r
- {\r
- int[] indices2 = new int[indices.size()];\r
- for (int i=0; i<indices.size(); i++) indices2[i] = indices.get(i);\r
- setIdentifiers(indices2);\r
- }\r
- \r
- public boolean isIdentifier( int fieldIndex )\r
- {\r
- int[] ids = getIdentifiers();\r
- if (ids == null) return false;\r
- for (int index : ids)\r
- {\r
- if (index == fieldIndex) return true;\r
- }\r
- return false;\r
- }\r
- \r
- /**\r
- * Get a datatype that describes the identifier of this type.\r
- * If no field has Identifier annotation, the result is null.\r
- * If more than one field is an identifier the type is a record\r
- * with all composing fields.\r
- * \r
- * @return identifier type or null\r
- */\r
- public Datatype getIdentifierType() \r
- { \r
- if ( identifierType != null ) return identifierType;\r
- \r
- int[] ids = getIdentifiers();\r
- if (ids.length==0) return null;\r
- \r
- if (ids.length==1) {\r
- identifierType = getComponentType(ids[0]);\r
- }\r
- \r
- RecordType rt = new RecordType();\r
- for (int i : ids) {\r
- Component c = getComponent(i);\r
- rt.addComponent( c.name, c.type );\r
- }\r
- identifierType = rt; \r
- return identifierType;\r
- }\r
-\r
- @SuppressWarnings("unchecked")\r
- public <T extends Datatype> T getChildType( ChildReference reference ) throws ReferenceException\r
- {\r
- if (reference==null) return (T) this;\r
- \r
- if (reference instanceof LabelReference) {\r
- LabelReference lr = (LabelReference) reference;\r
- String fieldName = lr.label;\r
- int index = getComponentIndex2(fieldName);\r
- if (index<0) throw new ReferenceException("RecordType doesn't have field by name \""+fieldName+"\"");\r
- return components[index].type.getChildType(reference.childReference);\r
- } \r
- \r
- if (reference instanceof IndexReference) {\r
- IndexReference ref = (IndexReference) reference;\r
- int index = ref.getIndex();\r
- if ( index<0 || index>=components.length ) new ReferenceException("RecordType doesn't have field at index+"+index);\r
- return components[index].type.getChildType(reference.childReference);\r
- } \r
- \r
- if (reference instanceof NameReference) {\r
- NameReference lr = (NameReference) reference;\r
- String fieldName = lr.name;\r
- int index = getComponentIndex2(fieldName);\r
- if (index<0) throw new ReferenceException("RecordType doesn't have field by name \""+fieldName+"\"");\r
- return components[index].type.getChildType(reference.childReference);\r
- } \r
- \r
- throw new ReferenceException(reference.getClass()+" is not a subreference of RecordType");\r
- \r
+ }
+
+ /**
+ * Get component type by index
+ * @param index index
+ * @return componenet type or <tt>null</tt> if index was invalid
+ */
+ @Override
+ public Datatype getComponentType(int index) {
+ if (index<0||index>=components.length) return null;
+ return components[index].type;
+ }
+
+ @Override
+ public Datatype getComponentType(ChildReference path) throws IllegalArgumentException {
+ if (path==null) return this;
+ if (path instanceof IndexReference) {
+ IndexReference ir = (IndexReference) path;
+ return components[ir.index].type.getComponentType(path.childReference);
+ }
+ if (path instanceof NameReference) {
+ NameReference nr = (NameReference) path;
+ return getComponent( nr.name ).type.getComponentType(path.childReference);
+ }
+ if (path instanceof LabelReference) {
+ LabelReference lr = (LabelReference) path;
+ try {
+ Integer i = new Integer(lr.label);
+ return getComponent( i ).type.getComponentType(path.childReference);
+ } catch (NumberFormatException nfe) {
+ return getComponent( lr.label ).type.getComponentType(path.childReference);
+ }
+ }
+ throw new IllegalArgumentException();
+ }
+
+ public boolean hasComponent(String fieldName) {
+ for (int i=0; i<components.length; i++)
+ if (components[i].name.equals(fieldName)) return true;
+ return false;
+ }
+
+ /**
+ * Get component by name.
+ *
+ * @param fieldName component name
+ * @return component index or <code>null</code> if one does not exist
+ */
+ public Integer getComponentIndex(String fieldName) {
+ for (int i=0; i<components.length; i++)
+ if (components[i].name.equals(fieldName)) return i;
+ return null;
+ }
+
+ /**
+ * Get component by name.
+ *
+ * @param fieldName component name
+ * @return component index or -1 if one does not exist
+ */
+ public int getComponentIndex2(String fieldName) {
+ for (int i=0; i<components.length; i++)
+ if (components[i].name.equals(fieldName)) return i;
+ return -1;
+ }
+
+ /**
+ * Get component Datatype by field name
+ * @param fieldName
+ * @return datatype or <code>null</code>
+ */
+ public Datatype getComponentType(String fieldName) {
+ int index = getComponentIndex2(fieldName);
+ if (index<0) return null;
+ return components[index].type;
+ }
+
+ /**
+ * Get component by name.
+ *
+ * @param fieldName component name
+ * @return component or <code>null</code> if one does not exist
+ */
+ public Component getComponent(String fieldName) {
+ for (Component c : components)
+ if (c.name.equals(fieldName)) return c;
+ return null;
+ }
+
+ /**
+ * Get component by index.
+ *
+ * @param index component index
+ * @return component or <code>null</code> if one does not exist
+ */
+ public Component getComponent(int index) {
+ if (index<0||index>=components.length) return null;
+ return components[index];
+ }
+
+ public Component[] getComponents() {
+ return components;
+ }
+
+ /**
+ * Get an array of indices that describe which fields compose the identifier
+ * of this record
+ *
+ * @return indices
+ */
+ public int[] getIdentifiers() {
+ String ids = metadata.get( KEY_IDENTIFIER );
+ if (ids == null) {
+ identifiersIndices = new int[0];
+ } else {
+ // Parse
+ StringTokenizer st = new StringTokenizer(ids, ",");
+
+ int[] indices = new int[ st.countTokens() ];
+ for (int i=0; i<indices.length; i++) {
+ String token = st.nextToken();
+ try {
+ indices[i] = Integer.valueOf(token);
+ } catch ( NumberFormatException nfe ) {
+ indices[i] = -1;
+ }
+ }
+ identifiersIndices = indices;
+ }
+ return identifiersIndices;
+ }
+
+ /**
+ * Set which fields compose the identifier of this record
+ *
+ * @param indices
+ */
+ public void setIdentifiers(int...indices)
+ {
+ if (indices.length==0) {
+ metadata.remove( KEY_IDENTIFIER );
+ return;
+ }
+ identifiersIndices = indices;
+ StringBuilder sb = new StringBuilder();
+ for (int i=0; i<indices.length; i++) {
+ if (i>0) sb.append(',');
+ sb.append( Integer.toString(indices[i]) );
+ }
+
+ String str = sb.toString();
+ if ( str.isEmpty() ) {
+ metadata.remove( KEY_IDENTIFIER );
+ } else {
+ metadata.put( KEY_IDENTIFIER, str );
+ }
+ }
+
+ /**
+ * Set which fields compose the identifier of this record
+ * @param indices
+ */
+ public void setIdentifiers(List<Integer> indices)
+ {
+ int[] indices2 = new int[indices.size()];
+ for (int i=0; i<indices.size(); i++) indices2[i] = indices.get(i);
+ setIdentifiers(indices2);
+ }
+
+ public boolean isIdentifier( int fieldIndex )
+ {
+ int[] ids = getIdentifiers();
+ if (ids == null) return false;
+ for (int index : ids)
+ {
+ if (index == fieldIndex) return true;
+ }
+ return false;
+ }
+
+ /**
+ * Get a datatype that describes the identifier of this type.
+ * If no field has Identifier annotation, the result is null.
+ * If more than one field is an identifier the type is a record
+ * with all composing fields.
+ *
+ * @return identifier type or null
+ */
+ public Datatype getIdentifierType()
+ {
+ if ( identifierType != null ) return identifierType;
+
+ int[] ids = getIdentifiers();
+ if (ids.length==0) return null;
+
+ if (ids.length==1) {
+ identifierType = getComponentType(ids[0]);
+ }
+
+ RecordType rt = new RecordType();
+ for (int i : ids) {
+ Component c = getComponent(i);
+ rt.addComponent( c.name, c.type );
+ }
+ identifierType = rt;
+ return identifierType;
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T extends Datatype> T getChildType( ChildReference reference ) throws ReferenceException
+ {
+ if (reference==null) return (T) this;
+
+ if (reference instanceof LabelReference) {
+ LabelReference lr = (LabelReference) reference;
+ String fieldName = lr.label;
+ int index = getComponentIndex2(fieldName);
+ if (index<0) throw new ReferenceException("RecordType doesn't have field by name \""+fieldName+"\"");
+ return components[index].type.getChildType(reference.childReference);
+ }
+
+ if (reference instanceof IndexReference) {
+ IndexReference ref = (IndexReference) reference;
+ int index = ref.getIndex();
+ if ( index<0 || index>=components.length ) new ReferenceException("RecordType doesn't have field at index+"+index);
+ return components[index].type.getChildType(reference.childReference);
+ }
+
+ if (reference instanceof NameReference) {
+ NameReference lr = (NameReference) reference;
+ String fieldName = lr.name;
+ int index = getComponentIndex2(fieldName);
+ if (index<0) throw new ReferenceException("RecordType doesn't have field by name \""+fieldName+"\"");
+ return components[index].type.getChildType(reference.childReference);
+ }
+
+ throw new ReferenceException(reference.getClass()+" is not a subreference of RecordType");
+
}
}