1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2011 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.simulation.data;
\r
14 import java.util.ArrayList;
\r
15 import java.util.Collection;
\r
16 import java.util.HashSet;
\r
17 import java.util.List;
\r
18 import java.util.Set;
\r
19 import java.util.concurrent.Executor;
\r
20 import java.util.concurrent.locks.Lock;
\r
21 import java.util.concurrent.locks.ReentrantLock;
\r
22 import java.util.logging.Level;
\r
23 import java.util.logging.Logger;
\r
25 import org.simantics.databoard.Bindings;
\r
26 import org.simantics.databoard.accessor.error.AccessorException;
\r
27 import org.simantics.databoard.binding.Binding;
\r
28 import org.simantics.databoard.binding.NumberBinding;
\r
29 import org.simantics.databoard.type.Datatype;
\r
30 import org.simantics.history.Collector;
\r
31 import org.simantics.history.HistoryException;
\r
32 import org.simantics.history.util.subscription.SubscriptionItem;
\r
33 import org.simantics.simulation.data.Datasource.DatasourceListener;
\r
34 import org.simantics.utils.datastructures.Triple;
\r
37 * This adapter reads data from Datasource and writes to an open Subscription.
\r
38 * This class is used as a listener.
\r
40 * @author Toni Kalajainen <toni.kalajainen@semantum.fi>
\r
42 public class DatasourceAdapter implements DatasourceListener {
\r
44 protected Logger logger = Logger.getLogger( DatasourceAdapter.class.toString() );
\r
45 protected Collector session;
\r
46 protected boolean loaded = false;
\r
47 protected List<VariableHandle> handles = new ArrayList<VariableHandle>();
\r
48 protected List<String> ids = new ArrayList<String>();
\r
49 protected List<Binding> bindings = new ArrayList<Binding>();
\r
52 * Variables whose {@link VariableHandle#getValue()} has previously failed
\r
53 * and has been reported to have failed through {@link #logger}. Resetting
\r
54 * the adapter will also reset this set.
\r
56 protected Set<String> failedIds = new HashSet<String>();
\r
58 protected Lock stepLock = new ReentrantLock();
\r
61 * Create new adapter. Subscribed items are read from collector.
\r
63 * @param subscription
\r
65 public DatasourceAdapter(Collector subscription) {
\r
66 this.session = subscription;
\r
69 public void setSubscriptionSession(Collector session) {
\r
70 this.session = session;
\r
73 public Collector getSubscriptionSession() {
\r
77 public void flush() throws HistoryException {
\r
82 * @return the lock that is used for synchronizing each
\r
83 * {@link #onStep(Datasource)} invocation. The lock can be used
\r
84 * elsewhere to guarantee that history collection steps are not
\r
85 * taken meanwhile. For example, while setting up history
\r
88 public Lock stepLock() {
\r
93 * Reset internal caches. Call this when subscribed items in collector
\r
96 public void reset() {
\r
97 for (VariableHandle h : handles) if (h!=null) h.dispose();
\r
105 protected void load(Datasource source) {
\r
109 SubscriptionItem[] items = session.getItems();
\r
110 Set<String> idSet = new HashSet<String>(items.length);
\r
111 for (SubscriptionItem bean : items) {
\r
112 String variableId = (String) bean.getFieldUnchecked("variableId");
\r
113 if (!idSet.add( variableId )) continue;
\r
114 Datatype variableType = source.getType( variableId );
\r
115 if (variableType == null) continue;
\r
116 Binding valueBinding = Bindings.getBinding( variableType );
\r
117 VariableHandle handle = source.openHandle( bean, variableId, valueBinding );
\r
118 handles.add( handle );
\r
119 ids.add( variableId );
\r
120 bindings.add( valueBinding );
\r
125 protected void list(Collection<Triple<String,Binding,Object>> result, Collection<GraphHandle> graphHandles) {
\r
127 int c = ids.size();
\r
128 for (int i=0; i<c; i++) {
\r
129 String key = ids.get(i);
\r
130 VariableHandle handle = handles.get(i);
\r
131 Object value = null;
\r
132 if (handle != null) {
\r
133 if (handle instanceof GraphHandle) {
\r
134 graphHandles.add((GraphHandle)handle);
\r
137 value = handle.getValue();
\r
138 Binding binding = bindings.get(i);
\r
139 result.add(Triple.make(key, binding, value));
\r
140 } catch (AccessorException e) {
\r
141 if (failedIds.add(key))
\r
142 logger.log(Level.SEVERE, e.toString(), e);
\r
147 Binding binding = bindings.get(i);
\r
148 result.add(Triple.make(key, binding, value));
\r
154 public void onStep(Datasource source) {
\r
157 NumberBinding timeBinding = Bindings.DOUBLE;
\r
158 Object time = source.getTime( timeBinding );
\r
159 session.beginStep( timeBinding, time );
\r
161 if (!loaded) load( source );
\r
165 int c = ids.size();
\r
166 for (int i=0; i<c; i++) {
\r
167 String key = ids.get(i);
\r
168 VariableHandle handle = handles.get(i);
\r
169 Object value = null;
\r
170 if (handle != null) {
\r
172 value = handle.getValue();
\r
173 } catch (AccessorException e) {
\r
174 if (failedIds.add(key))
\r
175 logger.log(Level.SEVERE, e.toString(), e);
\r
178 Binding binding = handle.binding();
\r
180 session.setValue( key, binding, value );
\r
181 } catch (HistoryException e) {
\r
182 logger.log(Level.SEVERE, e.toString(), e);
\r
185 Binding binding = bindings.get(i);
\r
186 if (binding != null) {
\r
187 session.setValue( key, binding, value );
\r
195 } catch (HistoryException e) {
\r
196 logger.log(Level.SEVERE, e.toString(), e);
\r
199 } catch (HistoryException e) {
\r
200 logger.log(Level.SEVERE, e.toString(), e);
\r
207 public Executor getExecutor() {
\r