/******************************************************************************* * 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.binding; import java.util.Collection; import java.util.IdentityHashMap; import java.util.Iterator; import java.util.Set; import org.simantics.databoard.Bindings; 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.adapter.AdaptException; import org.simantics.databoard.adapter.Adapter; import org.simantics.databoard.adapter.AdapterConstructionException; import org.simantics.databoard.binding.error.BindingException; import org.simantics.databoard.binding.error.RuntimeBindingException; import org.simantics.databoard.binding.impl.ArrayListBinding; import org.simantics.databoard.binding.impl.BindingPrintContext; import org.simantics.databoard.binding.impl.ByteArrayBinding; import org.simantics.databoard.binding.impl.DoubleArrayBinding; import org.simantics.databoard.binding.impl.FloatArrayBinding; import org.simantics.databoard.binding.impl.IntArrayBinding; import org.simantics.databoard.binding.impl.LinkedListBinding; import org.simantics.databoard.binding.impl.LongArrayBinding; import org.simantics.databoard.binding.impl.ObjectArrayBinding; import org.simantics.databoard.type.ArrayType; import org.simantics.databoard.util.IdentityPair; import org.simantics.databoard.util.Range; /** * This is a binding of Array type and a Java Object. * * @see ArrayType * @see ArrayListBinding for Binding of java.util.ArrayList * @see LinkedListBinding for Binding of java.util.LinkedList * @see ObjectArrayBinding for Binding of Object[] * @see IntArrayBinding for primitive array int[] binding * @see ByteArrayBinding for primitive array byte[] binding * @see LongArrayBinding for primitive array long[] binding * @see DoubleArrayBinding for primitive array double[] binding * @see FloatArrayBinding for primitive array float[] binding * @author Toni Kalajainen */ public abstract class ArrayBinding extends Binding { public Binding componentBinding; public ArrayBinding(ArrayType type, Binding componentBinding) { // if (!type.getComponentType().equals(componentBinding.type())) // throw new IllegalArgumentException("Binding for "+type.componentType+" expected, got "+componentBinding.type()); this.componentBinding = componentBinding; this.type = type; } @Override public Binding getComponentBinding(ChildReference path) { if (path==null) return this; if (path instanceof org.simantics.databoard.accessor.reference.ComponentReference) { return componentBinding.getComponentBinding(path.childReference); } if (path instanceof IndexReference) { IndexReference ir = (IndexReference) path; if (ir.index == 0) { return componentBinding.getComponentBinding(path.childReference); } } if (path instanceof LabelReference) { LabelReference lr = (LabelReference) path; if (lr.label.equals("v")) { return componentBinding.getComponentBinding(path.childReference); } } throw new IllegalArgumentException(); } /** * Returns true if array length can be modified. * * @return true if array length can be modified, false if not */ @Override public boolean isImmutable() { return super.isImmutable(); } /** * Return true if the array's size can be adjusted and false if not * * @return true if array is resizable */ public abstract boolean isResizable(); @Override public ArrayType type() { return (ArrayType) type; } public Binding getComponentBinding() { return componentBinding; } /** * Create a new empty array * @return array object */ public abstract Object create(); /** * Create a new array with initial values copied or referred from a collection. * * @param collection * @return array object * @throws BindingException */ public Object create(Collection collection) throws BindingException { return create(collection.size(), collection.iterator()); } /** * Create new array instance with initial values possibly borrowed from an interator. *

* The implementation iterate the iterator before returning. * * @param length array length * @param values value iterator * @return new instance */ public abstract Object create(int length, Iterator values) throws BindingException; /** * * @param length * @return array * @throws BindingException */ public Object create(int length) throws BindingException { try { return create(length, new Iterator() { @Override public boolean hasNext() { return true; } @Override public Object next() { try { return componentBinding.createDefault(); } catch (BindingException e) { throw new RuntimeBindingException(e); } } @Override public void remove() { }}); } catch (RuntimeBindingException e) { throw e.getCause(); } } /** * Create Array with initial values possibly borrowed from an java.lang.Array * * @param array * @return array of ArrayType * @throws BindingException */ public abstract Object create(Object[] array) throws BindingException; public Object createUnchecked(Object...array) throws RuntimeBindingException { try { return create(array); } catch (BindingException e) { throw new RuntimeBindingException(e); } } @Override public void readFrom(Binding srcBinding, Object src, Object dst) throws BindingException { try { // Src Binding ArrayBinding sb = (ArrayBinding) srcBinding; // Src Component Binding Binding scb = sb.getComponentBinding(); // Dst Component Binding Binding dcb = getComponentBinding(); int newLen = sb.size(src); int oldLen = size(dst); boolean cbImmutable = dcb.isImmutable(); Adapter cloner = cbImmutable ? Bindings.adapterFactory.getAdapter(scb, dcb, false, true) : null; // Set elements for (int i=0; inewLen) { setSize(dst, newLen); } if (!Bindings.equals(srcBinding, src, this, dst)) throw new BindingException("internal error"); } catch (AdaptException e) { throw new BindingException(e); } catch (AdapterConstructionException e) { throw new BindingException(e); } } public void add(Object array, Object element) throws BindingException { int size = size(array); add(array, size, element); } public abstract void add(Object array, int index, Object element) throws BindingException, IndexOutOfBoundsException; public void remove(Object array, int index) throws BindingException, IndexOutOfBoundsException { remove(array, index, 1); } public abstract void remove(Object array, int index, int count) throws BindingException, IndexOutOfBoundsException; public abstract Object get(Object array, int index) throws BindingException, IndexOutOfBoundsException; public abstract void getAll(Object array, Object[] result) throws BindingException; public abstract void set(Object array, int index, Object value) throws BindingException; public abstract void setSize(Object array, int newSize) throws BindingException; public abstract int size(Object array) throws BindingException; @Override public void accept(Visitor1 v, Object obj) { v.visit(this, obj); } @Override public T accept(Visitor v) { return v.visit(this); } /** * Assert the instance is valid and follows restrictions set in data type. * Assertions: * 1. The Length of the array meets ArrayType range * 2. Recursive assertion of each element * * @param obj the instance * @throws BindingException on invalid instance */ public void assertInstaceIsValid(Object obj, Set validInstances) throws BindingException { ArrayType type = type(); // Assert The Length of the array meets ArrayType range int length = size(obj); Range range = type.getLength(); if (range!=null && !range.contains(length)) { throw new BindingException("Array length (="+length+")out of bounds. "+range+" was expected."); } // Recursive assertion of each element for (int i=0; i hashedObjects) throws BindingException { int result = 1; int len = size(value); for (int i=0; i> compareHistory) throws BindingException { // Compare Lengths int l1 = size(o1); int l2 = size(o2); int dif = l1 - l2; if (dif!=0) return dif; // Compare elements Binding c = getComponentBinding(); for (int i=0; i 1; for(int i=0;i0) { ctx.b.append(", "); if ( hasMany && !numberArray && !ctx.singleLine ) { ctx.b.append("\n"); } } componentBinding.toString(get(value, i), ctx); } ctx.b.append(']'); } /** * Get the number of component bindings */ @Override public int getComponentCount() { return 1; } @Override public Binding getComponentBinding(int index) { if (index!=0) throw new IllegalArgumentException(); return componentBinding; } @Override protected boolean deepEquals(Object obj, Set> compareHistory) { return super.deepEquals( obj, compareHistory ) && componentBinding.equals(((ArrayBinding)obj).componentBinding, compareHistory); } @Override public int deepHashCode(IdentityHashMap hashedObjects) { return super.deepHashCode(hashedObjects) + 13 * componentBinding.hashCode(hashedObjects); } }