/******************************************************************************* * 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; import java.util.Collection; import java.util.LinkedList; import java.util.List; import java.util.concurrent.Executor; import org.simantics.databoard.Accessors; import org.simantics.databoard.accessor.binary.BinaryObject; import org.simantics.databoard.accessor.error.AccessorConstructionException; import org.simantics.databoard.accessor.error.AccessorException; import org.simantics.databoard.accessor.event.Event; import org.simantics.databoard.accessor.event.InvalidatedEvent; import org.simantics.databoard.accessor.impl.ChangeSet; import org.simantics.databoard.accessor.interestset.InterestSet; import org.simantics.databoard.accessor.java.JavaObject; import org.simantics.databoard.accessor.reference.ChildReference; import org.simantics.databoard.binding.Binding; import org.simantics.databoard.binding.error.BindingException; import org.simantics.databoard.type.Datatype; /** * Accessor is an interface to access, modify and monitor a data container. * The actual storage format and location is implementation specific. * For instance, container could be: a bunch of bytes, a Java object, a file, * a folder with files, a network location, or direct memory of a simulation * experiment.
* * The structure is presentable with Databoard type system. The type can be * anything but a recursive structure.
* * The listening model allows placing of listener objects to accessors. * Each listener is associated with a InterestSet. It describes a sub-tree of * nodes to listen and aspects to monitor. Accessors emit Events on modifications * of structure and value. There is a reference in each event, and it is relative * to the accessor where the listener was placed. For instance, a listener, that is * interested in whole tree, is placed on a root accessor. A modification at a * leaf-node spawns an event with a reference path from the root to the leaf. * If the listener was placed directly on the leaf, there wouldn't be a path * in the evenr object.
* * Multi-thread-usage is implementation dependent, read the documentation.
* * Construction and destruction model is also implementation dependent. * A rule of thumb in life management of objects is that, the party that * constructs an object must destroy it. Both construction and destruction of * the container are also outside the scope of the Accessor interface.
* * However, as general implementation contract, the data container is disposed * as whole, individual nodes are not. While the container is alive, individual * nodes may be disposed using garbage collection mechanisms. Reference queue * mechanism is one implementatio strategy. More common strategy is usage of * weak references from parent to child.
* * @see Accessors * @see JavaObject Accessor to Java Object container * @see BinaryObject Accessor to a container in File or Memory * @see ArrayAccessor * @see BooleanAccessor * @see ByteAccessor * @see DoubleAccessor * @see FloatAccessor * @see IntegerAccessor * @see LongAccessor * @see MapAccessor * @see OptionalAccessor * @see RecordAccessor * @see StringAccessor * @see UnionAccessor * @see VariantAccessor * @author Toni Kalajainen (toni.kalajainen@iki.fi) */ public interface Accessor { /** * Get a snapshot of the object as a single data value.
* Accessor makes type adaption to users binding if possible.
* * @param binding * @return the value * @throws AccessorException */ Object getValue(Binding binding) throws AccessorException; /** * Read a copy of the accessor's object into the obj instance.
* Accessor makes type adaption to users binding if possible.
* * @param binding * @param obj object to read the value to * @throws AccessorException */ void getValue(Binding binding, Object obj) throws AccessorException; /** * Read value in path reference into an obj instance.
*
* @param path component reference path or null
to return _this_
* @param binding
* @param obj
* @return true if value existed, false if not
* @throws AccessorException
*/
boolean getValue(ChildReference path, Binding binding, Object obj) throws AccessorException;
/**
* Read value in path reference into an obj instance.
*
* @param path component reference path or null
to return _this_ accessor
* @param binding
* @param obj
* @return the object or null if value doesn't exist
* @throws AccessorException
*/
Object getValue(ChildReference path, Binding binding) throws AccessorException;
/**
* Set a complete new value to the data container.
* Accessor makes type adaption to users binding if possible.
* * If the new value removes old map entries, array entries, optional value, or * changes union or variant value type, it will disengage any existing * sub-accessors and send {@link InvalidatedEvent}.
* * Writing the current value again may not emit an event. This is implementation * specific.
* * Write is durable, once a the method returns successfully the value has been * stored in the implmentation.
*
* @param binding
* @param newValue
* @throws BindingException binding error
* @throws UnsupportedOperationException cannot set a new value
*/
void setValue(Binding binding, Object newValue) throws AccessorException;
/**
* Set value to path reference.
*
* @param path component reference path or null
to return _this_
* @param binding
* @param obj
* @return true if value existed in the accessor, false if not
* @throws AccessorException
*/
boolean setValue(ChildReference path, Binding binding, Object obj) throws AccessorException;
/**
* Open an accessor to a child. If one already exists, the existing is returned,
* otherwise a new is created. Child accessors are often remembered with
* weak reference.
* * InvalidatedEvent is thrown from the accessor if it is unlinked from the * parent hierarchy.
*
* @param path component reference path or
*
* When events are emited and in which thread processed is implementation
* specific. It is also implementation specific, whether the object can be mutated
* in the listener or whether it has to be done afterwards.
*
* In many implementations there is a pluggable event handling strategy
* EventEmitter. The default behaviour is to emit events as they are
* spawned in the current thread.
*
* There is a reference in each event instance that describes the path from
* the accessor where listener was placed to the node to which the event
* applies to.
*
* Listener is attached to the object that holds the value at the time at
* the of the adding.
* For example, If a listener is attached to an array of element at index 3,
* and a new value is inserted at position 2, the listener still monitors the same
* container, which is now at index 4. The references of incoming the events
* are modified to have the new index.
*
* Also, if a new value is assigned to the parent of an object that is listened,
* the listener keeps on monitoring the new value at the same reference.
* This doesn't apply when a new value is set to a union of different tag,
* to a variant with a new type, or value is removed from Optional type.
* In these two cases the listener is invalidated.
*
* See {@link ChangeSet} is an implementation that collects events.
*
* Executor argument determines the thread where the onEvents method is
* handled. null argument denotes current thread.
*
* @param listener
* @param interestSet
* @param pathPrefix path to the accessor or null
to return _this_ accessor
* @return accessor
* @throws AccessorConstructionException
*/
null
* @throws AccessorException failed to apply change set
*/
void apply(Listnull
. This is used in the events the accessor produces
* @param executor
* @see ChangeSet collects events
*/
void addListener(Listener listener, InterestSet interestSet, ChildReference pathPrefix, Executor executor) throws AccessorException;
/**
* Remove a listener. If the listener is added multiple times, the last
* one added is removed.
*
* @param listener
* @throws AccessorException
*/
void removeListener(Listener listener) throws AccessorException;
/**
* Accessor listener.
*
* @author Toni Kalajainen