1 /*******************************************************************************
\r
2 * Copyright (c) 2010 Association for Decentralized Information Management in
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.databoard.binding;
14 import java.util.Collection;
\r
15 import java.util.IdentityHashMap;
\r
16 import java.util.Iterator;
\r
17 import java.util.Set;
\r
19 import org.simantics.databoard.Bindings;
\r
20 import org.simantics.databoard.accessor.reference.ChildReference;
\r
21 import org.simantics.databoard.accessor.reference.IndexReference;
\r
22 import org.simantics.databoard.accessor.reference.LabelReference;
\r
23 import org.simantics.databoard.adapter.AdaptException;
\r
24 import org.simantics.databoard.adapter.Adapter;
\r
25 import org.simantics.databoard.adapter.AdapterConstructionException;
\r
26 import org.simantics.databoard.binding.error.BindingException;
\r
27 import org.simantics.databoard.binding.error.RuntimeBindingException;
\r
28 import org.simantics.databoard.binding.impl.ArrayListBinding;
\r
29 import org.simantics.databoard.binding.impl.BindingPrintContext;
\r
30 import org.simantics.databoard.binding.impl.ByteArrayBinding;
\r
31 import org.simantics.databoard.binding.impl.DoubleArrayBinding;
\r
32 import org.simantics.databoard.binding.impl.FloatArrayBinding;
\r
33 import org.simantics.databoard.binding.impl.IntArrayBinding;
\r
34 import org.simantics.databoard.binding.impl.LinkedListBinding;
\r
35 import org.simantics.databoard.binding.impl.LongArrayBinding;
\r
36 import org.simantics.databoard.binding.impl.ObjectArrayBinding;
\r
37 import org.simantics.databoard.type.ArrayType;
\r
38 import org.simantics.databoard.util.IdentityPair;
\r
39 import org.simantics.databoard.util.Range;
\r
42 * This is a binding of Array type and a Java Object.
45 * @see ArrayListBinding for Binding of java.util.ArrayList<?>
\r
46 * @see LinkedListBinding for Binding of java.util.LinkedList<?>
\r
47 * @see ObjectArrayBinding for Binding of Object[]
\r
48 * @see IntArrayBinding for primitive array int[] binding
\r
49 * @see ByteArrayBinding for primitive array byte[] binding
\r
50 * @see LongArrayBinding for primitive array long[] binding
\r
51 * @see DoubleArrayBinding for primitive array double[] binding
\r
52 * @see FloatArrayBinding for primitive array float[] binding
\r
53 * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
55 public abstract class ArrayBinding extends Binding {
57 public Binding componentBinding;
59 public ArrayBinding(ArrayType type, Binding componentBinding) {
60 // if (!type.getComponentType().equals(componentBinding.type()))
61 // throw new IllegalArgumentException("Binding for "+type.componentType+" expected, got "+componentBinding.type());
62 this.componentBinding = componentBinding;
67 public Binding getComponentBinding(ChildReference path) {
\r
68 if (path==null) return this;
\r
69 if (path instanceof org.simantics.databoard.accessor.reference.ComponentReference) {
\r
70 return componentBinding.getComponentBinding(path.childReference);
\r
72 if (path instanceof IndexReference) {
\r
73 IndexReference ir = (IndexReference) path;
\r
74 if (ir.index == 0) {
\r
75 return componentBinding.getComponentBinding(path.childReference);
\r
78 if (path instanceof LabelReference) {
\r
79 LabelReference lr = (LabelReference) path;
\r
80 if (lr.label.equals("v")) {
\r
81 return componentBinding.getComponentBinding(path.childReference);
\r
84 throw new IllegalArgumentException();
\r
88 * Returns true if array length can be modified.
90 * @return true if array length can be modified, false if not
93 public boolean isImmutable() {
94 return super.isImmutable();
98 * Return true if the array's size can be adjusted and false if not
\r
100 * @return true if array is resizable
\r
102 public abstract boolean isResizable();
\r
105 public ArrayType type() {
106 return (ArrayType) type;
109 public Binding getComponentBinding() {
110 return componentBinding;
114 * Create a new empty array
115 * @return array object
117 public abstract Object create();
120 * Create a new array with initial values copied or referred from a collection.
123 * @return array object
124 * @throws BindingException
126 public Object create(Collection<Object> collection) throws BindingException {
127 return create(collection.size(), collection.iterator());
131 * Create new array instance with initial values possibly borrowed from an interator.
133 * The implementation iterate the iterator before returning.
135 * @param length array length
136 * @param values value iterator
137 * @return new instance
139 public abstract Object create(int length, Iterator<Object> values)
140 throws BindingException;
\r
146 * @throws BindingException
\r
148 public Object create(int length) throws BindingException
\r
151 return create(length, new Iterator<Object>() {
\r
153 public boolean hasNext() {
\r
158 public Object next() {
\r
160 return componentBinding.createDefault();
\r
161 } catch (BindingException e) {
\r
162 throw new RuntimeBindingException(e);
\r
167 public void remove() {
\r
169 } catch (RuntimeBindingException e) {
\r
170 throw e.getCause();
\r
175 * Create Array with initial values possibly borrowed from an java.lang.Array
178 * @return array of ArrayType
179 * @throws BindingException
181 public abstract Object create(Object[] array)
182 throws BindingException;
184 public Object createUnchecked(Object...array)
185 throws RuntimeBindingException {
187 return create(array);
188 } catch (BindingException e) {
189 throw new RuntimeBindingException(e);
194 public void readFrom(Binding srcBinding, Object src, Object dst)
\r
195 throws BindingException {
\r
200 ArrayBinding sb = (ArrayBinding) srcBinding;
\r
201 // Src Component Binding
\r
202 Binding scb = sb.getComponentBinding();
\r
204 // Dst Component Binding
\r
205 Binding dcb = getComponentBinding();
\r
207 int newLen = sb.size(src);
\r
208 int oldLen = size(dst);
\r
209 boolean cbImmutable = dcb.isImmutable();
\r
210 Adapter cloner = cbImmutable ? Bindings.adapterFactory.getAdapter(scb, dcb, false, true) : null;
\r
213 for (int i=0; i<newLen; i++) {
\r
215 // Create new instance
\r
216 Object sc = sb.get(src, i);
\r
217 Object dc = cloner.adapt(sc);
\r
218 if (i<oldLen) set(dst, i, dc); else add(dst, dc);
\r
221 // Read over old instance
\r
222 Object dc = get(dst, i);
\r
223 Object sc = sb.get(src, i);
\r
224 dc = dcb.readFromTry(scb, sc, dc);
\r
225 // Safety-writeback - clone/reference nature of get is unknown
\r
229 Object sc = sb.get(src, i);
\r
230 Object dc = dcb.createDefault();
\r
231 dc = dcb.readFromTry(scb, sc, dc);
\r
236 // Remove excess elements
\r
237 if (oldLen>newLen) {
\r
238 setSize(dst, newLen);
\r
241 if (!Bindings.equals(srcBinding, src, this, dst))
\r
242 throw new BindingException("internal error");
\r
244 } catch (AdaptException e) {
\r
245 throw new BindingException(e);
\r
246 } catch (AdapterConstructionException e) {
\r
247 throw new BindingException(e);
\r
253 public void add(Object array, Object element) throws BindingException
255 int size = size(array);
256 add(array, size, element);
258 public abstract void add(Object array, int index, Object element) throws BindingException, IndexOutOfBoundsException;
259 public void remove(Object array, int index) throws BindingException, IndexOutOfBoundsException
261 remove(array, index, 1);
263 public abstract void remove(Object array, int index, int count) throws BindingException, IndexOutOfBoundsException;
264 public abstract Object get(Object array, int index) throws BindingException, IndexOutOfBoundsException;
265 public abstract void getAll(Object array, Object[] result) throws BindingException;
266 public abstract void set(Object array, int index, Object value) throws BindingException;
\r
267 public abstract void setSize(Object array, int newSize) throws BindingException;
269 public abstract int size(Object array) throws BindingException;
272 public void accept(Visitor1 v, Object obj) {
277 public <T> T accept(Visitor<T> v) {
278 return v.visit(this);
282 * Assert the instance is valid and follows restrictions set in data type.
284 * 1. The Length of the array meets ArrayType range
285 * 2. Recursive assertion of each element
287 * @param obj the instance
288 * @throws BindingException on invalid instance
290 public void assertInstaceIsValid(Object obj, Set<Object> validInstances)
291 throws BindingException
293 ArrayType type = type();
294 // Assert The Length of the array meets ArrayType range
295 int length = size(obj);
296 Range range = type.getLength();
297 if (range!=null && !range.contains(length)) {
298 throw new BindingException("Array length (="+length+")out of bounds. "+range+" was expected.");
300 // Recursive assertion of each element
301 for (int i=0; i<length; i++)
303 Object component = get(obj, i);
304 componentBinding.assertInstaceIsValid(component, validInstances);
309 public int deepHashValue(Object value, IdentityHashMap<Object, Object> hashedObjects) throws BindingException {
311 int len = size(value);
312 for (int i=0; i<len; i++) {
313 Object element = get(value, i);
314 result = 31*result + componentBinding.deepHashValue(element, hashedObjects);
320 public int deepCompare(Object o1, Object o2,
321 Set<IdentityPair<Object, Object>> compareHistory)
322 throws BindingException {
327 if (dif!=0) return dif;
329 Binding c = getComponentBinding();
330 for (int i=0; i<l1; i++) {
331 Object e1 = get(o1, i);
332 Object e2 = get(o2, i);
333 dif = c.deepCompare(e1, e2, compareHistory);
334 if (dif!=0) return dif;
340 protected void toString(Object value, BindingPrintContext ctx) throws BindingException {
\r
341 Binding componentBinding = getComponentBinding();
\r
343 int size = size(value);
\r
344 boolean numberArray = componentBinding instanceof NumberBinding;
\r
345 boolean hasMany = size > 1;
\r
346 for(int i=0;i<size;++i) {
\r
348 ctx.b.append(", ");
\r
349 if ( hasMany && !numberArray && !ctx.singleLine ) {
\r
350 ctx.b.append("\n");
\r
353 componentBinding.toString(get(value, i), ctx);
\r
359 * Get the number of component bindings
\r
362 public int getComponentCount() {
\r
367 public Binding getComponentBinding(int index) {
\r
368 if (index!=0) throw new IllegalArgumentException();
\r
369 return componentBinding;
\r
373 protected boolean deepEquals(Object obj,
\r
374 Set<IdentityPair<Binding, Binding>> compareHistory) {
\r
375 return super.deepEquals( obj, compareHistory ) && componentBinding.equals(((ArrayBinding)obj).componentBinding, compareHistory);
\r
379 public int deepHashCode(IdentityHashMap<Object, Object> hashedObjects) {
\r
380 return super.deepHashCode(hashedObjects) + 13 * componentBinding.hashCode(hashedObjects);
\r