/* * 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.csstudio.dal.spi; import org.csstudio.dal.RemoteException; import org.csstudio.dal.context.AbstractApplicationContext; import org.csstudio.dal.context.Connectable; import org.csstudio.dal.context.ConnectionEvent; import org.csstudio.dal.context.ConnectionException; import org.csstudio.dal.context.ConnectionState; import org.csstudio.dal.context.DeviceFamily; import org.csstudio.dal.context.LinkBlocker; import org.csstudio.dal.context.LinkListener; import org.csstudio.dal.context.Linkable; import org.csstudio.dal.device.AbstractDevice; import org.csstudio.dal.impl.AbstractDeviceImpl; import org.csstudio.dal.impl.DeviceBean; import org.csstudio.dal.impl.DeviceFamilyImpl; import org.csstudio.dal.impl.SynchronizedDeviceFamilyImpl; import org.csstudio.dal.proxy.DeviceProxy; import org.csstudio.dal.proxy.DirectoryProxy; import org.csstudio.dal.simple.RemoteInfo; import javax.naming.NamingException; /** * This is default implementation of <code>DeviceFactory</code> interface which * uses common glue code classes to provide devices. Implementation of device factory * is enchouraged to extend from this class in order to minimize work and mentain * compatibility with common glue code approach. * * @author Igor Kriznar (igor.kriznarATcosylab.com) * */ public abstract class AbstractDeviceFactory extends AbstractFactorySupport implements DeviceFactory { private DeviceFamilyImpl<AbstractDevice> family; /** * Default contructor. * */ protected AbstractDeviceFactory() { family = new DeviceFamilyImpl<AbstractDevice>(this); } /* * (non-Javadoc) * @see org.csstudio.dal.spi.AbstractFactorySupport#initialize(org.csstudio.dal.context.AbstractApplicationContext, org.csstudio.dal.spi.LinkPolicy) */ @Override public void initialize(AbstractApplicationContext ctx, LinkPolicy policy) { super.initialize(ctx,policy); boolean sync = Boolean.parseBoolean(ctx.getConfiguration().getProperty(AbstractFactory.SYNCHRONIZE_FAMILY,"false")); if (sync) { family = new SynchronizedDeviceFamilyImpl<AbstractDevice>(this); } else { family = new DeviceFamilyImpl<AbstractDevice>(this); } } /* (non-Javadoc) * @see org.csstudio.dal.spi.DeviceFactory#getDevice(java.lang.String) */ @Override public AbstractDevice getDevice(String uniqueName) throws InstantiationException, RemoteException { return getDevice(uniqueName, AbstractDevice.class, null); } /* (non-Javadoc) * @see org.csstudio.dal.spi.DeviceFactory#getDevice(org.csstudio.dal.context.RemoteInfo) */ @Override public AbstractDevice getDevice(RemoteInfo ri) throws InstantiationException, RemoteException { return getDevice(ri.getRemoteName(), AbstractDevice.class, null); } /* (non-Javadoc) * @see org.csstudio.dal.spi.DeviceFactory#getDevice(java.lang.String, java.lang.Class, org.csstudio.dal.context.LinkListener) */ @Override public <D extends AbstractDevice> D getDevice(String uniqueName, Class<D> type, LinkListener<? extends Linkable> l) throws InstantiationException, RemoteException { return createDevice(uniqueName, type, l); } private <D extends AbstractDevice> D createDevice(String uniqueName, Class<D> type, LinkListener<? extends Linkable> l) throws InstantiationException, RemoteException { if (family.contains(uniqueName)) { return type.cast(family.get(uniqueName)); } try { // Creates device implementation Class<? extends AbstractDevice> impClass = getPlugInstance() .getDeviceImplementationClass(type,uniqueName); AbstractDeviceImpl device = (AbstractDeviceImpl)impClass.getConstructor(String.class,DeviceFamily.class) .newInstance(uniqueName,family); if (l != null) { device.addLinkListener(l); } if (linkPolicy != LinkPolicy.NO_LINK_POLICY) { connect(uniqueName, type, impClass, device); if (linkPolicy == LinkPolicy.SYNC_LINK_POLICY) { LinkBlocker.blockUntillConnected(device, Plugs.getConnectionTimeout(ctx.getConfiguration(), 30000) * 2, true); } } family.add(device); return type.cast(device); } catch (ConnectionException e) { throw e; } catch (Exception e) { throw new RemoteException(this, "Failed to instantiate IFC.", e); } } /** * Connects device implementation with device and directory proxy. * @param uniqueName * @param type * @param device * @throws ConnectionException */ private void connect(String uniqueName, Class<?extends AbstractDevice> type, Class<?extends AbstractDevice> implementationType, AbstractDeviceImpl device) throws ConnectionException { // creates proxy implementation DeviceProxy proxy = null; DirectoryProxy dir = null; try { Class<?extends DeviceProxy> proxyImplType = getPlugInstance() .getDeviceProxyImplementationClass(type,implementationType,uniqueName); proxy = getPlugInstance().getDeviceProxy(uniqueName, proxyImplType); if (proxy instanceof DirectoryProxy) { dir = (DirectoryProxy)proxy; } else { dir = getPlugInstance().getDirectoryProxy(uniqueName); } device.initialize(proxy, dir); // cleanup if something fails, we don't want to leave hanging proxies // exception is rethrown } catch (ConnectionException e) { if (proxy != null) { getPlugInstance().releaseProxy(proxy); } if (dir != null) { getPlugInstance().releaseProxy(dir); } throw e; } catch (RemoteException e) { if (proxy != null) { getPlugInstance().releaseProxy(proxy); } if (dir != null) { getPlugInstance().releaseProxy(dir); } throw new ConnectionException(this,"Failed to obtain implementation class.",e); } catch (RuntimeException e) { if (proxy != null) { getPlugInstance().releaseProxy(proxy); } if (dir != null) { getPlugInstance().releaseProxy(dir); } throw e; } } /* (non-Javadoc) * @see org.csstudio.dal.spi.DeviceFactory#getDevice(org.csstudio.dal.context.RemoteInfo, java.lang.Class, org.csstudio.dal.context.LinkListener) */ @Override public <D extends AbstractDevice> D getDevice(RemoteInfo ri, Class<D> type, LinkListener<?> l) throws InstantiationException, RemoteException { return getDevice(ri.getRemoteName(), type, l); } /* (non-Javadoc) * @see org.csstudio.dal.spi.DeviceFactory#asyncLinkDevice(org.csstudio.dal.context.RemoteInfo, org.csstudio.dal.context.LinkListener) */ @Override public RemoteInfo asyncLinkDevice(RemoteInfo name, Class<?extends AbstractDevice> type, LinkListener<?> l) throws InstantiationException, RemoteException { AbstractDeviceImpl device = (AbstractDeviceImpl)family.get(name .getRemoteName()); if (device == null) { try { // Creates device implementation Class<? extends AbstractDevice> impClass = getPlugInstance() .getDeviceImplementationClass(type,name.getRemoteName()); device = (AbstractDeviceImpl)impClass.getConstructor(String.class,DeviceFamily.class) .newInstance(name.getRemoteName(),family); connect(name.getRemoteName(), type, impClass, device); family.add(device); } catch (ConnectionException e) { throw e; } catch (Exception e) { throw new RemoteException(this, "Failed to instantiate IFC.", e); } } if (l != null) { device.addLinkListener(l); } if (device.isConnected()) { l.connected(new ConnectionEvent(device, ConnectionState.CONNECTED)); } else if (device.isConnectionFailed()) { l.connectionFailed(new ConnectionEvent(device, ConnectionState.CONNECTION_FAILED)); } return name; } /* (non-Javadoc) * @see org.csstudio.dal.spi.DeviceFactory#asyncLinkDevice(java.lang.String, org.csstudio.dal.context.LinkListener) */ @Override public RemoteInfo asyncLinkDevice(String name, Class<?extends AbstractDevice> type, LinkListener<?> l) throws InstantiationException, RemoteException { try { return asyncLinkDevice(getPlugInstance().createRemoteInfo(name), type, l); } catch (NamingException e) { throw new InstantiationException("Failed to construct RemoteInfo: " + e.getMessage()); } } /* (non-Javadoc) * @see org.csstudio.dal.spi.DeviceFactory#getDeviceFamily() */ @Override public DeviceFamily getDeviceFamily() { return family; } /* (non-Javadoc) * @see org.csstudio.dal.spi.DeviceFactory#reconnectDevice(org.csstudio.dal.device.AbstractDevice) */ @Override public void reconnectDevice(AbstractDevice device) throws ConnectionException { if (!Connectable.class.isAssignableFrom(device.getClass())) { throw new ConnectionException(device, "Device " + device.getUniqueName() + " is not Connectable."); } if (!DeviceBean.class.isAssignableFrom(device.getClass())) { throw new ConnectionException(device, "Device " + device.getUniqueName() + " is not DeviceBean based implementation."); } Connectable c = (Connectable)device; if (c.getConnectionState() != ConnectionState.READY) { throw new ConnectionException(device, "Device " + device.getUniqueName() + " is not in Ready mode, but in " + c.getConnectionState() + "."); } connect(device.getUniqueName(), (Class<?extends AbstractDevice>)device.getClass(), (Class<?extends AbstractDevice>)device.getClass(), (AbstractDeviceImpl)device); } @Override protected void destroyAll() { family.destroyAll(); } } /* __oOo__ */