/*
* 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.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.csstudio.dal.context.AbstractApplicationContext;
import org.csstudio.dal.context.LifecycleEvent;
import org.csstudio.dal.context.LifecycleListener;
import org.csstudio.dal.proxy.AbstractPlug;
import java.util.Properties;
import javax.naming.directory.DirContext;
/**
* This is convenience implementation of common factory code.
*
* <p>
* This class implements plug sharing behaviour. By default plug instance is shared.
* There are two ways to for plug or application control plug sharing:
* </p>
* <ul>
* <li>Constructor AbstractFactorySupport(boolean) is used and factory implementation actively
* decides for only one option: or is plug share or not. Plug sharing can not be changed later
* trough application configuration.</li>
* <li>Sharing of plug is enabled or disabled with parameter provided with configuration with
* application context. This is possible if this factory is created with default constructor.</li>
* </ul>
*
* <p>If plug is not shared, then plug instance will be created using application
* context as constructor parameter.</p>
*
*
* @see AbstractFactorySupport#AbstractFactorySupport(boolean)
* @see AbstractFactory#SHARE_PLUG
*
* @author Igor Kriznar (igor.kriznarATcosylab.com)
*
*/
public abstract class AbstractFactorySupport implements AbstractFactory
{
protected AbstractApplicationContext ctx;
protected LinkPolicy linkPolicy;
private AbstractPlug plug;
protected LifecycleListener lifecycleListener = new LifecycleListenerImpl();
protected Boolean plugShared;
protected boolean propertiesCached=false;
private class LifecycleListenerImpl implements LifecycleListener
{
@Override
public void destroying(LifecycleEvent event)
{
destroyAll();
try
{
if (plug != null)
plug.releaseInstance();
} catch (Throwable e) {
if (plug != null) {
plug.getLogger().log(null, Level.WARN, "Unable to release factory.",e);
} else {
Logger.getLogger(this.getClass()).warn("Unable to release factory.", e);
}
}
}
@Override
public void destroyed(LifecycleEvent event)
{
}
@Override
public void initialized(LifecycleEvent event)
{
}
@Override
public void initializing(LifecycleEvent event)
{
}
}
/**
* Default constructor. Plug sharing option is provided with application context or default
* sharing policy is used.
*/
protected AbstractFactorySupport()
{
}
/**
* Constructor for those DAL implementations, which want to force from code plug factory to
* share or not share
*
*/
protected AbstractFactorySupport(boolean plugShared)
{
this.plugShared=plugShared;
}
/**
* Must destroy all created objects
*
*/
protected abstract void destroyAll();
/**
* Must return plug implemntation class, which extends <code>AbstractPlug</code>.
* @return plug implemntation class
*/
protected abstract Class<?extends AbstractPlug> getPlugClass();
/**
* Returns instance of plug, which must be used by this factory. Plug is created if necessary.
* @return instance of plug dedicated to this factory.
*/
protected synchronized AbstractPlug getPlugInstance(){
if (plug == null) {
if (plugShared !=null && !plugShared)
try {
plug = (AbstractPlug)getPlugClass()
.getMethod("getInstance", new Class[]{ AbstractApplicationContext.class })
.invoke(null, new Object[]{ ctx });
} catch (Exception e) {
Logger.getLogger(this.getClass()).debug("Heuristic plug instantiation failed, another try available.", e);
}
if (plug == null) {
try {
plug = (AbstractPlug)getPlugClass()
.getMethod("getInstance", new Class[]{ Properties.class })
.invoke(null, new Object[]{ ctx.getConfiguration() });
} catch (Exception e) {
Logger.getLogger(this.getClass()).fatal("Heuristic plug instantiation failed twice.", e);
throw new RuntimeException("Plug '" + getPlugClass()
+ "' is not correctly implemented. ", e);
}
}
}
return plug;
}
/* (non-Javadoc)
* @see org.csstudio.dal.spi.DeviceFactory#getLinkPolicy()
*/
@Override
public LinkPolicy getLinkPolicy()
{
return linkPolicy;
}
/* (non-Javadoc)
* @see org.csstudio.dal.spi.DeviceFactory#getApplicationContext()
*/
@Override
public AbstractApplicationContext getApplicationContext()
{
return ctx;
}
/**
* @see org.csstudio.dal.spi.DeviceFactory#initialize(org.csstudio.dal.context.AbstractApplicationContext, org.csstudio.dal.spi.LinkPolicy)
*/
@Override
public void initialize(AbstractApplicationContext ctx, LinkPolicy policy)
{
if (this.ctx!=null) {
throw new IllegalStateException("Factory is already initialized.");
}
this.ctx = ctx;
this.linkPolicy = policy;
ctx.addLifecycleListener(lifecycleListener);
if (plugShared==null) {
String s= ctx.getConfiguration().getProperty(SHARE_PLUG);
if (s != null) {
plugShared=Boolean.valueOf(s);
}
}
String s= ctx.getConfiguration().getProperty(Plugs.PROPERTIES_FROM_CACHE);
if (s !=null) {
propertiesCached= Boolean.parseBoolean(s);
}
}
/* (non-Javadoc)
* @see org.csstudio.dal.spi.DeviceFactory#getPlugType()
*/
@Override
public String getPlugType()
{
return getPlugInstance().getPlugType();
}
/* (non-Javadoc)
* @see org.csstudio.dal.spi.DeviceFactory#getDefaultDirectory()
*/
@Override
public DirContext getDefaultDirectory()
{
return getPlugInstance().getDefaultDirectory();
}
/**
* Return plug which is used for connection. If this factory serves as facade for multiple plugs,
* than default plug must be returned.
*
* @return plug which is used for connection
*/
@Override
public AbstractPlug getPlug()
{
return getPlugInstance();
}
/**
* Return <code>true</code> if this factory is sharing plug instance with other factories.
* Default DAL implementation is using shared plug instance if possible. This way
* all connections are shared among different factories and applications within same JVM.
* @return <code>true</code> if this factory is sharing plug instance with other factories
*/
@Override
public boolean isPlugShared() {
// TODO Auto-generated method stub
return false;
}
}
/* __oOo__ */