/** * 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.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import fr.imag.adele.apam.Composite; import fr.imag.adele.apam.CompositeType; import fr.imag.adele.apam.ContextualManager; import fr.imag.adele.apam.Implementation; import fr.imag.adele.apam.Instance; import fr.imag.adele.apam.ManagerModel; import fr.imag.adele.apam.apform.ApformInstance; public class CompositeImpl extends InstanceImpl implements Composite { private static final long serialVersionUID = 1L; /** * The root of the composite hierarchy * */ private static final Composite rootComposite; /** * The list of all composites in the APAM state model */ private static final Map<String, Composite> composites = new ConcurrentHashMap<String, Composite>(); public static Composite getComposite(String name) { return CompositeImpl.composites.get(name); } public static Collection<Composite> getComposites() { return Collections.unmodifiableCollection(CompositeImpl.composites.values()); } /* * the contained instances */ private Instance mainInst; private Set<Instance> hasInstance = Collections.newSetFromMap(new ConcurrentHashMap<Instance, Boolean>()); /* * The father-son relationship of the composite hierarchy * * This is a subset of the instance hierarchy restricted only to composites. */ private Set<Composite> sons = Collections.newSetFromMap(new ConcurrentHashMap<Composite, Boolean>()); private Composite father; // null if root composite // private Composite appliComposite; // root of father relationship /* * the dependencies between composites */ private Set<Composite> depend = Collections.newSetFromMap(new ConcurrentHashMap<Composite, Boolean>()); private Set<Composite> invDepend = Collections.newSetFromMap(new ConcurrentHashMap<Composite, Boolean>()); // ==== initialisations == /** * NOTE We can not directly initialize the field because the constructor may throw an exception, so we need * to make an static block to be able to catch the exception. * * The root composite bootstraps the system, so normally we SHOULD always be able to create it; if there * is an exception, that means there is some bug and we cannot normally continue, so we throw a class * initialization exception. */ static { Composite bootstrap = null; try { bootstrap = new CompositeImpl(CompositeTypeImpl.getRootCompositeType(), "rootComposite"); } catch (Exception e) { throw new ExceptionInInitializerError(e); } finally { rootComposite = bootstrap; } } /** * The root instance and the root composite are the same object. * getComposite() returns this. * * @return */ public static Composite getRootAllComposites() { return CompositeImpl.rootComposite; } public static Collection<Composite> getRootComposites() { return Collections.unmodifiableSet(CompositeImpl.rootComposite.getSons()); } // === public static Composite getRootInstance() { return CompositeImpl.rootComposite; } /** * Builds a new Apam composite to represent the specified platform instance * in the Apam model. */ protected CompositeImpl(Composite composite, ApformInstance apformInst) throws InvalidConfiguration { // First create the composite, as a normal instance super(composite, apformInst); /* * Reference the enclosing composite hierarchy */ father = ((CompositeImpl) composite).isSystemRoot() ? null : composite; // appliComposite = father == null ? this : father.getAppliComposite(); } /** * This is an special constructor only used for the root instance of the * system, and the dummy instance during construction */ CompositeImpl(CompositeType compoType, String name) throws InvalidConfiguration { super(compoType, name); this.mainInst = null; /* * NOTE the root instance is automatically registered in Apam in a * specific way that allows bootstraping the system */ this.father = null; // this.appliComposite = null; } public void addContainInst(Instance instance) { assert (instance != null); hasInstance.add(instance); } // Composite relation management =============== @Override public void addDepend(Composite destination) { assert destination != null && !depend.contains(destination); depend.add(destination); ((CompositeImpl) destination).addInvDepend(this); } /** * Ajoute une dependance inverse. Hidden, Internal; * * @param origin * @return */ private void addInvDepend(Composite origin) { assert origin != null && !invDepend.contains(origin); invDepend.add(origin); return; } // Father-son relationship management. Hidden, Internal; public void addSon(Composite destination) { assert destination != null && !sons.contains(destination); sons.add(destination); } @Override public boolean containsInst(Instance instance) { assert (instance != null); return hasInstance.contains(instance); } @Override public boolean dependsOn(Composite dest) { if (dest == null) { return false; } return (depend.contains(dest)); } @Override public Composite getAppliComposite() { return (father == null) ? this : father.getAppliComposite(); } @Override public final CompositeType getCompType() { return (CompositeType) getImpl(); } @Override public Set<Instance> getContainInsts() { return Collections.unmodifiableSet(hasInstance); } @Override public Set<Composite> getDepend() { return Collections.unmodifiableSet(depend); } @Override public Composite getFather() { return father; } /** * returns the reverse dependencies ! * * @return */ @Override public Set<Composite> getInvDepend() { return Collections.unmodifiableSet(invDepend); } @Override public final Implementation getMainImpl() { return getCompType().getMainImpl(); } @Override public Instance getMainInst() { return mainInst; } @Override public ManagerModel getModel(ContextualManager manager) { return getCompType().getModel(manager); } @Override public Set<ManagerModel> getModels() { return getCompType().getModels(); } /** * Overrides the instance method. A composite has no object, returns the * main instance object */ @Override public Object getServiceObject() { return mainInst != null ? mainInst.getApformInst().getServiceObject() : null; } @Override public Set<Composite> getSons() { return Collections.unmodifiableSet(sons); } /** * Whether this is the system root composite * */ public boolean isSystemRoot() { return this == rootComposite; } @Override public void register(Map<String, String> initialProperties) throws InvalidConfiguration { /* * Initialize the contained instances. The main instance will be eagerly created and the * other components will be lazily instantiated. * * TODO should there be a way to specify the properties of the main instance? */ if ((ImplementationImpl) getMainImpl() != null) { mainInst = ((ImplementationImpl) getMainImpl()).instantiate(this, null); } /* * Opposite reference from the enclosing composite. Notice that root application are sons * of the all root composite, but their father reference is null. */ ((CompositeImpl) getComposite()).addSon(this); /* * add to list of composites */ CompositeImpl.composites.put(getName(), this); /* * Complete normal registration */ super.register(initialProperties); /* * After composite is registered, register main instance that was eagerly created */ if (mainInst != null) { ((InstanceImpl) mainInst).register(null); } } /** * A composite cannot be isolated. Therefore remove is prohibited if the * destination will be isolated. */ public boolean removeDepend(Composite destination) { assert destination != null && depend.contains(destination); depend.remove(destination); ((CompositeImpl) destination).removeInvDepend(this); return true; } public void removeInst(Instance instance) { assert (instance != null); hasInstance.remove(instance); } /** * Retire une dependance inverse. Hidden, Internal; * * @param origin * @return */ private boolean removeInvDepend(Composite origin) { assert origin != null && invDepend.contains(origin); invDepend.remove(origin); return true; } /** * A son can be removed only when deleted. Warning : not checked. */ public boolean removeSon(Composite destination) { assert destination != null && sons.contains(destination); return sons.remove(destination); } @Override public void setOwner(Composite owner) { CompositeImpl previousOwner = (CompositeImpl) getComposite(); if (owner == previousOwner) { return; } super.setOwner(owner); previousOwner.removeSon(this); this.father = owner; ((CompositeImpl) owner).addSon(this); } @Override public String toString() { return "COMPOSITE " + getName(); } @Override public void unregister() { /* * Unbind from the enclosing composite */ ((CompositeImpl) getComposite()).removeSon(this); father = null; // appliComposite = null; /* * Remove depend relationships. * * NOTE We have to copy the list because we update it while iterating it */ for (Composite dependsOn : new HashSet<Composite>(depend)) { removeDepend(dependsOn); } for (Composite dependant : new HashSet<Composite>(invDepend)) { ((CompositeImpl) dependant).removeDepend(this); } /* * TODO Should we destroy the whole hierarchy rooted at this composite? * or should we try to reuse all created instances in the pool of unused * instances? what to do with wires that enter or leave this hierarchy? * what to do of shared instances with other hierarchies? can we reuse * the main instance? */ /* * Remove from list of composites */ CompositeImpl.composites.remove(getName()); /* * unbind from the graph of instances */ super.unregister(); } }