/**
* Copyright 2011-2012 Universite Joseph Fourier, LIG, ADELE team
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package fr.imag.adele.apam.apform.impl;
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.extender.DeclarationBuilderService;
import org.apache.felix.ipojo.extender.DeclarationHandle;
import org.apache.felix.ipojo.metadata.Element;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
import fr.imag.adele.apam.Apam;
import fr.imag.adele.apam.apform.ApformComponent;
import fr.imag.adele.apam.declarations.InstanceDeclaration;
import fr.imag.adele.apam.impl.APAMImpl;
/**
* This class is used to represent an instance declaration
*
* This automatically creates a corresponding iPOJO instance declaration, using the Declaration
* Builder Service (available since iPOJO 1.11.2). The iPOJO instance declaration is published
* as long as this factory remains valid.
*
* TODO Technically this class should not really be an iPOJO component factory. This is just an
* implementation hack to reuse the iPOJO extender, to process APAM metadata. In the future we
* could use another mechanism to load APAM metadata at runtime, and create the appropriate iPOJO
* declarations using the the Declaration Builder Service API, but we need to evaluate the impact
* on build-time tools.
*
* @author vega
*
*/
public class ApamInstanceDeclaration extends ApamComponentFactory {
/**
* A dynamic reference to the iPOJO builder service
*/
protected BuilderTracker builderTracker;
/**
*The APAM bundle context used to look for the iPOJO builder
*/
protected BundleContext apamContext;
/**
* The iPOJO instance handle corresponding to this declaration
*/
private DeclarationHandle iPojoInstance;
/**
* Creates a new declaration
*/
public ApamInstanceDeclaration(BundleContext context, Element element) throws ConfigurationException {
super(context, element);
}
public InstanceDeclaration getDeclaration() {
return (InstanceDeclaration) super.getDeclaration();
}
@Override
protected boolean hasInstrumentedCode() {
return false;
}
@Override
protected boolean isInstantiable() {
return false;
}
@Override
protected ApformComponent createApform() {
return null;
}
/**
* Gets the class name.
*
* @return the class name.
* @see org.apache.felix.ipojo.IPojoFactory#getClassName()
*/
@Override
public String getClassName() {
return getDeclaration().getName();
}
@Override
public ApamInstanceManager createApamInstance(IPojoContext context, HandlerManager[] handlers) {
throw new UnsupportedOperationException("APAM instance declaration is not instantiable");
}
@Override
public synchronized void start() {
super.start();
if (iPojoInstance != null) {
iPojoInstance.publish();
}
}
@Override
public synchronized void stop() {
super.stop();
if (iPojoInstance != null) {
iPojoInstance.retract();
}
}
@Override
protected void bindToApam(Apam apam) {
/*
* We have just bound to APAM for the first time, or it has been updated,
* we force building a new instance declaration
*/
if (this.apamContext != APAMImpl.context) {
if (iPojoInstance != null) {
iPojoInstance.retract();
}
if (builderTracker != null) {
builderTracker.close();
}
iPojoInstance = null;
apamContext = APAMImpl.context;
builderTracker = new BuilderTracker(apamContext);
}
builderTracker.open();
}
@Override
protected void unbindFromApam(Apam apam) {
builderTracker.close();
}
/**
* A class to dynamically track the iPOJO builder implementation.
*
*/
private class BuilderTracker extends ServiceTracker {
public BuilderTracker(BundleContext apamContext) {
super(apamContext,DeclarationBuilderService.class.getName(),null);
}
@Override
public Object addingService(ServiceReference reference) {
if (iPojoInstance != null)
return null;
DeclarationBuilderService builder = (DeclarationBuilderService) super.addingService(reference);
/*
* Create the iPOJo instance declaration as soon as the builder is available.
*/
iPojoInstance = builder.newInstance(getDeclaration().getImplementation().getName(),getDeclaration().getName()).
context(getBundleContext()).
configure().property(ApamInstanceManager.ATT_DECLARATION, getDeclaration()).
build();
/*
* Publish it, this is necessary if this event arrives after this factory has been started
*/
if (ApamInstanceDeclaration.this.getState() == Factory.VALID)
iPojoInstance.publish();
return builder;
}
}
}