/** * 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.command; /** * Copyright Universite Joseph Fourier (www.ujf-grenoble.fr) * 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. */ import java.io.IOException; import java.io.PrintWriter; import java.net.MalformedURLException; import java.net.URL; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import org.apache.felix.ipojo.annotations.Instantiate; import org.apache.felix.ipojo.annotations.Provides; import org.apache.felix.ipojo.annotations.Requires; import org.apache.felix.ipojo.annotations.ServiceProperty; import fr.imag.adele.apam.Apam; 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.Link; import fr.imag.adele.apam.RelationDefinition; import fr.imag.adele.apam.Specification; import fr.imag.adele.apam.apform.Apform2Apam; import fr.imag.adele.apam.apform.Apform2Apam.PendingThread; import fr.imag.adele.apam.declarations.references.resources.ResourceReference; import fr.imag.adele.apam.impl.APAMImpl; import fr.imag.adele.apam.impl.ComponentImpl; import fr.imag.adele.apam.impl.CompositeImpl; import fr.imag.adele.apam.util.Substitute; //import org.apache.felix.ipojo.annotations.Component; @Instantiate @org.apache.felix.ipojo.annotations.Component(public_factory = false, immediate = true, name = "apam.universal.shell") @Provides(specifications = ApamCommand.class) public class ApamCommand { enum CommandInvocationType { INVALID, DEFAULT, HELP, OTHER } @ServiceProperty(name = "org.knowhowlab.osgi.shell.group.id", value = "apam") String universalShell_groupID; @ServiceProperty(name = "org.knowhowlab.osgi.shell.group.name", value = "ApAM Commands") String universalShell_groupName; @ServiceProperty(name = "org.knowhowlab.osgi.shell.commands", value = "{}") String[] universalShell_groupCommands = new String[] { "spec#inspect an apam specification", "implem#inspect an apam implementation", "inst#inspect an apam instance", "dump#display the full apam state model", "compoType#inspect an apam composite type", "compo#inspect an apam composite instance", "app#inspect an apam application", "displaywires#display all the relations of an instance", "charge#creates and start a new instance of the target implementation", "l#creates and start a new instance of the target implementation", "pending#display all pending installations in apam platform", "updatecomponent#updates target component (Warning: updates the whole Bundle)", "changeproperty#set properties of an instance" }; // Apam injected @Requires Apam apam; /** * Display information about the target application" */ public void app(PrintWriter out, String... args) { CommandInvocationType typeCall = checkCommandInvocationType(out, 0, args); if (typeCall == CommandInvocationType.INVALID) { argumentMessageError( out, "invalid number of arguments, type --help to obtain more information about the syntax"); return; } else if (typeCall == CommandInvocationType.HELP) { out.println("syntax: app [application name]"); return; } else if (typeCall == CommandInvocationType.DEFAULT) { Collection<Composite> apps = apam.getComposites(); for (Composite app : apps) { out.println("app " + app.getName()); } return; } String appName = args[0]; Composite app = apam.getComposite(appName); if (app == null) { out.println("No such root composite : " + appName); return; } out.println("Application " + app); for (Composite compo : app.getSons()) { out.println("Son Composites : " + compo.getName()); } for (Composite compo : app.getDepend()) { out.println("Depends on composites : " + compo.getName()); } } private void argumentMessageError(PrintWriter out, String message) { out.println("Error : Invalid number of arguments \n ---> " + message); } /** * Change properties of an instance take as arguments : an instance name an * URL file.properties or a list of value=property, ex : * "lang=french vendor=adele" " * */ @SuppressWarnings("unchecked") public void changeproperty(PrintWriter out, String... args) { if (args.length <= 1) { argumentMessageError( out, "the command should be followed by an instance name and the properties or an url to file.properties, \n " + " example : \n " + " setproperty aninstance vendor=adele version=1.0 \n" + " setproperty aninstance file://path/to/file.properties"); return; } URL url; String instanceName = args[0]; String urlArg = args[1]; String[] propsArgs = Arrays.copyOfRange(args, 1, args.length); Properties properties = new Properties(); try { url = new URL(args[1]); properties.load(url.openStream()); } catch (MalformedURLException e) { for (String arg : propsArgs) { String[] property = arg.split("="); properties.put(property[0], property[1]); } } catch (IOException e) { out.println("Error while reading the file : " + urlArg); e.printStackTrace(); } if (properties.isEmpty()) { return; } Instance inst = CST.componentBroker.getInst(instanceName); if (inst != null) { // TODO verify values of properties with some types (string, int, // double, string[]) // TODO for now only string are used inst.setAllProperties((Map) properties); } else { out.println("The instance " + instanceName + " not exist !"); } } private CommandInvocationType checkCommandInvocationType(PrintWriter out, int minimum, String... args) { int length = args == null ? 0 : args.length; if (length < minimum) { return CommandInvocationType.INVALID; } if (length == 1 && args[0].equals("--help")) { return CommandInvocationType.HELP; } if (length == 0) { return CommandInvocationType.DEFAULT; } return CommandInvocationType.OTHER; } private Composite checkComposite(PrintWriter out, String compositeTarget, String componentName) { if (compositeTarget == null) {// if the composite target is null, use // the root composite compositeTarget = "root"; } Composite target = apam.getComposite(compositeTarget); if (target == null) { out.println("Invalid composite target name : " + compositeTarget); return null; } return target; } /** Display an Apam composites */ public void compo(PrintWriter out, String... args) { CommandInvocationType typeCall = checkCommandInvocationType(out, 0, args); if (typeCall == CommandInvocationType.INVALID) { argumentMessageError( out, "invalid number of arguments, type --help to obtain more information about the syntax"); return; } else if (typeCall == CommandInvocationType.HELP) { out.println("syntax: compo [composite name]"); return; } else if (typeCall == CommandInvocationType.DEFAULT) { Collection<Composite> comps = apam.getRootComposites(); for (Composite compo : comps) { out.println(" " + compo); } return; } String compoName = args[0]; Composite compo = compoName.equals("root") ? CompositeImpl .getRootAllComposites() : apam.getComposite(compoName); if (compo == null) { out.println("No such composite : " + compoName); return; } printComposite(out, compo, ""); out.println(""); } /** Display an Apam composite type */ public void compoType(PrintWriter out, String... args) { CommandInvocationType typeCall = checkCommandInvocationType(out, 0, args); if (typeCall == CommandInvocationType.INVALID) { argumentMessageError( out, "invalid number of arguments, type --help to obtain more information about the syntax"); return; } else if (typeCall == CommandInvocationType.HELP) { out.println("syntax: compoType [composite name]"); return; } else if (typeCall == CommandInvocationType.DEFAULT) { Collection<CompositeType> compositeTypes = apam.getCompositeTypes(); for (CompositeType compositeType : compositeTypes) { out.println(" " + compositeType); } return; } String compoTypeName = args[0]; CompositeType compo = apam.getCompositeType(compoTypeName); if (compoTypeName == null) { out.println("No such compositeType : " + compoTypeName); return; } printCompositeType(out, compo, ""); out.println(""); } /** * Display all the relations of an instance */ public void displaywires(PrintWriter out, String... args) { String instName = args[0]; Instance inst = CST.componentBroker.getInst(instName); if (inst != null) { dumpState(out, inst, " ", null); } } /** * Display the full Apam state model" */ public void dump(PrintWriter out, String... args) { dumpApam(out); } private void dumpApam(PrintWriter out) { for (CompositeType compo : apam.getRootCompositeTypes()) { dumpCompoType(out, compo.getName()); out.println("\n"); } } private void dumpCompoType(PrintWriter out, String name) { CompositeType compType = apam.getCompositeType(name); if (compType == null) { out.println("No such application :" + name); return; } printCompositeType(out, compType, ""); } private void dumpState(PrintWriter out, Instance inst, String indent, String dep) { if (inst == null) { return; } Set<Component> insts = new HashSet<Component>(); insts.add(inst); out.println(indent + dep + ": " + inst + " " + inst.getImpl() + " " + inst.getSpec()); indent = indent + " "; for (Link wire : inst.getRawLinks()) { out.println(indent + wire.getName() + ": " + wire.getDestination() + " "); // + ((Instance)wire.getDestination()).getImpl() + " " // + ((Instance)wire.getDestination()).getSpec()); dumpState0(out, (wire.getDestination()), indent, wire.getName(), insts); } } private void dumpState0(PrintWriter out, Component inst, String indent, String dep, Set<Component> insts) { if (insts.contains(inst)) { out.println(indent + "*" + dep + ": " + inst.getName()); return; } insts.add(inst); indent = indent + " "; for (Link wire : inst.getRawLinks()) { out.println(indent + wire.getName() + ": " + wire.getDestination() + " "); // + ((Instance)wire.getDestination()).getImpl() + " " // + ((Instance)wire.getDestination()).getSpec()); dumpState0(out, (wire.getDestination()), indent, wire.getName(), insts); } } /** * inspect an implementation arguments: - the implementation name */ public void implem(PrintWriter out, String... args) { CommandInvocationType typeCall = checkCommandInvocationType(out, 0, args); if (typeCall == CommandInvocationType.INVALID) { argumentMessageError( out, "invalid number of arguments, type --help to obtain more information about the syntax"); return; } else if (typeCall == CommandInvocationType.HELP) { out.println("syntax: implem [implementation name]"); return; } else if (typeCall == CommandInvocationType.DEFAULT) { Set<Implementation> implementations = CST.componentBroker .getImpls(); for (Implementation implementation : implementations) { out.println("implem " + implementation.getName()); } return; } String implementationName = args[0]; Implementation implementation = CST.componentBroker .getImpl(implementationName); if (implementation == null) { out.println("No such implementation : " + implementationName); return; } printImplementation(out, "", implementation); } /** * inspect an instance. arguments : - the instance name */ public void inst(PrintWriter out, String[] args) { CommandInvocationType typeCall = checkCommandInvocationType(out, 0, args); if (typeCall == CommandInvocationType.INVALID) { argumentMessageError( out, "invalid number of arguments, type --help to obtain more information about the syntax"); return; } else if (typeCall == CommandInvocationType.HELP) { out.println("syntax: inst [component name] [composite]"); return; } else if (typeCall == CommandInvocationType.DEFAULT) { Set<Instance> instances = CST.componentBroker.getInsts(); for (Instance instance : instances) { out.println("inst " + instance.getName()); } return; } String instanceName = args[0]; Instance instance = CST.componentBroker.getInst(instanceName); if (instance == null) { out.println("No such instance : " + instanceName); return; } printInstance(out, "", instance); } public void l(PrintWriter out, String... args) { load(out, args); } /** * Start a new instance of the target implementation in a composite * arguments : - an implementation name - (optional) a composite name */ public void load(PrintWriter out, String... args) { String componentName = null; String compositeName = null; Composite composite = null; if (args.length == 0) { argumentMessageError(out, "charge <component-name> [composite]\n"); return; } if (args.length >= 1) { componentName = args[0]; } if (args.length > 1) { compositeName = args[1]; composite = checkComposite(out, compositeName, componentName); } else { composite = CompositeImpl.getRootAllComposites(); } if (composite != null) { Thread t = new Thread(new AsyncFind(out, composite, componentName, true, args)); t.start(); } } private static void printPendingList(PrintWriter out, List<? extends PendingThread> pending) { for (PendingThread pendingThread : pending) { out.println("\t" + pendingThread.getDescription() + " is waiting for " + pendingThread.getCondition()); List<StackTraceElement> stack = pendingThread.getStack(); if (stack == null) { continue; } for (StackTraceElement frame : stack) { out.println("\t\t " + frame); } } } /** Display the pending platform installations */ public void pending(PrintWriter out, String... args) { out.println("APAM platform : pending threads for platform processing : "); printPendingList(out, Apform2Apam.gePlatformWaitingThreads()); out.println("APAM platform : pending threads for component deployment : "); printPendingList(out, Apform2Apam.getComponentWaitingThreads()); out.println("APAM platform: pending threads for relation resolution : "); printPendingList(out, ((APAMImpl)CST.apam).getFailedResolutionManager().getWaitingThreads()); } private void printComponent(PrintWriter out, String indent, Component elem) { out.println(indent + "----- [ " + elem.getKind() + " " + elem.getName() + " ] -----"); out.println(indent + "Relation declarations :"); for (RelationDefinition relToResolve : elem.getRelations()) { out.println(indent + " " + relToResolve.getName() + ": " + relToResolve); } // Links String w; out.println(indent + "Links towards:"); for (Link wire : elem.getRawLinks()) { if (wire.isInjected()) { w = wire.isWire() ? "IW-" : "IL-"; } else { w = ""; } out.println(indent + " " + w + wire.getName() + ": " + wire.getDestination()); } // Reverse Links out.println(indent + "Used by:"); for (Link wire : elem.getInvLinks()) { if (wire.isInjected()) { w = wire.isWire() ? "IW-" : "IL-"; } else { w = ""; } out.println(indent + " (" + w + wire.getName() + ") " + wire.getSource()); } // Properties printProperties(out, indent, (ComponentImpl) elem); out.println(elem.getApformComponent().getDeclaration() .printDeclaration(indent)); out.println(); } private void printComposite(PrintWriter out, Composite compo, String indent) { out.println(indent + "Composite " + compo.getName() + " Composite Type : " + compo.getCompType().getName() + " Father : " + compo.getFather()); out.println(indent + " In application : " + compo.getAppliComposite()); out.print(indent + " Son composites : "); for (Composite comDep : compo.getSons()) { out.print(comDep.getName() + " "); } out.println(""); out.print(indent + " Depends on composites : "); for (Composite comDep : compo.getDepend()) { out.print(comDep.getName() + " "); } out.println(""); if (!compo.getContainInsts().isEmpty()) { out.print(indent + " Contains instances : "); for (Instance inst : compo.getContainInsts()) { out.print(inst + " "); } out.println(""); } indent += " "; out.println(indent + " State " + compo); dumpState(out, compo.getMainInst(), indent, " "); // out.println(""); out.println(compo.getApformInst().getDeclaration() .printDeclaration(indent)); if (!compo.getSons().isEmpty()) { out.println("\n"); for (Composite comp : compo.getSons()) { printComposite(out, comp, indent + " "); } } } private void printCompositeType(PrintWriter out, CompositeType compo, String indent) { out.println(indent + "Composite Type " + compo.getName() + ". Main implementation : " + compo.getMainImpl() + ". Models : " + compo.getModels()); indent += " "; out.print(indent + "Provides resources : "); for (ResourceReference ref : compo.getCompoDeclaration() .getProvidedResources()) { out.print(ref + " "); } out.println(""); out.print(indent + "Embedded in composite types : "); for (CompositeType comType : compo.getInvEmbedded()) { out.print(comType.getName() + " "); } out.println(""); out.print(indent + "Contains composite types : "); for (CompositeType comType : compo.getEmbedded()) { out.print(comType.getName() + " "); } out.println(""); out.print(indent + "Imports composite types : "); for (CompositeType comDep : compo.getImport()) { out.print(comDep.getName() + " "); } out.println(""); // out.print(indent + "Uses composite types : "); // for (Implementation comDep : compo.getUses()) { // out.print(comDep.getName() + " "); // } // out.println(""); out.print(indent + "Contains Implementations: "); for (Implementation impl : compo.getImpls()) { out.print(impl + " "); } out.println(""); out.print(indent + "Composite Instances : "); for (Instance inst : compo.getInsts()) { out.print(inst + " "); } out.println(""); out.println(compo.getApformImpl().getDeclaration() .printDeclaration(indent)); for (Instance compInst : compo.getInsts()) { printComposite(out, (Composite) compInst, indent + " "); } for (CompositeType comType : compo.getEmbedded()) { out.println("\n"); printCompositeType(out, comType, indent); } } /** * Prints the implementation. * * @param out * the printWriter * * @param indent * the indent * @param impl * the impl */ private void printImplementation(PrintWriter out, String indent, Implementation impl) { printComponent(out, indent, impl); indent += " "; out.println(indent + "specification : " + impl.getSpec()); out.println(indent + "In composite types:"); for (CompositeType compo : impl.getInCompositeType()) { out.println(indent + " " + compo.getName()); } // out.println(indent + "Uses:"); // for (Implementation implem : impl.getUses()) { // out.println(indent + " " + implem); // } // // out.println(indent + "Used by:"); // for (Implementation implem : impl.getInvUses()) { // out.println(indent + " " + implem); // } out.println(indent + "Instances:"); for (Instance inst : impl.getInsts()) { out.println(indent + " " + inst); } // printProperties(out, indent, (ComponentImpl) impl); } /** * Prints the instance. * * @param out * the printWriter * * @param indent * the indent * @param instance * the instance */ private void printInstance(PrintWriter out, String indent, Instance instance) { // // if (instance == null) // return; printComponent(out, indent, instance); indent += " "; // out.println(indent + "links:"); // for (Link wire : instance.getLinks()) { // out.println(indent + " " + wire.getName() + ": " // + wire.getDestination()); // } // // out.println(indent + "Called by:"); // for (Link wire : instance.getInvLinks()) // out.println(indent + " (" + wire.getName() + ") " // + wire.getSource()); if (instance.getImpl() == null) { out.println(indent + "warning : no factory for this instance"); } else { out.println(indent + "specification : " + instance.getSpec()); out.println(indent + "implementation : " + instance.getImpl()); out.println(indent + "in composite : " + instance.getComposite()); out.println(indent + "in application : " + instance.getAppliComposite()); // printProperties(out, indent, (ComponentImpl) instance); } out.println(instance.getApformInst().getDeclaration() .printDeclaration(indent)); } /** * Prints the properties. * * @param out * the printWriter * * @param indent * the indent * @param properties * the properties */ private void printProperties(PrintWriter out, String indent, ComponentImpl comp) { Map<String, Object> properties = comp.getAllProperties(); out.println(indent + "Properties : "); for (String key : properties.keySet()) { out.print(indent + " " + key + " = " + comp.getProperty(key)); /* * display original expression in case of substitution */ Object value = properties.get(key); if (value != null && Substitute.isSubstitution(value)) { out.print(" (" + ((String) value).trim() + ")"); } out.println(); } } /** * Prints the specification. * * @param indent * the indent * @param specification * the specification */ private void printSpecification(PrintWriter out, String indent, Specification specification) { // out.println(indent + "----- [ ASMSpec : " + specification.getName() // + " ] -----"); printComponent(out, indent, specification); indent += " "; out.println(indent + "Interfaces:"); for (ResourceReference res : specification.getDeclaration() .getProvidedResources()) { out.println(indent + " " + res); } out.println(specification.getDeclaration().getRelations()); // out.println(indent + "Effective Required specs:"); // for (Specification spec : specification.getRequires()) { // out.println(indent + " " + spec); // } // // out.println(indent + "Required by:"); // // for (Specification spec : specification.getInvRequires()) { // out.println(indent + " " + spec); // } out.println(indent + "Implementations:"); for (Implementation impl : specification.getImpls()) { out.println(indent + " " + impl); } // printProperties(out, indent, (ComponentImpl) specification); } /** * inspect a specification. arguments : - the specification name */ public void spec(PrintWriter out, String... args) { CommandInvocationType typeCall = checkCommandInvocationType(out, 0, args); if (typeCall == CommandInvocationType.INVALID) { argumentMessageError( out, "invalid number of arguments, type --help to obtain more information about the syntax"); return; } else if (typeCall == CommandInvocationType.HELP) { out.println("syntax: spec [specification name]"); return; } else if (typeCall == CommandInvocationType.DEFAULT) { Set<Specification> specifications = CST.componentBroker.getSpecs(); for (Specification specification : specifications) { out.println("spec " + specification.getName()); } return; } String specificationName = args[0]; Specification specification = CST.componentBroker .getSpec(specificationName); if (specification == null) { out.println("No such specification : " + specificationName); return; } printSpecification(out, "", specification); } /** * Updates the target component. Warning: updates the whole Bundle. */ public void updatecomponent(PrintWriter out, String... args) { if (args.length <= 0) { argumentMessageError(out, "a component name should be specified, example : up acomponent"); return; } for (String arg : args) { // TODO make update synchronized and show message if the update was // performed or not // TODO should return null if the update is not performed , or the // object in case of success CST.apamResolver.updateComponent(arg); } } }