package org.epics.css.dal.simulation; import java.util.HashMap; import java.util.Map; import java.util.Properties; import java.util.Timer; import java.util.TimerTask; import org.apache.log4j.Logger; import org.csstudio.dal.DataExchangeException; import org.csstudio.dal.DoubleProperty; import org.csstudio.dal.RemoteException; import org.csstudio.dal.Request; import org.csstudio.dal.ResponseListener; import org.csstudio.dal.SimpleProperty; import org.csstudio.dal.context.ConnectionException; import org.csstudio.dal.context.ConnectionState; import org.csstudio.dal.device.PowerSupply; import org.csstudio.dal.impl.AbstractDeviceImpl; import org.csstudio.dal.impl.DoublePropertyImpl; import org.csstudio.dal.impl.RequestImpl; import org.csstudio.dal.impl.ResponseImpl; import org.csstudio.dal.proxy.AbstractPropertyProxyImpl; import org.csstudio.dal.proxy.AbstractProxyImpl; import org.csstudio.dal.proxy.CommandProxy; import org.csstudio.dal.proxy.DeviceProxy; import org.csstudio.dal.proxy.DirectoryProxy; import org.csstudio.dal.proxy.MonitorProxy; import org.csstudio.dal.proxy.PropertyProxy; import org.csstudio.dal.proxy.SyncPropertyProxy; import org.epics.css.dal.simulation.ps.PowerSupplyImpl; /** * An instance of simulator plug which provides separate Directory and Property Proxies. * <p><code>For testing purposes only</code></p> * * @author <a href="mailto:jaka.bobnar@cosylab.com">Jaka Bobnar</a> * */ public class MultipleProxySimulatorPlug extends SimulatorPlug { public static class MonitorProxyI<T> extends RequestImpl<T> implements MonitorProxy, Runnable{ protected SinglePropertyProxyImpl<T> proxy; protected long timerTrigger = 1000; protected boolean heartbeat = true; protected TimerTask task; protected boolean destroyed = false; public MonitorProxyI(SinglePropertyProxyImpl<T> source, ResponseListener<T> l) { super(source, l); this.proxy = source; proxy.addMonitor(this); resetTimer(); } public void reInitialize(SinglePropertyProxyImpl<T> proxy) throws RemoteException{ this.source = proxy; this.proxy = proxy; } /* (non-Javadoc) * @see org.epics.css.dal.proxy.MonitorProxy#getRequest() */ @Override public Request<T> getRequest(){ return this; } /* (non-Javadoc) * @see org.epics.css.dal.SimpleMonitor#getTimerTrigger() */ @Override public long getTimerTrigger() throws DataExchangeException{ return timerTrigger; } /* (non-Javadoc) * @see org.epics.css.dal.SimpleMonitor#setTimerTrigger(long) */ @Override public void setTimerTrigger(long trigger)throws DataExchangeException, UnsupportedOperationException{ timerTrigger = trigger; resetTimer(); } /* (non-Javadoc) * @see org.epics.css.dal.SimpleMonitor#setHeartbeat(boolean) */ @Override public void setHeartbeat(boolean heartbeat)throws DataExchangeException, UnsupportedOperationException{ this.heartbeat = heartbeat; resetTimer(); } /* (non-Javadoc) * @see org.epics.css.dal.SimpleMonitor#isHeartbeat() */ @Override public boolean isHeartbeat(){ return heartbeat; } /* (non-Javadoc) * @see org.epics.css.dal.SimpleMonitor#getDefaultTimerTrigger() */ @Override public long getDefaultTimerTrigger() throws DataExchangeException{ return 1000; } /* (non-Javadoc) * @see org.epics.css.dal.SimpleMonitor#isDefault() */ @Override public boolean isDefault(){ return true; } private void fireValueEvent(){ try { ResponseImpl<T> r = new ResponseImpl<T>(proxy, this, proxy.getValueSync(), "value", true, null, proxy.getCondition(), null, false); addResponse(r); } catch (DataExchangeException e) { Logger.getLogger(this.getClass()).warn("Simulator error.", e); } } /** * Fires value change event if monitor is not in heartbeat mode. */ public void fireValueChange(){ if (!heartbeat) fireValueEvent(); } /** * Run method executed at schedulet time intervals. */ @Override public void run(){ fireValueEvent(); } private synchronized void resetTimer(){ if (task != null) task.cancel(); if (heartbeat) task = MultipleProxySimulatorPlug.getInstance().schedule(this, timerTrigger); } /* (non-Javadoc) * @see org.epics.css.dal.SimpleMonitor#destroy() */ @Override public void destroy(){ if (task != null) task.cancel(); destroyed = true; proxy.removeMonitor(this); } /* (non-Javadoc) * @see org.epics.css.dal.SimpleMonitor#isDestroyed() */ @Override public boolean isDestroyed(){ return destroyed; } @Override public void refresh(){ // Override in order to clean up cached values. } } public static class DoublePropertyProxyImpl extends SinglePropertyProxyImpl<Double> { public DoublePropertyProxyImpl(String name, MultipleProxySimulatorPlug plug) { super(name,plug); // TODO Auto-generated constructor stub } } public static class SinglePropertyProxyImpl<E> extends AbstractPropertyProxyImpl<E, MultipleProxySimulatorPlug, MonitorProxyI<E>> implements PropertyProxy<E,MultipleProxySimulatorPlug>,SyncPropertyProxy<E,MultipleProxySimulatorPlug> { protected ValueProvider<E> valueProvider = new MemoryValueProvider<E>(); protected boolean isSettable = true; public SinglePropertyProxyImpl(String name, MultipleProxySimulatorPlug plug) { super(name,plug); setConnectionState(ConnectionState.READY); delayedConnect(1000); } public void refresh() { // TODO Auto-generated method stub } @Override public Request<? extends Object> getCharacteristics( String[] characteristics, ResponseListener<? extends Object> callback) throws DataExchangeException { // TODO Auto-generated method stub return null; } @Override protected Object processCharacteristicAfterCache(Object value, String characteristicName) { return value; } public String[] getCharacteristicNames() throws DataExchangeException { // TODO Auto-generated method stub return null; } @Override protected Object processCharacteristicBeforeCache(Object value, String characteristicName) { return value; } public void delayedConnect(long timeout){ setConnectionState(ConnectionState.CONNECTING); if (timeout > 0) { Timer t = new Timer(); t.schedule(new TimerTask() { @Override public void run(){ setConnectionState(ConnectionState.CONNECTED); } }, timeout); } else { setConnectionState(ConnectionState.CONNECTED); } } @Override public MonitorProxy createMonitor(ResponseListener<E> callback, Map<String,Object> p) throws RemoteException { MonitorProxyI<E> m = new MonitorProxyI<E>(this, callback); return m; } @Override public Request<E> getValueAsync(ResponseListener<E> callback) throws DataExchangeException { if (getConnectionState() != ConnectionState.CONNECTED) { throw new DataExchangeException(this, "Proxy not connected"); } RequestImpl<E> r = new RequestImpl<E>(this, callback); r.addResponse(new ResponseImpl<E>(this, r, valueProvider.get(), "value", true, null, getCondition(), null, true)); return r; } @Override public boolean isSettable() { return isSettable; } @Override public Request<E> setValueAsync(E value, ResponseListener<E> callback) throws DataExchangeException { if (getConnectionState() != ConnectionState.CONNECTED) throw new DataExchangeException(this, "Proxy not connected"); setValueSync(value); RequestImpl<E> r = new RequestImpl<E>(this, callback); r.addResponse(new ResponseImpl<E>(this, r, value, "", true, null, getCondition(), null, true)); return r; } @Override public E getValueSync() throws DataExchangeException { if (getConnectionState() != ConnectionState.CONNECTED) throw new DataExchangeException(this, "Proxy not connected"); return (E)valueProvider.get(); } @Override public void setValueSync(E value) throws DataExchangeException { if (getConnectionState() != ConnectionState.CONNECTED) throw new DataExchangeException(this, "Proxy not connected"); valueProvider.set(value); MonitorProxyImpl<?>[] m = getMonitors().toArray(new MonitorProxyImpl[getMonitors().size()]); for (int i = 0; i < m.length; i++) m[i].fireValueChange(); } } public static class SingleDeviceProxyImpl extends AbstractProxyImpl<MultipleProxySimulatorPlug> implements DeviceProxy<MultipleProxySimulatorPlug> { protected MultipleProxySimulatorPlug plug; protected Map<String, DirectoryProxy<MultipleProxySimulatorPlug>> directoryProxies; protected Map<String, PropertyProxy<?,MultipleProxySimulatorPlug>> propertyProxies; protected Map<String, CommandProxy> commands = new HashMap<String, CommandProxy>(); protected Map<String, Class<?extends SimpleProperty<?>>> propertyTypes = new HashMap<String, Class<? extends SimpleProperty<?>>>(); public SingleDeviceProxyImpl(String name, MultipleProxySimulatorPlug plug) { super(name,plug); this.plug = MultipleProxySimulatorPlug.getInstance(); setConnectionState(ConnectionState.READY); delayedConnect(2000); } public void delayedConnect(long timeout){ setConnectionState(ConnectionState.CONNECTING); if (timeout > 0) { Timer t = new Timer(); t.schedule(new TimerTask() { @Override public void run(){ setConnectionState(ConnectionState.CONNECTED); } }, timeout); } else setConnectionState(ConnectionState.CONNECTED); } @Override public CommandProxy getCommand(String name) throws RemoteException { return commands.get(name); } @Override @SuppressWarnings("unchecked") public DirectoryProxy<MultipleProxySimulatorPlug> getDirectoryProxy(String name) throws RemoteException { if (directoryProxies == null) directoryProxies = new HashMap<String, DirectoryProxy<MultipleProxySimulatorPlug>>(3); DirectoryProxy<MultipleProxySimulatorPlug> p = directoryProxies.get(name); if (p != null) return p; p = (DirectoryProxy<MultipleProxySimulatorPlug>) plug.getDirectoryProxy(this.name + '/' + name); directoryProxies.put(name, p); return p; } @Override @SuppressWarnings("unchecked") public PropertyProxy<?,MultipleProxySimulatorPlug> getPropertyProxy(String name) throws RemoteException { if (propertyProxies == null) propertyProxies = new HashMap<String, PropertyProxy<?,MultipleProxySimulatorPlug>>(3); PropertyProxy<?,MultipleProxySimulatorPlug> p = propertyProxies.get(name); if (p != null) return p; p = (PropertyProxy<?, MultipleProxySimulatorPlug>) plug.getPropertyProxy(this.name + '/' + name, plug.getPropertyProxyImplementationClass(getPropertyType(name),null,name)); propertyProxies.put(name, p); return p; } @Override public void refresh() { // TODO Auto-generated method stub } public Class<?extends SimpleProperty<?>> getPropertyType(String propertyName){ return propertyTypes.get(propertyName); } } private static MultipleProxySimulatorPlug instance; public static final MultipleProxySimulatorPlug getInstance(){ return getInstance((Properties)null); } public static final synchronized MultipleProxySimulatorPlug getInstance(Properties conf){ if (instance == null) instance = new MultipleProxySimulatorPlug(conf); return instance; } protected MultipleProxySimulatorPlug(Properties configuration) { super(configuration); registerPropertyProxyImplementationClass(DoublePropertyImpl.class, DoublePropertyProxyImpl.class); registerPropertyProxyImplementationClass(DoubleProperty.class, DoublePropertyProxyImpl.class); registerDeviceImplementationClass(PowerSupply.class, PowerSupplyImpl.class); registerDeviceProxyImplementationClass(PowerSupply.class, SingleDeviceProxyImpl.class); registerDeviceProxyImplementationClass(PowerSupplyImpl.class, SingleDeviceProxyImpl.class); registerDeviceProxyImplementationClass(AbstractDeviceImpl.class, SingleDeviceProxyImpl.class); } @Override protected DirectoryProxy<MultipleProxySimulatorPlug> createNewDirectoryProxy(String uniqueName) { try { PropertyProxyImpl<?> proxy = new PropertyProxyImpl<Object>(uniqueName,this,Object.class); return (DirectoryProxy)proxy; } catch (Exception e) { Logger.getLogger(this.getClass()).warn("Simulator error.", e); } return null; } @Override protected <TT extends PropertyProxy<?,?>> TT createNewPropertyProxy(String uniqueName, Class<TT> type) throws ConnectionException { try { if (type == DoublePropertyProxyImpl.class) { return type.cast(new DoublePropertyProxyImpl(uniqueName,this)); } SinglePropertyProxyImpl p = new SinglePropertyProxyImpl(uniqueName,this); return type.cast(p); } catch (Exception e) { throw new ConnectionException(this, "Failed to instantiate simulation proxy '" + uniqueName + "' for type '" + type.getName() + "'.", e); } } @Override protected <T extends DeviceProxy<?>> T createNewDeviceProxy(String uniqueName, Class<T> type) throws ConnectionException { try { SingleDeviceProxyImpl p = new SingleDeviceProxyImpl(uniqueName,this); return type.cast(p); } catch (Exception e) { throw new ConnectionException(this, "Failed to instantiate simulation proxy '" + uniqueName + "' for type '" + type.getName() + "'.", e); } } }