--- /dev/null
+/*******************************************************************************\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
+package org.simantics.databoard.type;\r
+\r
+import java.util.Iterator;\r
+import java.util.Map.Entry;\r
+import java.util.Set;\r
+import java.util.TreeMap;\r
+\r
+import org.simantics.databoard.Datatypes;\r
+import org.simantics.databoard.accessor.error.ReferenceException;\r
+import org.simantics.databoard.accessor.reference.ChildReference;\r
+import org.simantics.databoard.annotations.Union;\r
+import org.simantics.databoard.parser.unparsing.DataTypePrinter;\r
+import org.simantics.databoard.util.IdentityPair;\r
+\r
+@Union({BooleanType.class,\r
+ ByteType.class,\r
+ IntegerType.class, \r
+ LongType.class,\r
+ FloatType.class,\r
+ DoubleType.class,\r
+ StringType.class,\r
+ RecordType.class,\r
+ ArrayType.class,\r
+ MapType.class,\r
+ OptionalType.class,\r
+ UnionType.class,\r
+ VariantType.class}) \r
+public abstract class Datatype implements Cloneable {\r
+ \r
+ public TreeMap<String, String> metadata = new TreeMap<String, String>();\r
+ \r
+ protected void collectSubtypes(Set<Datatype> subtypes, Set<Datatype> recursiveSubtypes) { \r
+ }\r
+\r
+ /** \r
+ * Get component type count\r
+ * @return component count\r
+ */\r
+ public abstract int getComponentCount();\r
+ \r
+ /**\r
+ * Get component type\r
+ * @param index component index\r
+ * @return datatype\r
+ */\r
+ public abstract Datatype getComponentType(int index);\r
+ \r
+ /**\r
+ * Get component type\r
+ * @param path child path or <tt>null</tt> to return this.\r
+ * @return datatype\r
+ * @throws IllegalArgumentException if path cannot be applied to this type \r
+ */\r
+ public abstract Datatype getComponentType(ChildReference path);\r
+ \r
+ /**\r
+ * Print the type in data type notation.\r
+ * \r
+ * <a href="http://dev.simantics.org/index.php/Data_type_notation">Datatype Notation</a>\r
+ * \r
+ * See {@link Datatypes#getDatatype(String)} to parse string to data type.\r
+ * \r
+ * @return type\r
+ */\r
+ @Override\r
+ public String toString() {\r
+ return DataTypePrinter.toString(this, true);\r
+ }\r
+\r
+ /**\r
+ * Print the type in data type notation.\r
+ * \r
+ * <a href="http://dev.simantics.org/index.php/Data_type_notation">Datatype Notation</a>\r
+ * \r
+ * See {@link Datatypes#getDatatype(String)} to parse string to data type.\r
+ * \r
+ * @return type\r
+ */\r
+ public String toSingleLineString() {\r
+ return DataTypePrinter.toString(this, false);\r
+ }\r
+ \r
+ public interface Visitor1 {\r
+ void visit(ArrayType b, Object obj);\r
+ void visit(BooleanType b, Object obj);\r
+ void visit(DoubleType b, Object obj);\r
+ void visit(FloatType b, Object obj);\r
+ void visit(IntegerType b, Object obj);\r
+ void visit(ByteType b, Object obj);\r
+ void visit(LongType b, Object obj);\r
+ void visit(OptionalType b, Object obj);\r
+ void visit(RecordType b, Object obj);\r
+ void visit(StringType b, Object obj);\r
+ void visit(UnionType b, Object obj);\r
+ void visit(VariantType b, Object obj);\r
+ void visit(MapType b, Object obj);\r
+ }\r
+ \r
+ public abstract void accept(Visitor1 v, Object obj);\r
+ \r
+ public interface Visitor<T> {\r
+ T visit(ArrayType b);\r
+ T visit(BooleanType b);\r
+ T visit(DoubleType b);\r
+ T visit(FloatType b);\r
+ T visit(IntegerType b);\r
+ T visit(ByteType b);\r
+ T visit(LongType b);\r
+ T visit(OptionalType b);\r
+ T visit(RecordType b);\r
+ T visit(StringType b);\r
+ T visit(UnionType b);\r
+ T visit(VariantType b);\r
+ T visit(MapType b);\r
+ }\r
+ \r
+ public abstract <T> T accept(Visitor<T> v); \r
+\r
+ protected boolean hasEqualMetadata(Object obj) {\r
+ // Check metadata is equal\r
+ Datatype other = (Datatype) obj;\r
+ int s1 = metadata.size(), s2 = other.metadata.size(); \r
+ if ( s1 != s2 ) return false;\r
+ if ( s1>0 ) {\r
+ Iterator<Entry<String, String>> i1 = metadata.entrySet().iterator();\r
+ Iterator<Entry<String, String>> i2 = other.metadata.entrySet().iterator();\r
+ \r
+ while (i1.hasNext() && i2.hasNext()) {\r
+ if ( !i1.next().equals( i2.next() ) ) return false;\r
+ }\r
+ } \r
+ return true;\r
+ }\r
+ \r
+ /**\r
+ * Deep equals-compare\r
+ * \r
+ * @param obj object to compare with\r
+ * @return true if the object is equal (incl. structurally) with this object\r
+ */\r
+ @Override\r
+ public boolean equals(Object obj) {\r
+ if (this==obj) return true;\r
+ if (!this.getClass().isInstance(obj)) return false; \r
+ return deepEquals(obj, null); \r
+ }\r
+ \r
+ @Override\r
+ public int hashCode() {\r
+ return metadataHashCode();\r
+ }\r
+ \r
+ public int metadataHashCode() {\r
+ int hash = 13;\r
+ for (Entry<String, String> e : metadata.entrySet()) {\r
+ hash *= 13; \r
+ hash += e.hashCode();\r
+ }\r
+ return hash;\r
+ }\r
+ \r
+// public boolean isSubtypeOf(DataType type) {\r
+// return equals(type);\r
+// }\r
+ \r
+ protected abstract boolean deepEquals(Object obj, Set<IdentityPair<Datatype, Datatype>> compareHistory); \r
+ \r
+ /**\r
+ * Get child by reference\r
+ * @param reference type reference or null (for this instance)\r
+ * @return the child type \r
+ * @throws ReferenceException if child was not found\r
+ */\r
+ public abstract <T extends Datatype> T getChildType( ChildReference reference ) throws ReferenceException;\r
+ \r
+}\r
+\r