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.accessor;
\r
14 import java.util.Collection;
\r
15 import java.util.LinkedList;
\r
16 import java.util.List;
\r
17 import java.util.concurrent.Executor;
\r
19 import org.simantics.databoard.Accessors;
\r
20 import org.simantics.databoard.accessor.binary.BinaryObject;
\r
21 import org.simantics.databoard.accessor.error.AccessorConstructionException;
\r
22 import org.simantics.databoard.accessor.error.AccessorException;
\r
23 import org.simantics.databoard.accessor.event.Event;
\r
24 import org.simantics.databoard.accessor.event.InvalidatedEvent;
\r
25 import org.simantics.databoard.accessor.impl.ChangeSet;
\r
26 import org.simantics.databoard.accessor.interestset.InterestSet;
\r
27 import org.simantics.databoard.accessor.java.JavaObject;
\r
28 import org.simantics.databoard.accessor.reference.ChildReference;
\r
29 import org.simantics.databoard.binding.Binding;
\r
30 import org.simantics.databoard.binding.error.BindingException;
\r
31 import org.simantics.databoard.type.Datatype;
\r
34 * Accessor is an interface to access, modify and monitor a data container.
\r
35 * The actual storage format and location is implementation specific.
\r
36 * For instance, container could be: a bunch of bytes, a Java object, a file,
\r
37 * a folder with files, a network location, or direct memory of a simulation
\r
40 * The structure is presentable with Databoard type system. The type can be
\r
41 * anything but a recursive structure.<p>
\r
43 * The listening model allows placing of listener objects to accessors.
\r
44 * Each listener is associated with a InterestSet. It describes a sub-tree of
\r
45 * nodes to listen and aspects to monitor. Accessors emit Events on modifications
\r
46 * of structure and value. There is a reference in each event, and it is relative
\r
47 * to the accessor where the listener was placed. For instance, a listener, that is
\r
48 * interested in whole tree, is placed on a root accessor. A modification at a
\r
49 * leaf-node spawns an event with a reference path from the root to the leaf.
\r
50 * If the listener was placed directly on the leaf, there wouldn't be a path
\r
51 * in the evenr object.<p>
\r
53 * Multi-thread-usage is implementation dependent, read the documentation. <p>
\r
55 * Construction and destruction model is also implementation dependent.
\r
56 * A rule of thumb in life management of objects is that, the party that
\r
57 * constructs an object must destroy it. Both construction and destruction of
\r
58 * the container are also outside the scope of the Accessor interface. <p>
\r
60 * However, as general implementation contract, the data container is disposed
\r
61 * as whole, individual nodes are not. While the container is alive, individual
\r
62 * nodes may be disposed using garbage collection mechanisms. Reference queue
\r
63 * mechanism is one implementatio strategy. More common strategy is usage of
\r
64 * weak references from parent to child. <p>
\r
67 * @see JavaObject Accessor to Java Object container
\r
68 * @see BinaryObject Accessor to a container in File or Memory
\r
69 * @see ArrayAccessor
\r
70 * @see BooleanAccessor
\r
71 * @see ByteAccessor
\r
72 * @see DoubleAccessor
\r
73 * @see FloatAccessor
\r
74 * @see IntegerAccessor
\r
77 * @see OptionalAccessor
\r
78 * @see RecordAccessor
\r
79 * @see StringAccessor
\r
80 * @see UnionAccessor
\r
81 * @see VariantAccessor
\r
82 * @author Toni Kalajainen (toni.kalajainen@iki.fi)
\r
84 public interface Accessor {
\r
87 * Get a snapshot of the object as a single data value. <p>
\r
88 * Accessor makes type adaption to users binding if possible. <p>
\r
92 * @throws AccessorException
\r
94 Object getValue(Binding binding) throws AccessorException;
\r
97 * Read a copy of the accessor's object into the <tt>obj</tt> instance. <p>
\r
98 * Accessor makes type adaption to users binding if possible. <p>
\r
101 * @param obj object to read the value to
\r
102 * @throws AccessorException
\r
104 void getValue(Binding binding, Object obj) throws AccessorException;
\r
107 * Read value in <tt>path</tt> reference into an <tt>obj</tt> instance. <p>
\r
109 * @param path component reference path or <code>null</code> to return _this_
\r
112 * @return true if value existed, false if not
\r
113 * @throws AccessorException
\r
115 boolean getValue(ChildReference path, Binding binding, Object obj) throws AccessorException;
\r
118 * Read value in <tt>path</tt> reference into an <tt>obj</tt> instance. <p>
\r
120 * @param path component reference path or <code>null</code> to return _this_ accessor
\r
123 * @return the object or <tt>null</tt> if value doesn't exist
\r
124 * @throws AccessorException
\r
126 Object getValue(ChildReference path, Binding binding) throws AccessorException;
\r
129 * Set a complete new value to the data container.
\r
130 * Accessor makes type adaption to users binding if possible. <p>
\r
132 * If the new value removes old map entries, array entries, optional value, or
\r
133 * changes union or variant value type, it will disengage any existing
\r
134 * sub-accessors and send {@link InvalidatedEvent}. <p>
\r
136 * Writing the current value again may not emit an event. This is implementation
\r
139 * Write is durable, once a the method returns successfully the value has been
\r
140 * stored in the implmentation. <p>
\r
144 * @throws BindingException binding error
\r
145 * @throws UnsupportedOperationException cannot set a new value
\r
147 void setValue(Binding binding, Object newValue) throws AccessorException;
\r
150 * Set value to <tt>path</tt> reference.
\r
152 * @param path component reference path or <code>null</code> to return _this_
\r
155 * @return true if value existed in the accessor, false if not
\r
156 * @throws AccessorException
\r
158 boolean setValue(ChildReference path, Binding binding, Object obj) throws AccessorException;
\r
161 * Open an accessor to a child. If one already exists, the existing is returned,
\r
162 * otherwise a new is created. Child accessors are often remembered with
\r
163 * weak reference.<p>
\r
165 * InvalidatedEvent is thrown from the accessor if it is unlinked from the
\r
166 * parent hierarchy. <p>
\r
168 * @param path component reference path or <code>null</code> to return _this_ accessor
\r
170 * @throws AccessorConstructionException
\r
172 <T extends Accessor> T getComponent(ChildReference path) throws AccessorConstructionException;
\r
175 * Apply a change set in a single transaction operation.
\r
177 * If rollback log is supplied, it is filled with reverse events.
\r
179 * If the operation fails, rollback log can be applied to cancel changes.
\r
182 * @param rollback log to be filled with rollback events or <code>null</code>
\r
183 * @throws AccessorException failed to apply change set
\r
185 void apply(List<Event> changeSet, LinkedList<Event> rollback) throws AccessorException;
\r
188 * Get structural represtentation of the accessor presented in databoard's
\r
191 * @return type description
\r
196 * Place a listener to an accessor node. The listener will be notified for changes
\r
197 * in the node/node tree, depending on interest set.<p>
\r
199 * When events are emited and in which thread processed is implementation
\r
200 * specific. It is also implementation specific, whether the object can be mutated
\r
201 * in the listener or whether it has to be done afterwards. <p>
\r
203 * In many implementations there is a pluggable event handling strategy
\r
204 * EventEmitter. The default behaviour is to emit events as they are
\r
205 * spawned in the current thread.<p>
\r
207 * There is a reference in each event instance that describes the path from
\r
208 * the accessor where listener was placed to the node to which the event
\r
211 * Listener is attached to the object that holds the value at the time at
\r
212 * the of the adding.
\r
213 * For example, If a listener is attached to an array of element at index 3,
\r
214 * and a new value is inserted at position 2, the listener still monitors the same
\r
215 * container, which is now at index 4. The references of incoming the events
\r
216 * are modified to have the new index.<p>
\r
218 * Also, if a new value is assigned to the parent of an object that is listened,
\r
219 * the listener keeps on monitoring the new value at the same reference.
\r
220 * This doesn't apply when a new value is set to a union of different tag,
\r
221 * to a variant with a new type, or value is removed from Optional type.
\r
222 * In these two cases the listener is invalidated.<p>
\r
224 * See {@link ChangeSet} is an implementation that collects events.
\r
226 * Executor argument determines the thread where the onEvents method is
\r
227 * handled. <tt>null</tt> argument denotes current thread.
\r
230 * @param interestSet
\r
231 * @param pathPrefix path to the accessor or <code>null</code>. This is used in the events the accessor produces
\r
233 * @see ChangeSet collects events
\r
235 void addListener(Listener listener, InterestSet interestSet, ChildReference pathPrefix, Executor executor) throws AccessorException;
\r
238 * Remove a listener. If the listener is added multiple times, the last
\r
239 * one added is removed.
\r
242 * @throws AccessorException
\r
244 void removeListener(Listener listener) throws AccessorException;
\r
247 * Accessor listener.
\r
249 * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
\r
251 public static interface Listener {
\r
254 * Notify the listener on a new event
\r
258 void onEvents(Collection<Event> events);
\r