/*- * Copyright © 2009 Diamond Light Source Ltd. * * This file is part of GDA. * * GDA is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License version 3 as published by the Free * Software Foundation. * * GDA is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along * with GDA. If not, see <http://www.gnu.org/licenses/>. */ package uk.ac.gda.dal.dataprovider; import gda.device.DeviceException; import gda.device.Scannable; import gda.device.scannable.ScannablePositionChangeEvent; import gda.device.scannable.ScannableStatus; import gda.factory.Findable; import gda.factory.Finder; import gda.observable.IObserver; import java.util.ArrayList; import java.util.List; import java.util.Timer; import java.util.TimerTask; import org.csstudio.dal.Timestamp; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class ProvideDataRunnable<T> implements ProvideRunnable<T> { private static final Logger logger = LoggerFactory.getLogger(ProvideDataRunnable.class); private Scannable scannable; private boolean running = false; private IObserver observer = null; private static Timer timer = new Timer(); private TimerTask timerTask; private ProvideDataEvent<T> event = null; protected List<ProvideDataEventListener<T>> listeners = new ArrayList<ProvideDataEventListener<T>>(1); private long timeSinceLastBusy = 0; private boolean firstUpdate = true; @Override public T getCurrentValue() { return event != null ? event.value : null; } void setTargetValueT(final Object targetValue) { try { String reason = scannable.checkPositionValid(targetValue); if (reason == null || reason.isEmpty()) { Runnable x = new Runnable() { @Override public void run() { try { scannable.moveTo(targetValue); } catch (DeviceException e) { logger.error(e.getMessage(), e); } } }; Thread t = new Thread(x, "moveTo"); t.start(); } else logger.error("Unable to set " + scannable.getName() + " to " + targetValue + ":" + reason); } catch (DeviceException e) { logger.error(e.getMessage(), e); } } public ProvideDataRunnable(String scannableName) { int index = scannableName.indexOf("."); if (index != -1) scannableName = scannableName.substring(0, index); Findable findable = Finder.getInstance().find(scannableName); if (findable instanceof Scannable) { scannable = (Scannable) findable; scannable.addIObserver(observer = new IObserver() { @Override public void update(Object source, Object arg) { boolean scannableBusy = false; boolean scannableConnected = true; try { scannableBusy = scannable.isBusy(); scannableConnected=true; long currentTime = System.currentTimeMillis(); timeSinceLastBusy = currentTime-timeSinceLastBusy; } catch (DeviceException e) { logger.error("Error checking if scannable is busy", e); scannableConnected = false; } if(arg instanceof String && scannableConnected){ ProvideDataRunnable.this.readValAndUpdateListeners(); if (timerTask != null) timerTask.cancel(); timerTask = new TimerTask() { @Override public void run() { if (ProvideDataRunnable.this.observer != null) ProvideDataRunnable.this.observer.update(null, null); } }; timer.schedule(timerTask, 100); } readValAndUpdateListeners(); if ((scannableBusy || timeSinceLastBusy<10000000 || firstUpdate) && scannableConnected) { firstUpdate=false; if (source == null) { ProvideDataRunnable.this.readValAndUpdateListeners(); if (timerTask != null) timerTask.cancel(); timerTask = new TimerTask() { @Override public void run() { if (ProvideDataRunnable.this.observer != null) ProvideDataRunnable.this.observer.update(null, null); } }; timer.schedule(timerTask, 100); } else if (arg instanceof ScannableStatus) { TimerTask timerTaskScannableStatus = new TimerTask() { @Override public void run() { ProvideDataRunnable.this.observer.update(null, null); } }; timer.schedule(timerTaskScannableStatus, 100); } else if (arg instanceof ScannablePositionChangeEvent) updateListeners(((ScannablePositionChangeEvent) arg).newPosition); else if (arg instanceof Double) { TimerTask timerTaskDouble = new TimerTask() { @Override public void run() { if (ProvideDataRunnable.this.observer != null) ProvideDataRunnable.this.observer.update(null, null); } }; timer.schedule(timerTaskDouble, 100); } } } }); observer.update(null, null); running = true; } else { stop(); throw new RuntimeException("ProvideDataRunnable. " + scannableName + " is not a Scannable"); } } private void readValAndUpdateListeners() { try { updateListeners(scannable.getPosition()); } catch (DeviceException e) { logger.error(e.getMessage(), e); } } private void updateListeners(Object position) { event = new ProvideDataEvent<T>(); try { if (position != null) event.value = valueToType(position); } catch (Exception e) { logger.error(e.getMessage(), e); event = null; return; } event.timestamp = new Timestamp(); for (ProvideDataEventListener<T> listener : listeners) { try { listener.newData(event); } catch (Throwable e) { logger.error(e.getMessage(), e); } } } abstract T valueToType(Object val); @Override public void stop() { if (scannable != null && observer != null) { scannable.deleteIObserver(observer); observer = null; } running = false; } @Override public boolean isRunning() { return running; } @Override public void addListener(ProvideDataEventListener<T> newListener) { listeners.add(newListener); if (event != null) newListener.newData(event); } @Override public void removeListener(ProvideDataEventListener<T> listenerToRemove) { listeners.remove(listenerToRemove); } @Override public void refresh() { } }