/**
* 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.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentSkipListSet;
import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fr.imag.adele.apam.Apam;
import fr.imag.adele.apam.ApamManagers;
import fr.imag.adele.apam.CST;
import fr.imag.adele.apam.Composite;
import fr.imag.adele.apam.CompositeType;
import fr.imag.adele.apam.Implementation;
import fr.imag.adele.apam.Manager;
import fr.imag.adele.apam.ManagerModel;
import fr.imag.adele.apam.RelationManager;
import fr.imag.adele.apam.RelationManager.Priority;
import fr.imag.adele.apam.apform.ApformCompositeType;
import fr.imag.adele.apam.apform.ApformImplementation;
import fr.imag.adele.apam.apform.ApformInstance;
import fr.imag.adele.apam.declarations.ComponentDeclaration;
import fr.imag.adele.apam.declarations.CompositeDeclaration;
import fr.imag.adele.apam.declarations.InstanceDeclaration;
import fr.imag.adele.apam.declarations.references.components.ComponentReference;
import fr.imag.adele.apam.declarations.references.components.SpecificationReference;
import fr.imag.adele.apam.declarations.references.components.VersionedReference;
import fr.imag.adele.apam.impl.ComponentImpl.InvalidConfiguration;
import fr.imag.adele.apam.util.Attribute;
import fr.imag.adele.apam.util.Util;
public class APAMImpl implements Apam {
/**
* An special apform instance created only for those composites that do not exist in the Apform ipojo layer.
* Creates a minimal definition structure.
*/
private static class ApamOnlyComposite extends BaseApformComponent<Composite, InstanceDeclaration> implements ApformInstance {
public ApamOnlyComposite(ComponentReference<CompositeDeclaration> implementation, String name, Map<String, String> initialProperties) {
super(new InstanceDeclaration(VersionedReference.any(implementation),name));
if (initialProperties != null) {
for (Map.Entry<String, String> property : initialProperties.entrySet()) {
if (!Attribute.isFinalAttribute(property.getKey())) {
declaration.getProperties().put(property.getKey(), property.getValue());
}
}
}
}
@Override
public Object getServiceObject() {
throw new UnsupportedOperationException("method not available in application composite instance");
}
}
/**
* An special apform implementation created only for those composites types
* that do not exist in the Apform ipojo layer. Creates a minimal definition
* structure.
*/
private static class ApamOnlyCompositeType extends BaseApformComponent<CompositeType, CompositeDeclaration> implements ApformCompositeType {
/**
* The associated models
*/
private final Set<ManagerModel> models = new HashSet<ManagerModel>();
/**
* The number of instances created for this composite type
*/
private int numInstances;
public ApamOnlyCompositeType(String name, String specificationName, String mainName, Set<ManagerModel> models, Map<String, String> properties) {
super(new CompositeDeclaration(name, specificationName != null && !specificationName.trim().isEmpty() ? VersionedReference.any(new SpecificationReference(specificationName)) : null, new ComponentReference<ComponentDeclaration>(mainName)));
if (properties != null) {
declaration.getProperties().putAll(properties);
}
assert name != null && mainName != null && models != null;
this.models.addAll(models);
numInstances = 0;
}
@Override
public ApformInstance addDiscoveredInstance(Map<String, Object> configuration) throws InvalidConfiguration, UnsupportedOperationException {
throw new UnsupportedOperationException("method not available for appliation composite type");
}
@Override
public ApformInstance createInstance(Map<String, String> initialProperties) {
numInstances++;
String name = declaration.getName() + "-" + numInstances;
return new ApamOnlyComposite(declaration.getReference(), name, initialProperties);
}
@Override
public Set<ManagerModel> getModels() {
return models;
}
}
private static Logger logger = LoggerFactory.getLogger(APAMImpl.class);
/*
* The bundle context used for deployment in the execution paltform
*/
public static BundleContext context;
/*
* A reference to the ApamMan manager.
*
* This are the managers required to start the platform.
*/
private RelationManager apamMan;
private UpdateMan updateMan;
private FailedResolutionManager failureMan;
/**
* The list of expected managers
*/
private Set<String> expectedManagers = new ConcurrentSkipListSet<String>();
public APAMImpl(BundleContext context) {
APAMImpl.context = context;
apamMan = new ApamMan(context);
if (apamMan == null) {
throw new RuntimeException("Error while constructor of ApamMan");
}
updateMan = new UpdateMan();
if (updateMan == null) {
throw new RuntimeException("Error while constructor of updateMan");
}
failureMan = new FailedResolutionManager();
Map<String,URL> rootConfiguration = parseRootConfiguration(context.getProperty(Apam.CONFIGURATION_MANAGERS));
expectedManagers.addAll(Util.splitSet(context.getProperty(Apam.EXPECTED_MANAGERS)));
new CST(this, rootConfiguration);
// for (ManagerModel rootModel : CompositeTypeImpl.getRootCompositeType().getModels()) {
// expectedManagers.add(rootModel.getManagerName());
// }
/*
* disable resolution temporarily, until all the required managers of
* the root composite are registered
*/
if (!expectedManagers.isEmpty()) {
((ApamResolverImpl) CST.apamResolver).disable("Registration of the required managers " + expectedManagers, 20 * 1000/* ms */);
}
DynaMan dynaMan = new DynaMan();
ApamManagers.addRelationManager(apamMan,Priority.HIGHEST); // -1 to be sure it is not
// in the main loop
ApamManagers.addRelationManager(updateMan,Priority.HIGHEST); // -2 to be sure it is
// not in the main loop
ApamManagers.addDynamicManager(updateMan);
dynaMan.start(this);
failureMan.start(this);
try {
Util.printFileToConsole(context.getBundle().getResource("logo.txt"));
} catch (IOException e) {
}
}
/**
* Parse the system root configuration
*/
private static final Map<String,URL> parseRootConfiguration(String configuration) {
Map<String,URL> rootConfiguration = new HashMap<String, URL>();
/*
* Empty configuration
*/
if (configuration == null)
return rootConfiguration;
/*
* Parse expected manager configuration
*/
String managerConfigurations[] = Util.split(configuration);
for (String managerConfiguration : managerConfigurations) {
String managerName = managerConfiguration.trim();
String managerModel = null;
/*
* check if a model was specified
*/
int indexModel = managerConfiguration.indexOf(':');
if (indexModel >= 1) {
managerName = managerConfiguration.substring(0, indexModel).trim();
managerModel = managerConfiguration.substring(indexModel+1).trim();
}
URL managerModelLocation = null;
try {
/*
* try to load the specified URL for the manager
*/
if (managerModel != null) {
managerModelLocation = new URL(managerModel);
}
/*
* If no explicitly specified, try the default file Location
*/
if (managerModelLocation == null) {
File modelDirectory = new File("conf");
File modelFile = new File(modelDirectory,CST.ROOT_COMPOSITE_TYPE+"."+managerName+".cfg");
if (modelFile.exists() && ! modelFile.isDirectory()) {
managerModelLocation = modelFile.toURI().toURL();
}
}
} catch (MalformedURLException e) {
logger.error("Error parsing manager configuration for " + managerName
+ ", manager model "+managerModel
+", exception : "+e.getMessage());
}
/*
* ignore invalid definitions
*/
if (managerName.isEmpty() || managerModelLocation == null) {
continue;
}
/*
* register configuration
*/
rootConfiguration.put(managerName, managerModelLocation);
}
return rootConfiguration;
}
/**
* Creates a composite type from the specified parameters
*/
private CompositeType createCompositeType(CompositeType parent, String name, String specification, String mainComponent, Set<ManagerModel> models, Map<String, String> properties) {
assert name != null && mainComponent != null;
if (models == null) {
models = new HashSet<ManagerModel>();
}
if (parent == null) {
parent = CompositeTypeImpl.getRootCompositeType();
}
ApformImplementation apfCompo = new ApamOnlyCompositeType(name, specification, mainComponent, models, properties);
/*
* If the provided specification is not installed force a resolution
*/
if (specification != null && CST.componentBroker.getSpec(specification) == null) {
CST.apamResolver.findSpecByName(parent.getInst(), specification);
}
return (CompositeType) CST.componentBroker.addImpl(parent, apfCompo);
}
@Override
public CompositeType createCompositeType(String inCompoType, String name, String specification, String mainComponent, Set<ManagerModel> models, Map<String, String> attributes) {
/*
* Verify if it already exists
*/
CompositeType compositeType = getCompositeType(name);
if (compositeType != null) {
logger.error("Error creating composite type: already exists " + name);
return compositeType;
}
/*
* Get the specified enclosing composite type
*/
Implementation parent = null;
if (inCompoType != null) {
parent = CST.apamResolver.findImplByName(null, inCompoType);
if (parent == null || !(parent instanceof CompositeType)) {
logger.error("Error creating composite type: specified enclosing composite " + inCompoType + " is not a deployed composite type.");
return null;
}
}
return createCompositeType((CompositeType) parent, name, specification, mainComponent, models, attributes);
}
public RelationManager getApamMan() {
return apamMan;
}
@Override
public Composite getComposite(String name) {
return CompositeImpl.getComposite(name);
}
@Override
public Collection<Composite> getComposites() {
return CompositeImpl.getComposites();
}
@Override
public CompositeType getCompositeType(String name) {
return CompositeTypeImpl.getCompositeType(name);
}
@Override
public Collection<CompositeType> getCompositeTypes() {
return CompositeTypeImpl.getCompositeTypes();
}
public FailedResolutionManager getFailedResolutionManager() {
return failureMan;
}
@Override
public Collection<Composite> getRootComposites() {
return CompositeImpl.getRootComposites();
}
@Override
public Collection<CompositeType> getRootCompositeTypes() {
return CompositeTypeImpl.getRootCompositeTypes();
}
public RelationManager getUpdateMan() {
return updateMan;
}
public boolean isPredefinedManager(RelationManager manager) {
return manager.equals(getApamMan()) || manager.equals(getUpdateMan()) || manager.equals(getFailedResolutionManager());
}
public void managerRegistered(Manager manager) {
expectedManagers.remove(manager.getName());
if (expectedManagers.isEmpty()) {
((ApamResolverImpl) CST.apamResolver).enable();
}
}
@Override
public Composite startAppli(CompositeType composite) {
return (Composite) composite.createInstance(null, null);
}
@Override
public Composite startAppli(String compositeName) {
Implementation compoType = CST.apamResolver.findImplByName(null, compositeName);
if (compoType == null) {
logger.error("Error starting application: " + compositeName + " is not a deployed composite.");
return null;
}
if (!(compoType instanceof CompositeType)) {
logger.error("Error starting application: " + compoType.getName() + " is not a composite.");
return null;
}
return startAppli((CompositeType) compoType);
}
@Override
public Composite startAppli(URL compoURL, String compositeName) {
Implementation compoType = CST.componentBroker.createImpl(null, compositeName, compoURL, null);
if (compoType == null) {
logger.error("Error starting application: " + compositeName + " can not be deployed.");
return null;
}
if (!(compoType instanceof CompositeType)) {
logger.error("Error starting application: " + compoType.getName() + " is not a composite.");
return null;
}
return startAppli((CompositeType) compoType);
}
}