Repository: karaf Updated Branches: refs/heads/master 70d14e6e1 -> 084f579bd
[KARAF-2911] Add simple commands for subsystems Project: http://git-wip-us.apache.org/repos/asf/karaf/repo Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/084f579b Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/084f579b Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/084f579b Branch: refs/heads/master Commit: 084f579bd1d417504fe7fcedf39eb1d1e987761b Parents: 70d14e6 Author: Guillaume Nodet <[email protected]> Authored: Tue Apr 15 10:17:46 2014 +0200 Committer: Guillaume Nodet <[email protected]> Committed: Tue Apr 15 20:16:54 2014 +0200 ---------------------------------------------------------------------- .../enterprise/src/main/feature/feature.xml | 7 +- pom.xml | 3 +- services/coordinator/pom.xml | 11 +- .../main/java/org/eclipse/osgi/util/NLS.java | 127 +++++++ subsystem/NOTICE | 71 ++++ subsystem/pom.xml | 120 +++++++ .../karaf/subsystem/commands/InfoAction.java | 337 +++++++++++++++++++ .../karaf/subsystem/commands/InstallAction.java | 39 +++ .../karaf/subsystem/commands/ListAction.java | 56 +++ .../karaf/subsystem/commands/StartAction.java | 39 +++ .../karaf/subsystem/commands/StopAction.java | 39 +++ .../subsystem/commands/SubsystemCompleter.java | 38 +++ .../subsystem/commands/SubsystemSupport.java | 126 +++++++ .../subsystem/commands/UninstallAction.java | 39 +++ 14 files changed, 1037 insertions(+), 15 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/karaf/blob/084f579b/assemblies/features/enterprise/src/main/feature/feature.xml ---------------------------------------------------------------------- diff --git a/assemblies/features/enterprise/src/main/feature/feature.xml b/assemblies/features/enterprise/src/main/feature/feature.xml index 65ccf10..a0b8141 100644 --- a/assemblies/features/enterprise/src/main/feature/feature.xml +++ b/assemblies/features/enterprise/src/main/feature/feature.xml @@ -242,15 +242,12 @@ <feature name="subsystems" description="Support for OSGi subsystems" version="${aries.subsystem.version}"> <details>Support for Aries OSGi subsystems</details> - <!-- blueprint is required for application.modeller --> - <feature>aries-blueprint</feature> + <bundle dependency="true" start-level="30">mvn:org.apache.aries/org.apache.aries.util/${aries.util.version}</bundle> <bundle start-level="30">mvn:org.apache.felix/org.apache.felix.resolver/${felix.resolver.version}</bundle> <bundle start-level="30">mvn:org.apache.karaf.services/org.apache.karaf.services.coordinator/${project.version}</bundle> <bundle start-level="30">mvn:org.eclipse.equinox/org.eclipse.equinox.region/${equinox.region.version}</bundle> - <bundle start-level="30">mvn:org.apache.aries.application/org.apache.aries.application.api/${aries.application.api.version}</bundle> - <bundle start-level="30">mvn:org.apache.aries.application/org.apache.aries.application.utils/${aries.application.version}</bundle> - <bundle start-level="30">mvn:org.apache.aries.application/org.apache.aries.application.modeller/${aries.application.version}</bundle> <bundle start-level="30">mvn:org.apache.aries.subsystem/org.apache.aries.subsystem/${aries.subsystem.version}</bundle> + <bundle start-level="30">mvn:org.apache.karaf.subsystem/org.apache.karaf.subsystem.core/${project.version}</bundle> </feature> </features> http://git-wip-us.apache.org/repos/asf/karaf/blob/084f579b/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index fc446f0..2ef129f 100644 --- a/pom.xml +++ b/pom.xml @@ -71,6 +71,7 @@ <module>archetypes</module> <module>itests</module> <module>services</module> + <module>subsystem</module> </modules> <scm> @@ -201,7 +202,7 @@ <aries.jndi.api.version>1.0.0</aries.jndi.api.version> <aries.proxy.version>1.0.2</aries.proxy.version> <aries.proxy.api.version>1.0.0</aries.proxy.api.version> - <aries.subsystem.version>1.0.0</aries.subsystem.version> + <aries.subsystem.version>1.0.1-SNAPSHOT</aries.subsystem.version> <aries.transaction.version>1.0.1</aries.transaction.version> <aries.transaction.manager.version>1.1.0</aries.transaction.manager.version> <aries.transaction.blueprint.version>1.0.1</aries.transaction.blueprint.version> http://git-wip-us.apache.org/repos/asf/karaf/blob/084f579b/services/coordinator/pom.xml ---------------------------------------------------------------------- diff --git a/services/coordinator/pom.xml b/services/coordinator/pom.xml index 413587e..6dbb674 100644 --- a/services/coordinator/pom.xml +++ b/services/coordinator/pom.xml @@ -59,14 +59,12 @@ org.osgi.service.coordinator;version="1.0.0" </Export-Package> <Private-Package> - org.eclipse.equinox.coordinator + org.eclipse.equinox.coordinator, + org.eclipse.osgi.util </Private-Package> <Export-Service> org.osgi.service.coordinator.Coordinator </Export-Service> - <Embed-Dependency> - org.eclipse.osgi;inline="org/eclipse/osgi/util/NLS*.class" - </Embed-Dependency> </instructions> </configuration> </plugin> @@ -85,11 +83,6 @@ <version>1.1.0.v20120522-1841</version> <scope>provided</scope> </dependency> - <dependency> - <groupId>org.eclipse</groupId> - <artifactId>org.eclipse.osgi</artifactId> - <scope>provided</scope> - </dependency> </dependencies> </project> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/karaf/blob/084f579b/services/coordinator/src/main/java/org/eclipse/osgi/util/NLS.java ---------------------------------------------------------------------- diff --git a/services/coordinator/src/main/java/org/eclipse/osgi/util/NLS.java b/services/coordinator/src/main/java/org/eclipse/osgi/util/NLS.java new file mode 100644 index 0000000..7466346 --- /dev/null +++ b/services/coordinator/src/main/java/org/eclipse/osgi/util/NLS.java @@ -0,0 +1,127 @@ +/* + * 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 org.eclipse.osgi.util; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.util.Properties; + + +public class NLS { + + public static void initializeMessages(final String bundleName, final Class<?> clazz) { + String resource = bundleName.replace('.', '/') + ".properties"; + final InputStream input = clazz.getClassLoader().getResourceAsStream(resource); + try { + Properties properties = new Properties(); + properties.load(input); + for (String key : properties.stringPropertyNames()) { + String value = properties.getProperty(key); + + try { + Field field = clazz.getDeclaredField(key); + field.setAccessible(true); + field.set(null, value); + } catch (Exception e) { + // ignore + } + } + } catch (IOException e) { + // ignore + } finally { + try { + input.close(); + } catch (IOException e) { + // ignore + } + } + } + + public static String bind(String message, Object binding) { + return bind(message, new Object[] { binding }); + } + + public static String bind(String message, Object binding1, Object binding2) { + return bind(message, new Object[] { binding1, binding2 }); + } + + public static String bind(String message, Object[] bindings) { + int length = message.length(); + //estimate correct size of string buffer to avoid growth + StringBuilder buffer = new StringBuilder(message.length() + + (bindings != null ? bindings.length * 5 : 0)); + for (int i = 0; i < length; i++) { + char c = message.charAt(i); + switch (c) { + case '{' : + int index = message.indexOf('}', i); + // if we don't have a matching closing brace then... + if (index == -1) { + buffer.append(c); + break; + } + i++; + if (i >= length) { + buffer.append(c); + break; + } + // look for a substitution + int number = -1; + try { + number = Integer.parseInt(message.substring(i, index)); + } catch (NumberFormatException e) { + throw (IllegalArgumentException) new IllegalArgumentException().initCause(e); + } + if (bindings == null || number >= bindings.length || number < 0) { + buffer.append("<missing argument>"); //$NON-NLS-1$ + i = index; + break; + } + buffer.append(bindings[number]); + i = index; + break; + case '\'' : + // if a single quote is the last char on the line then skip it + int nextIndex = i + 1; + if (nextIndex >= length) { + buffer.append(c); + break; + } + char next = message.charAt(nextIndex); + // if the next char is another single quote then write out one + if (next == '\'') { + i++; + buffer.append(c); + break; + } + // otherwise we want to read until we get to the next single quote + index = message.indexOf('\'', nextIndex); + // if there are no more in the string, then skip it + if (index == -1) { + buffer.append(c); + break; + } + // otherwise write out the chars inside the quotes + buffer.append(message.substring(nextIndex, index)); + i = index; + break; + default : + buffer.append(c); + } + } + return buffer.toString(); + } + +} http://git-wip-us.apache.org/repos/asf/karaf/blob/084f579b/subsystem/NOTICE ---------------------------------------------------------------------- diff --git a/subsystem/NOTICE b/subsystem/NOTICE new file mode 100644 index 0000000..b70f1f9 --- /dev/null +++ b/subsystem/NOTICE @@ -0,0 +1,71 @@ +Apache Karaf +Copyright 2010-2014 The Apache Software Foundation + + +I. Included Software + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). +Licensed under the Apache License 2.0. + +This product uses software developed at +The OSGi Alliance (http://www.osgi.org/). +Copyright (c) OSGi Alliance (2000, 2010). +Licensed under the Apache License 2.0. + +This product includes software developed at +OW2 (http://www.ow2.org/). +Licensed under the BSD License. + +This product includes software developed at +OPS4J (http://www.ops4j.org/). +Licensed under the Apache License 2.0. + +This product includes software developed at +Eclipse Foundation (http://www.eclipse.org/). +Licensed under the EPL. + +This product includes software written by +Antony Lesuisse. +Licensed under Public Domain. + + +II. Used Software + +This product uses software developed at +FUSE Source (http://www.fusesource.org/). +Licensed under the Apache License 2.0. + +This product uses software developed at +AOP Alliance (http://aopalliance.sourceforge.net/). +Licensed under the Public Domain. + +This product uses software developed at +Tanuki Software (http://www.tanukisoftware.com/). +Licensed under the Apache License 2.0. + +This product uses software developed at +Jasypt (http://jasypt.sourceforge.net/). +Licensed under the Apache License 2.0. + +This product uses software developed at +JLine (http://jline.sourceforge.net). +Licensed under the BSD License. + +This product uses software developed at +SLF4J (http://www.slf4j.org/). +Licensed under the MIT License. + +This product uses software developed at +SpringSource (http://www.springsource.org/). +Licensed under the Apache License 2.0. + +This product includes software from http://www.json.org. +Copyright (c) 2002 JSON.org + + +III. License Summary +- Apache License 2.0 +- BSD License +- EPL License +- MIT License http://git-wip-us.apache.org/repos/asf/karaf/blob/084f579b/subsystem/pom.xml ---------------------------------------------------------------------- diff --git a/subsystem/pom.xml b/subsystem/pom.xml new file mode 100644 index 0000000..6dd6579 --- /dev/null +++ b/subsystem/pom.xml @@ -0,0 +1,120 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <!-- + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You 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. + --> + + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.karaf</groupId> + <artifactId>karaf</artifactId> + <version>4.0.0-SNAPSHOT</version> + </parent> + + <groupId>org.apache.karaf.subsystem</groupId> + <artifactId>org.apache.karaf.subsystem.core</artifactId> + <packaging>bundle</packaging> + <name>Apache Karaf :: Subsystem :: Core</name> + <description>This bundle provides support for Subsystems.</description> + + <properties> + <appendedResourcesDirectory>${basedir}/../../etc/appended-resources</appendedResourcesDirectory> + </properties> + + <dependencies> + <dependency> + <groupId>org.osgi</groupId> + <artifactId>org.osgi.core</artifactId> + <scope>provided</scope> + </dependency> + + <dependency> + <groupId>org.apache.karaf</groupId> + <artifactId>org.apache.karaf.util</artifactId> + <scope>provided</scope> + </dependency> + + <dependency> + <groupId>org.osgi</groupId> + <artifactId>org.osgi.compendium</artifactId> + <scope>provided</scope> + </dependency> + + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <scope>provided</scope> + </dependency> + + <dependency> + <groupId>org.apache.karaf.features</groupId> + <artifactId>org.apache.karaf.features.core</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.aries.subsystem</groupId> + <artifactId>org.apache.aries.subsystem</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.karaf.shell</groupId> + <artifactId>org.apache.karaf.shell.core</artifactId> + </dependency> + + </dependencies> + + <build> + <resources> + <resource> + <directory>${project.basedir}/src/main/resources</directory> + <includes> + <include>**/*</include> + </includes> + </resource> + <resource> + <directory>${project.basedir}/src/main/resources</directory> + <filtering>true</filtering> + <includes> + <include>**/*.info</include> + </includes> + </resource> + </resources> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <configuration> + <instructions> + <!-- + <Bundle-Activator> + org.apache.karaf.subsystem.internal.Activator + </Bundle-Activator> + --> + <Private-Package> + org.apache.karaf.subsystem.commands, + org.apache.felix.utils.manifest + </Private-Package> + <Karaf-Commands>*</Karaf-Commands> + </instructions> + </configuration> + </plugin> + </plugins> + </build> + +</project> http://git-wip-us.apache.org/repos/asf/karaf/blob/084f579b/subsystem/src/main/java/org/apache/karaf/subsystem/commands/InfoAction.java ---------------------------------------------------------------------- diff --git a/subsystem/src/main/java/org/apache/karaf/subsystem/commands/InfoAction.java b/subsystem/src/main/java/org/apache/karaf/subsystem/commands/InfoAction.java new file mode 100644 index 0000000..ad2cef2 --- /dev/null +++ b/subsystem/src/main/java/org/apache/karaf/subsystem/commands/InfoAction.java @@ -0,0 +1,337 @@ +/* + * 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 org.apache.karaf.subsystem.commands; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.TreeMap; + +import org.apache.felix.utils.manifest.Attribute; +import org.apache.felix.utils.manifest.Clause; +import org.apache.felix.utils.manifest.Directive; +import org.apache.felix.utils.manifest.Parser; +import org.apache.karaf.shell.api.action.Action; +import org.apache.karaf.shell.api.action.Argument; +import org.apache.karaf.shell.api.action.Command; +import org.apache.karaf.shell.api.action.Completion; +import org.apache.karaf.shell.api.action.Option; +import org.apache.karaf.shell.api.action.lifecycle.Reference; +import org.apache.karaf.shell.api.action.lifecycle.Service; +import org.apache.karaf.shell.api.console.Terminal; +import org.apache.karaf.shell.support.ShellUtil; +import org.osgi.service.subsystem.Subsystem; +import org.osgi.service.subsystem.SubsystemConstants; + +@Command(scope = "subsystem", name = "info", description = "Display information about subsystems") +@Service +public class InfoAction extends SubsystemSupport implements Action { + + protected final static String SUBSYSTEM_PREFIX = "Subsystem-"; + protected final static String PACKAGE_SUFFFIX = "-Package"; + protected final static String SERVICE_SUFFIX = "-Service"; + protected final static String CAPABILITY_SUFFIX = "-Capability"; + protected final static String IMPORT_PACKAGES_ATTRIB = "Import-Package"; + protected final static String REQUIRE_BUNDLE_ATTRIB = "Require-Bundle"; + + @Option(name = "--indent", description = "Indentation method") + int indent = -1; + + @Argument(description = "Subsystem names or ids") + @Completion(SubsystemCompleter.class) + String id; + + @Reference + Terminal terminal; + + @Override + public Object execute() throws Exception { + for (Subsystem ss : getSubsystems(id)) { + printHeaders(ss); + } + return null; + } + + protected void printHeaders(Subsystem subsystem) throws Exception { + String title = getSubsystemName(subsystem); + System.out.println("\n" + title); + System.out.println(ShellUtil.getUnderlineString(title)); + if (indent == 0) { + Map<String, String> dict = subsystem.getSubsystemHeaders(null); + for (String k : dict.keySet()) { + Object v = dict.get(k); + System.out.println(k + " = " + ShellUtil.getValueString(v)); + } + } else { + System.out.println(generateFormattedOutput(subsystem)); + } + } + + public static String getSubsystemName(Subsystem subsystem) { + String name = subsystem.getSubsystemHeaders(null).get(SubsystemConstants.SUBSYSTEM_NAME); + return (name == null) + ? "Subsystem " + Long.toString(subsystem.getSubsystemId()) + : name + " (" + Long.toString(subsystem.getSubsystemId()) + ")"; + } + + protected String generateFormattedOutput(Subsystem subsystem) { + StringBuilder output = new StringBuilder(); + Map<String, Object> otherAttribs = new TreeMap<String, Object>(); + Map<String, Object> subsystemAttribs = new TreeMap<String, Object>(); + Map<String, Object> serviceAttribs = new TreeMap<String, Object>(); + Map<String, Object> packagesAttribs = new TreeMap<String, Object>(); + Map<String, String> dict = subsystem.getSubsystemHeaders(null); + + // do an initial loop and separate the attributes in different groups + for (String k : dict.keySet()) { + Object v = dict.get(k); + if (k.startsWith(SUBSYSTEM_PREFIX)) { + // starts with Bundle-xxx + subsystemAttribs.put(k, v); + } else if (k.endsWith(SERVICE_SUFFIX) || k.endsWith(CAPABILITY_SUFFIX)) { + // ends with xxx-Service + serviceAttribs.put(k, v); + } else if (k.endsWith(PACKAGE_SUFFFIX)) { + // ends with xxx-Package + packagesAttribs.put(k, v); + } else if (k.endsWith(REQUIRE_BUNDLE_ATTRIB)) { + // require bundle statement + packagesAttribs.put(k, v); + } else { + // the remaining attribs + otherAttribs.put(k, v); + } + } + + // we will display the formatted result like this: + // Bundle-Name (ID) + // ----------------------- + // all other attributes + // + // all Subsystem attributes + // + // all Service attributes + // + // all Package attributes + Iterator<Map.Entry<String, Object>> it = otherAttribs.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry<String, Object> e = it.next(); + output.append(String.format("%s = %s\n", e.getKey(), ShellUtil.getValueString(e.getValue()))); + } + if (otherAttribs.size() > 0) { + output.append('\n'); + } + + it = subsystemAttribs.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry<String, Object> e = it.next(); + output.append(e.getKey()); + output.append(" = \n"); + formatHeader(ShellUtil.getValueString(e.getValue()), null, output, indent); + output.append("\n"); + } + if (subsystemAttribs.size() > 0) { + output.append('\n'); + } + + it = serviceAttribs.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry<String, Object> e = it.next(); + output.append(e.getKey()); + output.append(" = \n"); + formatHeader(ShellUtil.getValueString(e.getValue()), null, output, indent); + output.append("\n"); + } + if (serviceAttribs.size() > 0) { + output.append('\n'); + } + + Map<String, ClauseFormatter> formatters = new HashMap<String, ClauseFormatter>(); + /* + formatters.put(REQUIRE_BUNDLE_ATTRIB, new ClauseFormatter() { + public void pre(Clause clause, StringBuilder output) { + boolean isSatisfied = checkBundle(clause.getName(), clause.getAttribute("bundle-version")); + Ansi.ansi(output).fg(isSatisfied ? Ansi.Color.DEFAULT : Ansi.Color.RED).a(""); + } + public void post(Clause clause, StringBuilder output) { + Ansi.ansi(output).reset().a(""); + } + }); + formatters.put(IMPORT_PACKAGES_ATTRIB, new ClauseFormatter() { + public void pre(Clause clause, StringBuilder output) { + boolean isSatisfied = checkPackage(clause.getName(), clause.getAttribute("version")); + boolean isOptional = "optional".equals(clause.getDirective("resolution")); + Ansi.ansi(output).fg(isSatisfied ? Ansi.Color.DEFAULT : Ansi.Color.RED) + .a(isSatisfied || isOptional ? Ansi.Attribute.INTENSITY_BOLD_OFF : Ansi.Attribute.INTENSITY_BOLD) + .a(""); + } + public void post(Clause clause, StringBuilder output) { + Ansi.ansi(output).reset().a(""); + } + }); + */ + + it = packagesAttribs.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry<String, Object> e = it.next(); + output.append(e.getKey()); + output.append(" = \n"); + formatHeader(ShellUtil.getValueString(e.getValue()), formatters.get(e.getKey()), output, indent); + output.append("\n"); + } + if (packagesAttribs.size() > 0) { + output.append('\n'); + } + + return output.toString(); + } + + protected interface ClauseFormatter { + void pre(Clause clause, StringBuilder output); + void post(Clause clause, StringBuilder output); + } + + protected void formatHeader(String header, ClauseFormatter formatter, StringBuilder builder, int indent) { + Clause[] clauses = Parser.parseHeader(header); + formatClauses(clauses, formatter, builder, indent); + } + + protected void formatClauses(Clause[] clauses, ClauseFormatter formatter, StringBuilder builder, int indent) { + boolean first = true; + for (Clause clause : clauses) { + if (first) { + first = false; + } else { + builder.append(",\n"); + } + formatClause(clause, formatter, builder, indent); + } + } + + protected void formatClause(Clause clause, ClauseFormatter formatter, StringBuilder builder, int indent) { + builder.append("\t"); + if (formatter != null) { + formatter.pre(clause, builder); + } + formatClause(clause, builder, indent); + if (formatter != null) { + formatter.post(clause, builder); + } + } + + protected int getTermWidth() { + return terminal.getWidth(); + + } + + protected void formatClause(Clause clause, StringBuilder builder, int indent) { + if (indent < 0) { + if (clause.toString().length() < getTermWidth() - 8) { // -8 for tabs + indent = 1; + } else { + indent = 3; + } + } + String name = clause.getName(); + Directive[] directives = clause.getDirectives(); + Attribute[] attributes = clause.getAttributes(); + Arrays.sort(directives, new Comparator<Directive>() { + public int compare(Directive o1, Directive o2) { + return o1.getName().compareTo(o2.getName()); + } + }); + Arrays.sort(attributes, new Comparator<Attribute>() { + public int compare(Attribute o1, Attribute o2) { + return o1.getName().compareTo(o2.getName()); + } + }); + builder.append(name); + for (int i = 0; directives != null && i < directives.length; i++) { + builder.append(";"); + if (indent > 1) { + builder.append("\n\t\t"); + } + builder.append(directives[i].getName()).append(":="); + String v = directives[i].getValue(); + if (v.contains(",")) { + if (indent > 2 && v.length() > 20) { + v = v.replace(",", ",\n\t\t\t"); + } + builder.append("\"").append(v).append("\""); + } else { + builder.append(v); + } + } + for (int i = 0; attributes != null && i < attributes.length; i++) { + builder.append(";"); + if (indent > 1) { + builder.append("\n\t\t"); + } + builder.append(attributes[i].getName()).append("="); + String v = attributes[i].getValue(); + if (v.contains(",")) { + if (indent > 2 && v.length() > 20) { + v = v.replace(",", ",\n\t\t\t"); + } + builder.append("\"").append(v).append("\""); + } else { + builder.append(v); + } + } + } + + + /* + private boolean checkBundle(String bundleName, String version) { + VersionRange vr = VersionRange.parseVersionRange(version); + Bundle[] bundles = bundleContext.getBundles(); + for (int i = 0; (bundles != null) && (i < bundles.length); i++) { + String sym = bundles[i].getSymbolicName(); + if ((sym != null) && sym.equals(bundleName)) { + if (vr.contains(bundles[i].getVersion())) { + return true; + } + } + } + return false; + } + + private boolean checkPackage(String packageName, String version) { + VersionRange range = VersionRange.parseVersionRange(version); + Bundle[] bundles = bundleContext.getBundles(); + for (int i = 0; (bundles != null) && (i < bundles.length); i++) { + BundleWiring wiring = bundles[i].adapt(BundleWiring.class); + List<BundleCapability> caps = wiring != null ? wiring.getCapabilities(BundleRevision.PACKAGE_NAMESPACE) : null; + if (caps != null) { + for (BundleCapability cap : caps) { + String n = getAttribute(cap, BundleRevision.PACKAGE_NAMESPACE); + String v = getAttribute(cap, Constants.VERSION_ATTRIBUTE); + if (packageName.equals(n) && range.contains(VersionTable.getVersion(v))) { + return true; + } + } + } + } + return false; + } + + private String getAttribute(BundleCapability cap, String name) { + Object obj = cap.getAttributes().get(name); + return obj != null ? obj.toString() : null; + } + */ + +} http://git-wip-us.apache.org/repos/asf/karaf/blob/084f579b/subsystem/src/main/java/org/apache/karaf/subsystem/commands/InstallAction.java ---------------------------------------------------------------------- diff --git a/subsystem/src/main/java/org/apache/karaf/subsystem/commands/InstallAction.java b/subsystem/src/main/java/org/apache/karaf/subsystem/commands/InstallAction.java new file mode 100644 index 0000000..a086d2c --- /dev/null +++ b/subsystem/src/main/java/org/apache/karaf/subsystem/commands/InstallAction.java @@ -0,0 +1,39 @@ +/* + * 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 org.apache.karaf.subsystem.commands; + +import org.apache.karaf.shell.api.action.Action; +import org.apache.karaf.shell.api.action.Argument; +import org.apache.karaf.shell.api.action.Command; +import org.apache.karaf.shell.api.action.Completion; +import org.apache.karaf.shell.api.action.lifecycle.Service; + +@Command(scope = "subsystem", name = "install", description = "Install a new subsystem") +@Service +public class InstallAction extends SubsystemSupport implements Action { + + @Argument(name = "Subsystem to install the new subsystem into") + @Completion(SubsystemCompleter.class) + String id; + + @Argument(name = "New subsystem url", index = 1) + String location; + + @Override + public Object execute() throws Exception { + getSubsystem(id).install(location); + return null; + } + +} http://git-wip-us.apache.org/repos/asf/karaf/blob/084f579b/subsystem/src/main/java/org/apache/karaf/subsystem/commands/ListAction.java ---------------------------------------------------------------------- diff --git a/subsystem/src/main/java/org/apache/karaf/subsystem/commands/ListAction.java b/subsystem/src/main/java/org/apache/karaf/subsystem/commands/ListAction.java new file mode 100644 index 0000000..458ff5b --- /dev/null +++ b/subsystem/src/main/java/org/apache/karaf/subsystem/commands/ListAction.java @@ -0,0 +1,56 @@ +/* + * 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 org.apache.karaf.subsystem.commands; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import org.apache.karaf.shell.api.action.Action; +import org.apache.karaf.shell.api.action.Command; +import org.apache.karaf.shell.api.action.lifecycle.Service; +import org.apache.karaf.shell.support.table.ShellTable; +import org.osgi.service.subsystem.Subsystem; + +@Command(scope = "subsystem", name = "list", description = "List all subsystems") +@Service +public class ListAction extends SubsystemSupport implements Action { + + @Override + public Object execute() throws Exception { + ShellTable table = new ShellTable(); + table.column("ID").alignRight(); + table.column("SymbolicName"); + table.column("Version"); + table.column("State"); + table.column("Parents"); + table.column("Children"); + + for (Subsystem ss : getSubsystems()) { + table.addRow().addContent( + ss.getSubsystemId(), + ss.getSymbolicName(), + ss.getVersion(), + ss.getState().toString(), + getSubsytemIds(ss.getParents()), + getSubsytemIds(ss.getChildren()) + ); + } + table.print(System.out); + return null; + } + +} http://git-wip-us.apache.org/repos/asf/karaf/blob/084f579b/subsystem/src/main/java/org/apache/karaf/subsystem/commands/StartAction.java ---------------------------------------------------------------------- diff --git a/subsystem/src/main/java/org/apache/karaf/subsystem/commands/StartAction.java b/subsystem/src/main/java/org/apache/karaf/subsystem/commands/StartAction.java new file mode 100644 index 0000000..1ce126e --- /dev/null +++ b/subsystem/src/main/java/org/apache/karaf/subsystem/commands/StartAction.java @@ -0,0 +1,39 @@ +/* + * 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 org.apache.karaf.subsystem.commands; + +import org.apache.karaf.shell.api.action.Action; +import org.apache.karaf.shell.api.action.Argument; +import org.apache.karaf.shell.api.action.Command; +import org.apache.karaf.shell.api.action.Completion; +import org.apache.karaf.shell.api.action.lifecycle.Service; +import org.osgi.service.subsystem.Subsystem; + +@Command(scope = "subsystem", name = "start", description = "Start the specified subsystems") +@Service +public class StartAction extends SubsystemSupport implements Action { + + @Argument(description = "Subsystem names or ids") + @Completion(SubsystemCompleter.class) + String id; + + @Override + public Object execute() throws Exception { + for (Subsystem ss : getSubsystems(id)) { + ss.start(); + } + return null; + } + +} http://git-wip-us.apache.org/repos/asf/karaf/blob/084f579b/subsystem/src/main/java/org/apache/karaf/subsystem/commands/StopAction.java ---------------------------------------------------------------------- diff --git a/subsystem/src/main/java/org/apache/karaf/subsystem/commands/StopAction.java b/subsystem/src/main/java/org/apache/karaf/subsystem/commands/StopAction.java new file mode 100644 index 0000000..5b2255c --- /dev/null +++ b/subsystem/src/main/java/org/apache/karaf/subsystem/commands/StopAction.java @@ -0,0 +1,39 @@ +/* + * 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 org.apache.karaf.subsystem.commands; + +import org.apache.karaf.shell.api.action.Action; +import org.apache.karaf.shell.api.action.Argument; +import org.apache.karaf.shell.api.action.Command; +import org.apache.karaf.shell.api.action.Completion; +import org.apache.karaf.shell.api.action.lifecycle.Service; +import org.osgi.service.subsystem.Subsystem; + +@Command(scope = "subsystem", name = "stop", description = "Stop the specified subsystems") +@Service +public class StopAction extends SubsystemSupport implements Action { + + @Argument(description = "Subsystem names or ids") + @Completion(SubsystemCompleter.class) + String id; + + @Override + public Object execute() throws Exception { + for (Subsystem ss : getSubsystems(id)) { + ss.stop(); + } + return null; + } + +} http://git-wip-us.apache.org/repos/asf/karaf/blob/084f579b/subsystem/src/main/java/org/apache/karaf/subsystem/commands/SubsystemCompleter.java ---------------------------------------------------------------------- diff --git a/subsystem/src/main/java/org/apache/karaf/subsystem/commands/SubsystemCompleter.java b/subsystem/src/main/java/org/apache/karaf/subsystem/commands/SubsystemCompleter.java new file mode 100644 index 0000000..025b9f4 --- /dev/null +++ b/subsystem/src/main/java/org/apache/karaf/subsystem/commands/SubsystemCompleter.java @@ -0,0 +1,38 @@ +/* + * 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 org.apache.karaf.subsystem.commands; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.karaf.shell.api.action.lifecycle.Service; +import org.apache.karaf.shell.api.console.CommandLine; +import org.apache.karaf.shell.api.console.Completer; +import org.apache.karaf.shell.api.console.Session; +import org.apache.karaf.shell.support.completers.StringsCompleter; +import org.osgi.service.subsystem.Subsystem; + +@Service +public class SubsystemCompleter extends SubsystemSupport implements Completer { + + @Override + public int complete(Session session, CommandLine commandLine, List<String> candidates) { + List<String> strings = new ArrayList<String>(); + for (Subsystem ss : getSubsystems()) { + strings.add(Long.toString(ss.getSubsystemId())); + strings.add(ss.getSymbolicName() + "/" + ss.getVersion()); + } + return new StringsCompleter(strings).complete(session, commandLine, candidates); + } +} http://git-wip-us.apache.org/repos/asf/karaf/blob/084f579b/subsystem/src/main/java/org/apache/karaf/subsystem/commands/SubsystemSupport.java ---------------------------------------------------------------------- diff --git a/subsystem/src/main/java/org/apache/karaf/subsystem/commands/SubsystemSupport.java b/subsystem/src/main/java/org/apache/karaf/subsystem/commands/SubsystemSupport.java new file mode 100644 index 0000000..e91461e --- /dev/null +++ b/subsystem/src/main/java/org/apache/karaf/subsystem/commands/SubsystemSupport.java @@ -0,0 +1,126 @@ +/* + * 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 org.apache.karaf.subsystem.commands; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.karaf.shell.api.action.lifecycle.Reference; +import org.osgi.service.subsystem.Subsystem; +import org.osgi.service.subsystem.SubsystemConstants; + +public abstract class SubsystemSupport { + + @Reference + Subsystem subsystem; + + protected Subsystem getRoot() { + Subsystem ss = subsystem; + while (!ss.getParents().isEmpty()) { + ss = ss.getParents().iterator().next(); + } + return ss; + } + + protected Subsystem getSubsystem(String id) { + List<Subsystem> subsystems = getSubsystems(id); + int nb = subsystems.size(); + if (nb == 0) { + throw new IllegalArgumentException("No subsystem matching " + id); + } else if (nb > 1) { + throw new IllegalArgumentException("Multiple subsystems matching " + id); + } else { + return subsystems.get(0); + } + } + + protected List<Subsystem> getSubsystems(String id) { + // Null id + if (id == null || id.isEmpty()) { + return getSubsystems(); + } + List<Subsystem> subsystems = new ArrayList<Subsystem>(); + // Try with the id + Pattern pattern = Pattern.compile("^\\d+$"); + Matcher matcher = pattern.matcher(id); + if (matcher.find()) { + long lid = Long.parseLong(id); + for (Subsystem ss : getSubsystems()) { + if (ss.getSubsystemId() == lid) { + subsystems.add(ss); + } + } + return subsystems; + } + // Try with an id range + pattern = Pattern.compile("^(\\d+)-(\\d+)$"); + matcher = pattern.matcher(id); + if (matcher.find()) { + int index = id.indexOf('-'); + long startId = Long.parseLong(id.substring(0, index)); + long endId = Long.parseLong(id.substring(index + 1)); + for (Subsystem ss : getSubsystems()) { + if (startId <= ss.getSubsystemId() && ss.getSubsystemId() <= endId) { + subsystems.add(ss); + } + } + return subsystems; + } + int index = id.indexOf('/'); + Pattern p1, p2; + if (index < 0) { + p1 = Pattern.compile(id); + p2 = null; + } else { + p1 = Pattern.compile(id.substring(0, index)); + p2 = Pattern.compile(id.substring(index + 1)); + } + for (Subsystem ss : getSubsystems()) { + if (p1.matcher(ss.getSymbolicName()).find() && + (p2 == null || p2.matcher(ss.getVersion().toString()).find())) { + subsystems.add(ss); + } + } + return subsystems; + } + + protected List<Long> getSubsytemIds(Collection<Subsystem> subsystems) { + List<Long> ids = new ArrayList<Long>(); + for (Subsystem ss : subsystems) { + ids.add(ss.getSubsystemId()); + } + return ids; + } + + protected List<Subsystem> getSubsystems() { + Map<Long, Subsystem> subsystems = new TreeMap<Long, Subsystem>(); + doGetSubsystems(subsystems, getRoot()); + return new ArrayList<Subsystem>(subsystems.values()); + } + + private void doGetSubsystems(Map<Long, Subsystem> subsystems, Subsystem subsystem) { + if (subsystems.put(subsystem.getSubsystemId(), subsystem) == null) { + for (Subsystem child : subsystem.getChildren()) { + doGetSubsystems(subsystems, child); + } + } + } + +} http://git-wip-us.apache.org/repos/asf/karaf/blob/084f579b/subsystem/src/main/java/org/apache/karaf/subsystem/commands/UninstallAction.java ---------------------------------------------------------------------- diff --git a/subsystem/src/main/java/org/apache/karaf/subsystem/commands/UninstallAction.java b/subsystem/src/main/java/org/apache/karaf/subsystem/commands/UninstallAction.java new file mode 100644 index 0000000..93a924e --- /dev/null +++ b/subsystem/src/main/java/org/apache/karaf/subsystem/commands/UninstallAction.java @@ -0,0 +1,39 @@ +/* + * 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 org.apache.karaf.subsystem.commands; + +import org.apache.karaf.shell.api.action.Action; +import org.apache.karaf.shell.api.action.Argument; +import org.apache.karaf.shell.api.action.Command; +import org.apache.karaf.shell.api.action.Completion; +import org.apache.karaf.shell.api.action.lifecycle.Service; +import org.osgi.service.subsystem.Subsystem; + +@Command(scope = "subsystem", name = "uninstall", description = "Uninstall the specified subsystems") +@Service +public class UninstallAction extends SubsystemSupport implements Action { + + @Argument(description = "Subsystem names or ids") + @Completion(SubsystemCompleter.class) + String id; + + @Override + public Object execute() throws Exception { + for (Subsystem ss : getSubsystems(id)) { + ss.uninstall(); + } + return null; + } + +}
