/*
* Copyright (c) 2006 Stiftung Deutsches Elektronen-Synchroton,
* Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY.
*
* THIS SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "../AS IS" BASIS.
* WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR PARTICULAR PURPOSE AND
* NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
* THE USE OR OTHER DEALINGS IN THE SOFTWARE. SHOULD THE SOFTWARE PROVE DEFECTIVE
* IN ANY RESPECT, THE USER ASSUMES THE COST OF ANY NECESSARY SERVICING, REPAIR OR
* CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE.
* NO USE OF ANY SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
* DESY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
* OR MODIFICATIONS.
* THE FULL LICENSE SPECIFYING FOR THE SOFTWARE THE REDISTRIBUTION, MODIFICATION,
* USAGE AND OTHER RIGHTS AND OBLIGATIONS IS INCLUDED WITH THE DISTRIBUTION OF THIS
* PROJECT IN THE FILE LICENSE.HTML. IF THE LICENSE IS NOT INCLUDED YOU MAY FIND A COPY
* AT HTTP://WWW.DESY.DE/LEGAL/LICENSE.HTM
*/
/**
*
*/
package org.epics.css.dal.simulation;
import java.util.Properties;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import org.apache.log4j.Logger;
import org.csstudio.dal.CharacteristicInfo;
import org.csstudio.dal.DoubleProperty;
import org.csstudio.dal.EnumPropertyCharacteristics;
import org.csstudio.dal.NumericPropertyCharacteristics;
import org.csstudio.dal.PropertyCharacteristics;
import org.csstudio.dal.RemoteException;
import org.csstudio.dal.SequencePropertyCharacteristics;
import org.csstudio.dal.SimpleProperty;
import org.csstudio.dal.context.AbstractApplicationContext;
import org.csstudio.dal.context.ConnectionException;
import org.csstudio.dal.device.AbstractDevice;
import org.csstudio.dal.impl.AbstractDeviceImpl;
import org.csstudio.dal.impl.PropertyUtilities;
import org.csstudio.dal.proxy.AbstractPlug;
import org.csstudio.dal.proxy.DeviceProxy;
import org.csstudio.dal.proxy.DirectoryProxy;
import org.csstudio.dal.proxy.PropertyProxy;
import org.csstudio.dal.simple.impl.DataUtil;
import org.csstudio.dal.spi.Plugs;
import org.epics.css.dal.directory.DALDescriptor;
import org.epics.css.dal.directory.DescriptorType;
import org.epics.css.dal.directory.DeviceDescriptor;
import org.epics.css.dal.directory.DeviceDescriptorImpl;
import org.epics.css.dal.directory.DirectoryUtilities;
import org.epics.css.dal.simulation.ps.PowerSupplyImpl;
import com.cosylab.naming.URIName;
/**
* @author ikriznar
*
*/
public class SimulatorPlug extends AbstractPlug{
private ThreadPoolExecutor executor;
private Timer timer;
private DirContext simulatorContext;
public static final String PLUG_TYPE = Plugs.SIMULATOR_PLUG_TYPE;
public static final String SCHEME_SUFFIX = "Simulator";
public static final String DEFAULT_AUTHORITY = "DEFAULT";
private static SimulatorPlug instance;
class ScheduledTask extends TimerTask{
private Runnable r;
public ScheduledTask(Runnable r){
this.r = r;
}
@Override
public void run(){
try {
r.run();
} catch (Exception e) {
Logger.getLogger(this.getClass()).warn("Simulator error.", e);
}
}
}
public static SimulatorPlug getInstance(){
return getInstance((Properties)null);
}
public static synchronized SimulatorPlug getInstance(Properties conf){
if (instance == null)
instance = new SimulatorPlug(conf);
return instance;
}
public static synchronized SimulatorPlug getInstance(AbstractApplicationContext ctx){
return new SimulatorPlug(ctx);
}
/* (non-Javadoc)
* @see org.epics.css.dal.proxy.AbstractPlug#releaseInstance()
*/
@Override
public void releaseInstance() throws Exception {
// noop, since it is a singleton
}
protected SimulatorPlug(Properties configuration){
super(configuration);
}
public SimulatorPlug(AbstractApplicationContext ctx) {
super(ctx);
}
public void execute(Runnable r){
if (executor == null) {
synchronized (this) {
if (executor == null)
executor = new ThreadPoolExecutor(10,10,0,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
}
}
executor.execute(r);
}
public TimerTask schedule(Runnable r, long rate){
ScheduledTask t = new ScheduledTask(r);
if (timer == null) {
synchronized (this) {
if (timer == null)
timer = new Timer("SimulatorPlugTimer");
}
}
timer.scheduleAtFixedRate(t, 0, rate);
return t;
}
/* (non-Javadoc)
* @see org.epics.css.dal.proxy.AbstractPlug#createNewProxy(java.lang.String, java.lang.Class)
*/
@Override
protected <T extends PropertyProxy<?,?>> T createNewPropertyProxy(String uniqueName, Class<T> type) throws ConnectionException{
try {
if (type == PropertyProxy.class) {
@SuppressWarnings({ "unchecked", "rawtypes" })
PropertyProxyImpl<?> p = new PropertyProxyImpl(uniqueName,this,type);
putDirectoryProxyToCache(p);
return type.cast(p);
}
PropertyProxy<?,?> p = type.getConstructor(String.class,SimulatorPlug.class).newInstance(uniqueName,this);
// adding to directory cache as well
if (p instanceof DirectoryProxy)
putDirectoryProxyToCache((DirectoryProxy<?>)p);
return type.cast(p);
} catch (Exception e) {
throw new ConnectionException(this, "Failed to instantiate simulation proxy '" + uniqueName + "' for type '" + type.getName() + "'.", e);
}
}
/* (non-Javadoc)
* @see org.epics.css.dal.proxy.AbstractPlug#getPlugType()
*/
@Override
public String getPlugType(){
return PLUG_TYPE;
}
@Override
protected DirectoryProxy<?> createNewDirectoryProxy(String uniqueName){
throw new RuntimeException("Error in factory implementation, PropertyProxy must be created first.");
}
/* (non-Javadoc)
* @see org.epics.css.dal.proxy.AbstractPlug#createNewDeviceProxy(java.lang.String, java.lang.Class)
*/
@Override
protected <T extends DeviceProxy<?>> T createNewDeviceProxy(
String uniqueName, Class<T> type) throws ConnectionException{
try {
if (type == DeviceProxy.class) {
DeviceProxyImpl p = new DeviceProxyImpl(uniqueName,this);
putDirectoryProxyToCache(p);
return type.cast(p);
}
DeviceProxy<?> p = type.getConstructor(String.class,SimulatorPlug.class).newInstance(uniqueName,this);
// adding to directory cache as well
if (p instanceof DirectoryProxy)
putDirectoryProxyToCache((DirectoryProxy<?>)p);
return type.cast(p);
} catch (Exception e) {
throw new ConnectionException(this,
"Failed to instantiate simulation proxy '" + uniqueName
+ "' for type '" + type.getName() + "'.", e);
}
}
/*
* (non-Javadoc)
* @see org.epics.css.dal.proxy.AbstractPlug#getPropertyImplementationClass(java.lang.Class)
*/
@Override
public Class<?extends SimpleProperty<?>> getPropertyImplementationClass(Class<?extends SimpleProperty<?>> type, String propertyName) throws RemoteException{
if (type==null)
type= DoubleProperty.class;
Class<?extends SimpleProperty<?>> impl = super.getPropertyImplementationClass(type, propertyName);
if (impl == null)
return PropertyUtilities.getImplementationClass(type);
else
return impl;
}
/* (non-Javadoc)
* @see org.epics.css.dal.proxy.AbstractPlug#getDeviceImplementationClass(java.lang.String)
*/
@Override
protected Class<? extends AbstractDevice> getDeviceImplementationClass(String uniqueDeviceName) {
if (uniqueDeviceName.startsWith("PS"))
return PowerSupplyImpl.class;
if (uniqueDeviceName == "PowerSupply")
return PowerSupplyImpl.class;
return AbstractDeviceImpl.class;
}
/*
* (non-Javadoc)
* @see org.epics.css.dal.proxy.AbstractPlug#getPropertyProxyImplementationClass(java.lang.Class)
*/
@Override
public Class<?extends PropertyProxy<?,?>> getPropertyProxyImplementationClass(
Class<? extends SimpleProperty<?>> type, Class<? extends SimpleProperty <?>> implType, String propertyName) throws RemoteException{
Class<?extends PropertyProxy<?,?>> impl = super.getPropertyProxyImplementationClass(type,implType,propertyName);
if (impl == null)
return SimulatorUtilities.getPropertyProxyImplementationClass(type,implType);
else
return impl;
}
/* (non-Javadoc)
* @see org.epics.css.dal.proxy.AbstractPlug#getDeviceProxyImplementationClass(java.lang.Class, java.lang.Class, java.lang.String)
*/
@Override
public Class<? extends DeviceProxy<?>> getDeviceProxyImplementationClass(Class<? extends AbstractDevice> type, Class<? extends AbstractDevice> implementationType, String uniqueDeviceName) throws RemoteException {
Class<?extends DeviceProxy<?>> impl = super.getDeviceProxyImplementationClass(type, implementationType, uniqueDeviceName);
if (impl == null)
return SimulatorUtilities.getDeviceProxyImplementationClass(type);
else
return impl;
}
/**
* Returns simulated property proxy.
* @param uniqueName proxy name
* @return if exists returns simulated property proxy, otherwise <code>null</code>
*/
public PropertyProxyImpl<?> getSimulatedPropertyProxy(String uniqueName){
return (PropertyProxyImpl<?>)_getPropertyProxyFromCache(uniqueName);
}
/**
* Returns simulated device proxy.
* @param uniqueName proxy name
* @return if exists returns simulated device proxy, otherwise <code>null</code>
*/
public DeviceProxyImpl getSimulatedDeviceProxy(String uniqueName){
return (DeviceProxyImpl)_getDeviceProxyFromCache(uniqueName);
}
/* (non-Javadoc)
* @see org.epics.css.dal.context.PlugContext#getDefaultDirectory()
*/
@Override
public DirContext getDefaultDirectory(){
if (simulatorContext != null)
return simulatorContext;
try {
DirContext initialContext = DirectoryUtilities.getInitialContext();
URIName name = new URIName(org.csstudio.dal.simple.RemoteInfo.DAL_TYPE_PREFIX + SCHEME_SUFFIX,
null, null, null);
URIName nameS = (URIName)name.getPrefix(1);
Object simContext = initialContext.lookup(nameS);
if (simContext == null)
simulatorContext = (DirContext)initialContext.createSubcontext(nameS);
else
simulatorContext = (DirContext)simContext;
//bind proxy implementations
URIName ppi = new URIName(null, DEFAULT_AUTHORITY, "PropertyProxyImpl", null);
Attributes characteristics = new org.epics.css.dal.directory.Attributes();
characteristics.put(NumericPropertyCharacteristics.C_DESCRIPTION, "Simulated Property");
//characteristics.put(NumericPropertyCharacteristics.C_DISPLAY_NAME, name);
characteristics.put(NumericPropertyCharacteristics.C_POSITION, new Double(0));
characteristics.put(NumericPropertyCharacteristics.C_PROPERTY_TYPE, "property");
characteristics.put(NumericPropertyCharacteristics.C_RESOLUTION, 0xFFFF);
characteristics.put(NumericPropertyCharacteristics.C_SCALE_TYPE, "linear");
characteristics.put(NumericPropertyCharacteristics.C_UNITS, "amper");
simulatorContext.bind(ppi, new PropertyProxyImpl<Object>(ppi.toString(),null,Object.class), characteristics);
ppi = new URIName(null, DEFAULT_AUTHORITY, "DoublePropertyProxyImpl", null);
Attributes characteristicsD = new org.epics.css.dal.directory.Attributes();
characteristicsD.put(NumericPropertyCharacteristics.C_DESCRIPTION, "Simulated Property");
//characteristicsD.put(NumericPropertyCharacteristics.C_DISPLAY_NAME, name);
characteristicsD.put(NumericPropertyCharacteristics.C_POSITION, new Double(0));
characteristicsD.put(NumericPropertyCharacteristics.C_PROPERTY_TYPE, "property");
characteristicsD.put(NumericPropertyCharacteristics.C_RESOLUTION, 0xFFFF);
characteristicsD.put(NumericPropertyCharacteristics.C_SCALE_TYPE, "linear");
characteristicsD.put(NumericPropertyCharacteristics.C_UNITS, "amper");
characteristicsD.put(NumericPropertyCharacteristics.C_FORMAT, "%.4f");
characteristicsD.put(NumericPropertyCharacteristics.C_GRAPH_MAX, new Double(10));
characteristicsD.put(NumericPropertyCharacteristics.C_GRAPH_MIN, new Double(-10));
characteristicsD.put(NumericPropertyCharacteristics.C_MAXIMUM, new Double(10));
characteristicsD.put(NumericPropertyCharacteristics.C_MINIMUM, new Double(-10));
characteristicsD.put(NumericPropertyCharacteristics.C_WARNING_MAX, new Double(8));
characteristicsD.put(NumericPropertyCharacteristics.C_WARNING_MIN, new Double(-8));
characteristicsD.put(NumericPropertyCharacteristics.C_ALARM_MAX, new Double(9));
characteristicsD.put(NumericPropertyCharacteristics.C_ALARM_MIN, new Double(-9));
characteristicsD.put(CharacteristicInfo.C_META_DATA.getName(), DataUtil.createMetaData(characteristicsD));
simulatorContext.bind(ppi, new DoublePropertyProxyImpl(ppi.toString(),null), characteristicsD);
ppi = new URIName(null, DEFAULT_AUTHORITY, "DoubleSeqPropertyProxyImpl", null);
Attributes characteristicsDS = new org.epics.css.dal.directory.Attributes();
characteristicsDS.put(NumericPropertyCharacteristics.C_DESCRIPTION, "Simulated Property");
//characteristicsDS.put(NumericPropertyCharacteristics.C_DISPLAY_NAME, name);
characteristicsDS.put(NumericPropertyCharacteristics.C_POSITION, new Double(0));
characteristicsDS.put(NumericPropertyCharacteristics.C_PROPERTY_TYPE, "property");
characteristicsDS.put(NumericPropertyCharacteristics.C_RESOLUTION, 0xFFFF);
characteristicsDS.put(NumericPropertyCharacteristics.C_SCALE_TYPE, "linear");
characteristicsDS.put(NumericPropertyCharacteristics.C_UNITS, "amper");
characteristicsDS.put(NumericPropertyCharacteristics.C_FORMAT, "%.4f");
characteristicsDS.put(NumericPropertyCharacteristics.C_GRAPH_MAX, new Double(10));
characteristicsDS.put(NumericPropertyCharacteristics.C_GRAPH_MIN, new Double(-10));
characteristicsDS.put(NumericPropertyCharacteristics.C_MAXIMUM, new Double(10));
characteristicsDS.put(NumericPropertyCharacteristics.C_MINIMUM, new Double(-10));
characteristicsDS.put(NumericPropertyCharacteristics.C_WARNING_MAX, new Double(8));
characteristicsDS.put(NumericPropertyCharacteristics.C_WARNING_MIN, new Double(-8));
characteristicsDS.put(NumericPropertyCharacteristics.C_ALARM_MAX, new Double(9));
characteristicsDS.put(NumericPropertyCharacteristics.C_ALARM_MIN, new Double(-9));
characteristicsDS.put(SequencePropertyCharacteristics.C_SEQUENCE_LENGTH, new Integer(5));
characteristicsDS.put(CharacteristicInfo.C_META_DATA.getName(), DataUtil.createMetaData(characteristicsDS));
simulatorContext.bind(ppi, new DoubleSeqPropertyProxyImpl(ppi.toString(),null), characteristicsDS);
ppi = new URIName(null, DEFAULT_AUTHORITY, "LongPropertyProxyImpl", null);
Attributes characteristicsL = new org.epics.css.dal.directory.Attributes();
characteristicsL.put(NumericPropertyCharacteristics.C_DESCRIPTION, "Simulated Property");
//characteristicsL.put(NumericPropertyCharacteristics.C_DISPLAY_NAME, name);
characteristicsL.put(NumericPropertyCharacteristics.C_POSITION, new Double(0));
characteristicsL.put(NumericPropertyCharacteristics.C_PROPERTY_TYPE, "property");
characteristicsL.put(NumericPropertyCharacteristics.C_RESOLUTION, 0xFFFF);
characteristicsL.put(NumericPropertyCharacteristics.C_SCALE_TYPE, "linear");
characteristicsL.put(NumericPropertyCharacteristics.C_UNITS, "amper");
characteristicsL.put(NumericPropertyCharacteristics.C_FORMAT, "%d");
characteristicsL.put(NumericPropertyCharacteristics.C_GRAPH_MAX, new Long(10));
characteristicsL.put(NumericPropertyCharacteristics.C_GRAPH_MIN, new Long(-10));
characteristicsL.put(NumericPropertyCharacteristics.C_MAXIMUM, new Long(10));
characteristicsL.put(NumericPropertyCharacteristics.C_MINIMUM, new Long(-10));
characteristicsL.put(NumericPropertyCharacteristics.C_WARNING_MAX, new Long(8));
characteristicsL.put(NumericPropertyCharacteristics.C_WARNING_MIN, new Long(-8));
characteristicsL.put(NumericPropertyCharacteristics.C_ALARM_MAX, new Long(9));
characteristicsL.put(NumericPropertyCharacteristics.C_ALARM_MIN, new Long(-9));
characteristicsL.put(CharacteristicInfo.C_META_DATA.getName(), DataUtil.createMetaData(characteristicsL));
simulatorContext.bind(ppi, new LongPropertyProxyImpl(ppi.toString(),null), characteristicsL);
ppi = new URIName(null, DEFAULT_AUTHORITY, "EnumPropertyProxyImpl", null);
Attributes characteristicsEN = new org.epics.css.dal.directory.Attributes();
characteristicsEN.put(NumericPropertyCharacteristics.C_DESCRIPTION, "Simulated Property");
//characteristicsEN.put(NumericPropertyCharacteristics.C_DISPLAY_NAME, name);
characteristicsEN.put(NumericPropertyCharacteristics.C_POSITION, new Double(0));
characteristicsEN.put(NumericPropertyCharacteristics.C_PROPERTY_TYPE, "property");
characteristicsEN.put(NumericPropertyCharacteristics.C_RESOLUTION, 0xFFFF);
characteristicsEN.put(NumericPropertyCharacteristics.C_SCALE_TYPE, "linear");
characteristicsEN.put(NumericPropertyCharacteristics.C_UNITS, "amper");
characteristicsEN.put(NumericPropertyCharacteristics.C_FORMAT, "%d");
characteristicsEN.put(NumericPropertyCharacteristics.C_GRAPH_MAX, new Long(3));
characteristicsEN.put(NumericPropertyCharacteristics.C_GRAPH_MIN, new Long(0));
characteristicsEN.put(NumericPropertyCharacteristics.C_MAXIMUM, new Long(3));
characteristicsEN.put(NumericPropertyCharacteristics.C_MINIMUM, new Long(0));
characteristicsEN.put(EnumPropertyCharacteristics.C_ENUM_DESCRIPTIONS, new String[]{ "On", "Off", "not connected" });
characteristicsEN.put(EnumPropertyCharacteristics.C_ENUM_VALUES, new Double[]{ 1.1, 1.2, 1.3 });
characteristicsEN.put(CharacteristicInfo.C_META_DATA.getName(), DataUtil.createMetaData(characteristicsEN));
simulatorContext.bind(ppi, new EnumPropertyProxyImpl(ppi.toString(),null), characteristicsEN);
ppi = new URIName(null, DEFAULT_AUTHORITY, "StringPropertyProxyImpl", null);
Attributes characteristicsS = new org.epics.css.dal.directory.Attributes();
characteristicsS.put(PropertyCharacteristics.C_DESCRIPTION, "Simulated Property");
characteristicsS.put(PropertyCharacteristics.C_POSITION, new Double(0));
characteristicsS.put(PropertyCharacteristics.C_PROPERTY_TYPE, "property");
simulatorContext.bind(ppi, new StringPropertyProxyImpl(ppi.toString(), this), characteristicsS);
//add devices
for (int i = 0; i < 5; i++) {
String uniqueName = "test/PS" + i;
URIName uri = new URIName(null, null, uniqueName, null);
DeviceDescriptor desc = new DeviceDescriptorImpl();
desc.setName(uniqueName);
desc.setClassType(AbstractDevice.class);
desc.putAttributeValue(DALDescriptor.DESCRIPTOR_TYPE, DescriptorType.DEVICE);
simulatorContext.bind(uri, desc);
}
return simulatorContext;
} catch (NamingException e) {
throw new RuntimeException("Failed to instantiate context.", e);
}
}
@Override
public org.csstudio.dal.simple.RemoteInfo createRemoteInfo(String uniqueName) throws NamingException{
return new org.csstudio.dal.simple.RemoteInfo(PLUG_TYPE, uniqueName, null, null);
}
@Override
protected Class<? extends SimpleProperty<?>> getPropertyImplementationClass(String uniquePropertyName) {
return null;
}
@Override
protected Class<? extends PropertyProxy<?,?>> getPropertyProxyImplementationClass(String uniquePropertyName) {
return null;
}
/* (non-Javadoc)
* @see org.epics.css.dal.proxy.AbstractPlug#getDeviceProxyImplementationClass(java.lang.String)
*/
@Override
protected Class<? extends DeviceProxy<?>> getDeviceProxyImplementationClass(String uniqueDeviceName) {
// TODO Auto-generated method stub
return null;
}
public DeviceProxy<?> getDeviceProxyFromCache1(String uniqueName) {
DeviceProxy<?> proxy = super._getDeviceProxyFromCache(uniqueName);
return proxy;
}
public DirectoryProxy<?> getDirectoryProxyFromCache1(String uniqueName) {
DirectoryProxy<?> proxy = super._getDirectoryProxyFromCache(uniqueName);
return proxy;
}
}