/**
* 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.impl;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fr.imag.adele.apam.ApamManagers;
import fr.imag.adele.apam.CST;
import fr.imag.adele.apam.Component;
import fr.imag.adele.apam.Composite;
import fr.imag.adele.apam.CompositeType;
import fr.imag.adele.apam.Implementation;
import fr.imag.adele.apam.Instance;
import fr.imag.adele.apam.Specification;
import fr.imag.adele.apam.apform.ApformImplementation;
import fr.imag.adele.apam.apform.ApformInstance;
import fr.imag.adele.apam.declarations.ComponentKind;
import fr.imag.adele.apam.declarations.CompositeDeclaration;
import fr.imag.adele.apam.declarations.ImplementationDeclaration;
import fr.imag.adele.apam.declarations.references.components.ImplementationReference;
import fr.imag.adele.apam.declarations.references.resources.ResourceReference;
import fr.imag.adele.apam.util.Visible;
public class ImplementationImpl extends ComponentImpl implements Implementation {
/**
* This class represents the Apam root implementation.
*
* This is an APAM concept without mapping at the execution platform level,
* we build an special apform object to represent it.
*
*/
private static class SystemRootImplementation extends BaseApformComponent<CompositeType, ImplementationDeclaration> implements ApformImplementation {
public SystemRootImplementation(String name) {
super(new CompositeDeclaration(name, null, new ImplementationReference<ImplementationDeclaration>("Root Main Implem")));
}
@Override
public ApformInstance addDiscoveredInstance(Map<String, Object> configuration) throws InvalidConfiguration, UnsupportedOperationException {
throw new UnsupportedOperationException("method not available in root type");
}
@Override
public ApformInstance createInstance(Map<String, String> initialproperties) {
throw new UnsupportedOperationException("method not available in root type");
}
@Override
public boolean remLink(Component destInst, String depName) {
throw new UnsupportedOperationException("method not available in root type");
}
@Override
public void setApamComponent(Component apamComponent) {
throw new UnsupportedOperationException("method not available in root type");
}
@Override
public boolean setLink(Component destInst, String depName) {
throw new UnsupportedOperationException("method not available in root type");
}
@Override
public void setProperty(String attr, String value) {
throw new UnsupportedOperationException("method not available in root type");
}
}
private static Logger logger = LoggerFactory.getLogger(ImplementationImpl.class);
private static final long serialVersionUID = 1L;
// composite in which it is contained
private Set<CompositeType> inComposites = Collections.newSetFromMap(new ConcurrentHashMap<CompositeType, Boolean>());
// The specification this implementation implements
protected Specification mySpec;
// // all relationship use and their reverse
// private Set<Implementation> uses = Collections.newSetFromMap(new
// ConcurrentHashMap<Implementation, Boolean>());
// private Set<Implementation> invUses = Collections.newSetFromMap(new
// ConcurrentHashMap<Implementation, Boolean>());
// the instances
private Set<Instance> instances = Collections.newSetFromMap(new ConcurrentHashMap<Instance, Boolean>());
/**
* Builds a new Apam implementation to represent the specified platform
* implementation in the Apam model.
*/
protected ImplementationImpl(CompositeType composite, ApformImplementation apfImpl) throws InvalidConfiguration {
super(apfImpl);
ImplementationDeclaration declaration = apfImpl.getDeclaration();
/*
* Reference the declared provided specification
*/
if (declaration.getSpecification() != null) {
String specificationName = declaration.getSpecification().getName();
Specification specification = CST.componentBroker.getSpec(specificationName);
assert specification != null;
mySpec = specification;
}
/*
* If the implementation does not provides explicitly any specification,
* we build a dummy specification to allow the resolution algorithm to
* access the provided resources of this implementation
*/
if (mySpec == null) {
mySpec = CST.componentBroker.createSpec(declaration.getName() + "_spec", declaration.getProvidedResources(), (Map<String, String>) null);
}
/*
* Reference the enclosing composite type
*/
addInComposites(composite);
}
/**
* This is an special constructor only used for the root type of the system
*/
protected ImplementationImpl(String name) throws InvalidConfiguration {
super(new SystemRootImplementation(name));
mySpec = CST.componentBroker.createSpec(name + "_spec", new HashSet<ResourceReference>(), null);
}
public void addInComposites(CompositeType compo) {
inComposites.add(compo);
}
// WARNING : no control ! Only called by instance registration.
public void addInst(Instance instance) {
assert instance != null && !instances.contains(instance);
instances.add(instance);
}
/**
* If this implementation can be instantiated in the specified composite
*/
public boolean canBeInstantiatedIn(Composite composite) {
return Visible.isVisibleIn(composite, this);
}
/**
* From an implementation, create an instance. Creates both the apform and
* APAM instances. Can be called from the API.
*
* Must check if source composite can instantiate this implementation.
*/
@Override
public Instance createInstance(Composite composite, Map<String, String> initialProperties) {
if ((composite != null) && !this.canBeInstantiatedIn(composite)) {
logger.error("cannot instantiate " + this + ". It is not visible from composite " + composite);
return null;
}
if (composite == null) {
composite = CompositeImpl.getRootAllComposites();
}
/*
* Create and register the object in the APAM state model
*/
Instance instance = null;
try {
instance = instantiate(composite, initialProperties);
((InstanceImpl) instance).register(initialProperties);
setInstantiateFails(false);
return instance;
} catch (InvalidConfiguration configurationError) {
/*
* TODO this should be done in method register, we should try to have some form
* of atomic registration that includes registration and addition in the broker
*/
if (instance != null) {
if (CST.componentBroker.getComponent(instance.getName()) != null) {
/*
* If creation failed after broker registration, undo registration
*/
((ComponentBrokerImpl) CST.componentBroker).disappearedComponent(instance);
}
else {
/*
* The instance was partially created, just undo registration
*/
((ComponentImpl)instance).unregister();
}
}
logger.error("Error instantiating implementation " + this.getName() + ": exception registering instance in APAM " + configurationError.getMessage());
//to avoid trying again when attempting a resolution.
setInstantiateFails(true);
}
return null;
}
@Override
public ApformImplementation getApformImpl() {
return (ApformImplementation) getApformComponent();
}
@Override
public Component getGroup() {
return mySpec;
}
@Override
public ImplementationDeclaration getImplDeclaration() {
return (ImplementationDeclaration) getDeclaration();
}
@Override
public Set<CompositeType> getInCompositeType() {
return Collections.unmodifiableSet(inComposites);
}
/**
* returns the first instance only.
*/
@Override
public Instance getInst() {
if (instances.size() == 0) {
return null;
}
return (Instance) instances.toArray()[0];
}
@Override
public Instance getInst(String targetName) {
if (targetName == null) {
return null;
}
for (Instance inst : instances) {
if (inst.getName().equals(targetName)) {
return inst;
}
}
return null;
}
@Override
public Set<Instance> getInsts() {
return Collections.unmodifiableSet(instances);
}
@Override
public ComponentKind getKind() {
return ComponentKind.IMPLEMENTATION;
}
@Override
public Set<? extends Component> getMembers() {
return Collections.unmodifiableSet(instances);
}
@Override
public Specification getSpec() {
return mySpec;
}
/**
* Create a new instance from this implementation in Apam and in the
* underlying execution platform.
*
* WARNING The created Apam instance is not automatically published in the
* Apam state, nor added to the list of instances of this implementation.
* This is actually done when the returned instance is registered by the
* caller of this method.
*
* This method is not intended to be used as external API.
*/
protected Instance instantiate(Composite composite, Map<String, String> initialProperties) throws InvalidConfiguration {
if (!this.isInternalInstantiable()) {
throw new InvalidConfiguration("Implementation " + this + " is not instantiable");
}
if (this.isSingleton() && !instances.isEmpty()) {
throw new InvalidConfiguration("Implementation " + this + " is a singleton and an instance exists");
}
return reify(composite, getApformImpl().createInstance(initialProperties));
}
@Override
public boolean isUsed() {
return !inComposites.contains(CompositeTypeImpl.getRootCompositeType()) && inComposites.size() == 1;
}
@Override
public void register(Map<String, String> initialProperties) throws InvalidConfiguration {
/*
* Opposite references from specification and enclosing composite type
*/
((SpecificationImpl) mySpec).addImpl(this);
for (CompositeType inComposite : inComposites) {
((CompositeTypeImpl) inComposite).addImpl(this);
}
/*
* Terminates the initialization, and computes properties
*/
finishInitialize(initialProperties);
/*
* Add to broker
*/
((ComponentBrokerImpl) CST.componentBroker).add(this);
/*
* Bind to the underlying execution platform implementation
*/
getApformImpl().setApamComponent(this);
/*
* Notify managers
*/
ApamManagers.notifyAddedInApam(this);
}
/**
* Reifies in Apam an instance of this implementation from the information
* of the underlying platform.
*
* This method should be overridden to implement different reification
* semantics for different subclasses of implementation.
*
* WARNING The reified Apam instance is not automatically published in the
* Apam state, nor added to the list of instances of this implementation.
* This is actually done when the returned instance is registered by the
* caller of this method.
*
* This method is not intended to be used as external API.
*
*/
protected Instance reify(Composite composite, ApformInstance platformInstance) throws InvalidConfiguration {
return new InstanceImpl(composite, platformInstance);
}
// relation uses control
// @Override
// public Set<Implementation> getUses() {
// return Collections.unmodifiableSet(uses);
// }
//
// @Override
// public Set<Implementation> getInvUses() {
// return Collections.unmodifiableSet(invUses);
// }
//
// public void addUses(Implementation dest) {
// if (uses.contains(dest))
// return;
// uses.add(dest);
// ((ImplementationImpl) dest).addInvUses(this);
// ((SpecificationImpl) getSpec()).addRequires(dest.getSpec());
// }
//
// public void removeUses(Implementation dest) {
// for (Instance inst : instances) {
// for (Instance instDest : inst.getWireDests())
// if (instDest.getImpl() == dest) {
// return; // it exists another instance that uses that destination. Do
// nothing.
// }
// }
// uses.remove(dest);
// ((ImplementationImpl) dest).removeInvUses(this);
// ((SpecificationImpl) getSpec()).removeRequires(dest.getSpec());
// }
//
// private void addInvUses(Implementation orig) {
// invUses.add(orig);
// }
//
// private void removeInvUses(Implementation orig) {
// invUses.remove(orig);
// }
public void removeInComposites(CompositeType compo) {
inComposites.remove(compo);
}
public void removeInst(Instance instance) {
instances.remove(instance);
}
@Override
public void unregister() {
logger.debug("unregister implementation " + this);
/*
* Remove opposite references from specification and enclosing composite
* types
*/
((SpecificationImpl) getSpec()).removeImpl(this);
for (CompositeType inComposite : inComposites) {
((CompositeTypeImpl) inComposite).removeImpl(this);
}
/*
* remove all existing instances
*/
for (Instance inst : instances) {
((ComponentBrokerImpl)CST.componentBroker).disappearedComponent(inst);
}
// Do not remove inverse links, in case threads are still here.
}
}