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