/******************************************************************************* * 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.accessor.wire; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; import org.simantics.databoard.Bindings; import org.simantics.databoard.Datatypes; import org.simantics.databoard.Methods; import org.simantics.databoard.accessor.Accessor; import org.simantics.databoard.accessor.ArrayAccessor; import org.simantics.databoard.accessor.BooleanAccessor; import org.simantics.databoard.accessor.ByteAccessor; import org.simantics.databoard.accessor.CloseableAccessor; import org.simantics.databoard.accessor.DoubleAccessor; import org.simantics.databoard.accessor.FloatAccessor; import org.simantics.databoard.accessor.IntegerAccessor; import org.simantics.databoard.accessor.LongAccessor; import org.simantics.databoard.accessor.MapAccessor; import org.simantics.databoard.accessor.OptionalAccessor; import org.simantics.databoard.accessor.RecordAccessor; import org.simantics.databoard.accessor.StringAccessor; import org.simantics.databoard.accessor.UnionAccessor; import org.simantics.databoard.accessor.VariantAccessor; import org.simantics.databoard.accessor.error.AccessorConstructionException; import org.simantics.databoard.accessor.error.AccessorException; import org.simantics.databoard.accessor.error.ReferenceException; import org.simantics.databoard.accessor.event.ArrayElementRemoved; import org.simantics.databoard.accessor.event.Event; import org.simantics.databoard.accessor.event.MapEntryAdded; import org.simantics.databoard.accessor.event.MapEntryRemoved; import org.simantics.databoard.accessor.event.OptionalValueAssigned; import org.simantics.databoard.accessor.event.OptionalValueRemoved; import org.simantics.databoard.accessor.event.ValueAssigned; import org.simantics.databoard.accessor.impl.ListenerEntry; import org.simantics.databoard.accessor.interestset.InterestSet; import org.simantics.databoard.accessor.reference.ChildReference; import org.simantics.databoard.accessor.reference.ComponentReference; import org.simantics.databoard.accessor.reference.IndexReference; import org.simantics.databoard.accessor.reference.KeyReference; import org.simantics.databoard.accessor.reference.NameReference; import org.simantics.databoard.accessor.wire.IWireServer.AccessorInfo; import org.simantics.databoard.accessor.wire.IWireServer.ApplyResult; import org.simantics.databoard.adapter.AdaptException; import org.simantics.databoard.binding.ArrayBinding; import org.simantics.databoard.binding.Binding; import org.simantics.databoard.binding.MapBinding; import org.simantics.databoard.binding.error.BindingConstructionException; import org.simantics.databoard.binding.error.BindingException; import org.simantics.databoard.binding.impl.ArrayListBinding; import org.simantics.databoard.binding.impl.ObjectArrayBinding; import org.simantics.databoard.binding.impl.TreeMapBinding; import org.simantics.databoard.binding.mutable.MutableVariant; import org.simantics.databoard.method.MethodInterface; import org.simantics.databoard.type.ArrayType; import org.simantics.databoard.type.BooleanType; import org.simantics.databoard.type.ByteType; import org.simantics.databoard.type.Datatype; import org.simantics.databoard.type.DoubleType; import org.simantics.databoard.type.FloatType; import org.simantics.databoard.type.IntegerType; import org.simantics.databoard.type.LongType; import org.simantics.databoard.type.MapType; import org.simantics.databoard.type.OptionalType; import org.simantics.databoard.type.RecordType; import org.simantics.databoard.type.StringType; import org.simantics.databoard.type.UnionType; import org.simantics.databoard.type.VariantType; import org.simantics.databoard.util.BijectionMap; /** * WireAccessor provides an accessor over TCP/IP connection. * * All method invocation is blocking. WireAccessor may be accessed from * simultanous threads. * * * @author Toni Kalajainen */ public class WireClient implements IWireClient { /** A queue of released accessors */ ReferenceQueue releaseQueue = new ReferenceQueue(); Map subAccessorMap = new HashMap(); // Map accessorMap = new HashMap(); BijectionMap listenerMap = new BijectionMap(); MethodInterface serverMi; MethodInterface clientMi; IWireServer server; WireAccessor root; public WireClient() { try { this.clientMi = Methods.bindInterface(IWireClient.class, this); } catch (BindingConstructionException e) { throw new RuntimeException(e); } } public void setServerMethodInterface(MethodInterface serverMi) { try { this.serverMi = serverMi; this.server = Methods.createProxy(IWireServer.class, serverMi); } catch (BindingConstructionException e) { throw new RuntimeException(e); } } public MethodInterface getServerMethodInterface() { return serverMi; } public MethodInterface getClientMethodInterface() { return clientMi; } public void close() { try { closeReleasedAccessors(); } catch (WireException e) { e.printStackTrace(); } } /** * Create an accessor. Does not dispose or add to cache, use getAccessor instead * @param ref * @return * @throws WireException */ WireAccessor createAccessor(ChildReference ref) throws WireException { AccessorInfo ai = server.openAccessor(ref); if (ai.type instanceof BooleanType) { return new WireBoolean(ai.accessorId, ai.type, ref); } else if (ai.type instanceof ByteType) { return new WireByte(ai.accessorId, ai.type, ref); } else if (ai.type instanceof IntegerType) { return new WireInteger(ai.accessorId, ai.type, ref); } else if (ai.type instanceof LongType) { return new WireLong(ai.accessorId, ai.type, ref); } else if (ai.type instanceof FloatType) { return new WireFloat(ai.accessorId, ai.type, ref); } else if (ai.type instanceof DoubleType) { return new WireDouble(ai.accessorId, ai.type, ref); } else if (ai.type instanceof StringType) { return new WireByte(ai.accessorId, ai.type, ref); } else if (ai.type instanceof MapType) { return new WireMap(ai.accessorId, ai.type, ref); } else if (ai.type instanceof OptionalType) { return new WireOptional(ai.accessorId, ai.type, ref); } else if (ai.type instanceof RecordType) { return new WireRecord(ai.accessorId, ai.type, ref); } else if (ai.type instanceof UnionType) { return new WireUnion(ai.accessorId, ai.type, ref); } else if (ai.type instanceof VariantType) { return new WireVariant(ai.accessorId, ai.type, ref); } throw new WireException("error, unknown data type "+ai.type); } /** * Create or get wire accessor * @param ref path from root * @return wire accessor * @throws WireException */ public WireAccessor getAccessor(ChildReference ref) throws WireException { synchronized(subAccessorMap) { // Rseult Check cache closeReleasedAccessors(); WireAccessorReference war = subAccessorMap.get(ref); WireAccessor result = war == null ? null : war.get(); if (result != null) return result; result = createAccessor(ref); war = new WireAccessorReference(result); subAccessorMap.put(ref, war); return result; } } /** * Close garbage collected accessors * @throws WireException */ void closeReleasedAccessors() throws WireException { if (releaseQueue.poll()==null) return; ArrayList ids = new ArrayList(); while (releaseQueue.poll() != null) { try { WireAccessorReference ref = (WireAccessorReference) releaseQueue.remove(); ids.add( ref.accId ); } catch (InterruptedException e) { } } // Close accessors server.closeAccessors( ids.toArray(new Integer[ids.size()]) ); } @Override public int onEvents(int lisId, Event[] events) { ListenerEntry listener = null; synchronized(listenerMap) { listener = listenerMap.getRight(lisId); } if (listener==null) return 0; List list = new CopyOnWriteArrayList(events); listener.emitEvents(list); return 0; } class WireAccessorReference extends WeakReference { int accId; public WireAccessorReference(WireAccessor referent) { super(referent, releaseQueue); this.accId = referent.accId; } } abstract class WireAccessor implements Accessor, CloseableAccessor { int accId; ChildReference ref; Datatype type; WireAccessor(int accId, Datatype type, ChildReference ref) { this.accId = accId; this.type = type; this.ref = ref; } @Override public Object getValue(Binding binding) throws AccessorException { try { MutableVariant value = server.getValue(accId); return value.getValue(binding); } catch (WireException e) { throw new AccessorException(e); } catch (AdaptException e) { throw new AccessorException(e); } } @Override public void getValue(Binding binding, Object obj) throws AccessorException { try { MutableVariant value= server.getValue(accId); binding.readFrom(value.getBinding(), value.getValue(), obj); } catch ( WireException e ) { throw new AccessorException(e); } catch ( BindingException e ) { throw new AccessorException(e); } } @Override public boolean getValue(ChildReference path, Binding binding, Object obj) throws AccessorException { try { Accessor a = getComponent(path); a.getValue(binding, obj); return true; } catch (ReferenceException re) { return false; } catch (AccessorConstructionException e) { throw new AccessorException(e); } } public Object getValue(ChildReference path, Binding binding) throws AccessorException { try { Accessor a = getComponent(path); return a.getValue(binding); } catch (ReferenceException re) { return null; } catch (AccessorConstructionException e) { throw new AccessorException(e); } } void applyEvent(Event...events) throws AccessorException { ApplyResult result = server.apply(accId, events, false); if (result.error != null) throw new AccessorException( result.error ); } @Override public void setValue(Binding binding, Object newValue) throws AccessorException { applyEvent( new ValueAssigned(binding, newValue) ); } public boolean setValue(ChildReference path, Binding binding, Object obj) throws AccessorException { try { Accessor a = getComponent(path); a.setValue(binding, obj); return true; } catch (ReferenceException re) { return false; } catch (AccessorConstructionException e) { throw new AccessorException(e); } } @SuppressWarnings("unchecked") @Override public T getComponent(ChildReference reference) throws AccessorConstructionException { try { // Create a reference from the root ChildReference r = ChildReference.concatenate(ref, reference); return (T) WireClient.this.getAccessor( r ); } catch (WireException e) { throw new AccessorConstructionException( e ); } } @Override public void apply(List changeSet, LinkedList rollback) throws AccessorException { ApplyResult result = server.apply(accId, changeSet.toArray(new Event[changeSet.size()]), rollback!=null); if (rollback!=null && result.rollbackLog!=null) rollback.addAll( result.rollbackLog ); if (result.error != null) throw new AccessorException( result.error ); } @Override public Datatype type() { return type; } @Override public void addListener(Listener listener, InterestSet interestSet, ChildReference pathPrefix, Executor executor) throws AccessorException { try { ListenerEntry le = new ListenerEntry(listener, interestSet, pathPrefix, executor); int lisId = server.addListener(accId, interestSet, pathPrefix); synchronized(listenerMap) { listenerMap.map(lisId, le); } } catch (WireException e) { throw new AccessorException(e); } } @Override public void removeListener(Listener listener) throws AccessorException { Integer lisId = null; synchronized(listenerMap) { for (Entry e : listenerMap.getEntries()) { if (e.getValue().listener == listener) { lisId = e.getKey(); break; } } if (lisId==null) return; listenerMap.removeWithLeft(lisId); } try { server.removeListener(lisId); } catch (WireException e) { throw new AccessorException( e ); } } public void close() throws AccessorException { try { server.closeAccessors( new Integer[] {accId} ); } catch (WireException e) { throw new AccessorException( e ); } } } class WireBoolean extends WireAccessor implements BooleanAccessor { WireBoolean(int accId, Datatype type, ChildReference ref) { super(accId, type, ref); } @Override public BooleanType type() { return (BooleanType) type; } @Override public boolean getValue() throws AccessorException { try { MutableVariant value = server.getValue(accId); return (Boolean) value.getValue( Bindings.BOOLEAN ); } catch (WireException e) { throw new AccessorException( e ); } catch (AdaptException e) { throw new AccessorException( e ); } } @Override public void setValue(boolean value) throws AccessorException { Event e = new ValueAssigned(null, Bindings.BOOLEAN, value); Event[] list = new Event[] {e}; ApplyResult result = server.apply(accId, list, false); if (result.error != null) throw new AccessorException( result.error ); } } class WireByte extends WireAccessor implements ByteAccessor { WireByte(int accId, Datatype type, ChildReference ref) { super(accId, type, ref); } @Override public ByteType type() { return (ByteType) type; } @Override public byte getValue() throws AccessorException { try { MutableVariant value = server.getValue(accId); return (Byte) value.getValue( Bindings.BYTE ); } catch (WireException e) { throw new AccessorException( e ); } catch (AdaptException e) { throw new AccessorException( e ); } } @Override public void setValue(byte value) throws AccessorException { Event e = new ValueAssigned(null, Bindings.BYTE, value); Event[] list = new Event[] {e}; ApplyResult result = server.apply(accId, list, false); if (result.error != null) throw new AccessorException( result.error ); } } class WireInteger extends WireAccessor implements IntegerAccessor { WireInteger(int accId, Datatype type, ChildReference ref) { super(accId, type, ref); } @Override public IntegerType type() { return (IntegerType) type; } @Override public int getValue() throws AccessorException { try { MutableVariant value = server.getValue(accId); return (Integer) value.getValue( Bindings.INTEGER ); } catch (WireException e) { throw new AccessorException( e ); } catch (AdaptException e) { throw new AccessorException( e ); } } @Override public void setValue(int value) throws AccessorException { Event e = new ValueAssigned(Bindings.INTEGER, value); Event[] list = new Event[] {e}; ApplyResult result = server.apply(accId, list, false); if (result.error != null) throw new AccessorException( result.error ); } } class WireLong extends WireAccessor implements LongAccessor { WireLong(int accId, Datatype type, ChildReference ref) { super(accId, type, ref); } @Override public LongType type() { return (LongType) type; } @Override public long getValue() throws AccessorException { try { MutableVariant value = server.getValue(accId); return (Long) value.getValue( Bindings.LONG ); } catch (WireException e) { throw new AccessorException( e ); } catch (AdaptException e) { throw new AccessorException( e ); } } @Override public void setValue(long value) throws AccessorException { Event e = new ValueAssigned(Bindings.LONG, value); Event[] list = new Event[] {e}; ApplyResult result = server.apply(accId, list, false); if (result.error != null) throw new AccessorException( result.error ); } } class WireFloat extends WireAccessor implements FloatAccessor { WireFloat(int accId, Datatype type, ChildReference ref) { super(accId, type, ref); } @Override public FloatType type() { return (FloatType) type; } @Override public float getValue() throws AccessorException { try { MutableVariant value = server.getValue(accId); return (Float) value.getValue( Bindings.FLOAT ); } catch (WireException e) { throw new AccessorException( e ); } catch (AdaptException e) { throw new AccessorException( e ); } } @Override public void setValue(float value) throws AccessorException { Event e = new ValueAssigned(Bindings.FLOAT, value); Event[] list = new Event[] {e}; ApplyResult result = server.apply(accId, list, false); if (result.error != null) throw new AccessorException( result.error ); } } class WireDouble extends WireAccessor implements DoubleAccessor { WireDouble(int accId, Datatype type, ChildReference ref) { super(accId, type, ref); } @Override public DoubleType type() { return (DoubleType) type; } @Override public double getValue() throws AccessorException { try { MutableVariant value = server.getValue(accId); return (Double) value.getValue( Bindings.DOUBLE ); } catch (WireException e) { throw new AccessorException( e ); } catch (AdaptException e) { throw new AccessorException( e ); } } @Override public void setValue(double value) throws AccessorException { Event e = new ValueAssigned(Bindings.DOUBLE, value); Event[] list = new Event[] {e}; ApplyResult result = server.apply(accId, list, false); if (result.error != null) throw new AccessorException( result.error ); } } class WireArray extends WireAccessor implements ArrayAccessor { WireArray(int accId, Datatype type, ChildReference ref) { super(accId, type, ref); } @Override public ArrayType type() { return (ArrayType) type; } @Override public void add(Binding binding, Object value) throws AccessorException { try { server.addAll(accId, -1, new MutableVariant(binding, value)); } catch (WireException e) { throw new AccessorException(e); } } @Override public void addAll(Binding binding, Object[] values) throws AccessorException { try { ArrayBinding ab = new ObjectArrayBinding(new ArrayType(binding.type()), binding); MutableVariant array = new MutableVariant(ab, values); server.addAll(accId, -1, array); } catch (WireException e) { throw new AccessorException(e); } } @Override public void addAll(int index, Binding binding, Object[] values) throws AccessorException { try { ArrayBinding ab = new ObjectArrayBinding(new ArrayType(binding.type()), binding); MutableVariant array = new MutableVariant(ab, values); server.addAll(accId, index, array); } catch (WireException e) { throw new AccessorException(e); } } @Override public void add(int index, Binding binding, Object value) throws AccessorException { try { server.addAll(accId, index, new MutableVariant(binding, value)); } catch (WireException e) { throw new AccessorException(e); } } @Override public void set(int index, Binding binding, Object value) throws AccessorException { applyEvent(new ValueAssigned(new IndexReference(index), binding, value)); } @Override public void remove(int index, int count) throws AccessorException { applyEvent(new ArrayElementRemoved(index)); } @SuppressWarnings("unchecked") @Override public T getAccessor(int index) throws AccessorConstructionException { return (T) getComponent(new IndexReference(index)); } @Override public Object get(int index, Binding valueBinding) throws AccessorException { try { MutableVariant v = server.getArrayElement(accId, index); return v.getValue(valueBinding); } catch (WireException e) { throw new AccessorException(e); } catch (AdaptException e) { throw new AccessorException(e); } } @Override public void get(int index, Binding valueBinding, Object dst) throws AccessorException { try { MutableVariant v = server.getArrayElement(accId, index); valueBinding.readFrom(v.getBinding(), v.getValue(), v); } catch (WireException e) { throw new AccessorException(e); } catch (BindingException e) { throw new AccessorException(e); } } @Override public void getAll(Binding valueBinding, Object[] array) throws AccessorException { ObjectArrayBinding arrayBinding = new ObjectArrayBinding(type(), valueBinding); Object[] a2 = (Object[]) getValue(arrayBinding); System.arraycopy(a2, 0, array, 0, a2.length); } @Override public void getAll(Binding valueBinding, Collection values) throws AccessorException { ArrayListBinding arrayBinding = new ArrayListBinding(type(), valueBinding); ArrayList a2 = (ArrayList) getValue(arrayBinding); values.addAll(a2); } @Override public void setSize(int newSize) throws AccessorException { throw new AccessorException("Not implemented"); } @Override public int size() throws AccessorException { try { return server.size(accId); } catch (WireException e) { throw new AccessorException( e ); } } } class WireMap extends WireAccessor implements MapAccessor { WireMap(int accId, Datatype type, ChildReference ref) { super(accId, type, ref); } @Override public MapType type() { return (MapType) type; } @Override public int size() throws AccessorException { try { return server.size(accId); } catch (WireException e) { throw new AccessorException( e ); } } @Override public Object get(Binding keyBinding, Object key, Binding valueBinding) throws AccessorException { try { MutableVariant value = server.getMapValue(accId, new MutableVariant(keyBinding, key)); if (value.type().equals(Datatypes.VOID)) return null; return value.getValue(valueBinding); } catch (WireException e) { throw new AccessorException( e ); } catch (AdaptException e) { throw new AccessorException( e ); } } @Override public boolean containsKey(Binding keyBinding, Object key) throws AccessorException { try { return server.containsKey(accId, new MutableVariant(keyBinding, key)); } catch (WireException e) { throw new AccessorException( e ); } } @Override public boolean containsValue(Binding valueBinding, Object value) throws AccessorException { try { return server.containsValue(accId, new MutableVariant(valueBinding, value)); } catch (WireException e) { throw new AccessorException( e ); } } @Override public void put(Binding keyBinding, Object key, Binding valueBinding, Object value) throws AccessorException { applyEvent( new MapEntryAdded(new MutableVariant(keyBinding, key), new MutableVariant(valueBinding, value)) ); } @Override public void remove(Binding keyBinding, Object key) throws AccessorException { applyEvent( new MapEntryRemoved(new MutableVariant(keyBinding, key)) ); } @Override public void clear() throws AccessorException { try { server.clear(accId); } catch (WireException e) { throw new AccessorException(e); } } @Override public void putAll(Binding keyBinding, Binding valueBinding, Map from) throws AccessorException { int count = from.size(); Event events[] = new Event[ count ]; int i = 0; for (Entry e : from.entrySet()) { MutableVariant key = new MutableVariant( keyBinding, e.getKey() ); MutableVariant value = new MutableVariant( valueBinding, e.getValue() ); events[i] = new MapEntryAdded( key, value ); ++i; } applyEvent( events ); } @Override public void putAll(Binding keyBinding, Binding valueBinding, Object[] keys, Object[] values) throws AccessorException { if (keys.length != values.length) throw new AccessorException("bad args"); int count = keys.length; Event events[] = new Event[ count ]; for (int i=0; i to) throws AccessorException { MapBinding binding = new TreeMapBinding(keyBinding, valueBinding); TreeMap v = (TreeMap) getValue(binding); to.putAll(v); } @SuppressWarnings("unchecked") @Override public void getAll(Binding keyBinding, Binding valueBinding, Object[] keys, Object[] values) throws AccessorException { MapBinding binding = new TreeMapBinding(keyBinding, valueBinding); TreeMap v = (TreeMap) getValue(binding); int i=0; for (Entry e : v.entrySet()) { keys[i] = e.getKey(); values[i] = e.getValue(); ++i; } } @Override public Object[] getKeys(Binding keyBinding) throws AccessorException { try { MutableVariant array = server.getMapKeys(accId); ArrayBinding binding = new ObjectArrayBinding( keyBinding ); return (Object[]) array.getValue(binding); } catch (WireException e) { throw new AccessorException( e ); } catch (AdaptException e) { throw new AccessorException( e ); } } @Override public int count(Binding keyBinding, Object from, boolean fromInclusive, Object end, boolean endInclusive) throws AccessorException { throw new AccessorException("Not implemented"); } @Override public int getEntries(Binding keyBinding, Object from, boolean fromInclusive, Object end, boolean endInclusive, ArrayBinding keyArrayBinding, Object dstKeys, ArrayBinding valueArrayBinding, Object dstValues, int limit) throws AccessorException { throw new AccessorException("Not implemented"); } @Override public Object[] getValues(Binding valueBinding) throws AccessorException { try { MutableVariant array = server.getMapValues(accId); ArrayBinding binding = new ObjectArrayBinding( valueBinding ); return (Object[]) array.getValue(binding); } catch (WireException e) { throw new AccessorException( e ); } catch (AdaptException e) { throw new AccessorException( e ); } } @SuppressWarnings("unchecked") @Override public T getValueAccessor(Binding keyBinding, Object key) throws AccessorConstructionException { return (T) getComponent( new KeyReference(keyBinding, key) ); } @Override public Object getFirstKey(Binding keyBinding) throws AccessorException { try { MutableVariant result = server.getFirstKey(accId); if (result.type().equals(Datatypes.VOID)) return null; return result.getValue(keyBinding); } catch (WireException e) { throw new AccessorException(e); } catch (AdaptException e) { throw new AccessorException(e); } } @Override public Object getLastKey(Binding keyBinding) throws AccessorException { try { MutableVariant result = server.getLastKey(accId); if (result.type().equals(Datatypes.VOID)) return null; return result.getValue(keyBinding); } catch (WireException e) { throw new AccessorException(e); } catch (AdaptException e) { throw new AccessorException(e); } } @Override public Object getLowerKey(Binding keyBinding, Object key) throws AccessorException { try { MutableVariant result = server.getLowerKey(accId, new MutableVariant(keyBinding, key)); if (result.type().equals(Datatypes.VOID)) return null; return result.getValue(keyBinding); } catch (WireException e) { throw new AccessorException(e); } catch (AdaptException e) { throw new AccessorException(e); } } @Override public Object getFloorKey(Binding keyBinding, Object key) throws AccessorException { try { MutableVariant result = server.getFloorKey(accId, new MutableVariant(keyBinding, key)); if (result.type() == Datatypes.VOID) return null; return result.getValue(keyBinding); } catch (WireException e) { throw new AccessorException(e); } catch (AdaptException e) { throw new AccessorException(e); } } @Override public Object getCeilingKey(Binding keyBinding, Object key) throws AccessorException { try { MutableVariant result = server.getCeilingKey(accId, new MutableVariant(keyBinding, key)); if (result.type().equals(Datatypes.VOID)) return null; return result.getValue(keyBinding); } catch (WireException e) { throw new AccessorException(e); } catch (AdaptException e) { throw new AccessorException(e); } } @Override public Object getHigherKey(Binding keyBinding, Object key) throws AccessorException { try { MutableVariant result = server.getHigherKey(accId, new MutableVariant(keyBinding, key)); if (result.type().equals(Datatypes.VOID)) return null; return result.getValue(keyBinding); } catch (WireException e) { throw new AccessorException(e); } catch (AdaptException e) { throw new AccessorException(e); } } } class WireOptional extends WireAccessor implements OptionalAccessor { WireOptional(int accId, Datatype type, ChildReference ref) { super(accId, type, ref); } @Override public OptionalType type() { return (OptionalType) type; } @Override public void setNoValue() throws AccessorException { applyEvent( new OptionalValueRemoved() ); } @Override public boolean hasValue() throws AccessorException { try { return server.hasValue(accId); } catch (WireException e) { throw new AccessorException( e ); } } @Override public Object getComponentValue(Binding componentBinding) throws AccessorException { try { WireAccessor sa = createAccessor( new ComponentReference() ); try { return sa.getValue(componentBinding); } finally { sa.close(); } } catch (WireException e) { throw new AccessorException( e ); } } @Override public void setComponentValue(Binding binding, Object value) throws AccessorException { applyEvent(new OptionalValueAssigned(binding, value)); } @SuppressWarnings("unchecked") @Override public T getComponentAccessor() throws AccessorConstructionException { return (T) getComponent( new ComponentReference() ); } } class WireRecord extends WireAccessor implements RecordAccessor { WireRecord(int accId, Datatype type, ChildReference ref) { super(accId, type, ref); } @Override public RecordType type() { return (RecordType) type; } @Override public int count() throws AccessorException { try { return server.size(accId); } catch (WireException e) { throw new AccessorException(e); } } @SuppressWarnings("unchecked") @Override public T getFieldAccessor(int index) throws AccessorConstructionException { return (T) getComponent( new IndexReference(index) ); } @SuppressWarnings("unchecked") @Override public T getFieldAccessor(String fieldName) throws AccessorConstructionException { return (T) getComponent( new NameReference( fieldName ) ); } @Override public Object getFieldValue(String fieldName, Binding fieldBinding) throws AccessorException { int fieldIndex = type().getComponentIndex(fieldName); if (fieldIndex<0) throw new AccessorException("Field "+fieldName+" does not exist"); return getFieldValue(fieldIndex, fieldBinding); } @Override public Object getFieldValue(int index, Binding fieldBinding) throws AccessorException { try { WireAccessor sa = createAccessor( new IndexReference(index) ); try { return sa.getValue(fieldBinding); } finally { sa.close(); } } catch (WireException e) { throw new AccessorException( e ); } } public void setFieldValue(String fieldName, Binding fieldBinding, Object value) throws AccessorException { int fieldIndex = type().getComponentIndex(fieldName); if (fieldIndex<0) throw new AccessorException("Field "+fieldName+" does not exist"); setFieldValue(fieldIndex, fieldBinding, value); }; @Override public void setFieldValue(int index, Binding fieldBinding, Object value) throws AccessorException { try { WireAccessor sa = createAccessor( new IndexReference(index) ); try { sa.setValue(fieldBinding, value); } finally { sa.close(); } } catch (WireException e) { throw new AccessorException( e ); } } } class WireString extends WireAccessor implements StringAccessor { WireString(int accId, Datatype type, ChildReference ref) { super(accId, type, ref); } @Override public StringType type() { return (StringType) type; } @Override public String getValue() throws AccessorException { try { MutableVariant value = server.getValue(accId); return (String) value.getValue( Bindings.STRING ); } catch (WireException e) { throw new AccessorException( e ); } catch (AdaptException e) { throw new AccessorException( e ); } } @Override public void setValue(String newValue) throws AccessorException { Event e = new ValueAssigned( Bindings.STRING, newValue); Event[] list = new Event[] {e}; ApplyResult result = server.apply(accId, list, false); if (result.error != null) throw new AccessorException( result.error ); } } class WireUnion extends WireAccessor implements UnionAccessor { WireUnion(int accId, Datatype type, ChildReference ref) { super(accId, type, ref); } @Override public UnionType type() { return (UnionType) type; } @Override public int count() throws AccessorException { try { return server.size(accId); } catch (WireException e) { throw new AccessorException(e); } } @Override public int getTag() throws AccessorException { try { return server.getTag(accId); } catch (WireException e) { throw new AccessorException(e); } } @SuppressWarnings("unchecked") @Override public T getComponentAccessor() throws AccessorConstructionException { return (T) getComponent(new ComponentReference()); } @Override public Object getComponentValue(Binding componentBinding) throws AccessorException { try { WireAccessor sa = createAccessor( new ComponentReference() ); try { return sa.getValue(componentBinding); } finally { sa.close(); } } catch (WireException e) { throw new AccessorException( e ); } } @Override public void setComponentValue(int tag, Binding componentBinding, Object componentValue) throws AccessorException { try { WireAccessor sa = createAccessor( new ComponentReference() ); try { sa.setValue(componentBinding, componentValue); } finally { sa.close(); } } catch (WireException e) { throw new AccessorException( e ); } } } class WireVariant extends WireAccessor implements VariantAccessor { WireVariant(int accId, Datatype type, ChildReference ref) { super(accId, type, ref); } @Override public VariantType type() { return (VariantType) type; } @SuppressWarnings("unchecked") @Override public T getContentAccessor() throws AccessorConstructionException { return (T) getComponent(new ComponentReference()); } @Override public void setContentValue(Binding valueBinding, Object value) throws AccessorException { try { WireAccessor sa = createAccessor( new ComponentReference() ); try { sa.setValue(valueBinding, value); } finally { sa.close(); } } catch (WireException e) { throw new AccessorException( e ); } } @Override public Object getContentValue(Binding contentBinding) throws AccessorException { try { WireAccessor sa = createAccessor( new ComponentReference() ); try { return sa.getValue(contentBinding); } finally { sa.close(); } } catch (WireException e) { throw new AccessorException( e ); } } @Override public Datatype getContentType() throws AccessorException { try { WireAccessor sa = createAccessor( new ComponentReference() ); try { return sa.type(); } finally { sa.close(); } } catch (WireException e) { throw new AccessorException( e ); } } } }