/*
* 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 java.util.HashSet;
import java.util.Set;
import javax.naming.NamingException;
import org.apache.log4j.Logger;
import org.csstudio.dal.DynamicValueProperty;
import org.csstudio.dal.RemoteException;
import org.csstudio.dal.SimpleProperty;
import org.csstudio.dal.context.AbstractApplicationContext;
import org.csstudio.dal.context.ConnectionException;
import org.csstudio.dal.context.LinkBlocker;
import org.csstudio.dal.context.LinkListener;
import org.csstudio.dal.context.PropertyContext;
import org.csstudio.dal.context.PropertyFamily;
import org.csstudio.dal.impl.DynamicValuePropertyImpl;
import org.csstudio.dal.impl.PropertyFamilyImpl;
import org.csstudio.dal.impl.SynchronizedPropertyFamilyImpl;
import org.csstudio.dal.proxy.DirectoryProxy;
import org.csstudio.dal.proxy.PropertyProxy;
import org.csstudio.dal.simple.RemoteInfo;
/**
* @author ikriznar
*
*/
public abstract class AbstractPropertyFactory extends AbstractFactorySupport implements PropertyFactory{
private PropertyFamilyImpl family;
private Set<String> connecting;
/**
* Default constructor.
*/
protected AbstractPropertyFactory(){
super();
family = new PropertyFamilyImpl(this);
connecting= new HashSet<String>();
}
/*
* (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 SynchronizedPropertyFamilyImpl(this);
else
family = new PropertyFamilyImpl(this);
}
/* (non-Javadoc)
* @see org.csstudio.dal.spi.PropertyFactory#getProperty(java.lang.String)
*/
@Override
public DynamicValueProperty<?> getProperty(String uniqueName)throws InstantiationException, RemoteException{
return createProperty(uniqueName, null, null);
}
/* (non-Javadoc)
* @see org.csstudio.dal.spi.PropertyFactory#getProperty(org.csstudio.dal.context.RemoteInfo)
*/
@Override
public DynamicValueProperty<?> getProperty(RemoteInfo ri) throws InstantiationException, RemoteException{
String plugType = ri.getPlugType();
return createProperty(ri.getRemoteName(), null, null);
}
private DynamicValueProperty<?> createProperty (String uniqueName, Class<? extends DynamicValueProperty<?>> type, LinkListener<?> l) throws RemoteException{
String uid= uniqueName+type;
if (propertiesCached) {
DynamicValueProperty<?> p = getFromFamily(uniqueName, type);
if (p!=null)
return p;
synchronized (this) {
long timer= System.currentTimeMillis();
while (connecting.contains(uid) && System.currentTimeMillis()-timer<60000) {
try {
wait(60000);
} catch (InterruptedException e) {
Logger.getLogger(this.getClass()).debug("Wait interrupted.", e);
}
}
p = getFromFamily(uniqueName, type);
if (p!=null)
return p;
connecting.add(uid);
}
}
try {
// Creates device implementation
Class<?extends SimpleProperty<?>> impClass = getPlugInstance().getPropertyImplementationClass(type, uniqueName);
DynamicValuePropertyImpl<?> property = (DynamicValuePropertyImpl<?>)impClass.getConstructor(String.class, PropertyContext.class).newInstance(uniqueName, family);
if (l != null)
property.addLinkListener(l);
if (linkPolicy != LinkPolicy.NO_LINK_POLICY) {
connect(uniqueName, type,impClass, property);
if (linkPolicy == LinkPolicy.SYNC_LINK_POLICY)
LinkBlocker.blockUntillConnected(property, Plugs.getConnectionTimeout(ctx.getConfiguration(), 30000) * 2, true);
}
family.add(property);
return property;
} catch (ConnectionException e) {
throw e;
} catch (Exception e) {
throw new RemoteException(this, "Failed to instantiate '"+uniqueName+"'.", e);
} finally {
if (propertiesCached) {
synchronized (this) {
connecting.remove(uid);
this.notifyAll();
}
}
}
}
/**
* Tries to get property from family (cache).
* @param uniqueName
* @param type
* @return property if found, otherwise null
*/
private DynamicValueProperty<?> getFromFamily(String uniqueName, Class<? extends DynamicValueProperty<?>> type) {
if (type == null)
return family.getFirst(uniqueName);
return family.getFirst(uniqueName,type);
}
/* (non-Javadoc)
* @see org.csstudio.dal.spi.PropertyFactory#getProperty(java.lang.String, java.lang.Class, org.csstudio.dal.context.LinkListener)
*/
@Override
public <P extends DynamicValueProperty<?>> P getProperty(String uniqueName, Class<P> type, LinkListener<?> l) throws InstantiationException, RemoteException{
if (type == null)
throw new IllegalArgumentException("type may not be null");
return type.cast(createProperty(uniqueName,type,l));
}
/* (non-Javadoc)
* @see org.csstudio.dal.spi.PropertyFactory#getProperty(org.csstudio.dal.context.RemoteInfo, java.lang.Class, org.csstudio.dal.context.LinkListener)
*/
@Override
public <P extends DynamicValueProperty<?>> P getProperty(RemoteInfo ri, Class<P> type, LinkListener<?> l) throws InstantiationException, RemoteException{
return getProperty(ri.getRemoteName(), type, l);
}
/* (non-Javadoc)
* @see org.csstudio.dal.spi.PropertyFactory#asyncLinkProperty(org.csstudio.dal.context.RemoteInfo, org.csstudio.dal.context.LinkListener)
*/
@Override
public RemoteInfo asyncLinkProperty(RemoteInfo name, Class<?extends DynamicValueProperty<?>> type, LinkListener<?> l) throws InstantiationException, RemoteException{
String uid= name.getRemoteName()+type;
DynamicValuePropertyImpl<?> property = null;
if (propertiesCached) {
property= (DynamicValuePropertyImpl<?>)getFromFamily(name.getRemoteName(), type);
if (property==null) {
synchronized (this) {
long timer= System.currentTimeMillis();
while (connecting.contains(uid) && System.currentTimeMillis()-timer<60000) {
try {
wait(60000);
} catch (InterruptedException e) {
Logger.getLogger(this.getClass()).debug("Wait interrupted.", e);
}
}
property= (DynamicValuePropertyImpl<?>)getFromFamily(name.getRemoteName(), type);
if (property==null)
connecting.add(uid);
}
}
}
try {
Class<?extends SimpleProperty<?>> impClass = getPlugInstance().getPropertyImplementationClass(type, name.getRemoteName());
boolean newProp= false;
if (property == null) {
// Creates device implementation
try {
property = (DynamicValuePropertyImpl<?>)impClass.getConstructor(String.class, PropertyContext.class).newInstance(name.getRemoteName(), family);
family.add(property);
newProp=true;
} catch (Exception e) {
throw new RemoteException(this, "Failed to instantiate '"+name+"'.", e);
}
}
if (l != null)
property.addLinkListener(l);
if (newProp) {
try {
connect(name.getRemoteName(),type, impClass, property);
} catch (ConnectionException e) {
throw e;
}
}
return name;
} finally {
if (propertiesCached) {
synchronized (this) {
connecting.remove(uid);
this.notifyAll();
}
}
}
}
/* (non-Javadoc)
* @see org.csstudio.dal.spi.PropertyFactory#asyncLinkProperty(java.lang.String, org.csstudio.dal.context.LinkListener)
*/
@Override
public RemoteInfo asyncLinkProperty(String name, Class<?extends DynamicValueProperty<?>> type, LinkListener<?> l) throws InstantiationException, RemoteException{
try {
return asyncLinkProperty(getPlugInstance().createRemoteInfo(name),
type, l);
} catch (NamingException e) {
throw new InstantiationException("Failed to construct RemoteInfo: "
+ e.getMessage());
}
}
/* (non-Javadoc)
* @see org.csstudio.dal.spi.PropertyFactory#getPropertyFamily()
*/
@Override
public PropertyFamily getPropertyFamily(){
return family;
}
/**
* Connects device implementation with device and directory proxy.
* @param uniqueName
* @param type
* @param device
* @throws ConnectionException
*/
private void connect(String uniqueName, Class<?extends SimpleProperty<?>> type, Class<?extends SimpleProperty<?>> implementationType, DynamicValuePropertyImpl<?> property)throws ConnectionException{
// creates proxy implementation
PropertyProxy proxy = null;
DirectoryProxy<?> dir = null;
try {
Class<?extends PropertyProxy<?,?>> proxyImplType = getPlugInstance().getPropertyProxyImplementationClass(type, implementationType, uniqueName);
proxy = getPlugInstance().getPropertyProxy(uniqueName, proxyImplType);
if (proxy instanceof DirectoryProxy)
dir = (DirectoryProxy<?>)proxy;
else
dir = getPlugInstance().getDirectoryProxy(uniqueName);
property.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;
}
}
@Override
protected void destroyAll(){
family.destroyAll();
}
}