package fr.imag.adele.apam.apform.impl;
import java.util.Map;
import java.util.Properties;
import org.apache.felix.ipojo.ConfigurationException;
import org.apache.felix.ipojo.Factory;
import org.apache.felix.ipojo.HandlerManager;
import org.apache.felix.ipojo.IPojoContext;
import org.apache.felix.ipojo.metadata.Element;
import org.osgi.framework.BundleContext;
import fr.imag.adele.apam.Apam;
import fr.imag.adele.apam.CST;
import fr.imag.adele.apam.Implementation;
import fr.imag.adele.apam.apform.Apform2Apam;
import fr.imag.adele.apam.apform.ApformImplementation;
import fr.imag.adele.apam.apform.ApformInstance;
import fr.imag.adele.apam.declarations.ImplementationDeclaration;
import fr.imag.adele.apam.impl.ComponentImpl;
import fr.imag.adele.apam.impl.ComponentImpl.InvalidConfiguration;
public abstract class ApamImplementationFactory extends ApamComponentFactory {
public ApamImplementationFactory(BundleContext context, Element element) throws ConfigurationException {
super(context,element);
}
@Override
protected boolean isInstantiable() {
return true;
}
/**
* Get the associated Apform component
*/
public ApformImplementation getApform() {
return (ApformImplementation) this.apform;
}
public ImplementationDeclaration getDeclaration() {
return (ImplementationDeclaration)declaration;
}
/**
* Register this component with APAM
*/
protected final void bindToApam(Apam apam) {
Apform2Apam.newImplementation(getApform());
}
/**
* Creates a new native APAM instance, if this component represents an instantiable entity.
*/
protected ApamInstanceManager createApamInstance(IPojoContext context, HandlerManager[] handlers) {
return new ApamInstanceManager(this, isCreatedByApam(), context, handlers);
}
/**
* Whether the instance is being created using the APAM API or using the iPOJO API
*
* NOTE There are slight difference in both cases that are handled in class ApamInstanceManager.
* Specifically, when the iPOJO API is used, the component instance in APAM is created asynchronously
* to avoid blocking the calling thread.
*/
private final boolean isCreatedByApam() {
return createdByApam.get();
}
/**
* Thread local variable used to determine which API was used (APAM or directly iPOJO)
*/
private final ThreadLocal<Boolean> createdByApam = new ThreadLocal<Boolean>() {
@Override
protected Boolean initialValue() {
return false;
};
};
/**
* Must be used by subclasses to signal that the APAM API is used
*/
private final void beginApamCreation() {
createdByApam.set(true);
}
/**
* Must be used by subclasses to signal that the APAM API is used
*/
private final void endApamCreation() {
createdByApam.set(false);
}
/**
* This class represents the base functionality of Apform mediation object between APAM and a implementation factory
*/
protected abstract class Apform<I extends Implementation, D extends ImplementationDeclaration> extends ApamComponentFactory.Apform<I,D> implements ApformImplementation {
public Apform() {
super();
}
/**
* Creates an instance of the factory, and initialize its properties with the set of
* provided properties.
*
* NOTE this method is called when an instance is created by the APAM platform (explicitly
* by the API or implicitly by a relation resolution)
*
*/
@Override
public ApformInstance createInstance(Map<String, String> initialProperties) throws InvalidConfiguration {
try {
ApamInstanceManager instance = null;
try {
beginApamCreation();
instance = (ApamInstanceManager) createComponentInstance(initializeConfiguration(initialProperties));
} finally {
endApamCreation();
}
return instance.getApform();
} catch (Exception cause) {
throw new ComponentImpl.InvalidConfiguration(cause);
}
}
/**
* Creates an instance of the factory, and register it directly with APAM.
*
* This method can be used by external services (like device discovery protocols) to create instances
* in APAM that are not the result of a resolution.
*/
@Override
public ApformInstance addDiscoveredInstance(Map<String,Object> initialProperties) throws InvalidConfiguration, UnsupportedOperationException {
try {
ApamInstanceManager instance = (ApamInstanceManager) createComponentInstance(initializeConfiguration(initialProperties));
return instance.getApform();
} catch (Exception cause) {
throw new ComponentImpl.InvalidConfiguration(cause);
}
}
/**
* Handle special properties initialized in the configuration
*/
private Properties initializeConfiguration(Map<String,?> initialProperties) {
Properties configuration = new Properties();
if (initialProperties == null)
return configuration;
configuration.putAll(initialProperties);
/*
* Get the name of the component from the initial properties, and translate to
* the iPOJO convention
*/
Object name = configuration.remove(CST.NAME);
if (name != null) {
configuration.put(Factory.INSTANCE_NAME_PROPERTY, name);
}
return configuration;
}
}
}