Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGlyn Normington2010-05-11 08:15:08 -0400
committerGlyn Normington2010-05-11 08:15:08 -0400
commit5dfdbe75bdf1ba2476fe2e60e62e3454a3565de7 (patch)
tree5522099ce269769cdd39fe31fbe2d20afd416a1c /org.eclipse.virgo.kernel.shell/src
parentb99bf75af622c030c6c9b479c1639925bd1ea872 (diff)
downloadorg.eclipse.virgo.kernel-5dfdbe75bdf1ba2476fe2e60e62e3454a3565de7.tar.gz
org.eclipse.virgo.kernel-5dfdbe75bdf1ba2476fe2e60e62e3454a3565de7.tar.xz
org.eclipse.virgo.kernel-5dfdbe75bdf1ba2476fe2e60e62e3454a3565de7.zip
initial checkin from dm Server kernel commit dffbc217a919cefba04886160ba820f2c6cf5f57 omitting build-kernel/bin/service
Diffstat (limited to 'org.eclipse.virgo.kernel.shell/src')
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/Command.java47
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/CommandCompleter.java49
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/Converter.java88
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/AnnotationBasedCommandResolver.java75
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandDescriptor.java63
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandInvoker.java39
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandNotFoundException.java32
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandProcessor.java52
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandProviderResolver.java32
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandRegistry.java114
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandRegistryCommandInvoker.java174
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandResolver.java38
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandSession.java41
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CompoundCommandResolver.java49
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/ExitCallback.java33
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/JLineLocalShell.java224
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/LocalInputOutputManager.java123
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/LocalShell.java33
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/LocalShellFactory.java40
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/ParametersMismatchException.java40
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/RemoteShellsManager.java230
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/ServicePropertyCommandResolver.java98
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/ServiceRegistryCommandProviderResolver.java43
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/ServiceUtils.java84
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/ShellLauncher.java137
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/ShellLogEvents.java57
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/SshdShell.java129
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/StandardCommandProcessor.java44
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/StandardCommandSession.java81
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/StandardLocalShellFactory.java59
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/AbstractInstallArtifactBasedCommands.java172
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/BundleCommands.java155
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/ConfigCommands.java94
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/ExitCommand.java39
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/HelpCommand.java116
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/InstallCommand.java69
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/PackageCommands.java77
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/ParCommands.java27
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/PlanCommands.java28
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/ServiceCommands.java49
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/ShutdownCommand.java66
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/AbstractInstallArtifactCompleter.java98
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/BundleCompleter.java24
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/CommandCompleterRegistry.java36
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/CommandRegistryBackedJLineCompletor.java121
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/ConfigCompleter.java95
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/DelegatingJLineCompletor.java124
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/HelpCommandCompleter.java58
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/InstallCompleter.java182
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/PackageCompleter.java87
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/ParCompleter.java24
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/PlanCompleter.java24
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/ServiceRegistryCommandCompleterRegistry.java122
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/converters/ConverterRegistry.java35
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/converters/LongConverter.java76
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/converters/ServiceRegistryConverterRegistry.java124
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/converters/StringConverter.java53
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/formatting/AbstractInstallArtifactCommandFormatter.java79
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/formatting/BundleInstallArtifactCommandFormatter.java435
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/formatting/CompositeInstallArtifactCommandFormatter.java41
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/formatting/ConfigInstallArtifactCommandFormatter.java83
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/formatting/InstallArtifactCommandFormatter.java24
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/formatting/PackageCommandFormatter.java142
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/formatting/PropertyFormatter.java111
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/formatting/ServiceCommandFormatter.java151
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/help/HelpAccessor.java47
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/help/SimpleFileHelpAccessor.java156
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/parsing/ParsedCommand.java80
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/parsing/ParsingUtils.java76
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/util/ArtifactRetriever.java84
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/model/helper/ArtifactAccessor.java64
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/model/helper/ArtifactAccessorPointer.java47
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/model/helper/RamAccessorHelper.java101
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/model/helper/StandardArtifactAccessor.java136
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/model/helper/StandardArtifactAccessorPointer.java126
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/model/helper/StandardRamAccessorHelper.java244
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/QuasiLiveBundle.java52
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/QuasiLiveService.java58
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/QuasiPackage.java55
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/StateService.java109
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/internal/StandardQuasiLiveBundle.java194
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/internal/StandardQuasiLiveFramework.java123
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/internal/StandardQuasiLiveService.java137
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/internal/StandardQuasiPackage.java71
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/internal/StandardStateService.java204
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/resources/EventLogMessages.properties2
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/resources/META-INF/spring/module-context.xml140
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/resources/META-INF/spring/osgi-context.xml137
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.BundleCommands.help19
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.ConfigCommands.help18
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.ExitCommand.help6
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.HelpCommand.help5
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.InstallCommand.help4
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.PackageCommands.help5
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.ParCommands.help10
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.PlanCommands.help10
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.ServiceCommands.help5
-rw-r--r--org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.ShutdownCommand.help4
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/AnnotationBasedCommandResolverTests.java84
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/DelegatingCompletorTests.java71
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/RemoteShellsManagerTests.java218
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/ServiceRegistryCommandProviderResolverTests.java64
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/StandardCommandProcessorTests.java47
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/StandardCommandSessionTests.java50
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/StubLocalShell.java42
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/StubLocalShellFactory.java33
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/commands/AbztractCompositeInstallArtifactBasedCommandsTests.java103
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/commands/ConfigCommandsTests.java74
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/commands/InstallCommandTests.java137
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/commands/StubAbstractCompositeInstallArtifactBasedCommands.java23
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/commands/StubInstallArtifactCommandFormatter.java30
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/commands/StubRuntimeArtifactModelObjectNameCreator.java71
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/completers/AbztractInstallArtifactCompleterTests.java99
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/completers/ConfigCompleterTests.java85
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/completers/InstallCompleterTests.java105
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/converters/LongConverterTests.java69
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/converters/StringConverterTests.java84
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/formatting/AbztractInstallArtifactCommandFormatterTests.java44
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/formatting/CompositeInstallArtifactCommandFormatterTests.java31
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/formatting/ConfigInstallArtifactCommandFormatterTests.java92
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/formatting/PropertyFormatterTests.java53
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/formatting/ServiceCommandFormatterTests.java72
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/formatting/StubManageableCompositeArtifact.java182
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/formatting/TestOutputComparator.java48
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/help/SimpleFileHelpAccessorTests.java91
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/model/helper/DummyManagableArtifact.java80
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/model/helper/StandardArtifactAccessorPointerTests.java123
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/model/helper/StandardArtifactAccessorTests.java109
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/model/helper/StandardRamAccessorHelperTests.java200
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/state/internal/StandardQuasiLiveBundleTests.java185
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/state/internal/StandardQuasiLiveServiceTests.java109
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/state/internal/StandardQuasiPackageTests.java81
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/state/internal/StandardStateServiceTests.java108
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/stubs/StubQuasiExportPackage.java79
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/stubs/StubQuasiFramework.java85
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/stubs/StubQuasiFrameworkFactory.java31
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/stubs/StubQuasiImportPackage.java83
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/stubs/StubQuasiLiveBundle.java104
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/stubs/StubQuasiLiveService.java63
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/stubs/StubQuasiPackage.java53
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/stubs/StubStateService.java73
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/resources/helpAccessorTests.help7
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/resources/org/eclipse/virgo/kernel/shell/internal/formatting/abstract-list.txt2
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/resources/org/eclipse/virgo/kernel/shell/internal/formatting/composite-examine.txt7
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/resources/org/eclipse/virgo/kernel/shell/internal/formatting/config-examine.txt13
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/resources/org/eclipse/virgo/kernel/shell/internal/formatting/service-examine.txt8
-rw-r--r--org.eclipse.virgo.kernel.shell/src/test/resources/org/eclipse/virgo/kernel/shell/internal/formatting/service-list.txt3
147 files changed, 11826 insertions, 0 deletions
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/Command.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/Command.java
new file mode 100644
index 00000000..bfa61cc3
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/Command.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * <code>Command</code> is used to annotate shell commands. Applying the annotation to a class will identify it as a
+ * provider of shell commands and allows the base command name to be specified. Applying the annotation to a method will
+ * identify it as a shell command and allows the command's name to be specified. For example:
+ *
+ * <pre>
+ *{@link Command @Command}("do")
+ * public class MyCommands {
+ *
+ * {@link Command @Command}("something")
+ * public String performCommand() {
+ * return "hello";
+ * }
+ * }
+ * <p />
+ * </pre>
+ *
+ * This class will result in a top-level command called do that provides a sub-command named something, i.e.
+ * <code>do something</code> would be a valid command in the shell.
+ *
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target( { ElementType.TYPE, ElementType.METHOD })
+@Inherited
+public @interface Command {
+
+ String value();
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/CommandCompleter.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/CommandCompleter.java
new file mode 100644
index 00000000..bae667c0
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/CommandCompleter.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell;
+
+import java.util.List;
+
+/**
+ * A <code>CommandCompleter</code> is used to help the user complete a command. A <code>CommandCompleter</code> can be
+ * made available to the Shell by publishing it in the service registry and setting the required
+ * {@link #SERVICE_PROPERTY_COMPLETER_COMMAND_NAMES service property}.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Thread-safe.
+ *
+ */
+public interface CommandCompleter {
+
+ /**
+ * A service property used to specify the commands with which the completer should be associated. The property's
+ * value must be either a String or a String[].
+ */
+ public static final String SERVICE_PROPERTY_COMPLETER_COMMAND_NAMES = "org.eclipse.virgo.kernel.shell.completer.commmandNames";
+
+ /**
+ * Returns all of the completion candidates for the given <code>subCommand</code> and <code>arguments</code>. The
+ * argument which the user is attempting to complete is always the last argument. If the user is attempting to
+ * complete the first argument, <code>arguments</code> will contain a single entry that is an empty String, i.e.
+ * <code>arguments</code> will always have length >= 1, and will never contain <code>null</code> entries.
+ *
+ * @param subCommand The subCommand, or <code>null</code> if there is no sub-command.
+ *
+ * @param arguments The arguments that the user has entered thus far
+ *
+ * @return The completion candidates. If there are no candidates, an empty array is returned, <strong>not</strong>
+ * null.
+ */
+ List<String> getCompletionCandidates(String subCommand, String... arguments);
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/Converter.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/Converter.java
new file mode 100644
index 00000000..de74f88a
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/Converter.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) OSGi Alliance (2008). All Rights Reserved.
+ *
+ * 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.virgo.kernel.shell;
+
+/**
+ * A converter is a service that can help create specific object types from a
+ * string, and vice versa.
+ *
+ * The shell is capable of coercing arguments to the their proper type. However,
+ * sometimes commands require extra help to do this conversion. This service can
+ * implement a converter for a number of types.
+ *
+ * The command shell will rank these services in order of service.ranking and
+ * will then call them until one of the converters succeeds.
+ *
+ * TODO The javadoc in this class need a good scrub before release.
+ *
+ * @ThreadSafe
+ * @version $Revision: 5654 $
+ */
+public interface Converter {
+ /**
+ * This property is a string, or array of strings, and defines the classes
+ * or interfaces that this converter recognizes. Recognized classes can be
+ * converted from a string to a class and they can be printed in 3 different
+ * modes.
+ */
+ String CONVERTER_CLASSES = "osgi.converter.classes";
+
+ /**
+ * Print the object in detail. This can contain multiple lines.
+ */
+ int INSPECT = 0;
+
+ /**
+ * Print the object as a row in a table. The columns should align for
+ * multiple objects printed beneath each other. The print may run over
+ * multiple lines but must not end in a CR.
+ */
+ int LINE = 1;
+
+ /**
+ * Print the value in a small format so that it is identifiable. This
+ * printed format must be recognizable by the conversion method.
+ */
+ int PART = 2;
+
+ /**
+ * Convert an object to the desired type.
+ *
+ * Return null if the conversion can not be done. Otherwise return and
+ * object that extends the desired type or implements it.
+ *
+ * @param desiredType The type that the returned object can be assigned to
+ * @param in The object that must be converted
+ * @return An object that can be assigned to the desired type or null.
+ * @throws Exception
+ */
+ Object convert(Class<?> desiredType, Object in) throws Exception;
+
+ /**
+ * Convert an object to a CharSequence object in the requested format. The
+ * format can be INSPECT, LINE, or PART. Other values must throw
+ * IllegalArgumentException.
+ *
+ * @param target The object to be converted to a String
+ * @param level One of INSPECT, LINE, or PART.
+ * @param escape Use this object to format sub ordinate objects.
+ * @return A printed object of potentially multiple lines
+ * @throws Exception
+ */
+ CharSequence format(Object target, int level, Converter escape)
+ throws Exception;
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/AnnotationBasedCommandResolver.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/AnnotationBasedCommandResolver.java
new file mode 100644
index 00000000..ba8963e4
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/AnnotationBasedCommandResolver.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.virgo.kernel.shell.Command;
+import org.osgi.framework.ServiceReference;
+
+
+/**
+ * <p>
+ * A <code>CommandResolver</code> that examines the OSGi service for {@link Command} annotations to resolve the
+ * service's commands.
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Thread-safe.
+ *
+ */
+final class AnnotationBasedCommandResolver implements CommandResolver {
+
+ public List<CommandDescriptor> resolveCommands(ServiceReference serviceReference, Object object) {
+ List<CommandDescriptor> commandDescriptors = new ArrayList<CommandDescriptor>();
+
+ Class<? extends Object> clazz = object.getClass();
+ String commandName = getCommandName(clazz);
+
+ if (commandName != null) {
+ while (clazz != null) {
+ commandDescriptors.addAll(resolveCommands(clazz, object, commandName));
+ clazz = clazz.getSuperclass();
+ }
+ }
+
+ return commandDescriptors;
+ }
+
+ private List<CommandDescriptor> resolveCommands(Class<?> clazz, Object object, String commandName) {
+ List<CommandDescriptor> commandDescriptors = new ArrayList<CommandDescriptor>();
+
+ for (Method method : clazz.getDeclaredMethods()) {
+ String subCommandName = getCommandName(method);
+
+ if (subCommandName != null) {
+ commandDescriptors.add(new CommandDescriptor(commandName, subCommandName, method, object));
+ }
+ }
+
+ return commandDescriptors;
+ }
+
+ private String getCommandName(AnnotatedElement annotatedElement) {
+ Command command = annotatedElement.getAnnotation(Command.class);
+
+ if (command == null) {
+ return null;
+ } else {
+ return command.value();
+ }
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandDescriptor.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandDescriptor.java
new file mode 100644
index 00000000..9c495db3
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandDescriptor.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+import java.lang.reflect.Method;
+
+/**
+ * A <code>CommandDescriptor</code> describes a command that is known to the Shell.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ * Thread-safe.
+ *
+ */
+public final class CommandDescriptor {
+
+ private final String commandName;
+
+ private final String subCommandName;
+
+ private final Method method;
+
+ private final Object target;
+
+ CommandDescriptor(String commandName, String subCommandName, Method method, Object target) {
+ this.commandName = commandName;
+ this.subCommandName = subCommandName;
+ this.method = method;
+ this.target = target;
+ }
+
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append(commandName).append(" ").append(subCommandName).append(" ").append(method);
+ return builder.toString();
+ }
+
+ public String getCommandName() {
+ return commandName;
+ }
+
+
+ public String getSubCommandName() {
+ return subCommandName;
+ }
+
+ public Method getMethod() {
+ return method;
+ }
+
+ public Object getTarget() {
+ return target;
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandInvoker.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandInvoker.java
new file mode 100644
index 00000000..0c0b1a16
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandInvoker.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+import java.util.List;
+
+import org.eclipse.virgo.kernel.shell.internal.parsing.ParsedCommand;
+
+
+
+/**
+ * A <code>CommandInvoker</code> is used to invoke a command once it has been parsed.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Implementations <strong>must</strong> be thread-safe.
+ *
+ */
+public interface CommandInvoker {
+
+ /**
+ * Invokes the supplied <code>command</code>.
+ * @param command the command to invoke
+ * @return the result of invoking the command
+ * @throws CommandNotFoundException if a matching command could not be found
+ * @throws ParametersMismatchException if the command has too few parameters
+ */
+ List<String> invokeCommand(ParsedCommand command) throws CommandNotFoundException, ParametersMismatchException;
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandNotFoundException.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandNotFoundException.java
new file mode 100644
index 00000000..6654f18e
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandNotFoundException.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+
+/**
+ * Thrown to signal that a command that matches the supplied input could not be found.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Thread-safe.
+ *
+ * @see CommandInvoker#invokeCommand(org.eclipse.virgo.kernel.shell.internal.parsing.ParsedCommand)
+ */
+public class CommandNotFoundException extends Exception {
+
+ private static final long serialVersionUID = -5788920220311337018L;
+
+ CommandNotFoundException() {
+ super();
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandProcessor.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandProcessor.java
new file mode 100644
index 00000000..20e1d30d
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandProcessor.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+import java.io.PrintStream;
+
+
+/**
+ * A command shell can create and maintain a number of command sessions.
+ */
+public interface CommandProcessor
+{
+ /**
+ * The scope of commands provided by this service. This name can be used to distinguish
+ * between different command providers with the same function names.
+ */
+ final static String COMMAND_SCOPE = "osgi.command.scope";
+
+ /**
+ * A list of method names that may be called for this command provider. A
+ * name may end with a *, this will then be calculated from all declared public
+ * methods in this service.
+ * <p/>
+ * Help information for the command may be supplied with a space as
+ * separation.
+ */
+ final static String COMMAND_FUNCTION = "osgi.command.function";
+
+ /**
+ * Create a new command session associated with err streams.
+ * <p/>
+ * The session is bound to the life cycle of the bundle getting this
+ * service. The session will be automatically closed when this bundle is
+ * stopped or the service is returned.
+ * <p/>
+ * The shell will provide any available commands to this session and
+ * can set additional variables.
+ *
+ * @param err The stream used for System.err
+ * @return A new session.
+ */
+ CommandSession createSession(PrintStream err);
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandProviderResolver.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandProviderResolver.java
new file mode 100644
index 00000000..ea7fc1ea
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandProviderResolver.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+/**
+ * A <code>CommandProviderResolver</code> is responsible for resolving
+ * command providers by command name.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Implementations must be thread-safe.
+ *
+ */
+public interface CommandProviderResolver {
+
+ /**
+ * Returns an Object that provides the command with the given <code>command</code> name.
+ * @param command The command for which a provider is required
+ * @return The provider of the command, or <code>null</code> if no provider exists.
+ */
+ public abstract Object getCommandProvider(String command);
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandRegistry.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandRegistry.java
new file mode 100644
index 00000000..532f3179
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandRegistry.java
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * A <code>CommandRegistry</code> maintains a list of {@link CommandDescriptor CommandDescriptors} based on the contents
+ * of the OSGi service registry. Descriptors are created using a {@link CommandResolver}.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Thread-safe.
+ *
+ */
+public final class CommandRegistry {
+
+ private final CommandResolver commandResolver;
+
+ private final BundleContext bundleContext;
+
+ private final List<CommandDescriptor> commandDescriptors = new ArrayList<CommandDescriptor>();
+
+ private final Map<ServiceReference, List<CommandDescriptor>> commandDescriptorsByService = new HashMap<ServiceReference, List<CommandDescriptor>>();
+
+ private final Object monitor = new Object();
+
+ private final CommandRegistryServiceListener commandRegistryServiceListener = new CommandRegistryServiceListener();
+
+ /**
+ * @param commandResolver
+ * @param bundleContext
+ */
+ public CommandRegistry(CommandResolver commandResolver, BundleContext bundleContext) {
+ this.commandResolver = commandResolver;
+ this.bundleContext = bundleContext;
+ }
+
+ void initialize() {
+ // TODO Limit with a filter
+ this.bundleContext.addServiceListener(this.commandRegistryServiceListener);
+ try {
+ // TODO Limit with a filter
+ ServiceReference[] serviceReferences = this.bundleContext.getServiceReferences(null, null);
+ if (serviceReferences != null) {
+ for (ServiceReference serviceReference : serviceReferences) {
+ serviceRegistered(serviceReference);
+ }
+ }
+ } catch (InvalidSyntaxException e) {
+ throw new RuntimeException("Unexpected InvalidSyntaxException", e);
+ }
+ }
+
+ public List<CommandDescriptor> getCommandDescriptors() {
+ synchronized(this.monitor) {
+ return new ArrayList<CommandDescriptor>(this.commandDescriptors);
+ }
+ }
+
+
+ private void serviceRegistered(ServiceReference serviceReference) {
+ Object service = bundleContext.getService(serviceReference);
+ if (service != null) {
+ List<CommandDescriptor> commands = commandResolver.resolveCommands(serviceReference, service);
+ if (!commands.isEmpty()) {
+ synchronized (this.monitor) {
+ this.commandDescriptors.addAll(commands);
+ this.commandDescriptorsByService.put(serviceReference, commands);
+ }
+ }
+ }
+ }
+
+ private void serviceUnregistering(ServiceReference serviceReference) {
+ synchronized (this.monitor) {
+ List<CommandDescriptor> commandDescriptorsForService = this.commandDescriptorsByService.remove(serviceReference);
+ this.commandDescriptors.removeAll(commandDescriptorsForService);
+ }
+ }
+
+ private final class CommandRegistryServiceListener implements ServiceListener {
+
+ /**
+ * {@inheritDoc}
+ */
+ public void serviceChanged(ServiceEvent event) {
+ if (ServiceEvent.REGISTERED == event.getType()) {
+ serviceRegistered(event.getServiceReference());
+ } else if (ServiceEvent.UNREGISTERING == event.getType()) {
+ serviceUnregistering(event.getServiceReference());
+ }
+ }
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandRegistryCommandInvoker.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandRegistryCommandInvoker.java
new file mode 100644
index 00000000..2981dc7b
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandRegistryCommandInvoker.java
@@ -0,0 +1,174 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.virgo.kernel.shell.Converter;
+import org.eclipse.virgo.kernel.shell.internal.converters.ConverterRegistry;
+import org.eclipse.virgo.kernel.shell.internal.parsing.ParsedCommand;
+import org.springframework.util.ReflectionUtils;
+
+
+/**
+ * A <code>CommandInvoker</code> implementation that finds the command to invoke from a {@link CommandRegistry}.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Thread-safe.
+ *
+ */
+final class CommandRegistryCommandInvoker implements CommandInvoker {
+
+ private final CommandRegistry commandRegistry;
+
+ private final ConverterRegistry converterRegistry;
+
+ /**
+ * @param commandRegistry
+ * @param converterRegistry
+ */
+ CommandRegistryCommandInvoker(CommandRegistry commandRegistry, ConverterRegistry converterRegistry) {
+ this.commandRegistry = commandRegistry;
+ this.converterRegistry = converterRegistry;
+ }
+
+ public List<String> invokeCommand(ParsedCommand command) throws CommandNotFoundException, ParametersMismatchException {
+ List<CommandDescriptor> commands = commandsOfCommandName(this.commandRegistry, command.getCommand());
+
+ if (commands.isEmpty()) {
+ throw new CommandNotFoundException();
+ }
+
+ String[] arguments = command.getArguments();
+
+ String subcommandName = extractSubcommand(arguments);
+
+ String[] subcommandArguments = extractSubcommandArguments(arguments);
+
+ ParametersMismatchException lastException = null;
+
+ for (CommandDescriptor commandDescriptor : commands) {
+ List<String> objResult = null;
+ String commandSubcommandName = commandDescriptor.getSubCommandName();
+ String commandString = commandDescriptor.getCommandName();
+ try {
+ if (commandSubcommandName != null && !commandSubcommandName.equals("")) {
+ if (isSubcommandMatch(commandSubcommandName, subcommandName)) {
+ commandString += " " + subcommandName;
+ objResult = attemptExecution(commandDescriptor, subcommandArguments);
+ return objResult;
+ }
+ } else {
+ objResult = attemptExecution(commandDescriptor, arguments);
+ return objResult;
+ }
+ } catch (ParametersMismatchException e) {
+ lastException = new ParametersMismatchException("Command " + commandString + ": " + e.getMessage());
+ }
+ }
+
+ if (lastException != null) {
+ throw lastException;
+ }
+
+ throw new ParametersMismatchException("Command '" + command.getCommand() + "' expecting subcommand; try tab completion");
+ }
+
+ private static boolean isSubcommandMatch(String commandSubcommandName, String subcommandName) {
+ if (subcommandName == null) {
+ return false;
+ }
+ if (commandSubcommandName != null) {
+ if (commandSubcommandName.equals(subcommandName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static String[] extractSubcommandArguments(String[] arguments) {
+ if (arguments.length > 0) {
+ String[] result = new String[arguments.length - 1];
+ System.arraycopy(arguments, 1, result, 0, result.length);
+ return result;
+ }
+ return null;
+ }
+
+ private static String extractSubcommand(String[] arguments) {
+ if (arguments.length > 0) {
+ return arguments[0];
+ }
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ private List<String> attemptExecution(CommandDescriptor commandDescriptor, String[] arguments) throws ParametersMismatchException {
+ Method method = commandDescriptor.getMethod();
+
+ Object[] convertedArguments = convertArguments(method, arguments);
+
+ ReflectionUtils.makeAccessible(method);
+ return (List<String>) ReflectionUtils.invokeMethod(method, commandDescriptor.getTarget(), convertedArguments);
+ }
+
+ private static List<CommandDescriptor> commandsOfCommandName(final CommandRegistry commandRegistry, final String commandName) {
+ List<CommandDescriptor> commands = new ArrayList<CommandDescriptor>();
+ for (CommandDescriptor commandDescriptor : commandRegistry.getCommandDescriptors()) {
+ if (commandDescriptor.getCommandName().equals(commandName)) {
+ commands.add(commandDescriptor);
+ }
+ }
+ return commands;
+ }
+
+ private Object[] convertArguments(final Method method, final String[] arguments) throws ParametersMismatchException {
+ Class<?>[] parameterTypes = method.getParameterTypes();
+
+ if (parameterTypes.length != arguments.length) {
+ throw new ParametersMismatchException("Incorrect number of parameters");
+ }
+
+ Object[] parameters = new Object[parameterTypes.length];
+
+ for (int i = 0; i < parameterTypes.length; i++) {
+
+ Object convertedParameter = convertArgument(arguments[i], parameterTypes[i]);
+
+ if (convertedParameter != null) {
+ parameters[i] = convertedParameter;
+ } else {
+ throw new ParametersMismatchException("Cannot convert parameter " + i + ".");
+ }
+ }
+
+ return parameters;
+ }
+
+ private Object convertArgument(final String argument, Class<?> type) {
+ Converter converter = this.converterRegistry.getConverter(type);
+
+ if (converter == null) {
+ return null;
+ }
+
+ try {
+ return converter.convert(type, argument);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandResolver.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandResolver.java
new file mode 100644
index 00000000..5daa0b84
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandResolver.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+import java.util.List;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * A <code>CommandResolver</code> is used to resolve Shell commands provided by an OSGi service. The mechanism by which
+ * commands are resolved for a service are a detail of the implementation.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ * Implementations <strong>must</strong> be thread-safe.
+ *
+ */
+interface CommandResolver {
+
+ /**
+ * Resolve commands from the supplied {@link ServiceReference} and <code>service</code>
+ *
+ * @param serviceReference The reference to the service
+ * @param service The service
+ * @return A <code>List</code> of <code>CommandDescriptor</code>s or an empty list if no commands were found
+ */
+ List<CommandDescriptor> resolveCommands(ServiceReference serviceReference, Object service);
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandSession.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandSession.java
new file mode 100644
index 00000000..100d0059
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CommandSession.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+
+import java.util.List;
+
+/**
+ * This can take a typed command and figure out the correct Command to call or Completer to use if the command is not recognised.
+ *
+ * Implementations should be threadsafe
+ *
+ */
+interface CommandSession
+{
+ /**
+ * Execute a program in this session.
+ *
+ * @param commandline
+ * @return the result of the execution
+ * @throws Exception
+ */
+ List<String> execute(CharSequence commandline) throws Exception;
+
+ /**
+ * Close this command session. After the session is closed, it will throw
+ * IllegalStateException when it is used.
+ *
+ * @param
+ */
+ void close();
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CompoundCommandResolver.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CompoundCommandResolver.java
new file mode 100644
index 00000000..11a0c523
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/CompoundCommandResolver.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * A <code>CommandResolver</code> that combines results from one or more delegates.
+ *
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Thread-safe.
+ *
+ */
+final class CompoundCommandResolver implements CommandResolver {
+
+ private final CommandResolver[] commandResolvers;
+
+ CompoundCommandResolver(CommandResolver... commandResolvers) {
+ this.commandResolvers = commandResolvers;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<CommandDescriptor> resolveCommands(ServiceReference serviceReference, Object service) {
+ List<CommandDescriptor> commandDescriptors = new ArrayList<CommandDescriptor>();
+
+ for (CommandResolver commandResolver : commandResolvers) {
+ commandDescriptors.addAll(commandResolver.resolveCommands(serviceReference, service));
+ }
+
+ return commandDescriptors;
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/ExitCallback.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/ExitCallback.java
new file mode 100644
index 00000000..defa2333
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/ExitCallback.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+
+/**
+ * <p>
+ * Provides a mechanism for a shell to inform interested parties when it is going to exit.
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * ExitCallback implementations should be threadsafe
+ *
+ */
+interface ExitCallback {
+
+ /**
+ * To be called by the shell when it is about to exit.
+ * There is no need to call this when the shell is being stopped.
+ */
+ void onExit();
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/JLineLocalShell.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/JLineLocalShell.java
new file mode 100644
index 00000000..0621d867
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/JLineLocalShell.java
@@ -0,0 +1,224 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import jline.ConsoleReader;
+
+import org.eclipse.virgo.kernel.shell.internal.completers.CommandCompleterRegistry;
+import org.eclipse.virgo.kernel.shell.internal.completers.CommandRegistryBackedJLineCompletor;
+import org.eclipse.virgo.kernel.shell.internal.completers.DelegatingJLineCompletor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * <p>
+ * SpringShellWrapper is a wrapper around a JLine {@link ConsoleReader} that knows how to talk to
+ * the dm Server and handle shutdown from the client.
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * SpringShellWrapper is thread safe
+ *
+ */
+final class JLineLocalShell implements Runnable, LocalShell {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(JLineLocalShell.class);
+
+ private static final String PROMPT = ":> ";
+
+ private static final String EXIT = "exit";
+
+ private static final String EXIT_MSG = "Goodbye.";
+
+ private static final String CR_LF = "\r\n";
+
+ private final CommandProcessor commandProcessor;
+
+ private final InputStream in;
+
+ private final PrintStream out;
+
+ private final PrintStream err;
+
+ private final Set<ExitCallback> callbacks = new HashSet<ExitCallback>();
+
+ private final CommandRegistry commandRegistry;
+
+ private final CommandCompleterRegistry completerRegistry;
+
+ public JLineLocalShell(CommandRegistry commandRegistry, CommandCompleterRegistry completerRegistry, CommandProcessor commandProcessor,
+ InputStream in, PrintStream out, PrintStream err) {
+ this.commandRegistry = commandRegistry;
+ this.completerRegistry = completerRegistry;
+ this.commandProcessor = commandProcessor;
+ this.in = in;
+ this.out = out;
+ this.err = err;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void addExitCallback(ExitCallback exitCallback) {
+ if (exitCallback != null) {
+ this.callbacks.add(exitCallback);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void run() {
+ ConsoleReader console;
+ try {
+ console = new ConsoleReader(this.in, new LineSeparatorEnforcingWriter(new PrintWriter((this.out))));
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ LOGGER.info("Launching a new shell in thread %s", Thread.currentThread().getName());
+
+ console.setUseHistory(true);
+ console.setUsePagination(true);
+ console.setDefaultPrompt(PROMPT);
+
+ console.addCompletor(new CommandRegistryBackedJLineCompletor(this.commandRegistry));
+ console.addCompletor(new DelegatingJLineCompletor(this.completerRegistry));
+
+ CommandSession commandSession = this.commandProcessor.createSession(this.err);
+
+ String command;
+ boolean running = true;
+ List<String> executionResult;
+ try {
+ this.printHeader(console);
+ while (running) {
+ command = console.readLine();
+ if (command != null) {
+ command = command.trim();
+ if (command.length() > 0) {
+ if (EXIT.equalsIgnoreCase(command)) {
+ running = false;
+ printToScreen(console, Arrays.asList(EXIT_MSG));
+ informCallbacksOfExit();
+ } else {
+ try {
+ executionResult = commandSession.execute(command);
+ if (executionResult == null) {
+ executionResult = Arrays.asList(String.format("Null result returned for '%s'", command));
+ }
+ } catch (Exception e) {
+ executionResult = Arrays.asList(String.format("%s while executing command '%s': '%s'", e.getClass().getName(),
+ command, e.getMessage()));
+ }
+ printToScreen(console, executionResult);
+ }
+ }
+ }
+ }
+ } catch (IOException e) {
+ this.out.println("Error occurred while writing to the shell. Please restart the shell bundle.");
+ commandSession.close();
+ throw new IllegalStateException("The Shell was unable to recover from an IO error", e);
+ }
+ commandSession.close();
+ }
+
+ private void informCallbacksOfExit() {
+ for (ExitCallback exitCallback : this.callbacks) {
+ exitCallback.onExit();
+ }
+ }
+
+ /**
+ * Each line in this header must be kept under 80 characters in order to avoid line wrapping problems on some
+ * consoles.
+ *
+ * Generated with the help of http://www.network-science.de/ascii/ using the 'slant' font.
+ *
+ * @param console
+ * @throws IOException
+ */
+ private void printHeader(ConsoleReader console) throws IOException {
+ List<String> lines = new ArrayList<String>();
+ lines.add("");
+ lines.add(" _ ___");
+ lines.add(" | | / (_)________ _____");
+ lines.add(" | | / / / ___/ __ `/ __ \\");
+ lines.add(" | |/ / / / / /_/ / /_/ /");
+ lines.add(" |___/_/_/ \\__, /\\____/");
+ lines.add(" /____/");
+ lines.add("");
+ lines.add("Type 'help' to see the available commands.");
+ printToScreen(console, lines);
+ }
+
+ private void printToScreen(ConsoleReader console, List<String> lines) throws IOException {
+ console.printString(String.format(CR_LF));
+ for (String line : lines) {
+ console.printString(String.format("%s%s", line, CR_LF));
+ }
+ console.printString(String.format(CR_LF));
+ }
+
+ private static final class LineSeparatorEnforcingWriter extends Writer {
+
+ private final Writer delegate;
+
+ LineSeparatorEnforcingWriter(Writer delegate) {
+ this.delegate = delegate;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void close() throws IOException {
+ this.delegate.close();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void flush() throws IOException {
+ this.delegate.flush();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void write(char[] cbuf, int off, int len) throws IOException {
+ for (int i = off; i < len; i++) {
+ char c = cbuf[i];
+ if (c == '\n') {
+ this.delegate.write('\r');
+ }
+ this.delegate.write(c);
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/LocalInputOutputManager.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/LocalInputOutputManager.java
new file mode 100644
index 00000000..bc098408
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/LocalInputOutputManager.java
@@ -0,0 +1,123 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.PrintStream;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+import org.eclipse.virgo.medic.log.DelegatingPrintStream;
+
+
+/**
+ * <p>
+ * LocalInputOutputManager can grab the system input and output streams from the service registry and block and release them
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * LocalInputOutputManager is thread safe
+ *
+ */
+public final class LocalInputOutputManager {
+
+ private static final String SERVICE_FILTER_SYSERR_DELEGATE = "(org.eclipse.virgo.medic.log.printStream=delegating.System.err)";
+
+ private static final String SERVICE_FILTER_SYSOUT_DELEGATE = "(org.eclipse.virgo.medic.log.printStream=delegating.System.out)";
+
+ private final InputStream in;
+
+ private final PrintStream out;
+
+ private final PrintStream err;
+
+ private final DelegatingPrintStream delegatingSysOut;
+
+ private final DelegatingPrintStream delegatingSysErr;
+
+ public LocalInputOutputManager(BundleContext bundleContext) {
+ this.in = new FileInputStream(FileDescriptor.in);
+
+ this.out = getPrintStreamFromServiceRegistry(bundleContext, "(org.eclipse.virgo.medic.log.printStream=System.out)");
+ this.err = getPrintStreamFromServiceRegistry(bundleContext, "(org.eclipse.virgo.medic.log.printStream=System.err)");
+
+ this.delegatingSysOut = getDelegatingPrintStreamFromServiceRegistry(bundleContext,SERVICE_FILTER_SYSOUT_DELEGATE);
+ this.delegatingSysErr = getDelegatingPrintStreamFromServiceRegistry(bundleContext,SERVICE_FILTER_SYSERR_DELEGATE);
+ }
+
+ /**
+ *
+ */
+ public void grabSystemIO() {
+ this.delegatingSysOut.setDelegate(null);
+ this.delegatingSysErr.setDelegate(null);
+ }
+
+ /**
+ *
+ */
+ public void releaseSystemIO() {
+ this.delegatingSysOut.setDelegate(this.out);
+ this.delegatingSysErr.setDelegate(this.err);
+ }
+
+ /**
+ * Get the original {@link PrintStream} for the local command line
+ * @return PrintStream
+ */
+ public PrintStream getErr() {
+ return err;
+ }
+
+ /**
+ * Get the original {@link PrintStream} for the local command line
+ * @return PrintStream
+ */
+ public PrintStream getOut() {
+ return out;
+ }
+
+ /**
+ * Get the original {@link InputStream} for the local command line
+ * @return InputStream
+ */
+ public InputStream getIn() {
+ return in;
+ }
+
+ private static PrintStream getPrintStreamFromServiceRegistry(BundleContext bundleContext, String filter) {
+ return (PrintStream) getService(PrintStream.class, bundleContext, filter);
+ }
+
+ private static DelegatingPrintStream getDelegatingPrintStreamFromServiceRegistry(BundleContext bundleContext, String filter) {
+ return (DelegatingPrintStream) getService(DelegatingPrintStream.class, bundleContext, filter);
+ }
+
+ private static Object getService(Class<?> clazz, BundleContext bundleContext, String filter) {
+ ServiceReference[] serviceReferences;
+ try {
+ serviceReferences = bundleContext.getServiceReferences(clazz.getName(), filter);
+ } catch (InvalidSyntaxException e) {
+ throw new RuntimeException("Unexpected InvalidSyntaxException", e);
+ }
+ if (serviceReferences != null && serviceReferences.length > 0) {
+ return bundleContext.getService(serviceReferences[0]);
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/LocalShell.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/LocalShell.java
new file mode 100644
index 00000000..70c316e2
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/LocalShell.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+/**
+ * <p>
+ * Interface for local shell implementations.
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Implementations should be thread safe
+ *
+ */
+interface LocalShell extends Runnable{
+
+ /**
+ * When the shell closes down all registered callbacks will be synchronously informed
+ *
+ * @param exitCallback
+ */
+ void addExitCallback(ExitCallback exitCallback);
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/LocalShellFactory.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/LocalShellFactory.java
new file mode 100644
index 00000000..c1d12fc7
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/LocalShellFactory.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+import java.io.InputStream;
+import java.io.PrintStream;
+
+
+/**
+ * <p>
+ * ShellFactory implementations will create a new shell that reads and writes using the provided streams.
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * ShellFactory implementations should be thread safe
+ *
+ */
+interface LocalShellFactory {
+
+ /**
+ * Create a new {@link Runnable} shell using the given streams. The new shell is returned.
+ *
+ * @param in
+ * @param out
+ * @param err
+ * @return The new shell
+ */
+ LocalShell newShell(InputStream in, PrintStream out, PrintStream err);
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/ParametersMismatchException.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/ParametersMismatchException.java
new file mode 100644
index 00000000..a5e7e87f
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/ParametersMismatchException.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+
+/**
+ * An exception thrown when a command to be invoked has incorrect parameters.
+ * This might be too many, too few, or the wrong types.
+ * <p />
+ * <strong>Concurrent Semantics</strong><br />
+ * Thread-safe
+ *
+ */
+public class ParametersMismatchException extends Exception {
+
+ private static final long serialVersionUID = -1264972215460449046L;
+
+ /**
+ *
+ */
+ public ParametersMismatchException() {
+ }
+
+ /**
+ * @param message Exception detail -- in this case the nature of the mismatch
+ */
+ public ParametersMismatchException(String message) {
+ super(message);
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/RemoteShellsManager.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/RemoteShellsManager.java
new file mode 100644
index 00000000..1cc01794
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/RemoteShellsManager.java
@@ -0,0 +1,230 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.util.HashSet;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.sshd.SshServer;
+import org.apache.sshd.common.Factory;
+import org.apache.sshd.server.Command;
+import org.apache.sshd.server.PasswordAuthenticator;
+import org.apache.sshd.server.jaas.JaasPasswordAuthenticator;
+import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.eclipse.virgo.medic.eventlog.EventLogger;
+import org.eclipse.virgo.util.io.NetUtils;
+
+/**
+ * <p>
+ * RemoteShellsManager looks after the exporting of a local shell over ssh. It is mainly concerned with startup and
+ * shutdown of the shell and the sshd system.
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * RemoteShellManager is thread safe
+ *
+ */
+class RemoteShellsManager {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(RemoteShellsManager.class);
+
+ private static final String TRUE = "true";
+
+ private static final long SHUTDOWN_TIMEOUT = 30000; //30 seconds in milli seconds
+
+ private static final String JAAS_SECURITY_DOMAIN = "virgo-kernel";
+
+ private static final String PROPERTY_SHELL_PORT = "shell.port";
+
+ private static final String PROPERTY_SHELL_ENABLED = "shell.enabled";
+
+ private static final String HOST_KEY_LOCATION = "config/hostkey.ser";
+
+ private static final String DEFAULT_KERNEL_DOMAIN = "org.eclipse.virgo.kernel";
+
+ private static final String MBEAN_VALUE_SHUTDOWN = "Shutdown";
+
+ private static final String MBEAN_KEY_TYPE = "type";
+
+ private final SshdShellFactory shellFactory;
+
+ private final EventLogger eventLogger;
+
+ private final int port;
+
+ private final String portEnabled;
+
+ private SshServer sshd = null;
+
+ RemoteShellsManager(LocalShellFactory shellFactory, Properties configuration, EventLogger eventLogger) {
+ this.portEnabled = configuration.getProperty(PROPERTY_SHELL_ENABLED);
+ String portString = configuration.getProperty(PROPERTY_SHELL_PORT);
+ int initialisingPort = -1;
+ try {
+ initialisingPort = Integer.valueOf(portString);
+ if(initialisingPort < 0 || initialisingPort > 65535){
+ initialisingPort = -1;
+ }
+ } catch (NumberFormatException e) {
+ initialisingPort = -1;
+ }
+ this.port = initialisingPort;
+
+ this.shellFactory = new SshdShellFactory(shellFactory);
+ this.eventLogger = eventLogger;
+ }
+
+ /**
+ * Start the sshd shell manager using the port configured in the provided properties set. If there is no configured
+ * port then no server will be started.
+ */
+ final void start() {
+ if (this.sshd == null && portEnabled != null && TRUE.equals(portEnabled) && this.port != -1) {
+ if (NetUtils.isPortAvailable(port)) {
+ doStart(port);
+ } else {
+ this.eventLogger.log(ShellLogEvents.SERVER_SHELL_PORT_IN_USE, String.valueOf(port));
+ callShutdownMBean();
+ }
+ }
+ }
+
+ /**
+ * Start the sshd shell manager using the provided port.
+ *
+ * @param port
+ */
+ private void doStart(int port) {
+ SshServer sshd = SshServer.setUpDefaultServer();
+ sshd.setPort(port);
+ sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(HOST_KEY_LOCATION));
+ sshd.setShellFactory(this.shellFactory);
+ sshd.setPasswordAuthenticator(createPasswordAuthenticator());
+ try {
+ sshd.start();
+ this.sshd = sshd;
+ this.eventLogger.log(ShellLogEvents.SERVER_CONSOLE_PORT, port);
+ } catch (IOException e) {
+ LOGGER.warn("Error occurred while trying to start the ssh shell server.", e);
+ try {
+ sshd.stop(true);
+ } catch (InterruptedException e1) {
+ LOGGER.warn("Shell sshd server shutdown was interrupted.", e);
+ }finally{
+ this.sshd = null;
+ }
+ }
+ }
+
+ /**
+ * @return
+ */
+ protected PasswordAuthenticator createPasswordAuthenticator() {
+ JaasPasswordAuthenticator jaasPasswordAuthenticator = new JaasPasswordAuthenticator();
+ jaasPasswordAuthenticator.setDomain(JAAS_SECURITY_DOMAIN);
+ return jaasPasswordAuthenticator;
+ }
+
+ /**
+ *
+ */
+ final void stop() {
+ this.shellFactory.exit();
+ SshServer sshd = this.sshd;
+ if (sshd != null) {
+ try {
+ sshd.stop(true);
+ } catch (InterruptedException e) {
+ LOGGER.warn("Shell sshd server shutdown was interrupted.", e);
+ } finally {
+ this.sshd = null;
+ }
+ // Only wait for the port to be cleared if we have actually just tried to shutdown the ssh server
+ long shutdownTimer = 0;
+ while (shutdownTimer < SHUTDOWN_TIMEOUT) {
+ if (NetUtils.isPortAvailable(this.port)) {
+ break;
+ }
+ try {
+ shutdownTimer = shutdownTimer + (500);
+ Thread.sleep(500);
+ } catch (InterruptedException e) {
+ break;
+ }
+ }
+ }
+ }
+
+ private void callShutdownMBean() {
+ MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+ try {
+ // TODO The kernel's domain needs to be read from configuration
+ ObjectName shutdownName = ObjectName.getInstance(DEFAULT_KERNEL_DOMAIN, MBEAN_KEY_TYPE, MBEAN_VALUE_SHUTDOWN);
+ server.invoke(shutdownName, "shutdown", new Object[0], new String[0]);
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to find the shutdown MBean", e);
+ }
+ }
+
+ /**
+ */
+ private static final class SshdShellFactory implements Factory<Command> {
+
+ private static final AtomicInteger THREAD_COUNTER = new AtomicInteger();
+
+ private final Set<SshdShell> createdSshdShells = new HashSet<SshdShell>();
+
+ private final LocalShellFactory shellFactory;
+
+ /**
+ * Create a new Factory with a backing factory for the local shells
+ *
+ * @param shellFactory
+ */
+ public SshdShellFactory(LocalShellFactory shellFactory) {
+ this.shellFactory = shellFactory;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Command create() {
+ SshdShell sshdShell = new SshdShell(this.shellFactory, THREAD_COUNTER.incrementAndGet());
+ this.createdSshdShells.add(sshdShell);
+ return sshdShell;
+ }
+
+ /**
+ * Call {@link SshdShell#onExit()} to terminate the ssh session associated with each shell
+ */
+ void exit() {
+ for (SshdShell shell : this.createdSshdShells) {
+ if (shell != null) {
+ shell.onExit(); // Call this and not destroy. The local factory will handle that, we need to bring
+ // the ssh connection down here.
+ }
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/ServicePropertyCommandResolver.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/ServicePropertyCommandResolver.java
new file mode 100644
index 00000000..627835c5
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/ServicePropertyCommandResolver.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.osgi.framework.ServiceReference;
+
+
+/**
+ * A <code>CommandResolver</code> which resolves commands based on service properties.
+ *
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Thread-safe.
+ *
+ */
+public class ServicePropertyCommandResolver implements CommandResolver {
+
+ private static final String SERVICE_PROPERTY_COMMAND_FUNCTION = "osgi.command.function";
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<CommandDescriptor> resolveCommands(ServiceReference serviceReference, Object service) {
+
+ String[] commands = (String[])serviceReference.getProperty(SERVICE_PROPERTY_COMMAND_FUNCTION);
+
+ if (commands != null) {
+ List<Method> methods = new ArrayList<Method>();
+ Class<?> clazz = service.getClass();
+
+ for (String command : commands) {
+ if (command.endsWith("*")) {
+ methods.addAll(findMethods(command.substring(0, command.length() - 1), clazz));
+ } else {
+ Method method = findMethod(command, clazz);
+ if (method != null) {
+ methods.add(method);
+ }
+ }
+ }
+ return createCommandDescriptors(methods, service);
+ }
+
+ return Collections.<CommandDescriptor>emptyList();
+ }
+
+ private static Method findMethod(String methodName, Class<?> clazz) {
+ Method[] methods = clazz.getMethods();
+
+ for (Method method : methods) {
+ if (methodName.equals(method.getName())) {
+ return method;
+ }
+ }
+
+ return null;
+ }
+
+ private static List<Method> findMethods(String methodNamePrefix, Class<?> clazz) {
+ Method[] methods = clazz.getMethods();
+
+ List<Method> matchingMethods = new ArrayList<Method>();
+
+ for (Method method : methods) {
+ if (method.getName().startsWith(methodNamePrefix)) {
+ matchingMethods.add(method);
+ }
+ }
+
+ return matchingMethods;
+ }
+
+ private static List<CommandDescriptor> createCommandDescriptors(List<Method> methods, Object target) {
+ List<CommandDescriptor> commandDescriptors = new ArrayList<CommandDescriptor>();
+
+ for (Method method : methods) {
+ commandDescriptors.add(new CommandDescriptor(method.getName(), null, method, target));
+ }
+
+ return commandDescriptors;
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/ServiceRegistryCommandProviderResolver.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/ServiceRegistryCommandProviderResolver.java
new file mode 100644
index 00000000..4b62c41f
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/ServiceRegistryCommandProviderResolver.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+import org.osgi.framework.BundleContext;
+
+/**
+ * A <code>CommandProviderResolver<code> the resolves command providers by finding them in the OSGi service registry.
+ *
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Thread-safe.
+ *
+ */
+public final class ServiceRegistryCommandProviderResolver implements CommandProviderResolver {
+
+ private final BundleContext bundleContext;
+
+ /**
+ * @param bundleContext
+ */
+ public ServiceRegistryCommandProviderResolver(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object getCommandProvider(String command) {
+ return ServiceUtils.getService(this.bundleContext, Object.class, CommandProcessor.COMMAND_FUNCTION, command);
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/ServiceUtils.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/ServiceUtils.java
new file mode 100644
index 00000000..10894843
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/ServiceUtils.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Utility methods for working with services in the OSGi service registry.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Thread-safe.
+ *
+ */
+public final class ServiceUtils {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ServiceUtils.class);
+
+ public static <T> T getService(BundleContext bundleContext, Class<T> clazz, String requiredProperty, String requiredPropertyValue) {
+ T result = null;
+ try {
+ ServiceReference[] serviceReferences = bundleContext.getServiceReferences(null, String.format("(%s=*)", requiredProperty));
+ if (serviceReferences != null) {
+ for (ServiceReference serviceReference : serviceReferences) {
+ Object offeredPropertyValue = serviceReference.getProperty(requiredProperty);
+ if (offeredPropertyValue instanceof String) { // String value
+ String offeredProperty = (String) offeredPropertyValue;
+ if (offeredProperty != null && requiredPropertyValue.equals(offeredProperty)) {
+ Object potentialResult = bundleContext.getService(serviceReference);
+ if (clazz.isInstance(potentialResult)) {
+ result = clazz.cast(bundleContext.getService(serviceReference));
+ break;
+ }
+ }
+ } else if (offeredPropertyValue instanceof String[]) { // String[] value
+ String[] offeredProperties = (String[]) offeredPropertyValue;
+ if (offeredProperties != null && arrayContainsEntry(offeredProperties, requiredPropertyValue)) {
+ Object potentialResult = bundleContext.getService(serviceReference);
+ if (clazz.isInstance(potentialResult)) {
+ result = clazz.cast(bundleContext.getService(serviceReference));
+ break;
+ }
+ }
+ } else {
+ LOGGER.warn(String.format(
+ "Matching service found from bundle %d but with a bad type for the '%s' property, String or String[] expected.",
+ serviceReference.getBundle().getBundleId(), requiredProperty));
+ }
+ }
+ }
+ } catch (InvalidSyntaxException e) {
+ throw new RuntimeException("Unexpected InvalidSyntaxException", e);
+ }
+
+ return result;
+ }
+
+ private static <T> boolean arrayContainsEntry(T[] array, T entry) {
+ if (entry == null || array == null) {
+ return false;
+ }
+ for (T arrayEntry : array) {
+ if (arrayEntry != null && arrayEntry.equals(entry)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/ShellLauncher.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/ShellLauncher.java
new file mode 100644
index 00000000..9438f8f9
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/ShellLauncher.java
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Properties;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.eclipse.virgo.medic.eventlog.EventLogger;
+
+/**
+ * <p>
+ * ShellLaunchingEventHandler is responsible for starting and stopping the local
+ * and remote shells if they are configured
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * ShellLaunchingEventHandler is thread safe
+ *
+ */
+final class ShellLauncher implements ExitCallback {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ShellLauncher.class);
+
+ private static final String SHELL_LOCAL = "org.eclipse.virgo.kernel.shell.local";
+
+ private static final String KERNEL_PID = "org.eclipse.virgo.kernel";
+
+ private static final String TRUE = "true";
+
+ private final LocalInputOutputManager ioManager;
+
+ private final BundleContext bundleContext;
+
+ private final LocalShellFactory shellFactory;
+
+ private final ConfigurationAdmin configurationAdmin;
+
+ private final EventLogger eventLogger;
+
+ private RemoteShellsManager remoteShellManager = null;
+
+ private Thread localShellThread = null;
+
+ public ShellLauncher(LocalShellFactory shellFactory, ConfigurationAdmin configurationAdmin, EventLogger eventLogger, BundleContext bundleContext, LocalInputOutputManager ioManager) {
+ this.shellFactory = shellFactory;
+ this.configurationAdmin = configurationAdmin;
+ this.bundleContext = bundleContext;
+ this.eventLogger = eventLogger;
+ this.ioManager = ioManager;
+ }
+
+ void launchShells() {
+ if(this.remoteShellManager == null){
+ RemoteShellsManager remoteShellManager = new RemoteShellsManager(this.shellFactory, this.getKernelConfiguration(), this.eventLogger);
+ remoteShellManager.start();
+ this.remoteShellManager = remoteShellManager;
+ }
+ if(TRUE.equals(bundleContext.getProperty(SHELL_LOCAL))){
+ if(this.localShellThread != null){
+ LOGGER.warn("Can not start a new local shell, one is already running.");
+ } else {
+ LocalShell newLocalShell = this.shellFactory.newShell(this.ioManager.getIn(), this.ioManager.getOut(), this.ioManager.getErr());
+ newLocalShell.addExitCallback(this);
+ Thread shellInstance = new Thread(newLocalShell, "local-shell-thread");
+ shellInstance.setDaemon(true);
+ this.ioManager.grabSystemIO();
+ shellInstance.start();
+ this.localShellThread = shellInstance;
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void onExit() {
+ this.ioManager.releaseSystemIO();
+ }
+
+ /**
+ * Called by the springframework when the server is going down to stop sshd server if it has been started.
+ */
+ @SuppressWarnings("deprecation")
+ public void stop(){
+ this.ioManager.releaseSystemIO();
+ RemoteShellsManager tempRemoteShellsManager = this.remoteShellManager;
+ if(tempRemoteShellsManager != null){
+ tempRemoteShellsManager.stop();
+ this.remoteShellManager = null;
+ }
+ Thread tempLocalThread = this.localShellThread;
+ if(tempLocalThread != null){
+ tempLocalThread.stop();
+ this.localShellThread = null;
+ }
+ }
+
+ /**
+ * Return all the properties in config admin under the kernel PID as a <code>Properties</code> object.
+ *
+ */
+ private Properties getKernelConfiguration(){
+ Properties configProperties = new Properties();
+ try {
+ Configuration configuration = this.configurationAdmin.getConfiguration(KERNEL_PID);
+ Dictionary<?, ?> configDictionary = configuration.getProperties();
+ Enumeration<?> keys = configDictionary.keys();
+ String key;
+ while(keys.hasMoreElements()){
+ key = keys.nextElement().toString();
+ configProperties.put(key, configDictionary.get(key).toString());
+ }
+ } catch (IOException e) {
+ LOGGER.warn(String.format("Error occurred while reading the Kernel config from PID '%s'", KERNEL_PID), e);
+ }
+ return configProperties;
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/ShellLogEvents.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/ShellLogEvents.java
new file mode 100644
index 00000000..c670e3a3
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/ShellLogEvents.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+import org.eclipse.virgo.medic.eventlog.Level;
+import org.eclipse.virgo.medic.eventlog.LogEvent;
+
+/**
+ * <p>
+ * {@link LogEvent} for the OSGi provisioning bundle.
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Threadsafe.
+ *
+ */
+public enum ShellLogEvents implements LogEvent {
+
+ SERVER_CONSOLE_PORT(1, Level.INFO),
+ SERVER_SHELL_PORT_IN_USE(2, Level.ERROR);
+
+ private static final String PREFIX = "SH";
+
+ private final int code;
+
+ private final Level level;
+
+ private ShellLogEvents(int code, Level level) {
+ this.code = code;
+ this.level = level;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getEventCode() {
+ return String.format("%s%04d%1.1s", PREFIX, this.code, this.level);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Level getLevel() {
+ return this.level;
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/SshdShell.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/SshdShell.java
new file mode 100644
index 00000000..3276333d
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/SshdShell.java
@@ -0,0 +1,129 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+import org.apache.sshd.server.Command;
+import org.apache.sshd.server.Environment;
+
+/**
+ * <p>
+ * SshdShell is a shell that Apache sshd knows how to export over the wire.
+ * This impl simply wraps itself around a {@link LocalShell}.
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Thread-safe
+ *
+ */
+final class SshdShell implements Command, ExitCallback {
+
+ private final LocalShellFactory localShellFactory;
+
+ private final int threadNumber;
+
+ private volatile InputStream in = null;
+
+ private volatile OutputStream out = null;
+
+ private volatile OutputStream err = null;
+
+ private volatile org.apache.sshd.server.ExitCallback callback;
+
+ private volatile Thread wrappedShellThread = null;
+
+ /**
+ * @param localShellFactory
+ * @param threadNumber
+ */
+ public SshdShell(LocalShellFactory localShellFactory, int threadNumber) {
+ this.localShellFactory = localShellFactory;
+ this.threadNumber = threadNumber;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setErrorStream(OutputStream err) {
+ this.err = err;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setInputStream(InputStream in) {
+ this.in = in;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setOutputStream(OutputStream out) {
+ this.out = out;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setExitCallback(org.apache.sshd.server.ExitCallback callback) {
+ this.callback = callback;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void start(Environment env) throws IOException {
+ Thread localWrappedShellThread = this.wrappedShellThread;
+ if (localWrappedShellThread == null) {
+ InputStream localIn = this.in;
+ OutputStream localOut = this.out;
+ OutputStream localErr = this.err;
+
+ assert localIn != null;
+ assert localOut != null;
+ assert localErr != null;
+
+ LocalShell localShell = this.localShellFactory.newShell(localIn, new PrintStream(localOut), new PrintStream(localErr));
+ localShell.addExitCallback(this);
+
+ Thread shellThread = new Thread(localShell, String.format("remote-shell-thread-%d", this.threadNumber));
+ shellThread.setDaemon(true);
+ shellThread.start();
+
+ this.wrappedShellThread = shellThread;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("deprecation")
+ public void destroy() {
+ Thread shellThread = this.wrappedShellThread;
+ if (shellThread != null) {
+ shellThread.stop();
+ this.wrappedShellThread = null;
+ }
+ }
+
+ public void onExit() {
+ org.apache.sshd.server.ExitCallback localCallback = this.callback;
+ if (localCallback != null) {
+ localCallback.onExit(0);
+ }
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/StandardCommandProcessor.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/StandardCommandProcessor.java
new file mode 100644
index 00000000..e9d5ae71
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/StandardCommandProcessor.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+import java.io.PrintStream;
+
+
+/**
+ * <p>
+ * StandardCommandProcessor
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * StandardCommandProcessor is Thread safe
+ *
+ */
+final class StandardCommandProcessor implements CommandProcessor {
+
+ private final CommandInvoker commandInvoker;
+
+ /**
+ * @param commandInvoker
+ */
+ StandardCommandProcessor(CommandInvoker commandInvoker) {
+ this.commandInvoker = commandInvoker;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public CommandSession createSession(PrintStream err) {
+ return new StandardCommandSession(commandInvoker, err);
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/StandardCommandSession.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/StandardCommandSession.java
new file mode 100644
index 00000000..2d50e3f5
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/StandardCommandSession.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+import java.io.PrintStream;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.virgo.kernel.shell.internal.parsing.ParsedCommand;
+import org.eclipse.virgo.kernel.shell.internal.parsing.ParsingUtils;
+
+
+/**
+ * <p>
+ * StandardCommandSession is the standard imple of {@link CommandSession}
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * StandardCommandSession is thread safe
+ *
+ */
+final class StandardCommandSession implements CommandSession {
+
+ private final PrintStream err;
+
+ private boolean closed = false;
+
+ private final CommandInvoker commandInvoker;
+
+ StandardCommandSession(CommandInvoker commandInvoker, PrintStream err) {
+ this.commandInvoker = commandInvoker;
+ this.err = err;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<String> execute(CharSequence commandLine) {
+ testOpen();
+
+ ParsedCommand command = ParsingUtils.parseCommand(commandLine);
+
+ if (command == null) {
+ return null;
+ }
+
+ try {
+ return this.commandInvoker.invokeCommand(command);
+ } catch (CommandNotFoundException cnfe) {
+ return Arrays.asList(String.format("No command found for input %s", command));
+ } catch (ParametersMismatchException pme) {
+ return Arrays.asList(pme.getMessage());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void close() {
+ testOpen();
+ this.closed = true;
+ }
+
+ private void testOpen() {
+ if (closed) {
+ this.err.print("Command session is already closed");
+ throw new IllegalArgumentException("Command session is already closed");
+ }
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/StandardLocalShellFactory.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/StandardLocalShellFactory.java
new file mode 100644
index 00000000..6b59ec25
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/StandardLocalShellFactory.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+import java.io.InputStream;
+import java.io.PrintStream;
+
+import org.eclipse.virgo.kernel.shell.internal.completers.CommandCompleterRegistry;
+
+
+/**
+ * <p>
+ * StandardLocalShellFactory creates new local shells based on JLine and with the
+ * appropriate command information and the provided in/out streams. These shells
+ * can be wrapped to be made available remotely.
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * StandardShellFactory is thread safe
+ *
+ */
+final class StandardLocalShellFactory implements LocalShellFactory {
+
+ private final CommandProcessor commandProcessor;
+
+ private final CommandRegistry commandRegistry;
+
+ private final CommandCompleterRegistry completerRegistry;
+
+ /**
+ * Constructor taking the port that remote shells should be created on.
+ *
+ * @param commandProcessor manages sessions
+ * @param commandRegistry in which commands are to be found
+ * @param completerRegistry of command completers
+ */
+ public StandardLocalShellFactory(CommandProcessor commandProcessor, CommandRegistry commandRegistry, CommandCompleterRegistry completerRegistry) {
+ this.commandProcessor = commandProcessor;
+ this.completerRegistry = completerRegistry;
+ this.commandRegistry = commandRegistry;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public LocalShell newShell(InputStream in, PrintStream out, PrintStream err) {
+ return new JLineLocalShell(this.commandRegistry, this.completerRegistry, this.commandProcessor, in, out, err);
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/AbstractInstallArtifactBasedCommands.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/AbstractInstallArtifactBasedCommands.java
new file mode 100644
index 00000000..f99531e0
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/AbstractInstallArtifactBasedCommands.java
@@ -0,0 +1,172 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.commands;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.management.ManagementFactory;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.osgi.framework.Version;
+
+import org.eclipse.virgo.kernel.model.management.ManageableArtifact;
+import org.eclipse.virgo.kernel.model.management.RuntimeArtifactModelObjectNameCreator;
+import org.eclipse.virgo.kernel.shell.Command;
+import org.eclipse.virgo.kernel.shell.internal.formatting.InstallArtifactCommandFormatter;
+import org.eclipse.virgo.kernel.shell.internal.util.ArtifactRetriever;
+
+/**
+ * An abstract class that handles the methods that are delegated to an install artifact.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ * Thread-safe
+ *
+ */
+abstract class AbstractInstallArtifactBasedCommands<T extends ManageableArtifact> {
+
+ private static final String NO_ARTIFACT_FOR_NAME_AND_VERSION = "No %s with name '%s' and version '%s' was found";
+
+ private final MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+
+ private final String type;
+
+ private final RuntimeArtifactModelObjectNameCreator objectNameCreator;
+
+ private final InstallArtifactCommandFormatter<T> formatter;
+
+ private final ArtifactRetriever<T> artifactRetriever;
+
+ public AbstractInstallArtifactBasedCommands(String type, RuntimeArtifactModelObjectNameCreator objectNameCreator,
+ InstallArtifactCommandFormatter<T> formatter, Class<T> artifactType) {
+ this.type = type;
+ this.objectNameCreator = objectNameCreator;
+ this.formatter = formatter;
+ this.artifactRetriever = new ArtifactRetriever<T>(type, objectNameCreator, artifactType);
+ }
+
+ @Command("list")
+ public List<String> list() {
+ Set<ObjectName> objectNames = this.server.queryNames(this.objectNameCreator.createArtifactsOfTypeQuery(this.type), null);
+ List<T> artifacts = new ArrayList<T>(objectNames.size());
+ for (ObjectName objectName : objectNames) {
+ try {
+ artifacts.add(this.artifactRetriever.getArtifact(objectName));
+ } catch (InstanceNotFoundException e) {
+ // Swallow to allow other to proceed
+ }
+ }
+
+ return this.formatter.formatList(artifacts);
+ }
+
+ @Command("examine")
+ public List<String> examine(String name, String version) {
+ try {
+ return this.formatter.formatExamine(this.artifactRetriever.getArtifact(name, convertToVersion(version)));
+ } catch (IllegalArgumentException iae) {
+ return Arrays.asList(iae.getMessage());
+ } catch (InstanceNotFoundException e) {
+ return getDoesNotExistMessage(this.type, name, version);
+ }
+ }
+
+ protected List<String> getDoesNotExistMessage(String type, String name, String version) {
+ return Arrays.asList(String.format(NO_ARTIFACT_FOR_NAME_AND_VERSION, type, name, version));
+ }
+
+ @Command("start")
+ public List<String> start(String name, String version) {
+ try {
+ this.artifactRetriever.getArtifact(name, convertToVersion(version)).start();
+ return Arrays.asList(String.format("%s %s:%s started successfully", this.type, name, version));
+ } catch (IllegalArgumentException iae) {
+ return Arrays.asList(iae.getMessage());
+ } catch (InstanceNotFoundException e) {
+ return getDoesNotExistMessage(this.type, name, version);
+ } catch (Exception e) {
+ return Arrays.asList(String.format("%s %s:%s start failed", this.type, name, version), "", "", formatException(e));
+ }
+ }
+
+ @Command("stop")
+ public List<String> stop(String name, String version) {
+ try {
+ this.artifactRetriever.getArtifact(name, convertToVersion(version)).stop();
+ return Arrays.asList(String.format("%s %s:%s stopped successfully", this.type, name, version));
+ } catch (IllegalArgumentException iae) {
+ return Arrays.asList(iae.getMessage());
+ } catch (InstanceNotFoundException e) {
+ return getDoesNotExistMessage(this.type, name, version);
+ } catch (Exception e) {
+ return Arrays.asList(String.format("%s %s:%s stop failed", this.type, name, version), "", "", formatException(e));
+ }
+ }
+
+ @Command("refresh")
+ public List<String> refresh(String name, String version) {
+ try {
+ if (this.artifactRetriever.getArtifact(name, convertToVersion(version)).refresh()) {
+ return Arrays.asList(String.format("%s %s:%s refreshed successfully", this.type, name, version));
+ } else {
+ return Arrays.asList(String.format("%s %s:%s not refreshed, no changes made", this.type, name, version));
+ }
+ } catch (IllegalArgumentException iae) {
+ return Arrays.asList(iae.getMessage());
+ } catch (InstanceNotFoundException e) {
+ return getDoesNotExistMessage(this.type, name, version);
+ } catch (Exception e) {
+ return Arrays.asList(String.format("%s %s:%s refresh failed", this.type, name, version), "", "", formatException(e));
+ }
+ }
+
+ @Command("uninstall")
+ public List<String> uninstall(String name, String version) {
+ try {
+ this.artifactRetriever.getArtifact(name, convertToVersion(version)).uninstall();
+ return Arrays.asList(String.format("%s %s%s uninstalled successfully", this.type, name, version));
+ } catch (IllegalArgumentException iae) {
+ return Arrays.asList(iae.getMessage());
+ } catch (InstanceNotFoundException e) {
+ return getDoesNotExistMessage(this.type, name, version);
+ } catch (Exception e) {
+ return Arrays.asList(String.format("%s %s:%s uninstall failed", this.type, name, version), "", "", formatException(e));
+ }
+ }
+
+ protected final ArtifactRetriever<T> getArtifactRetriever() {
+ return this.artifactRetriever;
+ }
+
+ private String formatException(Exception e) {
+ StringWriter formattedException = new StringWriter();
+ PrintWriter writer = new PrintWriter(formattedException);
+ e.printStackTrace(writer);
+
+ return formattedException.toString();
+ }
+
+ static Version convertToVersion(String versionString) {
+ try {
+ return new Version(versionString);
+ } catch (IllegalArgumentException iae) {
+ throw new IllegalArgumentException(String.format("'%s' is not a valid version", versionString));
+ }
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/BundleCommands.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/BundleCommands.java
new file mode 100644
index 00000000..1c740396
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/BundleCommands.java
@@ -0,0 +1,155 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.commands;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.osgi.framework.Version;
+
+import org.eclipse.virgo.kernel.model.management.ManageableArtifact;
+import org.eclipse.virgo.kernel.model.management.RuntimeArtifactModelObjectNameCreator;
+import org.eclipse.virgo.kernel.module.ModuleContextAccessor;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiBundle;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiResolutionFailure;
+import org.eclipse.virgo.kernel.shell.Command;
+import org.eclipse.virgo.kernel.shell.internal.formatting.BundleInstallArtifactCommandFormatter;
+import org.eclipse.virgo.kernel.shell.state.StateService;
+
+/**
+ * <p>
+ * BundleCommands provides implementations of all the supported commands that can be
+ * performed on a bundle or bundles. In some cases it can fall back to generic behaviour
+ * in it super class {@link AbstractInstallArtifactBasedCommands}.
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * BundleCommands is threadsafe
+ *
+ */
+@Command("bundle")
+final class BundleCommands extends AbstractInstallArtifactBasedCommands<ManageableArtifact> {
+
+ private static final String NO_BUNDLE_FOR_BUNDLE_ID = "No bundle with id '%s' was found";
+
+ private static final String TYPE = "bundle";
+
+ private final BundleInstallArtifactCommandFormatter formatter;
+
+ private final StateService stateService;
+
+ public BundleCommands(RuntimeArtifactModelObjectNameCreator objectNameCreator, StateService stateService,
+ ModuleContextAccessor moduleContextAccessor) {
+ super(TYPE, objectNameCreator, new BundleInstallArtifactCommandFormatter(stateService, moduleContextAccessor), ManageableArtifact.class);
+ this.stateService = stateService;
+ this.formatter = new BundleInstallArtifactCommandFormatter(stateService, moduleContextAccessor);
+ }
+
+ @Command("examine")
+ public List<String> examine(long id) {
+ QuasiBundle bundle = this.stateService.getBundle(null, id);
+ if (bundle != null) {
+ return examine(bundle.getSymbolicName(), bundle.getVersion().toString());
+ } else {
+ return Arrays.asList(String.format(NO_BUNDLE_FOR_BUNDLE_ID, id));
+ }
+ }
+
+ @Command("start")
+ public List<String> start(long id) {
+ QuasiBundle bundle = this.stateService.getBundle(null, id);
+ if (bundle != null) {
+ return start(bundle.getSymbolicName(), bundle.getVersion().toString());
+ } else {
+ return Arrays.asList(String.format(NO_BUNDLE_FOR_BUNDLE_ID, id));
+ }
+ }
+
+ @Command("stop")
+ public List<String> stop(long id) {
+ QuasiBundle bundle = this.stateService.getBundle(null, id);
+ if (bundle != null) {
+ return stop(bundle.getSymbolicName(), bundle.getVersion().toString());
+ } else {
+ return Arrays.asList(String.format(NO_BUNDLE_FOR_BUNDLE_ID, id));
+ }
+ }
+
+ @Command("refresh")
+ public List<String> refresh(long id) {
+ QuasiBundle bundle = this.stateService.getBundle(null, id);
+ if (bundle != null) {
+ return refresh(bundle.getSymbolicName(), bundle.getVersion().toString());
+ } else {
+ return Arrays.asList(String.format(NO_BUNDLE_FOR_BUNDLE_ID, id));
+ }
+ }
+
+ @Command("uninstall")
+ public List<String> uninstall(long id) {
+ QuasiBundle bundle = this.stateService.getBundle(null, id);
+ if (bundle != null) {
+ return uninstall(bundle.getSymbolicName(), bundle.getVersion().toString());
+ } else {
+ return Arrays.asList(String.format(NO_BUNDLE_FOR_BUNDLE_ID, id));
+ }
+ }
+
+ @Command("diag")
+ public List<String> diag(long id) {
+ QuasiBundle bundle = this.stateService.getBundle(null, id);
+ if (bundle != null) {
+ return diag(bundle.getSymbolicName(), bundle.getVersion().toString());
+ } else {
+ return Arrays.asList(String.format(NO_BUNDLE_FOR_BUNDLE_ID, id));
+ }
+ }
+
+ @Command("diag")
+ public List<String> diag(String name, String version) {
+ QuasiBundle bundle = getBundle(name, version);
+ if (bundle != null) {
+ List<QuasiResolutionFailure> resolverReport = this.stateService.getResolverReport(null, bundle.getBundleId());
+ return this.formatter.formatDiag(bundle, resolverReport);
+ } else {
+ return getDoesNotExistMessage(TYPE, name, version);
+ }
+ }
+
+ @Command("headers")
+ public List<String> headers(long id) {
+ QuasiBundle bundle = this.stateService.getBundle(null, id);
+ if (bundle != null) {
+ return headers(bundle.getSymbolicName(), bundle.getVersion().toString());
+ } else {
+ return Arrays.asList(String.format(NO_BUNDLE_FOR_BUNDLE_ID, id));
+ }
+ }
+
+ @Command("headers")
+ public List<String> headers(String name, String version) {
+ return this.formatter.formatHeaders(getBundle(name, version));
+ }
+
+ private QuasiBundle getBundle(String name, String version) {
+ Version v = new Version(version);
+ List<QuasiBundle> bundles = this.stateService.getAllBundles(null);
+ for (QuasiBundle bundle : bundles) {
+ if (bundle.getSymbolicName().equals(name) && bundle.getVersion().equals(v)) {
+ return bundle;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/ConfigCommands.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/ConfigCommands.java
new file mode 100644
index 00000000..8a6044d8
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/ConfigCommands.java
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.commands;
+
+import java.util.Arrays;
+import java.util.List;
+
+import javax.management.InstanceNotFoundException;
+
+import org.osgi.framework.Version;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+import org.eclipse.virgo.kernel.model.management.ManageableArtifact;
+import org.eclipse.virgo.kernel.model.management.RuntimeArtifactModelObjectNameCreator;
+import org.eclipse.virgo.kernel.shell.Command;
+import org.eclipse.virgo.kernel.shell.internal.formatting.ConfigInstallArtifactCommandFormatter;
+
+/**
+ * Commands for config artifacts.
+ *
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Thread-safe.
+ *
+ */
+@Command("config")
+final class ConfigCommands extends AbstractInstallArtifactBasedCommands<ManageableArtifact> {
+
+ private static final String UNABLE_TO_EXAMINE_CONFIGURATION_IN_NON_ACTIVE_STATE = String.format("Unable to examine configuration in non-active state");
+
+ private static final String EMPTY_VERSION_STRING = Version.emptyVersion.toString();
+
+ private static final String TYPE = "configuration";
+
+ private static final String STATE_ACTIVE = "ACTIVE";
+
+ public ConfigCommands(RuntimeArtifactModelObjectNameCreator objectNameCreator, ConfigurationAdmin configurationAdmin) {
+ super(TYPE, objectNameCreator, new ConfigInstallArtifactCommandFormatter(configurationAdmin), ManageableArtifact.class);
+ }
+
+ @Command("examine")
+ public List<String> examine(String name) {
+ return examine(name, EMPTY_VERSION_STRING);
+ }
+
+ @Override
+ public List<String> examine(String name, String versionString) {
+ ManageableArtifact artifact;
+
+ try {
+ artifact = getArtifactRetriever().getArtifact(name, convertToVersion(versionString));
+ } catch (IllegalArgumentException iae) {
+ return Arrays.asList(iae.getMessage());
+ } catch (InstanceNotFoundException e) {
+ return getDoesNotExistMessage(TYPE, name, versionString);
+ }
+
+ if (STATE_ACTIVE.equals(artifact.getState())) {
+ return super.examine(name, versionString);
+ }
+ return Arrays.asList(UNABLE_TO_EXAMINE_CONFIGURATION_IN_NON_ACTIVE_STATE);
+ }
+
+ @Command("start")
+ public List<String> start(String name) {
+ return start(name, EMPTY_VERSION_STRING);
+ }
+
+ @Command("stop")
+ public List<String> stop(String name) {
+ return stop(name, EMPTY_VERSION_STRING);
+ }
+
+ @Command("refresh")
+ public List<String> refresh(String name) {
+ return refresh(name, EMPTY_VERSION_STRING);
+ }
+
+ @Command("uninstall")
+ public List<String> uninstall(String name) {
+ return uninstall(name, EMPTY_VERSION_STRING);
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/ExitCommand.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/ExitCommand.java
new file mode 100644
index 00000000..8eb6d306
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/ExitCommand.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.commands;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.virgo.kernel.shell.Command;
+
+
+/**
+ * Provides a dummy place-holder for the exit command. <br/>
+ * Since the exit command is treated specially by the command processor, this implementation cannot be invoked from the
+ * shell. The existence of this definition implies that there can be help for it, which is automatically found and
+ * displayed (by help) and that another command for 'exit' cannot be defined without a clash.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Severely thread-safe.
+ *
+ */
+@Command("exit")
+public class ExitCommand {
+
+ @Command("")
+ public List<String> exit() {
+ return Arrays.asList("No-op exit command called.");
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/HelpCommand.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/HelpCommand.java
new file mode 100644
index 00000000..1cb88956
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/HelpCommand.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.commands;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.eclipse.virgo.kernel.shell.Command;
+import org.eclipse.virgo.kernel.shell.internal.CommandDescriptor;
+import org.eclipse.virgo.kernel.shell.internal.CommandRegistry;
+import org.eclipse.virgo.kernel.shell.internal.help.HelpAccessor;
+
+
+/**
+ * A Shell command that provides help information for all of the commands known to a {@link CommandRegistry}.
+ *
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Thread-safe.
+ *
+ */
+@Command("help")
+final class HelpCommand {
+
+ private final CommandRegistry commandRegistry;
+
+ private final HelpAccessor helpAccessor;
+
+ HelpCommand(CommandRegistry commandRegistry, HelpAccessor helpAccessor) {
+ this.commandRegistry = commandRegistry;
+ this.helpAccessor = helpAccessor;
+ }
+
+ @Command("")
+ public List<String> summaryHelp() {
+ List<String> lines = new ArrayList<String>();
+
+ SortedMap<String, CommandDescriptor> topLevelCommands = getTopLevelCommands();
+ Set<String> sortedCommandNames = topLevelCommands.keySet();
+
+ int width = maxWidthOfCommandNames(sortedCommandNames);
+ String lineFormatNull = String.format(" %%-%ds", width);
+ String lineFormat = String.format(" %%-%ds - %%s", width);
+
+ lines.add("");
+
+ for (String commandName : sortedCommandNames) {
+ String commandHelp = this.helpAccessor.getSummaryHelp(topLevelCommands.get(commandName).getTarget().getClass());
+ if (commandHelp == null) {
+ lines.add(String.format(lineFormatNull, commandName));
+ } else {
+ lines.add(String.format(lineFormat, commandName, commandHelp));
+ }
+ }
+
+ lines.add("");
+
+ return lines;
+ }
+
+ private int maxWidthOfCommandNames(Set<String> keySet) {
+ int result = 0;
+ for (String key : keySet) {
+ if (result < key.length())
+ result = key.length();
+ }
+ return (result < 8 ? 8 : result);
+ }
+
+ @Command("")
+ public List<String> detailedHelp(String command) {
+
+ Map<String, CommandDescriptor> commandMap = getTopLevelCommands();
+ CommandDescriptor descriptor = commandMap.get(command);
+
+ if (descriptor == null) {
+ return Arrays.asList(String.format("No help is available as command '%s' is unknown", command));
+ }
+
+ List<String> detailedHelp = this.helpAccessor.getDetailedHelp(descriptor.getTarget().getClass());
+
+ if (detailedHelp == null || detailedHelp.size() == 0) {
+ return Arrays.asList(String.format("No help is available for command '%s'", command));
+ }
+
+ return detailedHelp;
+ }
+
+ private SortedMap<String, CommandDescriptor> getTopLevelCommands() {
+ SortedMap<String, CommandDescriptor> commandMap = new TreeMap<String, CommandDescriptor>();
+
+ List<CommandDescriptor> commands = this.commandRegistry.getCommandDescriptors();
+
+ for (CommandDescriptor command : commands) {
+ commandMap.put(command.getCommandName(), command);
+ }
+
+ return commandMap;
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/InstallCommand.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/InstallCommand.java
new file mode 100644
index 00000000..e61ab6bb
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/InstallCommand.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.commands;
+
+import java.lang.management.ManagementFactory;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.management.JMX;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.eclipse.virgo.kernel.deployer.ArtifactIdentity;
+import org.eclipse.virgo.kernel.deployer.Deployer;
+import org.eclipse.virgo.kernel.deployer.core.ApplicationDeployer;
+import org.eclipse.virgo.kernel.shell.Command;
+
+
+/**
+ * A Shell command that allows artifacts to be installed using an {@link ApplicationDeployer}.
+ *
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Thread-safe.
+ *
+ */
+@Command("install")
+public final class InstallCommand {
+
+ private static final String ARTIFACT_INSTALLATION_FAILED = "Artifact installation failed: %s";
+
+ private static final String ARTIFACT_INSTALLED = "Artifact %s %s %s installed";
+
+ private final MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+
+ private final ObjectName deployerObjectName;
+
+ public InstallCommand() throws MalformedObjectNameException, NullPointerException {
+ this.deployerObjectName = new ObjectName("org.eclipse.virgo.kernel:category=Control,type=Deployer");
+ }
+
+ @Command("")
+ public List<String> install(String artifactLocation) {
+ ArtifactIdentity artifactIdentity;
+ try {
+ artifactIdentity = getDeployer().install(artifactLocation);
+ } catch (Exception e) {
+ return Arrays.asList(String.format(ARTIFACT_INSTALLATION_FAILED, e.getMessage()));
+ }
+
+ return Arrays.asList(String.format(ARTIFACT_INSTALLED, artifactIdentity.getType(), artifactIdentity.getName(), artifactIdentity.getVersion()));
+ }
+
+ private Deployer getDeployer() {
+ return JMX.newMXBeanProxy(this.server, this.deployerObjectName, Deployer.class);
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/PackageCommands.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/PackageCommands.java
new file mode 100644
index 00000000..e5329a11
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/PackageCommands.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.commands;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.osgi.framework.Version;
+
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiBundle;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiExportPackage;
+import org.eclipse.virgo.kernel.shell.Command;
+import org.eclipse.virgo.kernel.shell.internal.formatting.PackageCommandFormatter;
+import org.eclipse.virgo.kernel.shell.state.QuasiPackage;
+import org.eclipse.virgo.kernel.shell.state.StateService;
+
+@Command("package")
+public final class PackageCommands {
+
+ private final StateService stateService;
+
+ private final PackageCommandFormatter formatter;
+
+ public PackageCommands(StateService stateService) {
+ this.stateService = stateService;
+ this.formatter = new PackageCommandFormatter();
+ }
+
+ @Command("list")
+ public List<String> list() {
+ return this.formatter.formatList(getAllPackages());
+ }
+
+ @Command("examine")
+ public List<String> examine(String name, String versionString) {
+ List<QuasiExportPackage> matchingExports = new ArrayList<QuasiExportPackage>();
+
+ Version version;
+
+ try {
+ version = AbstractInstallArtifactBasedCommands.convertToVersion(versionString);
+ } catch (IllegalArgumentException iae) {
+ return Arrays.asList(iae.getMessage());
+ }
+
+ QuasiPackage packages = this.stateService.getPackages(null, name);
+ for (QuasiExportPackage exportPackage : packages.getExporters()) {
+ if (exportPackage.getVersion().equals(version)) {
+ matchingExports.add(exportPackage);
+ }
+ }
+
+ if (matchingExports.isEmpty()) {
+ return Arrays.asList(String.format("No package with name '%s' and version '%s' was found", name, version));
+ } else {
+ return this.formatter.formatExamine(matchingExports);
+ }
+ }
+
+ private List<QuasiExportPackage> getAllPackages() {
+ List<QuasiExportPackage> packages = new ArrayList<QuasiExportPackage>();
+ for (QuasiBundle bundle : this.stateService.getAllBundles(null)) {
+ packages.addAll(bundle.getExportPackages());
+ }
+ return packages;
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/ParCommands.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/ParCommands.java
new file mode 100644
index 00000000..04437e28
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/ParCommands.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.commands;
+
+import org.eclipse.virgo.kernel.model.management.ManageableCompositeArtifact;
+import org.eclipse.virgo.kernel.model.management.RuntimeArtifactModelObjectNameCreator;
+import org.eclipse.virgo.kernel.shell.Command;
+import org.eclipse.virgo.kernel.shell.internal.formatting.CompositeInstallArtifactCommandFormatter;
+
+@Command("par")
+final class ParCommands extends AbstractInstallArtifactBasedCommands<ManageableCompositeArtifact> {
+
+ private static final String TYPE = "par";
+
+ public ParCommands(RuntimeArtifactModelObjectNameCreator objectNameCreator) {
+ super(TYPE, objectNameCreator, new CompositeInstallArtifactCommandFormatter(), ManageableCompositeArtifact.class);
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/PlanCommands.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/PlanCommands.java
new file mode 100644
index 00000000..14999abd
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/PlanCommands.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.commands;
+
+import org.eclipse.virgo.kernel.model.management.ManageableCompositeArtifact;
+import org.eclipse.virgo.kernel.model.management.RuntimeArtifactModelObjectNameCreator;
+import org.eclipse.virgo.kernel.shell.Command;
+import org.eclipse.virgo.kernel.shell.internal.formatting.CompositeInstallArtifactCommandFormatter;
+
+@Command("plan")
+final class PlanCommands extends AbstractInstallArtifactBasedCommands<ManageableCompositeArtifact> {
+
+ private static final String TYPE = "plan";
+
+ public PlanCommands(RuntimeArtifactModelObjectNameCreator objectNameCreator) {
+ super(TYPE, objectNameCreator, new CompositeInstallArtifactCommandFormatter(), ManageableCompositeArtifact.class);
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/ServiceCommands.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/ServiceCommands.java
new file mode 100644
index 00000000..bd32de48
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/ServiceCommands.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.commands;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.virgo.kernel.shell.Command;
+import org.eclipse.virgo.kernel.shell.internal.formatting.ServiceCommandFormatter;
+import org.eclipse.virgo.kernel.shell.state.QuasiLiveService;
+import org.eclipse.virgo.kernel.shell.state.StateService;
+
+
+@Command("service")
+public final class ServiceCommands {
+
+ private final StateService stateService;
+
+ private final ServiceCommandFormatter formatter;
+
+ public ServiceCommands(StateService stateService) {
+ this.stateService = stateService;
+ this.formatter = new ServiceCommandFormatter();
+ }
+
+ @Command("list")
+ public List<String> list() {
+ return this.formatter.formatList(this.stateService.getAllServices(null));
+ }
+
+ @Command("examine")
+ public List<String> examine(long serviceId) {
+ QuasiLiveService service = this.stateService.getService(null, serviceId);
+ if (service == null) {
+ return Arrays.asList(String.format("No service with id '%s' was found", serviceId));
+ } else {
+ return this.formatter.formatExamine(service);
+ }
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/ShutdownCommand.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/ShutdownCommand.java
new file mode 100644
index 00000000..c69cdc76
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/commands/ShutdownCommand.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.commands;
+
+import java.lang.management.ManagementFactory;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.eclipse.virgo.kernel.shell.Command;
+import org.eclipse.virgo.kernel.shell.internal.LocalInputOutputManager;
+
+
+/**
+ * Provides the Shell's <code>shutdown</code> command that will shutdown the kernel.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Thread-safe.
+ *
+ */
+@Command("shutdown")
+final class ShutdownCommand {
+
+ private static final String DEFAULT_KERNEL_DOMAIN = "org.eclipse.virgo.kernel";
+
+ private static final String MBEAN_VALUE_SHUTDOWN = "Shutdown";
+
+ private static final String MBEAN_KEY_TYPE = "type";
+
+ private final LocalInputOutputManager ioManager;
+
+ ShutdownCommand(LocalInputOutputManager ioManager) {
+ this.ioManager = ioManager;
+ }
+
+ @Command("")
+ public List<String> shutdown() {
+
+ this.ioManager.releaseSystemIO();
+
+ MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+ try {
+ // TODO The kernel's domain needs to be read from configuration
+ ObjectName shutdownName = ObjectName.getInstance(DEFAULT_KERNEL_DOMAIN, MBEAN_KEY_TYPE, MBEAN_VALUE_SHUTDOWN);
+ server.invoke(shutdownName, "shutdown", new Object[0], new String[0]);
+ } catch (Exception e) {
+ this.ioManager.grabSystemIO();
+ return Arrays.asList(String.format("Error occurred '%s'", e.getMessage()));
+ }
+ return Collections.emptyList();
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/AbstractInstallArtifactCompleter.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/AbstractInstallArtifactCompleter.java
new file mode 100644
index 00000000..e596e17b
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/AbstractInstallArtifactCompleter.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.completers;
+
+import java.lang.management.ManagementFactory;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.eclipse.virgo.kernel.model.management.RuntimeArtifactModelObjectNameCreator;
+import org.eclipse.virgo.kernel.shell.CommandCompleter;
+
+class AbstractInstallArtifactCompleter implements CommandCompleter {
+
+ private static final String SUBCOMMAND_LIST = "list";
+
+ private final MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+
+ private final String type;
+
+ private final RuntimeArtifactModelObjectNameCreator objectNameCreator;
+
+ public AbstractInstallArtifactCompleter(String type, RuntimeArtifactModelObjectNameCreator objectNameCreator) {
+ this.type = type;
+ this.objectNameCreator = objectNameCreator;
+ }
+
+ public final List<String> getCompletionCandidates(String subcommand, String... tokens) {
+ Set<String> candidates;
+
+ if (SUBCOMMAND_LIST.equals(subcommand)) {
+ candidates = Collections.<String> emptySet();
+ } else if (tokens.length == 2) {
+ candidates = versions(tokens[0], tokens[1]);
+ } else if (tokens.length == 1) {
+ candidates = names(tokens[0]);
+ } else {
+ candidates = Collections.<String> emptySet();
+ }
+
+ filter(candidates, subcommand, tokens);
+ List<String> candidateList = new ArrayList<String>(candidates);
+ Collections.sort(candidateList);
+ return candidateList;
+ }
+
+ /**
+ * To be over ridden by sub-classes that want to filter the completions to be offered back to the user.
+ *
+ * @param candidates
+ * @param subcommand
+ * @param tokens
+ */
+ protected void filter(@SuppressWarnings("unused") Set<String> candidates, @SuppressWarnings("unused") String subcommand, @SuppressWarnings("unused") String... tokens) {
+ }
+
+ private Set<String> versions(String name, String version) {
+ Set<String> candidates = new HashSet<String>();
+
+ Set<ObjectName> objectNames = this.server.queryNames(this.objectNameCreator.createArtifactVersionsQuery(this.type, name), null);
+ for (ObjectName objectName : objectNames) {
+ String candidateVersion = this.objectNameCreator.getVersion(objectName);
+ if (candidateVersion.startsWith(version)) {
+ candidates.add(candidateVersion);
+ }
+ }
+
+ return candidates;
+ }
+
+ private Set<String> names(String name) {
+ Set<String> candidates = new HashSet<String>();
+
+ Set<ObjectName> objectNames = this.server.queryNames(this.objectNameCreator.createArtifactsOfTypeQuery(this.type), null);
+ for (ObjectName objectName : objectNames) {
+ String candidateName = this.objectNameCreator.getName(objectName);
+ if (candidateName.startsWith(name)) {
+ candidates.add(candidateName);
+ }
+ }
+
+ return candidates;
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/BundleCompleter.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/BundleCompleter.java
new file mode 100644
index 00000000..9f6e8d2a
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/BundleCompleter.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.completers;
+
+import org.eclipse.virgo.kernel.model.management.RuntimeArtifactModelObjectNameCreator;
+
+final class BundleCompleter extends AbstractInstallArtifactCompleter {
+
+ private static final String TYPE = "bundle";
+
+ public BundleCompleter(RuntimeArtifactModelObjectNameCreator objectNameCreator) {
+ super(TYPE, objectNameCreator);
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/CommandCompleterRegistry.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/CommandCompleterRegistry.java
new file mode 100644
index 00000000..1be580b1
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/CommandCompleterRegistry.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.completers;
+
+import org.eclipse.virgo.kernel.shell.CommandCompleter;
+
+/**
+ * A <code>CommandCompleterRegistry</code> provides access to all of the currently available {@link CommandCompleter CommandCompleters}.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Implementations must be thread-safe.
+ *
+ */
+public interface CommandCompleterRegistry {
+
+ /**
+ * Returns the {@link CommandCompleter} for the command with the given <code>commandName</code>, or
+ * <code>null</code> if no such completer is known to the registry.
+ *
+ * @param commandName The name of the command for which a completer is required
+ * @return The completer for the command
+ */
+ CommandCompleter getCommandCompleter(String commandName);
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/CommandRegistryBackedJLineCompletor.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/CommandRegistryBackedJLineCompletor.java
new file mode 100644
index 00000000..3f7f3e69
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/CommandRegistryBackedJLineCompletor.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.completers;
+
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.eclipse.virgo.kernel.shell.internal.CommandDescriptor;
+import org.eclipse.virgo.kernel.shell.internal.CommandRegistry;
+import org.eclipse.virgo.kernel.shell.internal.parsing.ParsedCommand;
+import org.eclipse.virgo.kernel.shell.internal.parsing.ParsingUtils;
+
+import jline.Completor;
+
+
+/**
+ * A JLine {@link Completor} implementation that offers completions of commands and
+ * sub-commands based on the contents of a {@link CommandRegistry}.
+ * <p />
+ * <strong>Concurrent Semantics</strong><br />
+ * Thread-safe.
+ *
+ */
+public final class CommandRegistryBackedJLineCompletor implements Completor {
+
+ private final CommandRegistry commandRegistry;
+
+ /**
+ * @param commandRegistry
+ */
+ public CommandRegistryBackedJLineCompletor(CommandRegistry commandRegistry) {
+ this.commandRegistry = commandRegistry;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("unchecked")
+ public int complete(String buffer, int cursor, List candidates) {
+
+ String toParse = buffer.substring(0, cursor);
+ ParsedCommand parsedCommand = ParsingUtils.parseCommand(toParse);
+
+ if (parsedCommand == null) {
+ candidates.addAll(getCommandNames());
+ } else {
+ String commandName = parsedCommand.getCommand();
+
+ String[] arguments = parsedCommand.getArguments();
+
+ if (arguments.length == 0) {
+ candidates.addAll(getCommandNameCandidates(commandName));
+ return candidates.isEmpty() ? -1 : 0;
+ }
+
+ if (arguments.length == 1) {
+ candidates.addAll(getSubCommandNameCandidates(commandName, arguments[0]));
+ if (!candidates.isEmpty()) {
+ return commandName.length() + 1;
+ }
+ }
+ }
+
+ return candidates.isEmpty() ? -1 : 0;
+ }
+
+ private SortedSet<String> getSubCommandNameCandidates(String name, String subName) {
+ SortedSet<String> candidates = new TreeSet<String>();
+
+ List<CommandDescriptor> commandDescriptors = this.commandRegistry.getCommandDescriptors();
+
+ for (CommandDescriptor commandDescriptor : commandDescriptors) {
+ if (commandDescriptor.getCommandName().equals(name)) {
+ String candidateSubName = commandDescriptor.getSubCommandName();
+
+ if (candidateSubName != null && !"".equals(candidateSubName) && candidateSubName.startsWith(subName)) {
+ candidates.add(candidateSubName + " ");
+ }
+ }
+ }
+
+ return candidates;
+ }
+
+ private SortedSet<String> getCommandNameCandidates(String name) {
+ SortedSet<String> candidates = new TreeSet<String>();
+
+ List<CommandDescriptor> commandDescriptors = this.commandRegistry.getCommandDescriptors();
+
+ for (CommandDescriptor commandDescriptor : commandDescriptors) {
+ if (commandDescriptor.getCommandName().startsWith(name)) {
+ String candidate = commandDescriptor.getCommandName() + " ";
+ candidates.add(candidate);
+ }
+ }
+
+ return candidates;
+ }
+
+ private SortedSet<String> getCommandNames() {
+ SortedSet<String> commandNames = new TreeSet<String>();
+
+ List<CommandDescriptor> commandDescriptors = this.commandRegistry.getCommandDescriptors();
+
+ for (CommandDescriptor commandDescriptor : commandDescriptors) {
+ commandNames.add(commandDescriptor.getCommandName());
+ }
+
+ return commandNames;
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/ConfigCompleter.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/ConfigCompleter.java
new file mode 100644
index 00000000..5f5d8837
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/ConfigCompleter.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.completers;
+
+import java.lang.management.ManagementFactory;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.osgi.framework.Version;
+
+import org.eclipse.virgo.kernel.model.management.ManageableArtifact;
+import org.eclipse.virgo.kernel.model.management.RuntimeArtifactModelObjectNameCreator;
+import org.eclipse.virgo.kernel.shell.internal.util.ArtifactRetriever;
+
+final class ConfigCompleter extends AbstractInstallArtifactCompleter {
+
+ private static final String TYPE = "configuration";
+
+ private static final String COMMAND_EXAMINE = "examine";
+
+ private static final String STATE_ACTIVE = "ACTIVE";
+
+ private final MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+
+ private final RuntimeArtifactModelObjectNameCreator objectNameCreator;
+
+ private final ArtifactRetriever<ManageableArtifact> artifactRetriever;
+
+ public ConfigCompleter(RuntimeArtifactModelObjectNameCreator objectNameCreator) {
+ super(TYPE, objectNameCreator);
+ this.objectNameCreator = objectNameCreator;
+ this.artifactRetriever = new ArtifactRetriever<ManageableArtifact>(TYPE, objectNameCreator, ManageableArtifact.class);
+ }
+
+ @Override
+ protected void filter(Set<String> candidates, String subcommand, String... tokens) {
+ if (COMMAND_EXAMINE.equals(subcommand)) {
+ if (tokens.length == 2) {
+ filterVersions(tokens[0], candidates);
+ } else if (tokens.length == 1) {
+ filterNames(candidates);
+ }
+ }
+ }
+
+ private void filterVersions(String name, Set<String> candidates) {
+ for (Iterator<String> i = candidates.iterator(); i.hasNext();) {
+ try {
+ ManageableArtifact artifact = this.artifactRetriever.getArtifact(name, new Version(i.next()));
+ if (!STATE_ACTIVE.equals(artifact.getState())) {
+ i.remove();
+ }
+ } catch (InstanceNotFoundException e) {
+ // Swallow to allow others to proceed
+ }
+ }
+
+ }
+
+ private void filterNames(Set<String> candidates) {
+ for (Iterator<String> i = candidates.iterator(); i.hasNext();) {
+ Set<ObjectName> objectNames = this.server.queryNames(this.objectNameCreator.createArtifactVersionsQuery(TYPE, i.next()), null);
+ boolean hasActive = false;
+ for (ObjectName objectName : objectNames) {
+ try {
+ ManageableArtifact artifact = this.artifactRetriever.getArtifact(objectName);
+ if (STATE_ACTIVE.equals(artifact.getState())) {
+ hasActive = true;
+ break;
+ }
+ } catch (InstanceNotFoundException e) {
+ // Swallow to allow others to proceed
+ }
+ }
+ if (!hasActive) {
+ i.remove();
+ }
+ }
+
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/DelegatingJLineCompletor.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/DelegatingJLineCompletor.java
new file mode 100644
index 00000000..9f740ffe
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/DelegatingJLineCompletor.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.completers;
+
+import java.util.List;
+
+import org.eclipse.virgo.kernel.shell.CommandCompleter;
+import org.eclipse.virgo.kernel.shell.internal.parsing.ParsedCommand;
+import org.eclipse.virgo.kernel.shell.internal.parsing.ParsingUtils;
+
+import jline.Completor;
+
+
+/**
+ * A JLine {@link Completor} implementation that delegates to {@link CommandCompleter}s for command parameter completion.
+ * <p />
+ * <strong>Concurrent Semantics</strong><br />
+ * Thread-safe.
+ *
+ */
+public final class DelegatingJLineCompletor implements Completor {
+
+ private static final String EMPTY_STRING = "";
+
+ private final CommandCompleterRegistry completerRegistry;
+
+ public DelegatingJLineCompletor(CommandCompleterRegistry completerRegistry) {
+ this.completerRegistry = completerRegistry;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("unchecked")
+ public int complete(String buffer, int cursor, List candidates) {
+ if (buffer == null) {
+ buffer = EMPTY_STRING;
+ }
+
+ String toParse = buffer.substring(0, cursor);
+ ParsedCommand parsedCommand = ParsingUtils.parseCommand(toParse);
+
+ if (parsedCommand != null) {
+ CommandCompleter commandCompleter = this.completerRegistry.getCommandCompleter(parsedCommand.getCommand());
+
+ if (commandCompleter != null) {
+ String[] arguments = parsedCommand.getArguments();
+
+ String subCommand = null;
+
+ if (arguments.length > 0) {
+ subCommand = arguments[0];
+
+ String[] completionArguments = new String[arguments.length - 1];
+ System.arraycopy(arguments, 1, completionArguments, 0, completionArguments.length);
+
+ final List<String> newCandidates = commandCompleter.getCompletionCandidates(subCommand, completionArguments);
+ if (newCandidates.size() > 0) {
+ int basePosition = calculatePosition(parsedCommand.getCommand(), arguments);
+ addCandidatesOrExtension(candidates, newCandidates, cursor-basePosition);
+ return basePosition;
+ }
+ }
+ }
+ }
+
+ return candidates.isEmpty() ? -1 : 0;
+ }
+
+ private static int calculatePosition(String command, String[] arguments) {
+ int length = command.length() + 1;
+ for (int i = 0; i < arguments.length - 1; i++) {
+ length += arguments[i].length() + 1;
+ }
+ return length;
+ }
+
+ private static void addCandidatesOrExtension(List<String> candidates, final List<String> newCandidates, int rootLength) {
+ if (newCandidates.size() > 1) {
+ String newRoot = commonRoot(newCandidates);
+ if (newRoot.length() > rootLength) {
+ candidates.add(newRoot);
+ return;
+ }
+ }
+
+ for (String newCandidate : newCandidates) {
+ candidates.add(newCandidate);
+ }
+ }
+
+ private static String commonRoot(final List<String> newCandidates) {
+ StringBuilder sb = new StringBuilder();
+ String first = newCandidates.get(0);
+ for (int i = 0; i<first.length(); ++i) {
+ if (allHaveCharAtPos(newCandidates, first.charAt(i), i)) {
+ sb.append(first.charAt(i));
+ } else {
+ break;
+ }
+ }
+ return sb.toString();
+ }
+
+ private static boolean allHaveCharAtPos(final List<String> newCandidates, char testChar, int pos) {
+ for (String str : newCandidates) {
+ if (pos >= str.length() || str.charAt(pos) != testChar) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/HelpCommandCompleter.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/HelpCommandCompleter.java
new file mode 100644
index 00000000..d8a04a5d
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/HelpCommandCompleter.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.completers;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.virgo.kernel.shell.CommandCompleter;
+import org.eclipse.virgo.kernel.shell.internal.CommandDescriptor;
+import org.eclipse.virgo.kernel.shell.internal.CommandRegistry;
+
+
+/**
+ * A <code>CommandCompleter<code> for the <code>help</code> command that offers completions based on all the commands in
+ * a {@link CommandRegistry}.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Thread-safe.
+ *
+ */
+final class HelpCommandCompleter implements CommandCompleter {
+
+ private final CommandRegistry commandRegistry;
+
+ HelpCommandCompleter(CommandRegistry commandRegistry) {
+ this.commandRegistry = commandRegistry;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<String> getCompletionCandidates(String subCommand, String... arguments) {
+ List<String> candidates = new ArrayList<String>();
+ if (arguments.length == 0) {
+ // only complete first argument (subCommand)
+ List<CommandDescriptor> commandDescriptors = this.commandRegistry.getCommandDescriptors();
+ for (CommandDescriptor commandDescriptor : commandDescriptors) {
+ if (commandDescriptor.getCommandName().startsWith(subCommand)) {
+ candidates.add(commandDescriptor.getCommandName());
+ }
+ }
+ }
+ Collections.sort(candidates);
+ return candidates;
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/InstallCompleter.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/InstallCompleter.java
new file mode 100644
index 00000000..53abbedd
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/InstallCompleter.java
@@ -0,0 +1,182 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.completers;
+
+import java.lang.management.ManagementFactory;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.management.JMX;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import jline.FileNameCompletor;
+
+import org.eclipse.virgo.kernel.shell.CommandCompleter;
+import org.eclipse.virgo.repository.management.ArtifactDescriptorSummary;
+import org.eclipse.virgo.repository.management.RepositoryInfo;
+
+public class InstallCompleter implements CommandCompleter {
+
+ private static final String FILE_PREFIX = "file:";
+
+ private static final String FILE_PATH_CANDIDATE_FORMAT = FILE_PREFIX + "%s%s";
+
+ private static final String REPOSITORY_PREFIX = "repository:";
+
+ private static final String REPOSITORY_TYPE_NAME_VERSION_FORMAT = REPOSITORY_PREFIX + "%s/%s/%s";
+
+ private static final String REPOSITORY_TYPE_NAME_FORMAT = REPOSITORY_PREFIX + "%s/%s/";
+
+ private static final String REPOSITORY_TYPE_FORMAT = REPOSITORY_PREFIX + "%s/";
+
+ private static final String[] SCHEMES = { FILE_PREFIX, REPOSITORY_PREFIX };
+
+ private final MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+
+ private final ObjectName repositoryQuery;
+
+ private final ObjectName hostedRepositoryQuery;
+
+ public InstallCompleter() throws MalformedObjectNameException, NullPointerException {
+ this.repositoryQuery = new ObjectName("org.eclipse.virgo.kernel:type=Repository,*");
+ this.hostedRepositoryQuery = new ObjectName("org.eclipse.virgo.server:type=HostedRepository,*");
+ }
+
+ public List<String> getCompletionCandidates(String subcommand, String... arguments) {
+ Set<String> candidates;
+ if (arguments.length == 0) {
+ if (subcommand.startsWith(REPOSITORY_PREFIX)) {
+ candidates = repository(subcommand);
+ } else if (subcommand.startsWith(FILE_PREFIX)) {
+ candidates = file(subcommand);
+ } else {
+ candidates = new HashSet<String>();
+ for (String scheme : SCHEMES) {
+ if (scheme.startsWith(subcommand)) {
+ candidates.add(scheme);
+ }
+ }
+ }
+ } else {
+ // We do not complete anything after the 'subcommand' argument
+ candidates = new HashSet<String>();
+ }
+
+ List<String> candidateList = new ArrayList<String>(candidates);
+ Collections.sort(candidateList);
+ return candidateList;
+ }
+
+ private Set<String> file(String subcommand) {
+ List<String> candidates = new ArrayList<String>();
+
+ String path = subcommand.substring(FILE_PREFIX.length());
+ int completionIndex = new FileNameCompletor().complete(path, path.length(), candidates);
+
+ Set<String> candidateSet = new HashSet<String>(candidates.size());
+
+ if (completionIndex >= 0) {
+ String completablePath = path.substring(0, completionIndex);
+
+ for (String candidate : candidates) {
+ candidateSet.add(String.format(FILE_PATH_CANDIDATE_FORMAT, completablePath, candidate));
+ }
+ }
+
+ return candidateSet;
+ }
+
+ private Set<String> repository(String subcommand) {
+ List<String> uriParts = getUriParts(subcommand);
+
+ if (uriParts.size() == 1) {
+ return type(uriParts.get(0));
+ } else if (uriParts.size() == 2) {
+ return name(uriParts.get(0), uriParts.get(1));
+ } else if (uriParts.size() == 3) {
+ return version(uriParts.get(0), uriParts.get(1), uriParts.get(2));
+ }
+ return Collections.emptySet();
+ }
+
+ private List<String> getUriParts(String subcommand) {
+ List<String> uriParts = new ArrayList<String>(Arrays.asList(subcommand.substring(REPOSITORY_PREFIX.length()).split("/")));
+ if (subcommand.endsWith("/")) {
+ uriParts.add("");
+ }
+ return uriParts;
+ }
+
+ private Set<String> type(String type) {
+ Set<String> types = new HashSet<String>();
+
+ for (RepositoryInfo repository : getRepositories()) {
+ for (ArtifactDescriptorSummary artifact : repository.getAllArtifactDescriptorSummaries()) {
+ if (artifact.getType().startsWith(type)) {
+ types.add(String.format(REPOSITORY_TYPE_FORMAT, artifact.getType()));
+ }
+ }
+ }
+
+ return types;
+ }
+
+ private Set<String> name(String type, String name) {
+ Set<String> names = new HashSet<String>();
+
+ for (RepositoryInfo repository : getRepositories()) {
+ for (ArtifactDescriptorSummary artifact : repository.getAllArtifactDescriptorSummaries()) {
+ if (artifact.getType().equals(type) && artifact.getName().startsWith(name)) {
+ names.add(String.format(REPOSITORY_TYPE_NAME_FORMAT, artifact.getType(), artifact.getName()));
+ }
+ }
+ }
+
+ return names;
+ }
+
+ private Set<String> version(String type, String name, String version) {
+ Set<String> versions = new HashSet<String>();
+
+ for (RepositoryInfo repository : getRepositories()) {
+ for (ArtifactDescriptorSummary artifact : repository.getAllArtifactDescriptorSummaries()) {
+ if (artifact.getType().equals(type) && artifact.getName().equals(name) && artifact.getVersion().startsWith(version)) {
+ versions.add(String.format(REPOSITORY_TYPE_NAME_VERSION_FORMAT, artifact.getType(), artifact.getName(), artifact.getVersion()));
+ }
+ }
+ }
+
+ return versions;
+ }
+
+ private Set<RepositoryInfo> getRepositories() {
+ Set<String> hostedRepositoryNames = new HashSet<String>();
+ for (ObjectName objectName : this.server.queryNames(this.hostedRepositoryQuery, null)) {
+ hostedRepositoryNames.add(objectName.getKeyProperty("name"));
+ }
+
+ Set<RepositoryInfo> repositories = new HashSet<RepositoryInfo>();
+ for (ObjectName objectName : this.server.queryNames(this.repositoryQuery, null)) {
+ String name = objectName.getKeyProperty("name");
+ if (!hostedRepositoryNames.contains(name)) {
+ repositories.add(JMX.newMXBeanProxy(this.server, objectName, RepositoryInfo.class));
+ }
+ }
+ return repositories;
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/PackageCompleter.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/PackageCompleter.java
new file mode 100644
index 00000000..4cad1d3b
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/PackageCompleter.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.completers;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiBundle;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiExportPackage;
+import org.eclipse.virgo.kernel.shell.CommandCompleter;
+import org.eclipse.virgo.kernel.shell.state.StateService;
+
+public class PackageCompleter implements CommandCompleter {
+
+ private static final String SUBCOMMAND_LIST = "list";
+
+ private final StateService stateService;
+
+ public PackageCompleter(StateService stateService) {
+ this.stateService = stateService;
+ }
+
+ public List<String> getCompletionCandidates(String subcommand, String... tokens) {
+ Set<String> candidates;
+
+ if (SUBCOMMAND_LIST.equals(subcommand)) {
+ candidates = Collections.<String> emptySet();
+ } else if (tokens.length == 2) {
+ candidates = versions(tokens[0], tokens[1]);
+ } else if (tokens.length == 1) {
+ candidates = names(tokens[0]);
+ } else {
+ candidates = Collections.<String> emptySet();
+ }
+
+ List<String> candidateList = new ArrayList<String>(candidates);
+ Collections.sort(candidateList);
+ return candidateList;
+ }
+
+ private Set<String> versions(String name, String version) {
+ Set<String> versions = new HashSet<String>();
+
+ for (QuasiExportPackage exportPackage : getAllPackages()) {
+ String packageName = exportPackage.getPackageName();
+ String packageVersion = exportPackage.getVersion().toString();
+ if (packageName.equals(name) && packageVersion.startsWith(version)) {
+ versions.add(packageVersion);
+ }
+ }
+
+ return versions;
+ }
+
+ private Set<String> names(String name) {
+ Set<String> names = new HashSet<String>();
+
+ for (QuasiExportPackage exportPackage : getAllPackages()) {
+ String packageName = exportPackage.getPackageName();
+ if (packageName.startsWith(name)) {
+ names.add(packageName);
+ }
+ }
+
+ return names;
+ }
+
+ private List<QuasiExportPackage> getAllPackages() {
+ List<QuasiExportPackage> packages = new ArrayList<QuasiExportPackage>();
+ for (QuasiBundle bundle : this.stateService.getAllBundles(null)) {
+ packages.addAll(bundle.getExportPackages());
+ }
+ return packages;
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/ParCompleter.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/ParCompleter.java
new file mode 100644
index 00000000..18172037
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/ParCompleter.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.completers;
+
+import org.eclipse.virgo.kernel.model.management.RuntimeArtifactModelObjectNameCreator;
+
+final class ParCompleter extends AbstractInstallArtifactCompleter {
+
+ private static final String TYPE = "par";
+
+ public ParCompleter(RuntimeArtifactModelObjectNameCreator objectNameCreator) {
+ super(TYPE, objectNameCreator);
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/PlanCompleter.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/PlanCompleter.java
new file mode 100644
index 00000000..51f35efd
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/PlanCompleter.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.completers;
+
+import org.eclipse.virgo.kernel.model.management.RuntimeArtifactModelObjectNameCreator;
+
+final class PlanCompleter extends AbstractInstallArtifactCompleter {
+
+ private static final String TYPE = "plan";
+
+ public PlanCompleter(RuntimeArtifactModelObjectNameCreator objectNameCreator) {
+ super(TYPE, objectNameCreator);
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/ServiceRegistryCommandCompleterRegistry.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/ServiceRegistryCommandCompleterRegistry.java
new file mode 100644
index 00000000..eda6c3a6
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/completers/ServiceRegistryCommandCompleterRegistry.java
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.completers;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.virgo.kernel.shell.CommandCompleter;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+
+
+
+/**
+ * A dynamic registry of {@link CommandCompleter CommandCompleters} backed by the OSGi
+ * service registry.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Thread-safe.
+ *
+ */
+final class ServiceRegistryCommandCompleterRegistry implements CommandCompleterRegistry {
+
+ private final ServiceListener commandCompleterRegistryServiceListener = new ConverterRegistryServiceListener();
+
+ private final Map<String, CommandCompleter> completers = new HashMap<String, CommandCompleter>();
+
+ private final Object monitor = new Object();
+
+ private final BundleContext bundleContext;
+
+ ServiceRegistryCommandCompleterRegistry(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public CommandCompleter getCommandCompleter(String commandName) {
+ synchronized(this.monitor) {
+ return this.completers.get(commandName);
+ }
+ }
+
+ void initialize() {
+ try {
+ this.bundleContext.addServiceListener(this.commandCompleterRegistryServiceListener, "(objectClass=" + CommandCompleter.class.getName() + ")");
+ ServiceReference[] serviceReferences = this.bundleContext.getServiceReferences(CommandCompleter.class.getName(), null);
+ if (serviceReferences != null) {
+ for (ServiceReference serviceReference : serviceReferences) {
+ serviceRegistered(serviceReference);
+ }
+ }
+ } catch (InvalidSyntaxException e) {
+ throw new RuntimeException("Unexpected InvalidSyntaxException", e);
+ }
+ }
+
+ private void serviceRegistered(ServiceReference serviceReference) {
+ CommandCompleter completer = (CommandCompleter)bundleContext.getService(serviceReference);
+ if (completer != null) {
+ String[] commandNames = getCommandNames(serviceReference);
+ for (String commandName : commandNames) {
+ this.completers.put(commandName, completer);
+ }
+ }
+ }
+
+ private String[] getCommandNames(ServiceReference serviceReference) {
+ Object commandNamesProperty = serviceReference.getProperty(CommandCompleter.SERVICE_PROPERTY_COMPLETER_COMMAND_NAMES);
+ String[] commandNames;
+
+ if (commandNamesProperty instanceof String[]) {
+ commandNames = (String[])commandNamesProperty;
+ } else if (commandNamesProperty instanceof String) {
+ commandNames = new String[] {(String)commandNamesProperty};
+ } else {
+ commandNames = new String[0];
+ }
+ return commandNames;
+ }
+
+ private void serviceUnregistering(ServiceReference serviceReference) {
+ Object converter = this.bundleContext.getService(serviceReference);
+ if (converter != null) {
+ String[] commandNames = getCommandNames(serviceReference);
+ synchronized (monitor) {
+ for (String commandName : commandNames) {
+ this.completers.remove(commandName);
+ }
+ }
+ }
+ }
+
+ private final class ConverterRegistryServiceListener implements ServiceListener {
+
+ /**
+ * {@inheritDoc}
+ */
+ public void serviceChanged(ServiceEvent event) {
+ if (ServiceEvent.REGISTERED == event.getType()) {
+ serviceRegistered(event.getServiceReference());
+ } else if (ServiceEvent.UNREGISTERING == event.getType()) {
+ serviceUnregistering(event.getServiceReference());
+ }
+ }
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/converters/ConverterRegistry.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/converters/ConverterRegistry.java
new file mode 100644
index 00000000..2bb3c204
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/converters/ConverterRegistry.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.converters;
+
+import org.eclipse.virgo.kernel.shell.Converter;
+
+/**
+ * A <code>ConverterRegistry</code> provides access to all of the currently available {@link Converter Converters}.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Implementations must be thread-safe.
+ *
+ */
+public interface ConverterRegistry {
+
+ /**
+ * Returns the converter for the given <code>clazz</code>
+ *
+ * @param clazz The Class for which a <code>Converter</code> is required
+ * @return The <code>Converter</code> for the Class, or <code>null</code> if no <code>Converter</code> is available.
+ */
+ Converter getConverter(Class<?> clazz);
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/converters/LongConverter.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/converters/LongConverter.java
new file mode 100644
index 00000000..3d868764
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/converters/LongConverter.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.converters;
+
+import org.eclipse.virgo.kernel.shell.Converter;
+
+
+
+/**
+ * <p>
+ * LongConverter is registered in the service registry to provide a conversion service
+ * from both {@link Long} and <code>long</code> to and from Strings for use by the command
+ *
+ * resolver.
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * LongConverter is thread safe
+ *
+ */
+final public class LongConverter implements Converter {
+
+ private static final String[] TYPES = new String[]{ Long.class.getName(), long.class.getName() };
+
+ /**
+ * Simple getter used when this class is created as a bean and placed in the service registry.
+ *
+ * @return String or String[] of the types this converter can convert
+ */
+ public static String[] getTypes() {
+ return TYPES;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object convert(Class<?> desiredType, Object in) throws Exception {
+ if(canConvert(desiredType)){
+ try{
+ return Long.valueOf(in.toString());
+ }catch (NumberFormatException e){
+ // no-op to just return null
+ }
+ }
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public CharSequence format(Object target, int level, Converter escape) throws Exception {
+ if(canFormat(target)){
+ return String.valueOf(target);
+ }
+ return null;
+ }
+
+ private boolean canConvert(Class<?> desiredType) {
+ return Long.class.equals(desiredType) || long.class.equals(desiredType);
+ }
+
+ private boolean canFormat(Object target) {
+ return target instanceof Long;
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/converters/ServiceRegistryConverterRegistry.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/converters/ServiceRegistryConverterRegistry.java
new file mode 100644
index 00000000..5a74e8c7
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/converters/ServiceRegistryConverterRegistry.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.converters;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.eclipse.virgo.kernel.shell.Converter;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+
+
+
+/**
+ * A registry of {@link Converter Converters} backed by the OSGi service registry.
+ *
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Thread-safe.
+ *
+ */
+final class ServiceRegistryConverterRegistry implements ConverterRegistry {
+
+ private final ServiceListener converterRegistryServiceListener = new ConverterRegistryServiceListener();
+
+ private final Map<String, Converter> converters = new HashMap<String, Converter>();
+
+ private final Object monitor = new Object();
+
+ private final BundleContext bundleContext;
+
+ ServiceRegistryConverterRegistry(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Converter getConverter(Class<?> clazz) {
+ synchronized(this.monitor) {
+ return this.converters.get(clazz.getName());
+ }
+ }
+
+ void initialize() {
+ try {
+ this.bundleContext.addServiceListener(this.converterRegistryServiceListener, "(objectClass=" + Converter.class.getName() + ")");
+ ServiceReference[] serviceReferences = this.bundleContext.getServiceReferences(Converter.class.getName(), null);
+ if (serviceReferences != null) {
+ for (ServiceReference serviceReference : serviceReferences) {
+ serviceRegistered(serviceReference);
+ }
+ }
+ } catch (InvalidSyntaxException e) {
+ throw new RuntimeException("Unexpected InvalidSyntaxException", e);
+ }
+ }
+
+ private void serviceRegistered(ServiceReference serviceReference) {
+ Converter converter = (Converter)bundleContext.getService(serviceReference);
+ if (converter != null) {
+ String[] converterClasses = getConverterClasses(serviceReference);
+ for (String converterClass : converterClasses) {
+ this.converters.put(converterClass, converter);
+ }
+ }
+ }
+
+ private String[] getConverterClasses(ServiceReference serviceReference) {
+ Object converterClassesProperty = serviceReference.getProperty(Converter.CONVERTER_CLASSES);
+ String[] converterClasses;
+
+ if (converterClassesProperty instanceof String[]) {
+ converterClasses = (String[])converterClassesProperty;
+ } else if (converterClassesProperty instanceof String) {
+ converterClasses = new String[] {(String)converterClassesProperty};
+ } else {
+ converterClasses = new String[0];
+ }
+ return converterClasses;
+ }
+
+ private void serviceUnregistering(ServiceReference serviceReference) {
+ Object converter = this.bundleContext.getService(serviceReference);
+ if (converter != null) {
+ synchronized (monitor) {
+ Iterator<Entry<String, Converter>> iterator = this.converters.entrySet().iterator();
+ while (iterator.hasNext()) {
+ Converter candidate = iterator.next().getValue();
+ if (converter.equals(candidate)) {
+ iterator.remove();
+ }
+ }
+ }
+ }
+ }
+
+ private final class ConverterRegistryServiceListener implements ServiceListener {
+
+ public void serviceChanged(ServiceEvent event) {
+ if (ServiceEvent.REGISTERED == event.getType()) {
+ serviceRegistered(event.getServiceReference());
+ } else if (ServiceEvent.UNREGISTERING == event.getType()) {
+ serviceUnregistering(event.getServiceReference());
+ }
+ }
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/converters/StringConverter.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/converters/StringConverter.java
new file mode 100644
index 00000000..124ea1a9
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/converters/StringConverter.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.converters;
+
+import org.eclipse.virgo.kernel.shell.Converter;
+
+
+
+/**
+ */
+final public class StringConverter implements Converter {
+
+ private static final String TYPES = String.class.getName();
+
+ /**
+ * Simple getter used when this class is created as a bean and placed in the service registry.
+ *
+ * @return String or String[] of the types this converter can convert
+ */
+ public static String getTypes() {
+ return TYPES;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object convert(Class<?> desiredType, Object in) throws Exception {
+ if(desiredType.equals(String.class)){
+ return in.toString();
+ }
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public CharSequence format(Object target, int level, Converter escape) throws Exception {
+ if(target instanceof String){
+ return target.toString();
+ }
+ return null;
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/formatting/AbstractInstallArtifactCommandFormatter.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/formatting/AbstractInstallArtifactCommandFormatter.java
new file mode 100644
index 00000000..c307cf61
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/formatting/AbstractInstallArtifactCommandFormatter.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.formatting;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import org.eclipse.virgo.kernel.model.BundleArtifact;
+import org.eclipse.virgo.kernel.model.management.ManageableArtifact;
+
+public abstract class AbstractInstallArtifactCommandFormatter<T extends ManageableArtifact> implements InstallArtifactCommandFormatter<T> {
+
+ protected static final int MAX_LINE_LENGTH = 80;
+
+ private static final String NAME_COLUMN_NAME = "Name";
+
+ private static final int NAME_COLUMN_MIN_WIDTH = NAME_COLUMN_NAME.length();
+
+ private static final String VERSION_COLUMN_NAME = "Version";
+
+ private static final int VERSION_COLUMN_MIN_WIDTH = VERSION_COLUMN_NAME.length();
+
+ private static final String STATE_COLUMN_NAME = "State";
+
+ /**
+ * longest state name from {@link BundleArtifact#mapBundleState()}
+ */
+ private static final int STATE_COLUMN_MIN_WIDTH = 11;
+
+ public List<String> formatList(List<T> artifacts) {
+ Collections.sort(artifacts, new ManageableArtifactComparator<T>());
+
+ int maxNameLength = NAME_COLUMN_MIN_WIDTH;
+ int maxVersionLength = VERSION_COLUMN_MIN_WIDTH;
+ for (T artifact : artifacts) {
+ final int nameLength = artifact.getName().length();
+ maxNameLength = nameLength > maxNameLength ? nameLength : maxNameLength;
+ final int versionLength = artifact.getVersion().length();
+ maxVersionLength = versionLength > maxVersionLength ? versionLength : maxVersionLength;
+ }
+
+ List<String> lines = new ArrayList<String>();
+ int stateLength = MAX_LINE_LENGTH - (2 + maxNameLength + maxVersionLength);
+ if (stateLength < STATE_COLUMN_MIN_WIDTH) {
+ stateLength = STATE_COLUMN_MIN_WIDTH;
+ }
+ final String singleLineFormat = String.format("%%-%ds %%-%ds %%%ds", maxNameLength, maxVersionLength, stateLength);
+ lines.add(String.format(singleLineFormat, NAME_COLUMN_NAME, VERSION_COLUMN_NAME, STATE_COLUMN_NAME));
+
+ for (T artifact : artifacts) {
+ lines.add(String.format(singleLineFormat, artifact.getName(), artifact.getVersion(), artifact.getState()));
+ }
+
+ return lines;
+ }
+
+ private static class ManageableArtifactComparator<T extends ManageableArtifact> implements Comparator<T> {
+
+ public int compare(T artifact1, T artifact2) {
+ int value = artifact1.getName().compareTo(artifact2.getName());
+ if (value != 0) {
+ return value;
+ }
+ return artifact1.getVersion().compareTo(artifact2.getVersion());
+ }
+
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/formatting/BundleInstallArtifactCommandFormatter.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/formatting/BundleInstallArtifactCommandFormatter.java
new file mode 100644
index 00000000..a1e97751
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/formatting/BundleInstallArtifactCommandFormatter.java
@@ -0,0 +1,435 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.formatting;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.List;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+
+import org.eclipse.virgo.kernel.model.BundleArtifact;
+import org.eclipse.virgo.kernel.model.management.ManageableArtifact;
+import org.eclipse.virgo.kernel.module.ModuleContext;
+import org.eclipse.virgo.kernel.module.ModuleContextAccessor;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiBundle;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiExportPackage;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiImportPackage;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiResolutionFailure;
+import org.eclipse.virgo.kernel.shell.state.QuasiLiveBundle;
+import org.eclipse.virgo.kernel.shell.state.QuasiLiveService;
+import org.eclipse.virgo.kernel.shell.state.StateService;
+import org.eclipse.virgo.util.common.StringUtils;
+
+public final class BundleInstallArtifactCommandFormatter implements InstallArtifactCommandFormatter<ManageableArtifact> {
+
+ private static final int MAX_LINE_LENGTH = 80;
+
+ private static final String ID_COLUMN_NAME = "Id";
+
+ private static final int ID_COLUMN_MIN_WIDTH = ID_COLUMN_NAME.length();
+
+ private static final String SPRING_POWERED_COLUMN_NAME = " ";
+
+ private static final int SPRING_POWERED_COLUMN_WIDTH = SPRING_POWERED_COLUMN_NAME.length();
+
+ private static final String NAME_COLUMN_NAME = "Name";
+
+ private static final int NAME_COLUMN_MIN_WIDTH = NAME_COLUMN_NAME.length();
+
+ private static final String VERSION_COLUMN_NAME = "Version";
+
+ private static final int VERSION_COLUMN_MIN_WIDTH = VERSION_COLUMN_NAME.length();
+
+ private static final String STATE_COLUMN_NAME = "State";
+
+ /**
+ * longest state name from {@link BundleArtifact#mapBundleState()}
+ */
+ private static final int STATE_COLUMN_MIN_WIDTH = 11;
+
+ private final StateService stateService;
+
+ private final ModuleContextAccessor moduleContextAccessor;
+
+ public BundleInstallArtifactCommandFormatter(StateService stateService, ModuleContextAccessor moduleContextAccessor) {
+ this.stateService = stateService;
+ this.moduleContextAccessor = moduleContextAccessor;
+ }
+
+ public List<String> formatList(List<ManageableArtifact> artifacts) {
+ List<ArtifactHolder> artifactHolders = getArtifactHolders(artifacts);
+ Collections.sort(artifactHolders);
+
+ int maxIdLength = ID_COLUMN_MIN_WIDTH;
+ int maxNameLength = NAME_COLUMN_MIN_WIDTH;
+ int maxVersionLength = VERSION_COLUMN_MIN_WIDTH;
+ for (ArtifactHolder artifact : artifactHolders) {
+ final int idLength = artifact.getId().toString().length();
+ maxIdLength = idLength > maxIdLength ? idLength : maxIdLength;
+ final int nameLength = artifact.getName().length();
+ maxNameLength = nameLength > maxNameLength ? nameLength : maxNameLength;
+ final int versionLength = artifact.getVersion().length();
+ maxVersionLength = versionLength > maxVersionLength ? versionLength : maxVersionLength;
+ }
+
+ List<String> lines = new ArrayList<String>();
+ int stateLength = MAX_LINE_LENGTH - (4 + maxIdLength + SPRING_POWERED_COLUMN_WIDTH + maxNameLength + maxVersionLength);
+ if (stateLength < STATE_COLUMN_MIN_WIDTH) {
+ stateLength = STATE_COLUMN_MIN_WIDTH;
+ }
+
+ final String singleLineFormat = String.format("%%-%ds %%s %%-%ds %%-%ds %%%ds", maxIdLength, maxNameLength, maxVersionLength, stateLength);
+ lines.add(String.format(singleLineFormat, ID_COLUMN_NAME, SPRING_POWERED_COLUMN_NAME, NAME_COLUMN_NAME, VERSION_COLUMN_NAME,
+ STATE_COLUMN_NAME));
+
+ for (ArtifactHolder artifact : artifactHolders) {
+ lines.add(String.format(singleLineFormat, artifact.getId(), artifact.getSpringPowered() ? "S" : " ", artifact.getName(),
+ artifact.getVersion(), artifact.getState()));
+ }
+
+ return lines;
+ }
+
+ public List<String> formatExamine(ManageableArtifact artifact) {
+ List<String> lines = new ArrayList<String>();
+
+ List<QuasiBundle> quasiBundles = this.stateService.getAllBundles(null);
+ ArtifactHolder artifactHolder = getArtifactHolder(artifact, quasiBundles);
+
+ if (artifactHolder == null) {
+ lines.add("No artifact found of type '" + artifact.getType() + "' name '" + artifact.getName() + "' and version '"
+ + artifact.getVersion() + "'");
+ } else {
+ lines.add(String.format("Id: %s", artifactHolder.getId()));
+ lines.add(String.format("Name: %s", artifactHolder.getName()));
+ lines.add(String.format("Version %s", artifactHolder.getVersion()));
+ lines.add(String.format("State: %s", artifactHolder.getState()));
+ lines.add(String.format("Spring Powered: %s", artifactHolder.getSpringPowered()));
+
+ String bundleLocation = artifactHolder.getBundleLocation();
+ lines.add(String.format("Bundle Location: %s", bundleLocation == null ? "" : bundleLocation));
+
+ lines.addAll(formatImportedPackages(artifactHolder));
+ lines.addAll(formatExportedPackages(artifactHolder));
+ lines.addAll(formatPublishedServices(artifactHolder));
+ lines.addAll(formatConsumedServices(artifactHolder));
+ lines.addAll(formatFragments(artifactHolder));
+ lines.addAll(formatHost(artifactHolder));
+ }
+ return lines;
+ }
+
+ private List<String> formatConsumedServices(ArtifactHolder artifactHolder) {
+ List<String> lines = new ArrayList<String>();
+
+ lines.add("");
+ lines.add(String.format("Consumed services:"));
+ List<QuasiLiveService> consumedServices = artifactHolder.getConsumedServices();
+ if (consumedServices.isEmpty()) {
+ lines.add(String.format(" None"));
+ } else {
+ for (QuasiLiveService consumedService : consumedServices) {
+ String objectClass = extractFirstObjectClass(consumedService.getProperties().get(Constants.OBJECTCLASS));
+ lines.add(String.format(" %3s %s", consumedService.getServiceId(), objectClass));
+ lines.add(String.format(" published by %s", formatBundleSummary(consumedService.getProvider())));
+ }
+ }
+ return lines;
+ }
+
+ private List<String> formatPublishedServices(ArtifactHolder artifactHolder) {
+ List<String> lines = new ArrayList<String>();
+
+ lines.add("");
+ lines.add(String.format("Published services:"));
+ List<QuasiLiveService> publishedServices = artifactHolder.getPublishedServices();
+ if (publishedServices.isEmpty()) {
+ lines.add(String.format(" None"));
+ } else {
+ for (QuasiLiveService publishedService : publishedServices) {
+ String objectClass = extractFirstObjectClass(publishedService.getProperties().get(Constants.OBJECTCLASS));
+ lines.add(String.format(" %3s %s", publishedService.getServiceId(), objectClass));
+ List<QuasiLiveBundle> consumers = publishedService.getConsumers();
+ for (QuasiLiveBundle consumer : consumers) {
+ lines.add(String.format(" consumed by %s", formatBundleSummary(consumer)));
+ }
+ }
+ }
+ return lines;
+ }
+
+ private String extractFirstObjectClass(Object objectClass) {
+ String[] objectClasses;
+
+ if (objectClass instanceof String) {
+ objectClasses = StringUtils.commaDelimitedListToStringArray((String) objectClass);
+ } else if (objectClass instanceof Object[]) {
+ objectClasses = (String[]) objectClass;
+ } else {
+ objectClasses = StringUtils.commaDelimitedListToStringArray(objectClass.toString());
+ }
+
+ if (objectClasses.length > 0) {
+ return objectClasses[0];
+ } else {
+ return "<no object classes>";
+ }
+ }
+
+ private List<String> formatHost(ArtifactHolder artifactHolder) {
+ List<String> lines = new ArrayList<String>();
+
+ List<QuasiBundle> hosts = artifactHolder.getHosts();
+ if (hosts != null && !hosts.isEmpty()) {
+ lines.add("");
+ lines.add(String.format("Host:"));
+ QuasiBundle host = hosts.get(0);
+ lines.add(String.format(" %s", formatBundleSummary(host)));
+ }
+
+ return lines;
+ }
+
+ private List<String> formatFragments(ArtifactHolder artifactHolder) {
+ List<String> lines = new ArrayList<String>();
+
+ lines.add("");
+ lines.add(String.format("Fragments:"));
+ List<QuasiBundle> fragments = artifactHolder.getFragments();
+ if (fragments.isEmpty()) {
+ lines.add(String.format(" None"));
+ } else {
+ for (QuasiBundle fragment : fragments) {
+ lines.add(String.format(" %s", formatBundleSummary(fragment)));
+ }
+ }
+
+ return lines;
+ }
+
+ private List<String> formatExportedPackages(ArtifactHolder artifactHolder) {
+ List<String> lines = new ArrayList<String>();
+
+ lines.add("");
+ lines.add(String.format("Exported Packages:"));
+ List<QuasiExportPackage> exportPackages = artifactHolder.getExportPackages();
+ if (exportPackages.isEmpty()) {
+ lines.add(String.format(" None"));
+ } else {
+ for (QuasiExportPackage exportPackage : exportPackages) {
+ lines.add(String.format(" %s %s", exportPackage.getPackageName(), exportPackage.getVersion().toString()));
+ for (QuasiImportPackage consumer : exportPackage.getConsumers()) {
+ QuasiBundle bundle = consumer.getImportingBundle();
+ lines.add(String.format(" imported by %s", formatBundleSummary(bundle)));
+ }
+ }
+ }
+
+ return lines;
+ }
+
+ private List<String> formatImportedPackages(ArtifactHolder artifactHolder) {
+ List<String> lines = new ArrayList<String>();
+
+ lines.add("");
+ lines.add(String.format("Imported Packages:"));
+ List<QuasiImportPackage> importPackages = artifactHolder.getImportPackages();
+ if (importPackages.isEmpty()) {
+ lines.add(String.format(" None"));
+ } else {
+ for (QuasiImportPackage importPackage : importPackages) {
+ if (importPackage.isResolved()) {
+ lines.add(String.format(" %s %s", importPackage.getPackageName(), importPackage.getVersionConstraint().toString()));
+ QuasiBundle bundle = importPackage.getProvider().getExportingBundle();
+ lines.add(String.format(" exported by %s", formatBundleSummary(bundle)));
+ }
+ }
+ }
+
+ return lines;
+ }
+
+ private String formatBundleSummary(QuasiBundle bundle) {
+ return String.format("%s %s [%s]", bundle.getSymbolicName(), bundle.getVersion(), bundle.getBundleId());
+ }
+
+ public List<String> formatDiag(QuasiBundle bundle, List<QuasiResolutionFailure> resolverReport) {
+ if (bundle == null) {
+ return Arrays.asList("Unable to locate bundle");
+ }
+
+ if (resolverReport.size() == 0) {
+ return Arrays.asList("No resolution errors found");
+ }
+
+ List<String> lines = new ArrayList<String>();
+ for (QuasiResolutionFailure quasiResolutionFailure : resolverReport) {
+ lines.add(String.format("%s", quasiResolutionFailure.getDescription()));
+ }
+ return lines;
+ }
+
+ @SuppressWarnings("unchecked")
+ public List<String> formatHeaders(QuasiBundle bundle) {
+ if (bundle == null) {
+ return Arrays.asList("Unable to locate bundle");
+ }
+
+ List<String> lines = new ArrayList<String>();
+
+ Dictionary<String, String> headers = bundle.getBundle().getHeaders();
+ Enumeration<String> keys = headers.keys();
+ while (keys.hasMoreElements()) {
+ String key = keys.nextElement();
+ lines.add(String.format("%s: ", key));
+ lines.addAll(formatHeaderValue(headers.get(key)));
+ }
+
+ return lines;
+ }
+
+ private List<ArtifactHolder> getArtifactHolders(List<ManageableArtifact> artifacts) {
+ List<ArtifactHolder> artifactHolders = new ArrayList<ArtifactHolder>(artifacts.size());
+
+ List<QuasiBundle> bundles = this.stateService.getAllBundles(null);
+
+ for (ManageableArtifact artifact : artifacts) {
+ ArtifactHolder artifactHolder = getArtifactHolder(artifact, bundles);
+ if (artifactHolder != null) {
+ artifactHolders.add(artifactHolder);
+ }
+ }
+
+ return artifactHolders;
+ }
+
+ private ArtifactHolder getArtifactHolder(ManageableArtifact artifact, List<QuasiBundle> bundles) {
+ Version v = new Version(artifact.getVersion());
+ for (QuasiBundle bundle : bundles) {
+ if (bundle.getSymbolicName().equals(artifact.getName()) && bundle.getVersion().equals(v)) {
+ return new ArtifactHolder(artifact, bundle, moduleContextAccessor);
+ }
+ }
+ return null;
+ }
+
+ private List<String> formatHeaderValue(String value) {
+ List<String> lines = new ArrayList<String>();
+
+ Reader reader = new StringReader(value);
+ char[] buffer = new char[71];
+ int length = 0;
+ try {
+ while ((length = reader.read(buffer)) != -1) {
+ lines.add(String.format(" %s", new String(buffer, 0, length)));
+ }
+ } catch (IOException e) {
+ // Do nothing
+ }
+ return lines;
+ }
+
+ private static class ArtifactHolder implements Comparable<ArtifactHolder> {
+
+ private final ModuleContextAccessor moduleContextAccessor;
+
+ private final ManageableArtifact artifact;
+
+ private final QuasiBundle bundle;
+
+ public ArtifactHolder(ManageableArtifact artifact, QuasiBundle bundle, ModuleContextAccessor moduleContextAccessor) {
+ this.artifact = artifact;
+ this.bundle = bundle;
+ this.moduleContextAccessor = moduleContextAccessor;
+ }
+
+ public Long getId() {
+ return this.bundle.getBundleId();
+ }
+
+ public String getName() {
+ return artifact.getName();
+ }
+
+ public String getState() {
+ return artifact.getState();
+ }
+
+ public String getVersion() {
+ return artifact.getVersion();
+ }
+
+ public String getBundleLocation() {
+ return this.bundle.getBundle().getLocation();
+ }
+
+ public boolean getSpringPowered() {
+ Bundle realBundle = bundle.getBundle();
+ if (realBundle != null) {
+ ModuleContext moduleContext = moduleContextAccessor.getModuleContext(realBundle);
+ if (moduleContext != null) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public List<QuasiExportPackage> getExportPackages() {
+ return bundle.getExportPackages();
+ }
+
+ public List<QuasiImportPackage> getImportPackages() {
+ return bundle.getImportPackages();
+ }
+
+ public List<QuasiBundle> getFragments() {
+ return bundle.getFragments();
+ }
+
+ public List<QuasiBundle> getHosts() {
+ return bundle.getHosts();
+ }
+
+ public List<QuasiLiveService> getPublishedServices() {
+ QuasiLiveBundle liveBundle = (QuasiLiveBundle) bundle;
+ return liveBundle.getExportedServices();
+ }
+
+ public List<QuasiLiveService> getConsumedServices() {
+ QuasiLiveBundle liveBundle = (QuasiLiveBundle) bundle;
+ return liveBundle.getImportedServices();
+ }
+
+ public int compareTo(ArtifactHolder o) {
+ return getId().compareTo(o.getId());
+ }
+
+ @Override
+ public int hashCode() {
+ return getId().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return getId().equals(((ArtifactHolder) obj).getId());
+ }
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/formatting/CompositeInstallArtifactCommandFormatter.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/formatting/CompositeInstallArtifactCommandFormatter.java
new file mode 100644
index 00000000..1c5f2dfa
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/formatting/CompositeInstallArtifactCommandFormatter.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.formatting;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.management.ObjectName;
+
+import org.eclipse.virgo.kernel.model.management.ManageableCompositeArtifact;
+
+public final class CompositeInstallArtifactCommandFormatter extends AbstractInstallArtifactCommandFormatter<ManageableCompositeArtifact> {
+
+ private static final String CHILD_FORMAT = " %s %s %s";
+
+ public List<String> formatExamine(ManageableCompositeArtifact artifact) {
+ List<String> lines = new ArrayList<String>();
+
+ lines.add(String.format("State: %s", artifact.getState()));
+ lines.add(String.format("Scoped: %s", artifact.isScoped()));
+ lines.add(String.format("Atomic: %s", artifact.isAtomic()));
+ lines.add("");
+ lines.add("Children:");
+
+ for (ObjectName child : artifact.getDependents()) {
+ lines.add(String.format(CHILD_FORMAT, child.getKeyProperty("artifact-type"), child.getKeyProperty("name"),
+ child.getKeyProperty("version")));
+ }
+
+ return lines;
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/formatting/ConfigInstallArtifactCommandFormatter.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/formatting/ConfigInstallArtifactCommandFormatter.java
new file mode 100644
index 00000000..815b3b52
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/formatting/ConfigInstallArtifactCommandFormatter.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.formatting;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.List;
+
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+import org.eclipse.virgo.kernel.model.management.ManageableArtifact;
+
+public final class ConfigInstallArtifactCommandFormatter extends AbstractInstallArtifactCommandFormatter<ManageableArtifact> {
+
+ private final ConfigurationAdmin configurationAdmin;
+
+ public ConfigInstallArtifactCommandFormatter(ConfigurationAdmin configurationAdmin) {
+ this.configurationAdmin = configurationAdmin;
+ }
+
+ public List<String> formatExamine(ManageableArtifact artifact) {
+ List<String> lines = new ArrayList<String>();
+
+ Configuration configuration;
+ try {
+ configuration = this.configurationAdmin.getConfiguration(artifact.getName());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ String factoryPid = configuration.getFactoryPid();
+ String bundleLocation = configuration.getBundleLocation();
+
+ lines.add(String.format("Factory pid: %s", factoryPid == null ? "" : factoryPid));
+ lines.add(String.format("Bundle Location: %s", bundleLocation == null ? "" : bundleLocation));
+
+ lines.addAll(formatProperties(configuration));
+
+ return lines;
+ }
+
+ @SuppressWarnings("unchecked")
+ private List<String> formatProperties(Configuration configuration) {
+ List<String> lines = new ArrayList<String>();
+ List<String> propertyKeys = new ArrayList<String>();
+
+ Dictionary<String, String> properties = configuration.getProperties();
+ if (properties != null) {
+ Enumeration<String> keys = properties.keys();
+ while (keys.hasMoreElements()) {
+ propertyKeys.add(keys.nextElement());
+ }
+ Collections.sort(propertyKeys);
+
+ lines.add("");
+ lines.add(String.format("Properties:"));
+ for (String propertyKey : propertyKeys) {
+ lines.add(String.format(" %s:", propertyKey));
+
+ List<String> values = PropertyFormatter.formatPropertyValue(properties.get(propertyKey), MAX_LINE_LENGTH);
+ for (String value : values) {
+ lines.add(String.format(" %s", value));
+ }
+ }
+ }
+
+ return lines;
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/formatting/InstallArtifactCommandFormatter.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/formatting/InstallArtifactCommandFormatter.java
new file mode 100644
index 00000000..078dc191
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/formatting/InstallArtifactCommandFormatter.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.formatting;
+
+import java.util.List;
+
+import org.eclipse.virgo.kernel.model.management.ManageableArtifact;
+
+public interface InstallArtifactCommandFormatter<T extends ManageableArtifact> {
+
+ List<String> formatList(List<T> artifacts);
+
+ List<String> formatExamine(T artifact);
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/formatting/PackageCommandFormatter.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/formatting/PackageCommandFormatter.java
new file mode 100644
index 00000000..f9ac96d4
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/formatting/PackageCommandFormatter.java
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.formatting;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiBundle;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiExportPackage;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiImportPackage;
+
+public final class PackageCommandFormatter {
+
+ private static final int MAX_LINE_LENGTH = 80;
+
+ private static final String NAME = "Name";
+
+ private static final String VERSION = "Version";
+
+ private static final String PROVIDER = "Providing Bundle";
+
+ public List<String> formatList(List<QuasiExportPackage> packages) {
+ Collections.sort(packages, new QuasiExportPackageComparator());
+
+ int maxNameLength = NAME.length();
+ int maxVersionLength = VERSION.length();
+ for (QuasiExportPackage exportPackage : packages) {
+ int nameLength = exportPackage.getPackageName().length();
+ maxNameLength = nameLength > maxNameLength ? nameLength : maxNameLength;
+ int versionLength = exportPackage.getVersion().toString().length();
+ maxVersionLength = versionLength > maxVersionLength ? versionLength : maxVersionLength;
+ }
+
+ List<String> lines = new ArrayList<String>();
+ String format = String.format("%%-%ds %%-%ds %%%ds", maxNameLength, maxVersionLength, MAX_LINE_LENGTH
+ - (2 + maxNameLength + maxVersionLength));
+ lines.add(String.format(format, NAME, VERSION, PROVIDER));
+
+ for (QuasiExportPackage exportPackage : packages) {
+ lines.add(String.format(format, exportPackage.getPackageName(), exportPackage.getVersion().toString(),
+ exportPackage.getExportingBundle().getBundleId()));
+ }
+
+ return lines;
+ }
+
+ public List<String> formatExamine(List<QuasiExportPackage> exportPackages) {
+ List<String> lines = new ArrayList<String>();
+
+ boolean first = true;
+
+ for (QuasiExportPackage exportPackage : exportPackages) {
+ if (!first) {
+ lines.add("");
+ lines.add("");
+ }
+ QuasiBundle exportingBundle = exportPackage.getExportingBundle();
+ lines.add(String.format("Exporter: %s %s [%s]", exportingBundle.getSymbolicName(), exportingBundle.getVersion().toString(),
+ exportingBundle.getBundleId()));
+
+ lines.add("");
+ lines.add(String.format("Attributes:"));
+ lines.addAll(formatProperties(exportPackage.getAttributes()));
+
+ lines.add("");
+ lines.add(String.format("Directives:"));
+ lines.addAll(formatProperties(exportPackage.getDirectives()));
+
+ lines.add("");
+ lines.add(String.format("Importer(s):"));
+ if (exportPackage.getConsumers().isEmpty()) {
+ lines.add(String.format(" %s", "None"));
+ } else {
+ for (QuasiImportPackage importPackage : exportPackage.getConsumers()) {
+ QuasiBundle importingBundle = importPackage.getImportingBundle();
+ lines.add(String.format(" %s %s [%s]", importingBundle.getSymbolicName(), importingBundle.getVersion().toString(),
+ importingBundle.getBundleId()));
+ lines.add(String.format(" Import-Package attributes:"));
+ lines.addAll(formatProperties(importPackage.getAttributes(), " "));
+ lines.add(String.format(" Import-Package directives:"));
+ lines.addAll(formatProperties(importPackage.getDirectives(), " "));
+ }
+ }
+ first = false;
+ }
+
+ return lines;
+ }
+
+ private List<String> formatProperties(Map<String, Object> properties) {
+ return formatProperties(properties, " ");
+ }
+
+ private List<String> formatProperties(Map<String, Object> properties, String indent) {
+ List<String> lines = new ArrayList<String>();
+ List<String> keys = new ArrayList<String>(properties.keySet());
+ if (keys.isEmpty()) {
+ lines.add(String.format("%s%s", indent, "None"));
+ } else {
+ Collections.sort(keys);
+
+ for (String key : keys) {
+ lines.add(String.format("%s%s:", indent, key));
+ Object value = properties.get(key);
+ if (value instanceof Object[]) {
+ List<String> propertyLines = PropertyFormatter.formatPropertyValue(value, MAX_LINE_LENGTH - 8);
+ for (String propertyLine : propertyLines) {
+ lines.add(String.format("%s %s", indent, propertyLine));
+ }
+ } else {
+ lines.add(String.format("%s %s", indent, value));
+ }
+ }
+ }
+ return lines;
+ }
+
+ private static class QuasiExportPackageComparator implements Comparator<QuasiExportPackage> {
+
+ public int compare(QuasiExportPackage package1, QuasiExportPackage package2) {
+ int value = package1.getPackageName().compareTo(package2.getPackageName());
+ if (value != 0) {
+ return value;
+ }
+ return package1.getVersion().compareTo(package2.getVersion());
+ }
+
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/formatting/PropertyFormatter.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/formatting/PropertyFormatter.java
new file mode 100644
index 00000000..3d44d9bb
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/formatting/PropertyFormatter.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.formatting;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A helper class for formatting properties.
+ *
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Thread-safe
+ *
+ */
+public class PropertyFormatter {
+
+ /**
+ * Formats the supplied value into one or more Strings. Each String in the <code>List</code> represents a line of
+ * output.
+ *
+ * <p />
+ * If <code>value</code> is a single object, i.e. it is not an array, the returned list will contain a single line -
+ * the <code>toString</code> of <code>value</code>. If <code>value</code> is an array, lines in the list are formed
+ * by concatenating the <code>toString</code> of each entry in the array, wrapping when <code>maxLineLength</code>
+ * is reached.
+ *
+ * <p />
+ * If an individual <code>toString</code> is longer that the given <code>maxLineLength</code> the full string will
+ * be included as a line in the returned <code>List</code>, i.e. individual Strings are not truncated and the
+ * <code>maxLineLength</code> will be exceeded.
+ *
+ * @param value the value to format
+ * @param maxLineLength the desired maximum line length
+ * @return the formatted value, one list entry per line
+ */
+ public static List<String> formatPropertyValue(Object value, int maxLineLength) {
+
+ String[] strings;
+ if (value.getClass().isArray()) {
+ strings = arrayToStrings(value);
+ } else {
+ strings = new String[] { value.toString() };
+ }
+
+ int lineLength = 0;
+
+ List<String> formatted = new ArrayList<String>();
+
+ StringBuilder builder = new StringBuilder();
+
+ for (int i = 0; i < strings.length; i++) {
+ String item;
+ if (i < strings.length - 1) {
+ item = strings[i] + ", ";
+ } else {
+ item = strings[i];
+ }
+
+ if (!isSufficientRoomForNextItem(item, lineLength, maxLineLength) && addEntryIfNecessary(builder, formatted)) {
+ builder = new StringBuilder();
+ lineLength = 0;
+ }
+
+ builder.append(item);
+ lineLength += item.length();
+ }
+
+ addEntryIfNecessary(builder, formatted);
+
+ return formatted;
+ }
+
+ private static boolean addEntryIfNecessary(StringBuilder builder, List<String> entries) {
+ String string = builder.toString();
+ if (!string.isEmpty()) {
+ entries.add(string);
+ return true;
+ }
+ return false;
+ }
+
+ private static boolean isSufficientRoomForNextItem(String item, int currentLineLength, int maxLineLength) {
+ return (currentLineLength + item.length()) <= maxLineLength;
+ }
+
+ private static String[] arrayToStrings(Object array) {
+
+ int length = Array.getLength(array);
+ String[] strings = new String[length];
+
+ for (int i = 0; i < length; i++) {
+ Object object = Array.get(array, i);
+ strings[i] = object == null ? "null" : object.toString();
+ }
+
+ return strings;
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/formatting/ServiceCommandFormatter.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/formatting/ServiceCommandFormatter.java
new file mode 100644
index 00000000..8a467567
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/formatting/ServiceCommandFormatter.java
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.formatting;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+import org.osgi.framework.Constants;
+
+import org.eclipse.virgo.kernel.shell.state.QuasiLiveBundle;
+import org.eclipse.virgo.kernel.shell.state.QuasiLiveService;
+import org.eclipse.virgo.util.common.StringUtils;
+
+public final class ServiceCommandFormatter {
+
+ private static final int MAX_LINE_LENGTH = 80;
+
+ private static final String MULTIPLE_OBJECT_CLASSES_SUFFIX = ", ...";
+
+ private static final String ID = "Id";
+
+ private static final String OBJECT_CLASSES = "Object Class(es)";
+
+ private static final String PROVIDER = "Providing Bundle";
+
+ public List<String> formatList(List<QuasiLiveService> services) {
+ Collections.sort(services, new QuasiLiveServiceComparator());
+
+ int maxIdLength = ID.length();
+ int maxProviderLength = PROVIDER.length();
+ for (QuasiLiveService service : services) {
+ int idLength = ((Long) service.getServiceId()).toString().length();
+ maxIdLength = idLength > maxIdLength ? idLength : maxIdLength;
+ int providerLength = ((Long) service.getProvider().getBundleId()).toString().length();
+ maxProviderLength = providerLength > maxProviderLength ? providerLength : maxProviderLength;
+ }
+
+ int objectClassWidth = MAX_LINE_LENGTH - (2 + maxIdLength + maxProviderLength);
+
+ List<String> lines = new ArrayList<String>();
+ String format = String.format("%%-%ds %%-%ds %%%ds", maxIdLength, objectClassWidth, maxProviderLength);
+ lines.add(String.format(format, ID, OBJECT_CLASSES, PROVIDER));
+
+ for (QuasiLiveService service : services) {
+ Object objectClass = service.getProperties().get(Constants.OBJECTCLASS);
+ lines.add(String.format(format, service.getServiceId(), formatObjectClass(objectClass, objectClassWidth),
+ service.getProvider().getBundleId()));
+ }
+
+ return lines;
+ }
+
+ public List<String> formatExamine(QuasiLiveService service) {
+ List<String> lines = new ArrayList<String>();
+
+ lines.add(String.format("Properties:"));
+ lines.addAll(formatProperties(service.getProperties()));
+
+ QuasiLiveBundle provider = service.getProvider();
+ lines.add("");
+ lines.add(String.format("Publisher: %s %s [%s]", provider.getSymbolicName(), provider.getVersion().toString(), provider.getBundleId()));
+
+ lines.add("");
+ lines.add(String.format("Consumer(s):"));
+ List<QuasiLiveBundle> consumers = service.getConsumers();
+ if (consumers.size() == 0) {
+ lines.add(String.format(" None"));
+ } else {
+ for (QuasiLiveBundle consumer : consumers) {
+ lines.add(String.format(" %s %s [%s]", consumer.getSymbolicName(), consumer.getVersion().toString(), consumer.getBundleId()));
+ }
+ }
+
+ return lines;
+ }
+
+ private static String formatObjectClass(Object objectClass, int maxLength) {
+ StringBuilder sb = new StringBuilder();
+ if (objectClass == null) {
+ objectClass = new String[0];
+ }
+ String[] objectClasses;
+ if (objectClass instanceof String) {
+ objectClasses = StringUtils.commaDelimitedListToStringArray((String) objectClass);
+ } else if (objectClass instanceof Object[]) {
+ objectClasses = (String[]) objectClass;
+ } else {
+ objectClasses = StringUtils.commaDelimitedListToStringArray(objectClass.toString());
+ }
+
+ if (objectClasses.length == 0) {
+ sb.append("<none>");
+ } else {
+ if (objectClasses.length > 1) {
+ maxLength -= MULTIPLE_OBJECT_CLASSES_SUFFIX.length();
+ }
+
+ String formattedObjectClass = StringUtils.abbreviateDotSeparatedString(objectClasses[0], maxLength);
+ sb.append(formattedObjectClass);
+
+ if (objectClasses.length > 1) {
+ sb.append(MULTIPLE_OBJECT_CLASSES_SUFFIX);
+ }
+ }
+
+ return sb.toString();
+ }
+
+ private List<String> formatProperties(Map<String, Object> properties) {
+ List<String> lines = new ArrayList<String>();
+ List<String> keys = new ArrayList<String>(properties.keySet());
+ Collections.sort(keys);
+
+ for (String key : keys) {
+ lines.add(String.format(" %s:", key));
+ Object value = properties.get(key);
+ if (value instanceof Object[]) {
+ List<String> propertyLines = PropertyFormatter.formatPropertyValue(value, MAX_LINE_LENGTH - 8);
+ for (String propertyLine : propertyLines) {
+ lines.add(String.format(" %s", propertyLine));
+ }
+ } else {
+ lines.add(String.format(" %s", value));
+ }
+ }
+
+ return lines;
+ }
+
+ private static class QuasiLiveServiceComparator implements Comparator<QuasiLiveService> {
+
+ public int compare(QuasiLiveService service1, QuasiLiveService service2) {
+ Long id1 = service1.getServiceId();
+ Long id2 = service2.getServiceId();
+ return id1.compareTo(id2);
+ }
+
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/help/HelpAccessor.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/help/HelpAccessor.java
new file mode 100644
index 00000000..9975221f
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/help/HelpAccessor.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.help;
+
+import java.util.List;
+
+
+/**
+ * Helper interface that retrieves summary and detailed help for a given shell class, if it exists.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ * Implementations must be thread-safe.
+ *
+ */
+public interface HelpAccessor {
+
+ /**
+ * Get the summary string (for use in a list) for the {@link Class} <code>clazz</code> obtained
+ * from a help resource file in the bundle in which the class belongs.
+ * <br/>
+ * <code>null</code> is returned if the class is not part of a bundle, or if no help resource is found there.
+ * @param clazz for which help is retrieved
+ * @return summary string for {@link Class} <code>clazz</code> - typically one line.
+ */
+ String getSummaryHelp(Class<?> clazz);
+
+ /**
+ * Get the detailed string (for use in a single description) for the {@link Class} <code>clazz</code> obtained
+ * from a help resource file in the bundle in which the class belongs.
+ * <br/>
+ * <code>null</code> is returned if the class is not part of a bundle, or if no help resource is found there.
+ * @param clazz for which help is retrieved
+ * @return summary string for {@link Class} <code>clazz</code> - typically multi-line.
+ */
+ List<String> getDetailedHelp(Class<?> clazz);
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/help/SimpleFileHelpAccessor.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/help/SimpleFileHelpAccessor.java
new file mode 100644
index 00000000..34b38fb2
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/help/SimpleFileHelpAccessor.java
@@ -0,0 +1,156 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.help;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.FrameworkUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.eclipse.virgo.util.io.IOUtils;
+
+/**
+ * Implementation of {@link HelpAccessor} which searches for a simple text file resource in the bundle of the class.
+ * <p/>
+ * The name of the file resource is the fully-qualified class name followed by "<code>.help</code>". <br/>
+ * Lines beginning with a hash (pound) sign '#', as the first character, are comment lines; all other lines are
+ * 'content' lines. <br/>
+ * Comment lines are ignored. <br/>
+ * All strings returned are terminated by a newline character.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ * Thread-safe.
+ *
+ */
+public class SimpleFileHelpAccessor implements HelpAccessor {
+
+ private static final char HELP_FILE_COMMENT_CHARACTER = '#';
+
+ private static final String HELP_ACCESSOR_RESOURCE_EXTENSION = ".help";
+
+ private static final Logger logger = LoggerFactory.getLogger(SimpleFileHelpAccessor.class);
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<String> getDetailedHelp(Class<?> clazz) {
+ BufferedReader readFileIn = null;
+ try {
+ readFileIn = this.helpResourceReader(clazz);
+ if (readFileIn != null) {
+ return readAllButFirstHelpLines(readFileIn);
+ }
+ } catch (IOException ioe) {
+ logger.error(String.format("Exception reading help resource for class '%s'.", clazz.getCanonicalName()), ioe);
+ } finally {
+ IOUtils.closeQuietly(readFileIn);
+ }
+ return Collections.emptyList();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getSummaryHelp(Class<?> clazz) {
+ BufferedReader readFileIn = null;
+ try {
+ readFileIn = this.helpResourceReader(clazz);
+ if (readFileIn != null) {
+ return readFirstHelpLine(readFileIn);
+ }
+ } catch (IOException ioe) {
+ logger.error(String.format("Exception reading help resource for class '%s'.", clazz.getCanonicalName()), ioe);
+ } finally {
+ IOUtils.closeQuietly(readFileIn);
+ }
+ return null;
+ }
+
+ private final String readFirstHelpLine(BufferedReader reader) throws IOException {
+ String line = reader.readLine();
+ while (line != null) {
+ if (contentLine(line)) {
+ return line;
+ }
+ line = reader.readLine();
+ }
+ return line;
+ }
+
+ private final List<String> readAllButFirstHelpLines(BufferedReader reader) throws IOException {
+ List<String> lines = new ArrayList<String>();
+
+ String line = reader.readLine();
+ boolean skipLine = true;
+ while (line != null) {
+ if (contentLine(line)) {
+ if (!skipLine) {
+ lines.add(line);
+ } else {
+ skipLine = false;
+ }
+ }
+ line = reader.readLine();
+ }
+
+ return lines;
+ }
+
+ private static final boolean contentLine(String line) {
+ if (line == null)
+ return false;
+ return (line.length() == 0 || line.charAt(0) != HELP_FILE_COMMENT_CHARACTER);
+ }
+
+ private final BufferedReader helpResourceReader(Class<?> clazz) {
+ BufferedReader readFileIn = null;
+ String className = clazz.getCanonicalName();
+ if (className != null) {
+ String fileResourceName = new StringBuffer(className).append(HELP_ACCESSOR_RESOURCE_EXTENSION).toString();
+ URL resourceUrl = this.helpResourceUrl(clazz, fileResourceName);
+ if (resourceUrl != null) {
+ InputStream resourceIn = null;
+ try {
+ resourceIn = resourceUrl.openStream();
+ readFileIn = new BufferedReader(new InputStreamReader(resourceIn));
+ } catch (IOException ioe) {
+ logger.error(String.format("Exception reading help resource '%s'.", resourceUrl), ioe);
+ IOUtils.closeQuietly(resourceIn);
+ return null;
+ }
+ }
+ }
+ return readFileIn;
+ }
+
+ protected URL helpResourceUrl(Class<?> clazz, String fileResourceName) {
+ Bundle bundle = FrameworkUtil.getBundle(clazz);
+ try {
+ if (bundle != null) {
+ return bundle.getResource(fileResourceName);
+ }
+ } catch (IllegalStateException ise) {
+ logger.error(String.format("Exception obtaining help resource file '%s'.", fileResourceName), ise);
+ }
+ return null;
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/parsing/ParsedCommand.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/parsing/ParsedCommand.java
new file mode 100644
index 00000000..6f70d0e3
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/parsing/ParsedCommand.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.parsing;
+
+import java.util.Arrays;
+
+/**
+ * A <code>ParsedCommand</code> represents a command that has been parsed into the top-level command and its arguments.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Thread-safe.
+ *
+ */
+public final class ParsedCommand {
+
+ private final String command;
+
+ private final String[] arguments;
+
+ public ParsedCommand(String command, String[] arguments) {
+ this.command = command;
+ this.arguments = arguments.clone();
+ }
+
+ public String getCommand() {
+ return command;
+ }
+
+ public String[] getArguments() {
+ return arguments.clone();
+ }
+
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append(command);
+
+ for (int i = 0; i < this.arguments.length; i++) {
+ builder.append(" ").append(this.arguments[i]);
+ }
+
+ return builder.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + Arrays.hashCode(this.arguments);
+ result = prime * result + ((this.command == null) ? 0 : this.command.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ ParsedCommand other = (ParsedCommand) obj;
+ if (!Arrays.equals(this.arguments, other.arguments))
+ return false;
+ if (!this.command.equals(other.command))
+ return false;
+ return true;
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/parsing/ParsingUtils.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/parsing/ParsingUtils.java
new file mode 100644
index 00000000..fe662aa2
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/parsing/ParsingUtils.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.parsing;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import org.eclipse.virgo.util.common.StringUtils;
+
+
+/**
+ * Utility methods for parsing command input.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Thread-safe.
+ *
+ */
+public class ParsingUtils {
+
+ private static final String DELIMITER = " ";
+
+ private static final String EMPTY_STRING = "";
+
+ /**
+ * Parses the supplied command.
+ *
+ * @param command the command to parse
+ *
+ * @return The parsed command.
+ */
+ public static ParsedCommand parseCommand(CharSequence command) {
+
+ String commandString = command.toString();
+ String[] tokens = StringUtils.tokenizeToStringArray(commandString, DELIMITER);
+ if (tokens.length == 0) {
+ return null;
+ }
+
+ String commandName = tokens[0];
+ String[] arguments = getArguments(commandString.substring(commandName.length()));
+
+ return new ParsedCommand(commandName, arguments);
+ }
+
+ private static String[] getArguments(String buffer) {
+
+ List<String> arguments = new ArrayList<String>();
+
+ StringTokenizer tokenizer = new StringTokenizer(buffer, DELIMITER, true);
+ while (tokenizer.hasMoreElements()) {
+ String token = tokenizer.nextToken();
+
+ if (DELIMITER.equals(token)) {
+ if (!tokenizer.hasMoreElements()) {
+ arguments.add(EMPTY_STRING);
+ }
+ } else {
+ arguments.add(token);
+ }
+ }
+
+ return arguments.toArray(new String[arguments.size()]);
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/util/ArtifactRetriever.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/util/ArtifactRetriever.java
new file mode 100644
index 00000000..3903770f
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/internal/util/ArtifactRetriever.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.util;
+
+import java.lang.management.ManagementFactory;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.JMX;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.osgi.framework.Version;
+
+import org.eclipse.virgo.kernel.model.management.ManageableArtifact;
+import org.eclipse.virgo.kernel.model.management.RuntimeArtifactModelObjectNameCreator;
+
+/**
+ * <p>
+ * ArtifactRetriever is responsible for obtaining artifacts from the MBean server
+ * MBeans published by the Runtime Artifact Model. One instance of this class can
+ * only retrieve MBeans backed by the given type T.
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * ArtifactRetriever is threadsafe
+ *
+ * @param <T> type of artifact retrieved
+ */
+public final class ArtifactRetriever<T extends ManageableArtifact> {
+
+ private final MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+
+ private final String type;
+
+ private final RuntimeArtifactModelObjectNameCreator objectNameCreator;
+
+ private final Class<T> artifactType;
+
+ /**
+ *
+ * @param type
+ * @param objectNameCreator
+ * @param artifactType
+ */
+ public ArtifactRetriever(String type, RuntimeArtifactModelObjectNameCreator objectNameCreator, Class<T> artifactType) {
+ this.type = type;
+ this.objectNameCreator = objectNameCreator;
+ this.artifactType = artifactType;
+ }
+
+ /**
+ *
+ * @param name
+ * @param version
+ * @return artifact
+ * @throws InstanceNotFoundException
+ */
+ public T getArtifact(String name, Version version) throws InstanceNotFoundException {
+ return getArtifact(this.objectNameCreator.create(this.type, name, version));
+ }
+
+ /**
+ *
+ * @param objectName
+ * @return artifact
+ * @throws InstanceNotFoundException
+ */
+ public T getArtifact(final ObjectName objectName) throws InstanceNotFoundException {
+ if (this.server.isRegistered(objectName)) {
+ return JMX.newMXBeanProxy(this.server, objectName, this.artifactType);
+ }
+ throw new InstanceNotFoundException(String.format("Instance '%s' not found", objectName.getCanonicalName()));
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/model/helper/ArtifactAccessor.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/model/helper/ArtifactAccessor.java
new file mode 100644
index 00000000..4d209d3d
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/model/helper/ArtifactAccessor.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.model.helper;
+
+import java.util.Map;
+import java.util.Set;
+
+
+/**
+ * <p>
+ * ArtifactAccessor is a representation of an Artifact from the Runtime Artifact Model.
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Implementations should be thread safe.
+ *
+ */
+public interface ArtifactAccessor {
+
+ /**
+ * @return the type of the Artifact
+ */
+ String getType();
+
+ /**
+ * @return The name of the Artifact
+ */
+ String getName();
+
+ /**
+ * @return The version of the Artifact as a String
+ */
+ String getVersion();
+
+ /**
+ * @return The state of the Artifact
+ */
+ String getState();
+
+ /**
+ * @return Any additional attributes that have been registered against the Artifact in the RAM
+ */
+ Map<String, Object> getAttributes();
+
+ /**
+ * @return a <code>Map&lt;String, String&gt;</code> of this artifact's properties
+ */
+ Map<String, String> getProperties();
+
+ /**
+ * @return A set of {@link ArtifactAccessorPointer}s of all the Artifacts that this Artifact depends on
+ */
+ Set<ArtifactAccessorPointer> getDependents();
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/model/helper/ArtifactAccessorPointer.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/model/helper/ArtifactAccessorPointer.java
new file mode 100644
index 00000000..6b46ab58
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/model/helper/ArtifactAccessorPointer.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.model.helper;
+
+/**
+ * <p>
+ * Simple store for a type, name and version that can be used to retrieve the full
+ * {@link ArtifactAccessor} at a later time.
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Implementations should be thread safe
+ *
+ */
+public interface ArtifactAccessorPointer extends Comparable<ArtifactAccessorPointer> {
+
+ /**
+ * @return The type of the Artifact
+ */
+ String getType();
+
+ /**
+ * @return The name of the Artifact
+ */
+ String getName();
+
+ /**
+ * @return The version of the Artifact as a String
+ */
+ String getVersion();
+
+ /**
+ * @return the state of the artifact represented by this pointer
+ */
+ String getState();
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/model/helper/RamAccessorHelper.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/model/helper/RamAccessorHelper.java
new file mode 100644
index 00000000..17c90900
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/model/helper/RamAccessorHelper.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.model.helper;
+
+import java.util.List;
+
+/**
+ * <p>
+ * RamAccessorHelper provides easy to use methods for getting information from the
+ * Runtime Artifact Model MBeans.
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * RamAccessorHelper implementations should be thread safe
+ *
+ */
+public interface RamAccessorHelper {
+
+ /**
+ * Start the Artifact with the given type, name and version.
+ * @param type
+ * @param name
+ * @param version
+ * @return a response string indicating success or failure
+ */
+ public String start(String type, String name, String version);
+
+ /**
+ * Stop the Artifact with the given type, name and version.
+ * @param type
+ * @param name
+ * @param version
+ * @return a response string indicating success or failure
+ */
+ public String stop(String type, String name, String version);
+
+ /**
+ * Uninstall the Artifact with the given type, name and version.
+ * @param type
+ * @param name
+ * @param version
+ * @return a response string indicating success or failure
+ */
+ public String uninstall(String type, String name, String version);
+
+ /**
+ * Refresh the Artifact with the given type, name and version.
+ * @param type
+ * @param name
+ * @param version
+ * @return a response string indicating success or failure
+ */
+ public String refresh(String type, String name, String version);
+
+ /**
+ * Return a list of all the types of the user installed artifacts in the system.
+ *
+ * @return a list of types, never <code>null</code>, possibly empty
+ */
+ public List<String> getTypes();
+
+ /**
+ * Return a list of {@link ArtifactAccessorPointer}s of the artifacts in the system of the given type
+ * that are user installed. If there are no artifacts of the given type then the empty list is returned.
+ *
+ * @param type of {@link org.eclipse.virgo.kernel.model.Artifact}
+ * @return list of {@link ArtifactAccessorPointer}s of given type
+ */
+ public List<ArtifactAccessorPointer> getArtifactsOfType(String type);
+
+ /**
+ * Return a list of {@link ArtifactAccessorPointer}s of all the artifacts in the system of the given
+ * type. If there are no artifacts of the given type then the empty list is returned.
+ *
+ * @param type of {@link org.eclipse.virgo.kernel.model.Artifact}
+ * @return list of {@link ArtifactAccessorPointer}s of given type
+ */
+ public List<ArtifactAccessorPointer> getAllArtifactsOfType(String type);
+
+ /**
+ * Return a representation of the requested artifact as an {@link ArtifactAccessor}. If no such artifact exists null
+ * may be returned.
+ *
+ * @param type of {@link org.eclipse.virgo.kernel.model.Artifact artifact}
+ * @param name of {@link org.eclipse.virgo.kernel.model.Artifact artifact}
+ * @param version of {@link org.eclipse.virgo.kernel.model.Artifact artifact}
+ * @return an {@link ArtifactAccessor} for the identified artifact, or <code>null</code> if there isn't one
+ */
+ public ArtifactAccessor getArtifact(String type, String name, String version);
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/model/helper/StandardArtifactAccessor.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/model/helper/StandardArtifactAccessor.java
new file mode 100644
index 00000000..c87da191
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/model/helper/StandardArtifactAccessor.java
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.model.helper;
+
+import java.util.Map;
+import java.util.Set;
+
+
+
+/**
+ * <p>
+ * StandardArtifactAccessor is the standard implementation of {@link ArtifactAccessor}.
+ * It represents an artifact and is backed by an MBean from the Runtime Artifact Model
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * StandardArtifactAccessor is thread safe
+ *
+ */
+final class StandardArtifactAccessor implements ArtifactAccessor {
+
+ private static final String TYPE_ATTRIBUTE = "Type";
+
+ private static final String NAME_ATTRIBUTE = "Name";
+
+ private static final String VERSION_ATTRIBUTE = "Version";
+
+ private static final String STATE_ATTRIBUTE = "state";
+
+ private final String type;
+
+ private final String name;
+
+ private final String version;
+
+ private final String state;
+
+ private final Map<String, Object> attributes;
+
+ private final Map<String, String> properties;
+
+ private final Set<ArtifactAccessorPointer> dependents;
+
+ public StandardArtifactAccessor(Map<String, Object> attributes, Map<String, String> properties, Set<ArtifactAccessorPointer> dependents) {
+ this.type = (String) attributes.remove(TYPE_ATTRIBUTE);
+ this.name = (String) attributes.remove(NAME_ATTRIBUTE);
+ this.version = (String) attributes.remove(VERSION_ATTRIBUTE);
+ this.state = (String) attributes.get(STATE_ATTRIBUTE);
+
+ this.attributes = attributes;
+ this.properties = properties;
+ this.dependents = dependents;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getType() {
+ return this.type;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getVersion() {
+ return this.version;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getState() {
+ return this.state;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<String, Object> getAttributes() {
+ return attributes;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<String, String> getProperties() {
+ return this.properties;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Set<ArtifactAccessorPointer> getDependents() {
+ return this.dependents;
+ }
+
+ public int compareTo(ArtifactAccessorPointer o) {
+ if(o == null) {
+ return 0;
+ }
+ int typeResult = this.type.compareTo(o.getType());
+ if (typeResult != 0) {
+ return typeResult;
+ }
+
+ int nameResult = this.name.compareTo(o.getName());
+ if (nameResult != 0) {
+ return nameResult;
+ }
+
+ int versionResult = this.version.compareTo(o.getVersion());
+ if (versionResult != 0) {
+ return versionResult;
+ }
+
+ return 0;
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/model/helper/StandardArtifactAccessorPointer.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/model/helper/StandardArtifactAccessorPointer.java
new file mode 100644
index 00000000..4427953c
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/model/helper/StandardArtifactAccessorPointer.java
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.model.helper;
+
+/**
+ * <p>
+ * Standard impl of ArtifactAccessorPointer, null values are not allowed for type, name or version.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * ArtifactAccessorPointer is threadsafe
+ *
+ */
+final class StandardArtifactAccessorPointer implements ArtifactAccessorPointer {
+
+ private final String type;
+
+ private final String name;
+
+ private final String version;
+
+ private final String state;
+
+
+ public StandardArtifactAccessorPointer(String type, String name, String version, String state) {
+ if(type == null || name == null || version == null || state == null ) {
+ throw new IllegalArgumentException(String.format("Null arguments can not be used for the construction of StandardArtifactAccessorPointer '%s' '%s' '%s'", type, name, version));
+ }
+ this.type = type;
+ this.name = name;
+ this.version = version;
+ this.state = state;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getType() {
+ return this.type;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getVersion() {
+ return this.version;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getState() {
+ return this.state;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ result = prime * result + ((state == null) ? 0 : state.hashCode());
+ result = prime * result + ((type == null) ? 0 : type.hashCode());
+ result = prime * result + ((version == null) ? 0 : version.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ StandardArtifactAccessorPointer other = (StandardArtifactAccessorPointer) obj;
+ if (!name.equals(other.name))
+ return false;
+ if (!state.equals(other.state))
+ return false;
+ if (!type.equals(other.type))
+ return false;
+ if (!version.equals(other.version))
+ return false;
+ return true;
+ }
+
+ public int compareTo(ArtifactAccessorPointer o) {
+ if(o == null) {
+ return 0;
+ }
+ int typeResult = this.type.compareTo(o.getType());
+ if (typeResult != 0) {
+ return typeResult;
+ }
+
+ int nameResult = this.name.compareTo(o.getName());
+ if (nameResult != 0) {
+ return nameResult;
+ }
+
+ int versionResult = this.version.compareTo(o.getVersion());
+ if (versionResult != 0) {
+ return versionResult;
+ }
+
+ return 0;
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/model/helper/StandardRamAccessorHelper.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/model/helper/StandardRamAccessorHelper.java
new file mode 100644
index 00000000..8a40f78c
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/model/helper/StandardRamAccessorHelper.java
@@ -0,0 +1,244 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.model.helper;
+
+import java.lang.management.ManagementFactory;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.IntrospectionException;
+import javax.management.JMX;
+import javax.management.MBeanInfo;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.eclipse.virgo.kernel.model.management.ManageableArtifact;
+import org.eclipse.virgo.kernel.model.management.ManageableCompositeArtifact;
+
+/**
+ * <p>
+ * <code>ModelAccessorHelper</code> defines a simple service API for managing artifacts within the server via the
+ * Runtime Artifact Model Mbeans.
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * StandardModelAccessorHelper is thread-safe
+ *
+ */
+final public class StandardRamAccessorHelper implements RamAccessorHelper {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(StandardRamAccessorHelper.class);
+
+ private static final String TYPE_ATTRIBUTE = "Type";
+
+ private static final String NAME_ATTRIBUTE = "Name";
+
+ private static final String VERSION_ATTRIBUTE = "Version";
+
+ private static final String STATE_ATTRIBUTE = "state";
+
+ private static final String USER_INSTALLED = "user.installed";
+
+ private static final String OPERATION_SUCSESS = "%s operation returned successful";
+
+ private static final String OPERATION_FAIL = "An error occurred during the %s operation";
+
+ private static final String ARTIFACT_MBEAN_QUERY = "org.eclipse.virgo.kernel:type=Model,artifact-type=%s,name=%s,version=%s";
+
+ public StandardRamAccessorHelper() {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String start(String type, String name, String version) {
+ return performOperation(type, name, version, "start");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String stop(String type, String name, String version) {
+ return performOperation(type, name, version, "stop");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String uninstall(String type, String name, String version) {
+ return performOperation(type, name, version, "uninstall");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String refresh(String type, String name, String version) {
+ return performOperation(type, name, version, "refresh");
+ }
+
+ private String performOperation(String type, String name, String version, String operationName) {
+ MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
+ try {
+ ObjectName objectName = new ObjectName(String.format(ARTIFACT_MBEAN_QUERY, type, name, version));
+ mBeanServer.invoke(objectName, operationName, new Object[0], new String[0]);
+ return String.format(OPERATION_SUCSESS, operationName);
+ } catch (Exception e) {
+ LOGGER.warn(String.format("Unexpected error while trying to read the Runtime Artifact Model MBeans. type: '%s' name: '%s' version: '%s'",
+ type, name, version));
+ return String.format(OPERATION_FAIL, operationName);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<String> getTypes() {
+ List<String> types = new ArrayList<String>();
+ MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
+ try {
+ Set<ObjectName> objectNames = mBeanServer.queryNames(new ObjectName("org.eclipse.virgo.kernel:type=Model,*"), null);
+ for (ObjectName objectName : objectNames) {
+ String type = objectName.getKeyProperty("artifact-type");
+ if (!(type == null || types.contains(type))) {
+ ManageableArtifact artifact = JMX.newMXBeanProxy(mBeanServer, objectName, ManageableArtifact.class);
+ if (Boolean.valueOf(artifact.getProperties().get(USER_INSTALLED))) {
+ types.add(type);
+ }
+ }
+ }
+ } catch (Exception e) {
+ LOGGER.warn("Unexpected error while trying to read the Runtime Artifact Model MBeans", e);
+ }
+ return types;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<ArtifactAccessorPointer> getArtifactsOfType(String type) {
+ return getArtifactsOfType(type, true);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<ArtifactAccessorPointer> getAllArtifactsOfType(String type) {
+ return getArtifactsOfType(type, false);
+ }
+
+ private List<ArtifactAccessorPointer> getArtifactsOfType(String type, boolean onlyUserInstalled) {
+ List<ArtifactAccessorPointer> artifacts = new ArrayList<ArtifactAccessorPointer>();
+ MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
+ try {
+ Set<ObjectName> objectNames = mBeanServer.queryNames(new ObjectName(String.format(
+ "org.eclipse.virgo.kernel:type=Model,artifact-type=%s,*", type)), null);
+ for (ObjectName objectName : objectNames) {
+ ArtifactAccessorPointer pointer = buildArtifactAccessorPointer(objectName);
+ if (pointer != null) {
+ ManageableArtifact artifact = JMX.newMXBeanProxy(mBeanServer, objectName, ManageableArtifact.class);
+ if(onlyUserInstalled) {
+ if (!Boolean.valueOf(artifact.getProperties().get(USER_INSTALLED)) ) {
+ continue;
+ }
+ }
+ artifacts.add(pointer);
+ }
+ }
+ } catch (MalformedObjectNameException e) {
+ LOGGER.warn("Unexpected error while trying to read the Runtime Artifact Model MBeans", e);
+ }
+ return artifacts;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ArtifactAccessor getArtifact(String type, String name, String version) {
+ MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
+ try {
+ ObjectName objectName = new ObjectName(String.format(ARTIFACT_MBEAN_QUERY, type, name, version));
+ ArtifactAccessorPointer pointer = buildArtifactAccessorPointer(objectName);
+
+ if(pointer != null) {
+ Map<String, Object> attributes = new TreeMap<String, Object>();
+ attributes.put(TYPE_ATTRIBUTE, pointer.getType());
+ attributes.put(NAME_ATTRIBUTE, pointer.getName());
+ attributes.put(VERSION_ATTRIBUTE, pointer.getVersion());
+ attributes.put(STATE_ATTRIBUTE, pointer.getState());
+
+
+ boolean scoped = false, atomic = false;
+ MBeanInfo info = mBeanServer.getMBeanInfo(objectName);
+ if (info.getDescriptor().getFieldValue("interfaceClassName").equals(ManageableCompositeArtifact.class.getName())) {
+ ManageableCompositeArtifact compositeArtifact = JMX.newMXBeanProxy(mBeanServer, objectName, ManageableCompositeArtifact.class);
+ scoped = compositeArtifact.isScoped();
+ atomic = compositeArtifact.isAtomic();
+ }
+
+ attributes.put("atomic", atomic);
+ attributes.put("scoped", scoped);
+
+ ManageableArtifact artifact = JMX.newMXBeanProxy(mBeanServer, objectName, ManageableArtifact.class);
+
+ Set<ArtifactAccessorPointer> dependents = new HashSet<ArtifactAccessorPointer>();
+ for (ObjectName dependentObjectName : artifact.getDependents()) {
+ ArtifactAccessorPointer dependentPointer = buildArtifactAccessorPointer(dependentObjectName);
+ if(dependentPointer != null) {
+ dependents.add(dependentPointer);
+ }
+ }
+ return new StandardArtifactAccessor(attributes, artifact.getProperties(), dependents);
+ }
+ } catch (MalformedObjectNameException e) {
+ LOGGER.warn("Unexpected error while trying to read the Runtime Artifact Model MBeans", e);
+ } catch (IntrospectionException e) {
+ LOGGER.warn("Unexpected error while trying to read the Runtime Artifact Model MBeans", e);
+ } catch (InstanceNotFoundException e) {
+ LOGGER.warn("Unexpected error while trying to read the Runtime Artifact Model MBeans", e);
+ } catch (ReflectionException e) {
+ LOGGER.warn("Unexpected error while trying to read the Runtime Artifact Model MBeans", e);
+ }
+ return null;
+ }
+
+ private ArtifactAccessorPointer buildArtifactAccessorPointer(ObjectName objectName) {
+ MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
+ ArtifactAccessorPointer result = null;
+ try {
+ String dependentType = objectName.getKeyProperty("artifact-type");
+ String dependentName = objectName.getKeyProperty("name");
+ String dependentVersion = objectName.getKeyProperty("version");
+
+ ManageableArtifact dependantArtifact = JMX.newMXBeanProxy(mBeanServer, objectName, ManageableArtifact.class);
+ String state = dependantArtifact.getState();
+
+ if (dependentType != null && dependentName != null && dependentVersion != null) {
+ result = new StandardArtifactAccessorPointer(dependentType, dependentName, dependentVersion, state);
+ }
+ } catch (Exception e) {
+ LOGGER.warn("Unexpected error while trying to read the Runtime Artifact Model MBeans", e);
+ }
+ return result;
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/QuasiLiveBundle.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/QuasiLiveBundle.java
new file mode 100644
index 00000000..01f9ee40
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/QuasiLiveBundle.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.state;
+
+import java.util.List;
+
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiBundle;
+
+/**
+ * <p>
+ * QuasiLiveBundle represents a bundle that is installed in a live running OSGi
+ * instance, as opposed to one that was captured in a state dump.
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Implementations of QuasiLiveBundle should be thread-safe
+ *
+ */
+public interface QuasiLiveBundle extends QuasiBundle {
+
+ /**
+ * A list of {@link QuasiLiveService}s that are published by this {@link QuasiLiveBundle}
+ *
+ * @return list of services
+ */
+ List<QuasiLiveService> getExportedServices();
+
+ /**
+ * A list of {@link QuasiLiveService}s that are consumed by this {@link QuasiLiveBundle}
+ *
+ * @return list of services
+ */
+ List<QuasiLiveService> getImportedServices();
+
+ /**
+ * A string that matches the state the bundle is currently in within OSGi
+ *
+ * @return the OSGi state
+ */
+ String getState();
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/QuasiLiveService.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/QuasiLiveService.java
new file mode 100644
index 00000000..9f455c05
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/QuasiLiveService.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.state;
+
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * <p>
+ * QuasiLiveService represents a service in the live running OSGi state
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Implementations of QuasiLiveService should be thread-safe
+ *
+ */
+public interface QuasiLiveService extends Comparable<QuasiLiveService> {
+
+ /**
+ * Return the Id of this service within OSGi.
+ *
+ * @return long service Id
+ */
+ long getServiceId();
+
+ /**
+ * A list of {@link QuasiLiveBundle}s that use this {@link QuasiLiveService}.
+ *
+ * @return List of <code>QuasiLiveBundle</code>s that are using this service
+ */
+ List<QuasiLiveBundle> getConsumers();
+
+ /**
+ * The {@link QuasiLiveBundle} that provides this {@link QuasiLiveService}.
+ *
+ * @return <code>QuasiLiveBundle</code> that registered this service
+ */
+ QuasiLiveBundle getProvider();
+
+ /**
+ * A map of the Service's properties.
+ *
+ * @return The service's properties
+ */
+ Map<String, Object> getProperties();
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/QuasiPackage.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/QuasiPackage.java
new file mode 100644
index 00000000..0deb833c
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/QuasiPackage.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.state;
+
+import java.util.List;
+
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiExportPackage;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiFramework;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiImportPackage;
+
+
+/**
+ * <p>
+ * A representation of a single package within the {@link QuasiFramework}
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Implementations should be thread-safe
+ *
+ */
+public interface QuasiPackage {
+
+ /**
+ * The name of the package this {@link QuasiPackage} represents.
+ * Will never be null.
+ *
+ * @return packageName
+ */
+ public String getPackageName();
+
+ /**
+ * A list of all the {@link QuasiImportPackage}s that are imports of this package.
+ *
+ * @return list of imports
+ */
+ public List<QuasiImportPackage> getImporters();
+
+ /**
+ * A list of all the {@link QuasiExportPackage}s that are exports of this package.
+ *
+ * @return list of exports
+ */
+ public List<QuasiExportPackage> getExporters();
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/StateService.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/StateService.java
new file mode 100644
index 00000000..64d21ae2
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/StateService.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.state;
+
+import java.io.File;
+import java.util.List;
+
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiBundle;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiFramework;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiResolutionFailure;
+
+/**
+ * <p>
+ * <code>StateService</code>
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Implementations should be thread-safe.
+ *
+ */
+public interface StateService {
+
+ /**
+ * Obtains {@link QuasiBundle} representations of all the bundles present
+ * in the underlying state.
+ *
+ * @param source can be null to request the live state
+ * @return all the bundles or the empty list if the source can't be found
+ */
+ public List<QuasiBundle> getAllBundles(File source);
+
+ /**
+ * Obtains {@link QuasiLiveService} representations of all the services present
+ * in the underlying osgi instance.
+ *
+ * @param source can be null to request the live state
+ * @return all the services or the empty list if the source can't be found
+ */
+ public List<QuasiLiveService> getAllServices(File source);
+
+ /**
+ * Looks at all the bundles in the underlying state and return the one with
+ * the given id, if no such bundle exists then null is returned.
+ *
+ * @param source can be null to request the live state
+ * @param bundleId of required bundle
+ * @return the requested bundle or null
+ */
+ public QuasiBundle getBundle(File source, long bundleId);
+
+ /**
+ * Returns the {@link QuasiLiveService} that represents the service with
+ * the requested service Id. If no such service exists then null is
+ * returned.
+ *
+ * @param source can be null to request the live state
+ * @param serviceId
+ * @return the service with id serviceId
+ */
+ public QuasiLiveService getService(File source, long serviceId) ;
+
+ /**
+ * Will return {@link QuasiResolutionFailure} for the requested bundle.
+ * If there are no resolution failures then null will be returned.
+ *
+ * @param source can be null to request the live state
+ * @param bundleId of the fail bundle
+ * @return <code>QuasiResolutionFailure</code>
+ */
+ public List<QuasiResolutionFailure> getResolverReport(File source, long bundleId);
+
+ /**
+ * Installs a bundle into the requested {@link QuasiFramework} using the given
+ * {@link String} location and returns a {@link QuasiBundle}.
+ *
+ * @param source can be null to request the live state
+ * @param location
+ * @return the bundle installed
+ */
+ public QuasiBundle installBundle(File source, String location);
+
+ /**
+ *
+ * @param source can be null to request the live state
+ * @param packageName to find
+ * @return the package found
+ */
+ public QuasiPackage getPackages(File source, String packageName);
+
+ /**
+ * Search the requested state for bundles matching the given string
+ *
+ * @param source can be null to request the live state
+ * @param term to search for
+ * @return a list of matched bundles
+ */
+ public List<QuasiBundle> search(File source, String term);
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/internal/StandardQuasiLiveBundle.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/internal/StandardQuasiLiveBundle.java
new file mode 100644
index 00000000..8930db6b
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/internal/StandardQuasiLiveBundle.java
@@ -0,0 +1,194 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.state.internal;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.Version;
+
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiBundle;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiExportPackage;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiFramework;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiImportPackage;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiRequiredBundle;
+import org.eclipse.virgo.kernel.shell.state.QuasiLiveBundle;
+import org.eclipse.virgo.kernel.shell.state.QuasiLiveService;
+
+
+/**
+ * <p>
+ * StandardQuasiLiveBundle is the standard implementation of {@link QuasiLiveBundle}. In
+ * many cases it simply passes requests off to a wrapped {@link QuasiBundle} only adding
+ * the extra functionality required for a <code>QuasiLiveBundle</code>.
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * StandardQuasiLiveBundle is threadsafe
+ *
+ */
+final class StandardQuasiLiveBundle implements QuasiLiveBundle {
+
+ private final QuasiBundle quasiBundle;
+
+ private final Bundle osgiBundle;
+
+ private final QuasiFramework quasiFramework;
+
+ public StandardQuasiLiveBundle(QuasiFramework quasiFramework, QuasiBundle quasiBundle, Bundle osgiBundle) {
+ this.quasiFramework = quasiFramework;
+ this.quasiBundle = quasiBundle;
+ this.osgiBundle = osgiBundle;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<QuasiLiveService> getExportedServices() {
+ List<QuasiLiveService> quasiLiveServices = new ArrayList<QuasiLiveService>();
+ ServiceReference[] registeredServices = this.osgiBundle.getRegisteredServices();
+ if(registeredServices == null){
+ return quasiLiveServices;
+ }
+ for(ServiceReference serviceReference : registeredServices){
+ quasiLiveServices.add(new StandardQuasiLiveService(this.quasiFramework, serviceReference));
+ }
+ return quasiLiveServices;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<QuasiLiveService> getImportedServices() {
+ List<QuasiLiveService> quasiLiveServices = new ArrayList<QuasiLiveService>();
+ ServiceReference[] registeredServices = this.osgiBundle.getServicesInUse();
+ if(registeredServices == null){
+ return quasiLiveServices;
+ }
+ for(ServiceReference serviceReference : registeredServices){
+ quasiLiveServices.add(new StandardQuasiLiveService(this.quasiFramework, serviceReference));
+ }
+ return quasiLiveServices;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getState() {
+ int state = this.osgiBundle.getState();
+ switch(state){
+ case Bundle.UNINSTALLED : return "Uninstalled";
+ case Bundle.INSTALLED : return "Installed";
+ case Bundle.RESOLVED : return "Resolved";
+ case Bundle.STARTING : return "Starting";
+ case Bundle.STOPPING : return "Stopping";
+ case Bundle.ACTIVE : return "Active";
+ default : return "Unknown";
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Bundle getBundle() {
+ return this.osgiBundle;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public long getBundleId() {
+ return this.quasiBundle.getBundleId();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<QuasiBundle> getDependents() {
+ return this.quasiBundle.getDependents();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<QuasiExportPackage> getExportPackages() {
+ return this.quasiBundle.getExportPackages();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<QuasiBundle> getFragments() {
+ return this.quasiBundle.getFragments();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<QuasiBundle> getHosts() {
+ return this.quasiBundle.getHosts();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<QuasiImportPackage> getImportPackages() {
+ return this.quasiBundle.getImportPackages();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<QuasiRequiredBundle> getRequiredBundles() {
+ return this.quasiBundle.getRequiredBundles();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getSymbolicName() {
+ return this.quasiBundle.getSymbolicName();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Version getVersion() {
+ return this.quasiBundle.getVersion();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isResolved() {
+ return this.quasiBundle.isResolved();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void uninstall() {
+ this.quasiBundle.uninstall();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public File getBundleFile() {
+ return this.quasiBundle.getBundleFile();
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/internal/StandardQuasiLiveFramework.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/internal/StandardQuasiLiveFramework.java
new file mode 100644
index 00000000..66e4772e
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/internal/StandardQuasiLiveFramework.java
@@ -0,0 +1,123 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.state.internal;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Version;
+
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiBundle;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiFramework;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiResolutionFailure;
+import org.eclipse.virgo.kernel.shell.state.QuasiLiveBundle;
+import org.eclipse.virgo.util.osgi.manifest.BundleManifest;
+
+/**
+ * <p>
+ * StandardQuasiLiveFramework is the Standard implementation of {@link QuasiFramework}. It will fall
+ * back to a regular QuasiFramework but use richer types with more information available from the
+ * live state opposed to a start from an equinox dump. This should be obtained by casting
+ * {@link QuasiBundle} references to a {@link QuasiLiveBundle}s.
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * StandardQuasiLiveFramework is threadsafe
+ *
+ */
+final class StandardQuasiLiveFramework implements QuasiFramework {
+
+ private final QuasiFramework quasiFramework;
+
+ private final BundleContext bundleContext;
+
+ /**
+ * Takes in the {@link QuasiFramework} to be decorated with the extra functionality
+ * of providing live information on services and Spring etc..
+ *
+ * @param quasiFramework
+ * @param bundleContext
+ */
+ public StandardQuasiLiveFramework(QuasiFramework quasiFramework, BundleContext bundleContext) {
+ this.quasiFramework = quasiFramework;
+ this.bundleContext = bundleContext;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public QuasiBundle getBundle(long bundleId) {
+ QuasiBundle quasiBundle = this.quasiFramework.getBundle(bundleId);
+ if(quasiBundle == null){
+ return null;
+ }
+ Bundle rawBundle = this.bundleContext.getBundle(bundleId);
+ return new StandardQuasiLiveBundle(this, quasiBundle, rawBundle);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<QuasiBundle> getBundles() {
+ List<QuasiBundle> quasiBundles = this.quasiFramework.getBundles();
+ List<QuasiBundle> quasiLiveBundles = new ArrayList<QuasiBundle>();
+ Bundle rawBundle;
+
+ for(QuasiBundle quasiBundle : quasiBundles){
+ rawBundle = this.bundleContext.getBundle(quasiBundle.getBundleId());
+ quasiLiveBundles.add(new StandardQuasiLiveBundle(this, quasiBundle, rawBundle));
+ }
+
+ return quasiLiveBundles;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void commit() throws BundleException {
+ this.quasiFramework.commit();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public QuasiBundle install(URI location, BundleManifest bundleManifest) throws BundleException {
+ return this.quasiFramework.install(location, bundleManifest);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<QuasiResolutionFailure> resolve() {
+ return this.quasiFramework.resolve();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<QuasiResolutionFailure> diagnose(long bundleId) {
+ return this.quasiFramework.diagnose(bundleId);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public QuasiBundle getBundle(String name, Version version) {
+ return this.quasiFramework.getBundle(name, version);
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/internal/StandardQuasiLiveService.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/internal/StandardQuasiLiveService.java
new file mode 100644
index 00000000..daaf1933
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/internal/StandardQuasiLiveService.java
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.state.internal;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiBundle;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiFramework;
+import org.eclipse.virgo.kernel.shell.state.QuasiLiveBundle;
+import org.eclipse.virgo.kernel.shell.state.QuasiLiveService;
+
+/**
+ * <p>
+ * StandardQuasiLiveService is the standard implementation of {@link QuasiLiveService}. It provides
+ * an extension of the Quasi abstraction that allows information on the services of a live/running
+ * OSGi state to be explored. It can also be sorted for when it is being rendered to a user interface
+ * from a set.
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * StandardQuasiLiveService is threadsafe
+ *
+ */
+final public class StandardQuasiLiveService implements QuasiLiveService, Comparable<QuasiLiveService> {
+
+ private final ServiceReference serviceReference;
+
+ private final QuasiFramework quasiFramework;
+
+ public StandardQuasiLiveService(QuasiFramework quasiFramework, ServiceReference serviceReference) {
+ this.serviceReference = serviceReference;
+ this.quasiFramework = quasiFramework;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public long getServiceId() {
+ return (Long) this.serviceReference.getProperty(Constants.SERVICE_ID);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<QuasiLiveBundle> getConsumers() {
+ List<QuasiLiveBundle> quasiUsers = new ArrayList<QuasiLiveBundle>();
+ Bundle[] usingBundles = this.serviceReference.getUsingBundles();
+ if(usingBundles != null){
+ for(Bundle user : usingBundles){
+ QuasiBundle quasiUser = this.quasiFramework.getBundle(user.getBundleId());
+ quasiUsers.add(new StandardQuasiLiveBundle(this.quasiFramework, quasiUser, user));
+ }
+ }
+ return quasiUsers;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public QuasiLiveBundle getProvider() {
+ Bundle providingBundle = this.serviceReference.getBundle();
+ QuasiBundle quasiProvidingBundle = this.quasiFramework.getBundle(providingBundle.getBundleId());
+ return new StandardQuasiLiveBundle(this.quasiFramework, quasiProvidingBundle, providingBundle);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<String, Object> getProperties() {
+ Map<String, Object> properties = new HashMap<String, Object>();
+ for(String key : this.serviceReference.getPropertyKeys()){
+ Object value = this.serviceReference.getProperty(key);
+ if (value != null) {
+ properties.put(key, value);
+ }
+ }
+ return properties;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int compareTo(QuasiLiveService other) {
+ return (int) (this.getServiceId() - other.getServiceId());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((this.serviceReference == null) ? 0 : this.serviceReference.hashCode());
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ StandardQuasiLiveService other = (StandardQuasiLiveService) obj;
+ if (this.serviceReference == null) {
+ if (other.serviceReference != null){
+ return false;
+ }
+ } else if (!this.serviceReference.equals(other.serviceReference)){
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/internal/StandardQuasiPackage.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/internal/StandardQuasiPackage.java
new file mode 100644
index 00000000..1b6579cd
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/internal/StandardQuasiPackage.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.state.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiExportPackage;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiImportPackage;
+import org.eclipse.virgo.kernel.shell.state.QuasiPackage;
+import org.eclipse.virgo.util.common.StringUtils;
+
+
+/**
+ * <p>
+ * Standard implementation of QuasiPackage that acts as a simple data holder
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * StandardQuasiPackage is immutable.
+ *
+ */
+final class StandardQuasiPackage implements QuasiPackage {
+
+ private final String packageName;
+
+ private final List<QuasiImportPackage> quasiImportPackages;
+
+ private final List<QuasiExportPackage> quasiExportPackages;
+
+ public StandardQuasiPackage(List<QuasiExportPackage> quasiExportPackages, List<QuasiImportPackage> quasiImportPackages, String packageName) {
+ if(!StringUtils.hasLength(packageName)){
+ throw new IllegalArgumentException("QuasiPackageName must not be null and have at least one character");
+ }
+ this.quasiExportPackages = quasiExportPackages == null ? new ArrayList<QuasiExportPackage>() : quasiExportPackages;
+ this.quasiImportPackages = quasiImportPackages == null ? new ArrayList<QuasiImportPackage>() : quasiImportPackages;
+ this.packageName = packageName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<QuasiExportPackage> getExporters() {
+ return this.quasiExportPackages;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<QuasiImportPackage> getImporters() {
+ return this.quasiImportPackages;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getPackageName() {
+ return this.packageName;
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/internal/StandardStateService.java b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/internal/StandardStateService.java
new file mode 100644
index 00000000..a7ccadd5
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/java/org/eclipse/virgo/kernel/shell/state/internal/StandardStateService.java
@@ -0,0 +1,204 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.state.internal;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.Map.Entry;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.springframework.util.AntPathMatcher;
+
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiBundle;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiExportPackage;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiFramework;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiFrameworkFactory;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiImportPackage;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiResolutionFailure;
+import org.eclipse.virgo.kernel.shell.state.QuasiLiveBundle;
+import org.eclipse.virgo.kernel.shell.state.QuasiLiveService;
+import org.eclipse.virgo.kernel.shell.state.QuasiPackage;
+import org.eclipse.virgo.kernel.shell.state.StateService;
+
+/**
+ *
+ */
+final public class StandardStateService implements StateService {
+
+ private final QuasiFrameworkFactory quasiFrameworkFactory;
+
+ private final BundleContext bundleContext;
+
+ public StandardStateService(QuasiFrameworkFactory quasiFrameworkFactory, BundleContext bundleContext) {
+ this.quasiFrameworkFactory = quasiFrameworkFactory;
+ this.bundleContext = bundleContext;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<QuasiBundle> getAllBundles(File source) {
+ return this.getQuasiFramework(source).getBundles();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public QuasiBundle getBundle(File source, long bundleId) {
+ return this.getQuasiFramework(source).getBundle(bundleId);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<QuasiLiveService> getAllServices(File source) {
+ SortedMap<Long, QuasiLiveService> services = getServicesSortedMap(this.getQuasiFramework(source));
+
+ List<QuasiLiveService> quasiLiveServices = new ArrayList<QuasiLiveService>();
+ for (Entry<Long, QuasiLiveService> serviceEntry : services.entrySet()) {
+ quasiLiveServices.add(serviceEntry.getValue());
+ }
+ return quasiLiveServices;
+ }
+
+ private SortedMap<Long, QuasiLiveService> getServicesSortedMap(QuasiFramework quasiFramework) {
+ SortedMap<Long, QuasiLiveService> services = new TreeMap<Long, QuasiLiveService>();
+ List<QuasiBundle> allBundles = quasiFramework.getBundles();
+ for (QuasiBundle bundle : allBundles) {
+ if (bundle instanceof QuasiLiveBundle) {
+ QuasiLiveBundle liveBundle = (QuasiLiveBundle) bundle;
+ for (QuasiLiveService service : liveBundle.getExportedServices()) {
+ services.put(service.getServiceId(), service);
+ }
+ }
+ }
+ return services;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public QuasiLiveService getService(File source, long serviceId) {
+ SortedMap<Long, QuasiLiveService> services = getServicesSortedMap(this.getQuasiFramework(source));
+ if (services.containsKey(serviceId)) {
+ return services.get(serviceId);
+ }
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<QuasiResolutionFailure> getResolverReport(File source, long bundleId) {
+ QuasiFramework framework = this.getQuasiFramework(source);
+ return framework.diagnose(bundleId);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public QuasiBundle installBundle(File source, String location) {
+ if (source != null) {
+ throw new IllegalStateException("Unable to install a bundle in to a non-live state.");
+ }
+ Bundle installBundle = null;
+ try {
+ installBundle = this.bundleContext.installBundle(location);
+ } catch (BundleException e) {
+ throw new IllegalStateException(String.format("Unable to install the bundle '%s'.", e.getMessage()), e);
+ }
+ if (installBundle == null) {
+ return null;
+ }
+ QuasiFramework framework = this.getQuasiFramework(null);
+ if (framework == null) {
+ return null;
+ }
+ return framework.getBundle(installBundle.getBundleId());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public QuasiPackage getPackages(File source, String packageName) {
+ QuasiFramework framework = this.getQuasiFramework(source);
+ if (packageName != null) {
+ List<QuasiImportPackage> importers = new ArrayList<QuasiImportPackage>();
+ List<QuasiExportPackage> exporters = new ArrayList<QuasiExportPackage>();
+ List<QuasiBundle> bundles = framework.getBundles();
+ for (QuasiBundle qBundle : bundles) {
+ QuasiImportPackage importPackage = processImporters(qBundle, packageName);
+ if (importPackage != null) {
+ importers.add(importPackage);
+ }
+ QuasiExportPackage exportPackage = processExporters(qBundle, packageName);
+ if (exportPackage != null) {
+ exporters.add(exportPackage);
+ }
+ }
+ return new StandardQuasiPackage(exporters, importers, packageName);
+ }
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<QuasiBundle> search(File source, String term) {
+ QuasiFramework framework = this.getQuasiFramework(source);
+ List<QuasiBundle> matchingBundles = new ArrayList<QuasiBundle>();
+ if (term != null) {
+ AntPathMatcher matcher = new AntPathMatcher();
+ matcher.setPathSeparator(".");
+ List<QuasiBundle> bundles = framework.getBundles();
+ for (QuasiBundle bundle : bundles) {
+ if (matcher.match(term, bundle.getSymbolicName())) {
+ matchingBundles.add(bundle);
+ }
+
+ }
+ }
+ return matchingBundles;
+ }
+
+ private QuasiFramework getQuasiFramework(File source) {
+ if (source == null) {
+ return new StandardQuasiLiveFramework(this.quasiFrameworkFactory.create(), this.bundleContext);
+ } else {
+ return this.quasiFrameworkFactory.create(source);
+ }
+ }
+
+ private QuasiImportPackage processImporters(QuasiBundle qBundle, String packageName) {
+ for (QuasiImportPackage qImportPackage : qBundle.getImportPackages()) {
+ if (qImportPackage.getPackageName().equals(packageName)) {
+ return qImportPackage;
+ }
+ }
+ return null;
+ }
+
+ private QuasiExportPackage processExporters(QuasiBundle qBundle, String packageName) {
+ for (QuasiExportPackage qExportPackage : qBundle.getExportPackages()) {
+ if (qExportPackage.getPackageName().equals(packageName)) {
+ return qExportPackage;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/main/resources/EventLogMessages.properties b/org.eclipse.virgo.kernel.shell/src/main/resources/EventLogMessages.properties
new file mode 100644
index 00000000..7e68e66d
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/resources/EventLogMessages.properties
@@ -0,0 +1,2 @@
+SH0001I=Kernel ssh shell available on port {}.
+SH0002E=Kernel ssh shell port {} already in use, shutting down.
diff --git a/org.eclipse.virgo.kernel.shell/src/main/resources/META-INF/spring/module-context.xml b/org.eclipse.virgo.kernel.shell/src/main/resources/META-INF/spring/module-context.xml
new file mode 100644
index 00000000..51be9eed
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/resources/META-INF/spring/module-context.xml
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
+
+ <!-- START UP THE SHELL -->
+
+ <bean id="commandProcessor" class="org.eclipse.virgo.kernel.shell.internal.StandardCommandProcessor">
+ <constructor-arg ref="commandInvoker" />
+ </bean>
+
+ <bean id="shellFactory" class="org.eclipse.virgo.kernel.shell.internal.StandardLocalShellFactory" >
+ <constructor-arg ref="commandProcessor" />
+ <constructor-arg ref="commandRegistry" />
+ <constructor-arg ref="completerRegistry" />
+ </bean>
+
+ <bean id="ioManager" class="org.eclipse.virgo.kernel.shell.internal.LocalInputOutputManager">
+ <constructor-arg ref="bundleContext"/>
+ </bean>
+
+ <bean id="launchingEventHandler" class="org.eclipse.virgo.kernel.shell.internal.ShellLauncher" init-method="launchShells" destroy-method="stop" >
+ <constructor-arg ref="shellFactory" />
+ <constructor-arg ref="configAdmin" />
+ <constructor-arg ref="eventLogger" />
+ <constructor-arg ref="bundleContext" />
+ <constructor-arg ref="ioManager" />
+ </bean>
+
+ <bean id="completerRegistry" class="org.eclipse.virgo.kernel.shell.internal.completers.ServiceRegistryCommandCompleterRegistry" init-method="initialize">
+ <constructor-arg ref="bundleContext"/>
+ </bean>
+
+ <bean id="modelAccessorHelper" class="org.eclipse.virgo.kernel.shell.model.helper.StandardRamAccessorHelper" />
+
+ <!-- START UP THE INTIAL COMMAND PROVIDER -->
+
+ <bean id="stateService" class="org.eclipse.virgo.kernel.shell.state.internal.StandardStateService">
+ <constructor-arg ref="quasiFrameworkFactory" />
+ <constructor-arg ref="userRegionBundleContext" />
+ </bean>
+
+ <bean id="installCommand" class="org.eclipse.virgo.kernel.shell.internal.commands.InstallCommand"/>
+
+ <bean id="bundleCommands" class="org.eclipse.virgo.kernel.shell.internal.commands.BundleCommands">
+ <constructor-arg ref="objectNameCreator"/>
+ <constructor-arg ref="stateService" />
+ <constructor-arg ref="moduleContextAccessor" />
+ </bean>
+
+ <bean id="serviceCommands" class="org.eclipse.virgo.kernel.shell.internal.commands.ServiceCommands">
+ <constructor-arg ref="stateService" />
+ </bean>
+
+ <bean id="packageCommands" class="org.eclipse.virgo.kernel.shell.internal.commands.PackageCommands">
+ <constructor-arg ref="stateService" />
+ </bean>
+
+ <bean id="configCommands" class="org.eclipse.virgo.kernel.shell.internal.commands.ConfigCommands">
+ <constructor-arg ref="objectNameCreator"/>
+ <constructor-arg ref="configAdmin" />
+ </bean>
+
+ <bean id="planCommands" class="org.eclipse.virgo.kernel.shell.internal.commands.PlanCommands">
+ <constructor-arg ref="objectNameCreator"/>
+ </bean>
+
+ <bean id="parCommands" class="org.eclipse.virgo.kernel.shell.internal.commands.ParCommands">
+ <constructor-arg ref="objectNameCreator"/>
+ </bean>
+
+ <bean id="shutdownCommand" class="org.eclipse.virgo.kernel.shell.internal.commands.ShutdownCommand">
+ <constructor-arg ref="ioManager"/>
+ </bean>
+
+ <bean id="exitCommand" class="org.eclipse.virgo.kernel.shell.internal.commands.ExitCommand"/>
+
+ <bean id="helpCommand" class="org.eclipse.virgo.kernel.shell.internal.commands.HelpCommand">
+ <constructor-arg ref="commandRegistry"/>
+ <constructor-arg ref="helpAccessor"/>
+ </bean>
+
+ <bean id="helpAccessor" class="org.eclipse.virgo.kernel.shell.internal.help.SimpleFileHelpAccessor"/>
+
+ <bean id="helpCommandCompleter" class="org.eclipse.virgo.kernel.shell.internal.completers.HelpCommandCompleter">
+ <constructor-arg ref="commandRegistry"/>
+ </bean>
+
+ <bean id="bundleCompleter" class="org.eclipse.virgo.kernel.shell.internal.completers.BundleCompleter">
+ <constructor-arg ref="objectNameCreator"/>
+ </bean>
+
+ <bean id="packageCompleter" class="org.eclipse.virgo.kernel.shell.internal.completers.PackageCompleter">
+ <constructor-arg ref="stateService"/>
+ </bean>
+
+ <bean id="configCompleter" class="org.eclipse.virgo.kernel.shell.internal.completers.ConfigCompleter">
+ <constructor-arg ref="objectNameCreator"/>
+ </bean>
+
+ <bean id="parCompleter" class="org.eclipse.virgo.kernel.shell.internal.completers.ParCompleter">
+ <constructor-arg ref="objectNameCreator"/>
+ </bean>
+
+ <bean id="planCompleter" class="org.eclipse.virgo.kernel.shell.internal.completers.PlanCompleter">
+ <constructor-arg ref="objectNameCreator"/>
+ </bean>
+
+ <bean id="installCompleter" class="org.eclipse.virgo.kernel.shell.internal.completers.InstallCompleter"/>
+
+ <!-- CREATE THE VARIOUS TYPE CONVERTERS -->
+
+ <bean id="longConverter" class="org.eclipse.virgo.kernel.shell.internal.converters.LongConverter" />
+
+ <bean id="stringConverter" class="org.eclipse.virgo.kernel.shell.internal.converters.StringConverter" />
+
+ <bean id="commandResolver" class="org.eclipse.virgo.kernel.shell.internal.CompoundCommandResolver">
+ <constructor-arg>
+ <list>
+ <bean class="org.eclipse.virgo.kernel.shell.internal.AnnotationBasedCommandResolver"/>
+ <bean class="org.eclipse.virgo.kernel.shell.internal.ServicePropertyCommandResolver"/>
+ </list>
+ </constructor-arg>
+ </bean>
+
+ <bean id="commandRegistry" class="org.eclipse.virgo.kernel.shell.internal.CommandRegistry" init-method="initialize">
+ <constructor-arg ref="commandResolver"/>
+ <constructor-arg ref="bundleContext"/>
+ </bean>
+
+ <bean id="commandInvoker" class="org.eclipse.virgo.kernel.shell.internal.CommandRegistryCommandInvoker">
+ <constructor-arg ref="commandRegistry"/>
+ <constructor-arg ref="converterRegistry"/>
+ </bean>
+
+ <bean id="converterRegistry" class="org.eclipse.virgo.kernel.shell.internal.converters.ServiceRegistryConverterRegistry" init-method="initialize">
+ <constructor-arg ref="bundleContext"/>
+ </bean>
+
+</beans>
diff --git a/org.eclipse.virgo.kernel.shell/src/main/resources/META-INF/spring/osgi-context.xml b/org.eclipse.virgo.kernel.shell/src/main/resources/META-INF/spring/osgi-context.xml
new file mode 100644
index 00000000..7aa2d254
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/resources/META-INF/spring/osgi-context.xml
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:osgi="http://www.springframework.org/schema/osgi"
+ xmlns:util="http://www.springframework.org/schema/util"
+ xsi:schemaLocation="http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi-1.0.xsd
+ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
+ http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd">
+
+<!-- SERVICES FOR THE CORE SHELL SYSTEM -->
+
+ <osgi:reference id="quasiFrameworkFactory" interface="org.eclipse.virgo.kernel.osgi.quasi.QuasiFrameworkFactory" />
+
+ <osgi:reference id="moduleContextAccessor" interface="org.eclipse.virgo.kernel.module.ModuleContextAccessor" />
+
+ <osgi:reference id="eventLogger" interface="org.eclipse.virgo.medic.eventlog.EventLogger" />
+
+ <osgi:reference id="configAdmin" interface="org.osgi.service.cm.ConfigurationAdmin" />
+
+ <osgi:service ref="commandProcessor" interface="org.eclipse.virgo.kernel.shell.internal.CommandProcessor" />
+
+ <osgi:service ref="stateService" interface="org.eclipse.virgo.kernel.shell.state.StateService" />
+
+ <osgi:reference id="userRegionBundleContext" interface="org.osgi.framework.BundleContext" filter="(org.eclipse.virgo.kernel.regionContext=true)"/>
+
+ <osgi:reference id="deployer" interface="org.eclipse.virgo.kernel.deployer.core.ApplicationDeployer"/>
+
+ <osgi:service ref="modelAccessorHelper" interface="org.eclipse.virgo.kernel.shell.model.helper.RamAccessorHelper" />
+
+<!-- SERVICES FOR THE TYPE CONVERTERS -->
+
+ <osgi:service ref="longConverter" interface="org.eclipse.virgo.kernel.shell.Converter">
+ <osgi:service-properties>
+ <entry>
+ <key><util:constant static-field="org.eclipse.virgo.kernel.shell.Converter.CONVERTER_CLASSES"/></key>
+ <value>#{longConverter.getTypes()}</value>
+ </entry>
+ </osgi:service-properties>
+ </osgi:service>
+
+ <osgi:service ref="stringConverter" interface="org.eclipse.virgo.kernel.shell.Converter">
+ <osgi:service-properties>
+ <entry>
+ <key><util:constant static-field="org.eclipse.virgo.kernel.shell.Converter.CONVERTER_CLASSES"/></key>
+ <value>#{stringConverter.getTypes()}</value>
+ </entry>
+ </osgi:service-properties>
+ </osgi:service>
+
+<!-- SERVICES FOR THE COMMAND PROVIDERS -->
+
+ <osgi:service ref="helpCommand" auto-export="class-hierarchy"/>
+
+ <osgi:service ref="installCommand" auto-export="class-hierarchy"/>
+
+ <osgi:service ref="shutdownCommand" auto-export="class-hierarchy"/>
+
+ <osgi:service ref="exitCommand" auto-export="class-hierarchy"/>
+
+ <osgi:service ref="serviceCommands" auto-export="class-hierarchy"/>
+
+ <osgi:service ref="bundleCommands" auto-export="class-hierarchy"/>
+
+ <osgi:service ref="packageCommands" auto-export="class-hierarchy"/>
+
+ <osgi:service ref="configCommands" auto-export="class-hierarchy"/>
+
+ <osgi:service ref="planCommands" auto-export="class-hierarchy"/>
+
+ <osgi:service ref="parCommands" auto-export="class-hierarchy"/>
+
+ <osgi:reference id="objectNameCreator" interface="org.eclipse.virgo.kernel.model.management.RuntimeArtifactModelObjectNameCreator"/>
+
+ <osgi:service ref="helpCommandCompleter" interface="org.eclipse.virgo.kernel.shell.CommandCompleter">
+ <osgi:service-properties>
+ <entry>
+ <key><util:constant static-field="org.eclipse.virgo.kernel.shell.CommandCompleter.SERVICE_PROPERTY_COMPLETER_COMMAND_NAMES"/></key>
+ <value>help</value>
+ </entry>
+ </osgi:service-properties>
+ </osgi:service>
+
+ <osgi:service ref="bundleCompleter" interface="org.eclipse.virgo.kernel.shell.CommandCompleter">
+ <osgi:service-properties>
+ <entry>
+ <key><util:constant static-field="org.eclipse.virgo.kernel.shell.CommandCompleter.SERVICE_PROPERTY_COMPLETER_COMMAND_NAMES"/></key>
+ <value>bundle</value>
+ </entry>
+ </osgi:service-properties>
+ </osgi:service>
+
+ <osgi:service ref="packageCompleter" interface="org.eclipse.virgo.kernel.shell.CommandCompleter">
+ <osgi:service-properties>
+ <entry>
+ <key><util:constant static-field="org.eclipse.virgo.kernel.shell.CommandCompleter.SERVICE_PROPERTY_COMPLETER_COMMAND_NAMES"/></key>
+ <value>package</value>
+ </entry>
+ </osgi:service-properties>
+ </osgi:service>
+
+ <osgi:service ref="configCompleter" interface="org.eclipse.virgo.kernel.shell.CommandCompleter">
+ <osgi:service-properties>
+ <entry>
+ <key><util:constant static-field="org.eclipse.virgo.kernel.shell.CommandCompleter.SERVICE_PROPERTY_COMPLETER_COMMAND_NAMES"/></key>
+ <value>config</value>
+ </entry>
+ </osgi:service-properties>
+ </osgi:service>
+
+ <osgi:service ref="parCompleter" interface="org.eclipse.virgo.kernel.shell.CommandCompleter">
+ <osgi:service-properties>
+ <entry>
+ <key><util:constant static-field="org.eclipse.virgo.kernel.shell.CommandCompleter.SERVICE_PROPERTY_COMPLETER_COMMAND_NAMES"/></key>
+ <value>par</value>
+ </entry>
+ </osgi:service-properties>
+ </osgi:service>
+
+ <osgi:service ref="planCompleter" interface="org.eclipse.virgo.kernel.shell.CommandCompleter">
+ <osgi:service-properties>
+ <entry>
+ <key><util:constant static-field="org.eclipse.virgo.kernel.shell.CommandCompleter.SERVICE_PROPERTY_COMPLETER_COMMAND_NAMES"/></key>
+ <value>plan</value>
+ </entry>
+ </osgi:service-properties>
+ </osgi:service>
+
+ <osgi:service ref="installCompleter" interface="org.eclipse.virgo.kernel.shell.CommandCompleter">
+ <osgi:service-properties>
+ <entry>
+ <key><util:constant static-field="org.eclipse.virgo.kernel.shell.CommandCompleter.SERVICE_PROPERTY_COMPLETER_COMMAND_NAMES"/></key>
+ <value>install</value>
+ </entry>
+ </osgi:service-properties>
+ </osgi:service>
+
+</beans>
diff --git a/org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.BundleCommands.help b/org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.BundleCommands.help
new file mode 100644
index 00000000..c0fe0478
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.BundleCommands.help
@@ -0,0 +1,19 @@
+# Summary
+Management and examination of bundle artifacts
+# Detail
+bundle list - List all bundle artifacts that are
+ currently installed
+bundle examine [ id | name version ] - Examine a bundle artifact
+bundle start [ id | name version ] - Start a bundle artifact. Starting this
+ artifact starts it in the OSGi
+ framework.
+bundle stop [ id | name version ] - Stop a bundle artifact. Stopping this
+ artifact stops it in the OSGi
+ framework.
+bundle refresh [ id | name version ] - Refresh a bundle artifact. Refreshing
+ this artifact updates its contents in
+ the OSGi framework.
+bundle uninstall [ id | name version ] - Uninstall a bundle artifact
+bundle diag [ id | name version ] - Provide diagnostics for a bundle
+ artifact
+bundle headers [ id | name version ] - Show the headers for a bundle artifact
diff --git a/org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.ConfigCommands.help b/org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.ConfigCommands.help
new file mode 100644
index 00000000..e756aa9e
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.ConfigCommands.help
@@ -0,0 +1,18 @@
+# Summary
+Management and examination of configuration artifacts
+# Detail
+config list - List all configuration artifacts that are
+ currently installed
+config examine <name> [version] - Examine a configuration artifact. A
+ configuration artifact must be active to
+ examine it.
+config start <name> [version] - Start a configuration artifact. Starting
+ this artifact makes it visible to
+ ConfigurationAdmin.
+config stop <name> [version] - Stop a configuration artifact. Stopping this
+ artifact makes it invisible to
+ ConfigurationAdmin.
+config refresh <name> [version] - Refresh a configuration artifact. Refreshing
+ this artifact updates its contents in
+ ConfigurationAdmin.
+config uninstall <name> [version] - Uninstall a configuration artifact
diff --git a/org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.ExitCommand.help b/org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.ExitCommand.help
new file mode 100644
index 00000000..1de4f444
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.ExitCommand.help
@@ -0,0 +1,6 @@
+# Summary
+Exit the shell
+# Detail
+exit - leave the shell. If the shell is local the console reverts to the kernel log.
+ If the shell is remote, the connection is dropped. Issue shutdown to terminate
+ the kernel.
diff --git a/org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.HelpCommand.help b/org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.HelpCommand.help
new file mode 100644
index 00000000..3945d76a
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.HelpCommand.help
@@ -0,0 +1,5 @@
+# Summary
+Get help on commands
+# Detail
+help - List all the commands with summary help
+help <command> - List the detailed help for <command>
diff --git a/org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.InstallCommand.help b/org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.InstallCommand.help
new file mode 100644
index 00000000..7b659c4d
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.InstallCommand.help
@@ -0,0 +1,4 @@
+# Summary
+Install (deploy) an artifact to the server
+# Detail
+install <uri> - Deploy the artifact, identified by URI
diff --git a/org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.PackageCommands.help b/org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.PackageCommands.help
new file mode 100644
index 00000000..a42267b1
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.PackageCommands.help
@@ -0,0 +1,5 @@
+# Summary
+Management and examination of exported packages
+# Detail
+package list - List all packages that are currently exported
+package examine <name> <version> - Examine an exported package
diff --git a/org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.ParCommands.help b/org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.ParCommands.help
new file mode 100644
index 00000000..aecf0525
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.ParCommands.help
@@ -0,0 +1,10 @@
+# Summary
+Management and examination of PAR artifacts
+# Detail
+par list - List all PAR artifacts that are currently
+ installed
+par examine <name> <version> - Examine a PAR artifact
+par start <name> <version> - Start a PAR artifact
+par stop <name> <version> - Stop a PAR artifact
+par refresh <name> <version> - Refresh a PAR artifact
+par uninstall <name> <version> - Uninstall a PAR artifact
diff --git a/org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.PlanCommands.help b/org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.PlanCommands.help
new file mode 100644
index 00000000..6114a746
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.PlanCommands.help
@@ -0,0 +1,10 @@
+# Summary
+Management and examination of plan artifacts
+# Detail
+plan list - List all plan artifacts that are currently
+ installed
+plan examine <name> <version> - Examine a plan artifact
+plan start <name> <version> - Start a plan artifact
+plan stop <name> <version> - Stop a plan artifact
+plan refresh <name> <version> - Refresh a plan artifact
+plan uninstall <name> <version> - Uninstall a plan artifact
diff --git a/org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.ServiceCommands.help b/org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.ServiceCommands.help
new file mode 100644
index 00000000..8350772c
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.ServiceCommands.help
@@ -0,0 +1,5 @@
+# Summary
+Examination of services
+# Detail
+service list - List all services in the service registry
+service examine <id> - Examine a specific service
diff --git a/org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.ShutdownCommand.help b/org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.ShutdownCommand.help
new file mode 100644
index 00000000..ab6f022a
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/main/resources/com.springsource.kernel.shell.internal.commands.ShutdownCommand.help
@@ -0,0 +1,4 @@
+# Summary
+Shutdown Virgo Kernel
+# Detail
+shutdown - terminate the shell and the running kernel
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/AnnotationBasedCommandResolverTests.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/AnnotationBasedCommandResolverTests.java
new file mode 100644
index 00000000..8f456adc
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/AnnotationBasedCommandResolverTests.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+import static org.junit.Assert.assertEquals;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+import org.eclipse.virgo.kernel.shell.Command;
+import org.eclipse.virgo.kernel.shell.internal.AnnotationBasedCommandResolver;
+import org.eclipse.virgo.kernel.shell.internal.CommandDescriptor;
+import org.junit.Test;
+
+
+/**
+ */
+public class AnnotationBasedCommandResolverTests {
+
+ private final AnnotationBasedCommandResolver resolver = new AnnotationBasedCommandResolver();
+
+ @Test
+ public void basicAnnotations() throws SecurityException, NoSuchMethodException {
+ List<CommandDescriptor> commands = resolver.resolveCommands(null, new TestCommands());
+ assertEquals(2, commands.size());
+
+ assertCommandEquals("test", "one", TestCommands.class.getMethod("foo"), commands.get(0));
+ assertCommandEquals("test", "two", TestCommands.class.getMethod("bar"), commands.get(1));
+ }
+
+ @Test
+ public void inheritedAnnotations() throws SecurityException, NoSuchMethodException {
+ List<CommandDescriptor> commands = resolver.resolveCommands(null, new SubTestCommands());
+ assertEquals(4, commands.size());
+
+ assertCommandEquals("test-sub", "three", SubTestCommands.class.getMethod("alpha"), commands.get(0));
+ assertCommandEquals("test-sub", "four", SubTestCommands.class.getMethod("bravo"), commands.get(1));
+ assertCommandEquals("test-sub", "one", SubTestCommands.class.getMethod("foo"), commands.get(2));
+ assertCommandEquals("test-sub", "two", SubTestCommands.class.getMethod("bar"), commands.get(3));
+ }
+
+ private void assertCommandEquals(String expectedCommandName, String expectedSubCommandName, Method expectedMethod, CommandDescriptor commandDescriptor) {
+ assertEquals(expectedCommandName, commandDescriptor.getCommandName());
+ assertEquals(expectedSubCommandName, commandDescriptor.getSubCommandName());
+ assertEquals(expectedMethod, commandDescriptor.getMethod());
+ }
+
+ @Command("test")
+ private static class TestCommands {
+
+ @Command("one")
+ public void foo() {
+
+ }
+
+ @Command("two")
+ public void bar() {
+
+ }
+ }
+
+ @Command("test-sub")
+ private static final class SubTestCommands extends TestCommands {
+
+ @Command("three")
+ public void alpha() {
+
+ }
+
+ @Command("four")
+ public void bravo() {
+
+ }
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/DelegatingCompletorTests.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/DelegatingCompletorTests.java
new file mode 100644
index 00000000..b7ef4111
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/DelegatingCompletorTests.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.virgo.kernel.shell.CommandCompleter;
+import org.eclipse.virgo.kernel.shell.internal.completers.CommandCompleterRegistry;
+import org.eclipse.virgo.kernel.shell.internal.completers.DelegatingJLineCompletor;
+import org.junit.Test;
+
+
+/**
+ */
+public class DelegatingCompletorTests {
+
+ private final CommandCompleterRegistry commandCompleterRegistry = createMock(CommandCompleterRegistry.class);
+
+ private final DelegatingJLineCompletor completor = new DelegatingJLineCompletor(this.commandCompleterRegistry);
+
+ @Test
+ public void completionWithNoCommandProvider() {
+ expect(commandCompleterRegistry.getCommandCompleter("command")).andReturn(null);
+ replay(commandCompleterRegistry);
+
+ List<String> candidates = new ArrayList<String>();
+
+ assertEquals(-1, this.completor.complete("command ", 8, candidates));
+
+ verify(commandCompleterRegistry);
+ }
+
+ @Test
+ public void completion() {
+ expect(commandCompleterRegistry.getCommandCompleter("command")).andReturn(new TestCommandCompletor());
+ replay(commandCompleterRegistry);
+
+ List<String> candidates = new ArrayList<String>();
+
+ assertEquals(11, this.completor.complete("command do te", 13, candidates));
+
+ verify(commandCompleterRegistry);
+ }
+
+ private static final class TestCommandCompletor implements CommandCompleter {
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<String> getCompletionCandidates(String subCommand, String... arguments) {
+ return Arrays.asList("test");
+ }
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/RemoteShellsManagerTests.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/RemoteShellsManagerTests.java
new file mode 100644
index 00000000..80330cbc
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/RemoteShellsManagerTests.java
@@ -0,0 +1,218 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.lang.management.ManagementFactory;
+import java.util.Properties;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.sshd.ClientChannel;
+import org.apache.sshd.ClientSession;
+import org.apache.sshd.SshClient;
+import org.apache.sshd.client.future.AuthFuture;
+import org.apache.sshd.client.future.ConnectFuture;
+import org.apache.sshd.client.future.OpenFuture;
+import org.apache.sshd.common.future.CloseFuture;
+import org.apache.sshd.server.PasswordAuthenticator;
+import org.apache.sshd.server.session.ServerSession;
+import org.junit.Test;
+
+import org.eclipse.virgo.kernel.shell.internal.RemoteShellsManager;
+import org.eclipse.virgo.medic.test.eventlog.MockEventLogger;
+import org.eclipse.virgo.util.io.NetUtils;
+
+/**
+ */
+public class RemoteShellsManagerTests {
+
+ private static final String PROPERTY_SHELL_PORT = "shell.port";
+
+ private static final String PROPERTY_SHELL_ENABLED = "shell.enabled";
+
+ private static final String KNOWN_USER = "Billy";
+
+ private static final String KNOWN_USER_PASSWORD = "Password";
+
+ private static final String DEFAULT_KERNEL_DOMAIN = "org.eclipse.virgo.kernel";
+
+ private static final String MBEAN_VALUE_SHUTDOWN = "Shutdown";
+
+ private static final String MBEAN_KEY_TYPE = "type";
+
+ @Test
+ public void testRemoteShellNotEnabled() throws Exception {
+ int port = NetUtils.getFreePort();
+ Properties configuration = new Properties();
+ configuration.setProperty(PROPERTY_SHELL_PORT, String.valueOf(port));
+ configuration.setProperty(PROPERTY_SHELL_ENABLED, String.valueOf(false));
+ RemoteShellsManager remoteShellManager = createRemoteShellManager(configuration);
+ try {
+ SshClient sshClient = SshClient.setUpDefaultClient();
+ sshClient.start();
+
+ ConnectFuture connect = connect(sshClient, port);
+ assertFalse(connect.isConnected());
+
+ sshClient.stop();
+ } finally {
+ remoteShellManager.stop();
+ assertTrue(NetUtils.isPortAvailable(port));
+ }
+ }
+
+ @Test
+ public void testRemoteShellEnabled() throws Exception {
+ int port = NetUtils.getFreePort();
+ Properties configuration = new Properties();
+ configuration.setProperty(PROPERTY_SHELL_PORT, String.valueOf(port));
+ configuration.setProperty(PROPERTY_SHELL_ENABLED, String.valueOf(true));
+ RemoteShellsManager remoteShellManager = createRemoteShellManager(configuration);
+ try {
+ SshClient sshClient = SshClient.setUpDefaultClient();
+ sshClient.start();
+
+ ConnectFuture connect = connect(sshClient, port);
+ assertTrue(connect.isConnected());
+
+ sshClient.stop();
+ } finally {
+ remoteShellManager.stop();
+ assertTrue(NetUtils.isPortAvailable(port));
+ }
+ }
+
+ @Test
+ public void testRemoteShellEnabledPortClash() throws Exception {
+ MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+ ObjectName shutdownName = ObjectName.getInstance(DEFAULT_KERNEL_DOMAIN, MBEAN_KEY_TYPE, MBEAN_VALUE_SHUTDOWN);
+ DummyShutdown dummyShutdownMBean = new DummyShutdown();
+ server.registerMBean(dummyShutdownMBean, shutdownName);
+
+ int port = NetUtils.getFreePort();
+ Properties configuration = new Properties();
+ configuration.setProperty(PROPERTY_SHELL_PORT, String.valueOf(port));
+ configuration.setProperty(PROPERTY_SHELL_ENABLED, String.valueOf(true));
+ RemoteShellsManager remoteShellManager1 = createRemoteShellManager(configuration);
+ RemoteShellsManager remoteShellManager2 = createRemoteShellManager(configuration);
+ Thread.sleep(500);
+ remoteShellManager1.stop();
+ remoteShellManager2.stop();
+ assertTrue(dummyShutdownMBean.shutDownCalled);
+ server.unregisterMBean(shutdownName);
+ }
+
+ @Test
+ public void testRemoteShellEnabledBadUser() throws Exception {
+ int port = NetUtils.getFreePort();
+ Properties configuration = new Properties();
+ configuration.setProperty(PROPERTY_SHELL_PORT, String.valueOf(port));
+ configuration.setProperty(PROPERTY_SHELL_ENABLED, String.valueOf(true));
+ RemoteShellsManager remoteShellManager = createRemoteShellManager(configuration);
+ try {
+ SshClient sshClient = SshClient.setUpDefaultClient();
+ sshClient.start();
+
+ ConnectFuture connect = connect(sshClient, port);
+ assertTrue(connect.isConnected());
+ ClientSession session = connect.getSession();
+ AuthFuture authFuture = session.authPassword("Monkey", "BadPassword").await();
+ assertTrue(authFuture.isDone());
+ assertFalse(authFuture.isSuccess());
+
+ session.close(true);
+
+ sshClient.stop();
+
+ } finally {
+ remoteShellManager.stop();
+ assertTrue(NetUtils.isPortAvailable(port));
+ }
+ }
+
+ @Test
+ public void testRemoteShellEnabledConnect() throws Exception {
+ int port = NetUtils.getFreePort();
+ Properties configuration = new Properties();
+ configuration.setProperty(PROPERTY_SHELL_PORT, String.valueOf(port));
+ configuration.setProperty(PROPERTY_SHELL_ENABLED, String.valueOf(true));
+ RemoteShellsManager remoteShellManager = createRemoteShellManager(configuration);
+ try {
+ SshClient sshClient = SshClient.setUpDefaultClient();
+ sshClient.start();
+
+ ConnectFuture connect = connect(sshClient, port);
+ assertTrue(connect.isConnected());
+ ClientSession session = connect.getSession();
+ AuthFuture authFuture = session.authPassword(KNOWN_USER, KNOWN_USER_PASSWORD).await();
+ assertTrue(authFuture.isSuccess());
+
+ ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL);
+ channel.setIn(System.in);
+ channel.setOut(System.out);
+ channel.setErr(System.err);
+ OpenFuture openFuture = channel.open().await();
+ assertTrue(openFuture.isOpened());
+
+ CloseFuture close = session.close(true);
+ assertTrue(close.await(10000));
+
+ sshClient.stop();
+
+ } finally {
+ remoteShellManager.stop();
+ assertTrue(NetUtils.isPortAvailable(port));
+ }
+ }
+
+ private ConnectFuture connect(SshClient sshClient, int port) throws InterruptedException, Exception {
+ ConnectFuture connect = sshClient.connect("localhost", port).await();
+ return connect;
+ }
+
+ private RemoteShellsManager createRemoteShellManager(Properties configuration) {
+ RemoteShellsManager remoteShellManager = new RemoteShellsManager(new StubLocalShellFactory(), configuration, new MockEventLogger()) {
+
+ @Override
+ protected PasswordAuthenticator createPasswordAuthenticator() {
+ return new PasswordAuthenticator() {
+
+ public boolean authenticate(String username, String password, ServerSession session) {
+ return KNOWN_USER.equals(username) && KNOWN_USER_PASSWORD.equals(password);
+ }
+ };
+ }
+
+ };
+ remoteShellManager.start();
+ return remoteShellManager;
+ }
+
+ public static interface DummyShutdownMBean {
+
+ public void shutdown();
+ }
+
+ public static class DummyShutdown implements DummyShutdownMBean {
+
+ private boolean shutDownCalled = false;
+
+ public void shutdown() {
+ this.shutDownCalled = true;
+ }
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/ServiceRegistryCommandProviderResolverTests.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/ServiceRegistryCommandProviderResolverTests.java
new file mode 100644
index 00000000..32e80f60
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/ServiceRegistryCommandProviderResolverTests.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import java.util.Properties;
+
+import org.junit.Test;
+
+import org.eclipse.virgo.kernel.shell.internal.CommandProviderResolver;
+import org.eclipse.virgo.kernel.shell.internal.ServiceRegistryCommandProviderResolver;
+import org.eclipse.virgo.teststubs.osgi.framework.StubBundleContext;
+import org.eclipse.virgo.teststubs.osgi.support.TrueFilter;
+
+
+/**
+ */
+public class ServiceRegistryCommandProviderResolverTests {
+
+ private final StubBundleContext bundleContext = new StubBundleContext();
+
+ private final CommandProviderResolver commandProviderResolver = new ServiceRegistryCommandProviderResolver(this.bundleContext);
+
+ @Test
+ public void noCommandProvider() {
+ this.bundleContext.addFilter(new TrueFilter("(osgi.command.function=*)"));
+ assertNull(this.commandProviderResolver.getCommandProvider("command"));
+ }
+
+ @Test
+ public void commandProvider() {
+ this.bundleContext.addFilter(new TrueFilter("(osgi.command.function=*)"));
+ Properties properties = new Properties();
+ properties.setProperty("osgi.command.function", "command");
+
+ Object commandProvider = new Object();
+
+ this.bundleContext.registerService("Foo", commandProvider, properties);
+ assertEquals(commandProvider, this.commandProviderResolver.getCommandProvider("command"));
+ }
+
+ @Test
+ public void noCommandProviderAsCommandFunctionDoesNotMatch() {
+ this.bundleContext.addFilter(new TrueFilter("(osgi.command.function=*)"));
+ Properties properties = new Properties();
+ properties.setProperty("osgi.command.function", "foo");
+
+ Object commandProvider = new Object();
+
+ this.bundleContext.registerService("Foo", commandProvider, properties);
+ assertNull(this.commandProviderResolver.getCommandProvider("command"));
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/StandardCommandProcessorTests.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/StandardCommandProcessorTests.java
new file mode 100644
index 00000000..cf03483f
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/StandardCommandProcessorTests.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+import static org.easymock.EasyMock.createNiceMock;
+import static org.junit.Assert.assertNotNull;
+
+import org.eclipse.virgo.kernel.shell.internal.CommandInvoker;
+import org.eclipse.virgo.kernel.shell.internal.CommandSession;
+import org.eclipse.virgo.kernel.shell.internal.StandardCommandProcessor;
+import org.junit.Before;
+import org.junit.Test;
+
+
+/**
+ */
+public class StandardCommandProcessorTests {
+
+ private StandardCommandProcessor standardCommandProcessor;
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @Before
+ public void setUp() throws Exception {
+ CommandInvoker commandInvoker = createNiceMock(CommandInvoker.class);
+ this.standardCommandProcessor = new StandardCommandProcessor(commandInvoker);
+ }
+
+ /**
+ * Test method for {@link StandardCommandProcessor#createSession(java.io.PrintStream)}.
+ */
+ @Test
+ public void testCreateSession() {
+ CommandSession commandSession = this.standardCommandProcessor.createSession(System.err);
+ assertNotNull(commandSession);
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/StandardCommandSessionTests.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/StandardCommandSessionTests.java
new file mode 100644
index 00000000..308b2880
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/StandardCommandSessionTests.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.virgo.kernel.shell.internal.CommandInvoker;
+import org.eclipse.virgo.kernel.shell.internal.CommandNotFoundException;
+import org.eclipse.virgo.kernel.shell.internal.ParametersMismatchException;
+import org.eclipse.virgo.kernel.shell.internal.StandardCommandSession;
+import org.eclipse.virgo.kernel.shell.internal.parsing.ParsedCommand;
+import org.eclipse.virgo.kernel.shell.internal.parsing.ParsingUtils;
+import org.junit.Test;
+
+
+/**
+ */
+public class StandardCommandSessionTests {
+
+ private final CommandInvoker commandInvoker = createMock(CommandInvoker.class);
+
+ private final StandardCommandSession standardCommandSession = new StandardCommandSession(commandInvoker, System.err);
+
+ @Test
+ public void testExecute() throws CommandNotFoundException, ParametersMismatchException {
+ ParsedCommand parsedCommand = ParsingUtils.parseCommand("bundle examine 5");
+
+ expect(this.commandInvoker.invokeCommand(eq(parsedCommand))).andReturn(Arrays.asList("result"));
+ replay(this.commandInvoker);
+
+ List<String> lines = this.standardCommandSession.execute("bundle examine 5");
+ assertEquals("result", lines.get(0));
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/StubLocalShell.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/StubLocalShell.java
new file mode 100644
index 00000000..4e15d98c
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/StubLocalShell.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.virgo.kernel.shell.internal.ExitCallback;
+import org.eclipse.virgo.kernel.shell.internal.LocalShell;
+
+
+
+/**
+ */
+public class StubLocalShell implements LocalShell {
+
+ private Set<ExitCallback> callBacks = new HashSet<ExitCallback>();
+
+ /**
+ * {@inheritDoc}
+ */
+ public void addExitCallback(ExitCallback exitCallback) {
+ this.callBacks.add(exitCallback);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void run() {
+
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/StubLocalShellFactory.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/StubLocalShellFactory.java
new file mode 100644
index 00000000..8883bc55
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/StubLocalShellFactory.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal;
+
+import java.io.InputStream;
+import java.io.PrintStream;
+
+import org.eclipse.virgo.kernel.shell.internal.LocalShell;
+import org.eclipse.virgo.kernel.shell.internal.LocalShellFactory;
+
+
+
+/**
+ */
+public class StubLocalShellFactory implements LocalShellFactory {
+
+ /**
+ * {@inheritDoc}
+ */
+ public LocalShell newShell(InputStream in, PrintStream out, PrintStream err) {
+ return new StubLocalShell();
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/commands/AbztractCompositeInstallArtifactBasedCommandsTests.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/commands/AbztractCompositeInstallArtifactBasedCommandsTests.java
new file mode 100644
index 00000000..062f3167
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/commands/AbztractCompositeInstallArtifactBasedCommandsTests.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.commands;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.lang.management.ManagementFactory;
+import java.util.List;
+
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanRegistrationException;
+import javax.management.MalformedObjectNameException;
+import javax.management.NotCompliantMBeanException;
+import javax.management.ObjectName;
+
+import org.eclipse.virgo.kernel.shell.internal.formatting.StubManageableCompositeArtifact;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+
+public class AbztractCompositeInstallArtifactBasedCommandsTests {
+
+ private final StubAbstractCompositeInstallArtifactBasedCommands commands = new StubAbstractCompositeInstallArtifactBasedCommands();
+
+ private final StubManageableCompositeArtifact artifact = new StubManageableCompositeArtifact();
+
+ private volatile ObjectName name;
+ {
+ try {
+ this.name = new ObjectName("test:type=Model,artifact-type=test,name=test1,version=0.0.0");
+ } catch (MalformedObjectNameException e) {
+ } catch (NullPointerException e) {
+ }
+ }
+
+ @Before
+ public void installTestBean() throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException {
+ ManagementFactory.getPlatformMBeanServer().registerMBean(this.artifact, this.name);
+ }
+
+ @After
+ public void uninstallTestBean() throws MBeanRegistrationException, InstanceNotFoundException {
+ ManagementFactory.getPlatformMBeanServer().unregisterMBean(this.name);
+ }
+
+ @Test
+ public void list() {
+ List<String> lines = this.commands.list();
+ assertFalse(lines.isEmpty());
+ }
+
+ @Test
+ public void examine() {
+ List<String> lines = this.commands.examine("test1", "0.0.0");
+ assertFalse(lines.isEmpty());
+ }
+
+ @Test
+ public void start() {
+ this.commands.start("test1", "0.0.0");
+ assertTrue(this.artifact.getStartCalled());
+ }
+
+ @Test
+ public void stop() {
+ this.commands.stop("test1", "0.0.0");
+ assertTrue(this.artifact.getStopCalled());
+ }
+
+ @Test
+ public void refreshWork() {
+ this.artifact.setShouldRefreshSucceed(true);
+ List<String> lines = this.commands.refresh("test1", "0.0.0");
+ assertTrue(this.artifact.getRefreshCalled());
+ assertTrue(lines.get(0).contains("refreshed successfully"));
+ }
+
+ @Test
+ public void refreshFail() {
+ this.artifact.setShouldRefreshSucceed(false);
+ List<String> lines = this.commands.refresh("test1", "0.0.0");
+ assertTrue(this.artifact.getRefreshCalled());
+ assertTrue(lines.get(0).contains("not refreshed"));
+ }
+
+ @Test
+ public void uninstall() {
+ this.commands.uninstall("test1", "0.0.0");
+ assertTrue(this.artifact.getUninstallCalled());
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/commands/ConfigCommandsTests.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/commands/ConfigCommandsTests.java
new file mode 100644
index 00000000..fb6fcc33
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/commands/ConfigCommandsTests.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.commands;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.util.Arrays;
+
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanRegistrationException;
+import javax.management.MalformedObjectNameException;
+import javax.management.NotCompliantMBeanException;
+import javax.management.ObjectName;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+
+import org.eclipse.virgo.kernel.shell.internal.commands.ConfigCommands;
+import org.eclipse.virgo.kernel.shell.internal.formatting.StubManageableCompositeArtifact;
+import org.eclipse.virgo.teststubs.osgi.service.cm.StubConfigurationAdmin;
+
+public class ConfigCommandsTests {
+
+ private final StubConfigurationAdmin configAdmin = new StubConfigurationAdmin();
+
+ private final ConfigCommands commands = new ConfigCommands(new StubRuntimeArtifactModelObjectNameCreator(), configAdmin);
+
+ private final StubManageableCompositeArtifact artifact = new StubManageableCompositeArtifact();
+
+ private volatile ObjectName name;
+ {
+ try {
+ this.name = new ObjectName("test:type=Model,artifact-type=configuration,name=test1,version=0.0.0");
+ } catch (MalformedObjectNameException e) {
+ } catch (NullPointerException e) {
+ }
+ }
+
+ @Before
+ public void installTestBean() throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException {
+ ManagementFactory.getPlatformMBeanServer().registerMBean(this.artifact, this.name);
+ }
+
+ @After
+ public void uninstallTestBean() throws MBeanRegistrationException, InstanceNotFoundException {
+ ManagementFactory.getPlatformMBeanServer().unregisterMBean(this.name);
+ }
+
+ @Test
+ public void examineActive() throws IOException {
+ configAdmin.createConfiguration("test1");
+ assertEquals(Arrays.asList("Factory pid: com.springsource.testName", "Bundle Location: "), this.commands.examine("test1", "0.0.0"));
+ }
+
+ @Test
+ public void examineNotActive() {
+ this.artifact.setState("RESOLVED");
+ assertEquals(Arrays.asList("Unable to examine configuration in non-active state"), this.commands.examine("test1", "0.0.0"));
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/commands/InstallCommandTests.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/commands/InstallCommandTests.java
new file mode 100644
index 00000000..595a719e
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/commands/InstallCommandTests.java
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.commands;
+
+import static org.junit.Assert.assertEquals;
+
+import java.lang.management.ManagementFactory;
+import java.util.List;
+
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanRegistrationException;
+import javax.management.MalformedObjectNameException;
+import javax.management.NotCompliantMBeanException;
+import javax.management.ObjectName;
+
+import org.eclipse.virgo.kernel.deployer.ArtifactIdentity;
+import org.eclipse.virgo.kernel.deployer.Deployer;
+import org.eclipse.virgo.kernel.deployer.core.DeploymentException;
+import org.eclipse.virgo.kernel.deployer.core.DeploymentIdentity;
+import org.eclipse.virgo.kernel.shell.internal.commands.InstallCommand;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+
+public class InstallCommandTests {
+
+ public final InstallCommand command;
+
+ private final ObjectName deployerObjectName;
+
+ public InstallCommandTests() throws MalformedObjectNameException, NullPointerException {
+ this.command = new InstallCommand();
+ this.deployerObjectName = new ObjectName("org.eclipse.virgo.kernel:category=Control,type=Deployer");
+ }
+
+ @Before
+ public void export() throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException {
+ ManagementFactory.getPlatformMBeanServer().registerMBean(new StubDeployer(), this.deployerObjectName);
+ }
+
+ @After
+ public void unexport() throws MBeanRegistrationException, InstanceNotFoundException {
+ ManagementFactory.getPlatformMBeanServer().unregisterMBean(this.deployerObjectName);
+ }
+
+ @Test
+ public void install() {
+ List<String> lines = this.command.install("test1");
+ assertEquals("Artifact testType testName testVersion installed", lines.get(0));
+ }
+
+ @Test
+ public void installException() {
+ List<String> lines = this.command.install("test2");
+ assertEquals("Artifact installation failed: test", lines.get(0));
+ }
+
+ private static class StubDeployer implements Deployer {
+
+ public DeploymentIdentity deploy(String uri) {
+ throw new UnsupportedOperationException();
+ }
+
+ public DeploymentIdentity deploy(String uri, boolean recoverable) throws DeploymentException {
+ throw new UnsupportedOperationException();
+ }
+
+ public ArtifactIdentity install(String artifactUri) throws DeploymentException {
+ if ("test1".equals(artifactUri)) {
+ return new ArtifactIdentity("testType", "testName", "testVersion");
+ } else if ("test2".equals(artifactUri)) {
+ throw new IllegalArgumentException("test");
+ }
+ return null;
+ }
+
+ public ArtifactIdentity install(String artifactUri, boolean recover) throws DeploymentException {
+ throw new UnsupportedOperationException();
+ }
+
+ public ArtifactIdentity install(String type, String name, String version) throws DeploymentException {
+ throw new UnsupportedOperationException();
+ }
+
+ public ArtifactIdentity install(String type, String name, String version, boolean recover) throws DeploymentException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void refresh(String uri, String symbolicName) throws DeploymentException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void refreshBundle(String bundleSymbolicName, String bundleVersion) throws DeploymentException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void start(ArtifactIdentity artifactIdentity) throws DeploymentException, IllegalStateException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void start(String type, String name, String version) throws DeploymentException, IllegalStateException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void stop(ArtifactIdentity artifactIdentity) throws DeploymentException, IllegalStateException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void stop(String type, String name, String version) throws DeploymentException, IllegalStateException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void undeploy(String applicationSymbolicName, String version) throws DeploymentException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void uninstall(ArtifactIdentity artifactIdentity) throws DeploymentException, IllegalStateException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void uninstall(String type, String name, String version) throws DeploymentException, IllegalStateException {
+ throw new UnsupportedOperationException();
+ }
+
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/commands/StubAbstractCompositeInstallArtifactBasedCommands.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/commands/StubAbstractCompositeInstallArtifactBasedCommands.java
new file mode 100644
index 00000000..27fa8298
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/commands/StubAbstractCompositeInstallArtifactBasedCommands.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.commands;
+
+import org.eclipse.virgo.kernel.model.management.ManageableCompositeArtifact;
+import org.eclipse.virgo.kernel.shell.internal.commands.AbstractInstallArtifactBasedCommands;
+
+final class StubAbstractCompositeInstallArtifactBasedCommands extends AbstractInstallArtifactBasedCommands<ManageableCompositeArtifact> {
+
+ public StubAbstractCompositeInstallArtifactBasedCommands() {
+ super("test", new StubRuntimeArtifactModelObjectNameCreator(), new StubInstallArtifactCommandFormatter(), ManageableCompositeArtifact.class);
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/commands/StubInstallArtifactCommandFormatter.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/commands/StubInstallArtifactCommandFormatter.java
new file mode 100644
index 00000000..e243c25a
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/commands/StubInstallArtifactCommandFormatter.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.commands;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.virgo.kernel.model.management.ManageableCompositeArtifact;
+import org.eclipse.virgo.kernel.shell.internal.formatting.InstallArtifactCommandFormatter;
+
+final class StubInstallArtifactCommandFormatter implements InstallArtifactCommandFormatter<ManageableCompositeArtifact> {
+
+ public List<String> formatExamine(ManageableCompositeArtifact artifact) {
+ return Arrays.asList("");
+ }
+
+ public List<String> formatList(List<ManageableCompositeArtifact> artifacts) {
+ return Arrays.asList("");
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/commands/StubRuntimeArtifactModelObjectNameCreator.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/commands/StubRuntimeArtifactModelObjectNameCreator.java
new file mode 100644
index 00000000..306830d2
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/commands/StubRuntimeArtifactModelObjectNameCreator.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.commands;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.osgi.framework.Version;
+
+import org.eclipse.virgo.kernel.model.Artifact;
+import org.eclipse.virgo.kernel.model.management.RuntimeArtifactModelObjectNameCreator;
+
+public final class StubRuntimeArtifactModelObjectNameCreator implements RuntimeArtifactModelObjectNameCreator {
+
+ public ObjectName create(Artifact artifact) {
+ throw new UnsupportedOperationException();
+ }
+
+ public ObjectName create(String type, String name, Version version) {
+ try {
+ return new ObjectName("test:type=Model,artifact-type=" + type + ",name=" + name + ",version=" + version);
+ } catch (MalformedObjectNameException e) {
+ } catch (NullPointerException e) {
+ }
+ return null;
+ }
+
+ public ObjectName createArtifactsOfTypeQuery(String type) {
+ try {
+ return new ObjectName("test:artifact-type=" + type + ",*");
+ } catch (MalformedObjectNameException e) {
+ } catch (NullPointerException e) {
+ }
+ return null;
+ }
+
+ public ObjectName createArtifactsQuery() {
+ throw new UnsupportedOperationException();
+ }
+
+ public ObjectName createArtifactVersionsQuery(String type, String name) {
+ try {
+ return new ObjectName("test:type=Model,artifact-type=" + type + ",name=" + name + ",*");
+ } catch (MalformedObjectNameException e) {
+ } catch (NullPointerException e) {
+ }
+ return null;
+ }
+
+ public String getName(ObjectName objectName) {
+ return objectName.getKeyProperty("name");
+ }
+
+ public String getType(ObjectName objectName) {
+ return objectName.getKeyProperty("type");
+ }
+
+ public String getVersion(ObjectName objectName) {
+ return objectName.getKeyProperty("version");
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/completers/AbztractInstallArtifactCompleterTests.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/completers/AbztractInstallArtifactCompleterTests.java
new file mode 100644
index 00000000..21f3a235
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/completers/AbztractInstallArtifactCompleterTests.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.completers;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.lang.management.ManagementFactory;
+import java.util.Set;
+
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanRegistrationException;
+import javax.management.MalformedObjectNameException;
+import javax.management.NotCompliantMBeanException;
+import javax.management.ObjectName;
+
+import org.eclipse.virgo.kernel.shell.internal.commands.StubRuntimeArtifactModelObjectNameCreator;
+import org.eclipse.virgo.kernel.shell.internal.completers.AbstractInstallArtifactCompleter;
+import org.eclipse.virgo.kernel.shell.internal.formatting.StubManageableCompositeArtifact;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+
+public class AbztractInstallArtifactCompleterTests {
+
+ private final StubInstallArtifactCompleter completer = new StubInstallArtifactCompleter();
+
+ private final StubManageableCompositeArtifact artifact = new StubManageableCompositeArtifact();
+
+ private volatile ObjectName name;
+ {
+ try {
+ this.name = new ObjectName("test:type=Model,artifact-type=test,name=test1,version=0.0.0");
+ } catch (MalformedObjectNameException e) {
+ } catch (NullPointerException e) {
+ }
+ }
+
+ @Before
+ public void installTestBean() throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException {
+ ManagementFactory.getPlatformMBeanServer().registerMBean(this.artifact, this.name);
+ }
+
+ @After
+ public void uninstallTestBean() throws MBeanRegistrationException, InstanceNotFoundException {
+ ManagementFactory.getPlatformMBeanServer().unregisterMBean(this.name);
+ }
+
+ @Test
+ public void list() {
+ assertEquals(0, this.completer.getCompletionCandidates("list").size());
+ }
+
+ @Test
+ public void name() {
+ assertEquals(1, this.completer.getCompletionCandidates("examine", "tes").size());
+ }
+
+ @Test
+ public void version() {
+ assertEquals(1, this.completer.getCompletionCandidates("examine", "test1", "").size());
+ }
+
+ @Test
+ public void tooManyArgs() {
+ assertEquals(0, this.completer.getCompletionCandidates("testCommand", "", "", "").size());
+ }
+
+ @Test
+ public void filter() {
+ assertTrue(this.completer.getCompletionCandidates("testFilter", "tes").contains("filtered"));
+ }
+
+ private static class StubInstallArtifactCompleter extends AbstractInstallArtifactCompleter {
+
+ public StubInstallArtifactCompleter() {
+ super("test", new StubRuntimeArtifactModelObjectNameCreator());
+ }
+
+ @Override
+ protected void filter(Set<String> candidates, String subcommand, String... tokens) {
+ if ("testFilter".equals(subcommand)) {
+ candidates.add("filtered");
+ }
+ }
+
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/completers/ConfigCompleterTests.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/completers/ConfigCompleterTests.java
new file mode 100644
index 00000000..9db48940
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/completers/ConfigCompleterTests.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.completers;
+
+import static org.junit.Assert.assertEquals;
+
+import java.lang.management.ManagementFactory;
+
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanRegistrationException;
+import javax.management.MalformedObjectNameException;
+import javax.management.NotCompliantMBeanException;
+import javax.management.ObjectName;
+
+import org.eclipse.virgo.kernel.shell.internal.commands.StubRuntimeArtifactModelObjectNameCreator;
+import org.eclipse.virgo.kernel.shell.internal.completers.ConfigCompleter;
+import org.eclipse.virgo.kernel.shell.internal.formatting.StubManageableCompositeArtifact;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+
+public class ConfigCompleterTests {
+
+ private final ConfigCompleter completer = new ConfigCompleter(new StubRuntimeArtifactModelObjectNameCreator());
+
+ @Before
+ public void installTestBean() throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException {
+ ManagementFactory.getPlatformMBeanServer().registerMBean(getActiveArtifact(), getObjectName("test1", "0.0.0"));
+ ManagementFactory.getPlatformMBeanServer().registerMBean(getActiveArtifact(), getObjectName("test1", "1.0.0"));
+ ManagementFactory.getPlatformMBeanServer().registerMBean(getActiveArtifact(), getObjectName("test2", "0.0.0"));
+ ManagementFactory.getPlatformMBeanServer().registerMBean(getInactiveArtifact(), getObjectName("test2", "1.0.0"));
+ ManagementFactory.getPlatformMBeanServer().registerMBean(getInactiveArtifact(), getObjectName("test3", "0.0.0"));
+ ManagementFactory.getPlatformMBeanServer().registerMBean(getInactiveArtifact(), getObjectName("test3", "1.0.0"));
+ }
+
+ @After
+ public void uninstallTestBean() throws MBeanRegistrationException, InstanceNotFoundException {
+ ManagementFactory.getPlatformMBeanServer().unregisterMBean(getObjectName("test1", "0.0.0"));
+ ManagementFactory.getPlatformMBeanServer().unregisterMBean(getObjectName("test1", "1.0.0"));
+ ManagementFactory.getPlatformMBeanServer().unregisterMBean(getObjectName("test2", "0.0.0"));
+ ManagementFactory.getPlatformMBeanServer().unregisterMBean(getObjectName("test2", "1.0.0"));
+ ManagementFactory.getPlatformMBeanServer().unregisterMBean(getObjectName("test3", "0.0.0"));
+ ManagementFactory.getPlatformMBeanServer().unregisterMBean(getObjectName("test3", "1.0.0"));
+ }
+
+ @Test
+ public void filterNames() {
+ assertEquals(2, this.completer.getCompletionCandidates("examine", "").size());
+ }
+
+ @Test
+ public void filterVersions() {
+ assertEquals(2, this.completer.getCompletionCandidates("examine", "test1", "").size());
+ assertEquals(1, this.completer.getCompletionCandidates("examine", "test2", "").size());
+ assertEquals(0, this.completer.getCompletionCandidates("examine", "test3", "").size());
+ }
+
+ private final ObjectName getObjectName(String name, String version) {
+ try {
+ return new ObjectName("test:type=Model,artifact-type=configuration,name=" + name + ",version=" + version);
+ } catch (MalformedObjectNameException e) {
+ } catch (NullPointerException e) {
+ }
+ return null;
+ }
+
+ private final StubManageableCompositeArtifact getActiveArtifact() {
+ return new StubManageableCompositeArtifact().setState("ACTIVE");
+ }
+
+ private final StubManageableCompositeArtifact getInactiveArtifact() {
+ return new StubManageableCompositeArtifact().setState("RESOLVED");
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/completers/InstallCompleterTests.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/completers/InstallCompleterTests.java
new file mode 100644
index 00000000..22b4d8f7
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/completers/InstallCompleterTests.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.completers;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.util.List;
+
+import org.eclipse.virgo.kernel.shell.internal.completers.InstallCompleter;
+import org.junit.Test;
+
+/**
+ */
+public class InstallCompleterTests {
+
+ private static final String FILE_PREFIX = "file:";
+
+ private static final File base = new File("target" + File.separatorChar + "install-completer" + File.separatorChar);
+
+ private static final String ALPHA = FILE_PREFIX + new File(base, "alpha ").getPath();
+
+ private static final String ALPHA_SINGLE = FILE_PREFIX + new File(base, "alpha").getPath() + File.separatorChar;
+
+ private static final String APPLE = FILE_PREFIX + new File(base, "apple.txt ").getPath();
+
+ private static final String BRAVO = FILE_PREFIX + new File(base, "bravo ").getPath();
+
+ private static final String BRAVO_SINGLE = FILE_PREFIX + new File(base, "bravo").getPath() + File.separatorChar;
+
+ private final InstallCompleter completer;
+
+ {
+ try {
+ this.completer = new InstallCompleter();
+
+ new File(base, "alpha").mkdirs();
+ new File(base, "bravo").mkdirs();
+ new File(base, "apple.txt").createNewFile();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Test
+ public void completionOfCompletelyUnmatchingPath() {
+ List<String> completionCandidates = this.completer.getCompletionCandidates("file:zebra" + File.separatorChar + "giraffe");
+ assertCompletionsPresent(completionCandidates);
+ }
+
+ @Test
+ public void completionWithMultipleOptions() {
+ List<String> completionCandidates = this.completer.getCompletionCandidates("file:target" + File.separatorChar + "install-completer"
+ + File.separatorChar);
+ assertCompletionsPresent(completionCandidates, ALPHA, APPLE, BRAVO);
+
+ completionCandidates = this.completer.getCompletionCandidates("file:target" + File.separatorChar + "install-completer" + File.separatorChar
+ + "a");
+ assertCompletionsPresent(completionCandidates, ALPHA, APPLE);
+ }
+
+ @Test
+ public void completionWithSingleOption() {
+ List<String> completionCandidates = this.completer.getCompletionCandidates("file:target" + File.separatorChar + "install-completer"
+ + File.separatorChar + "ap");
+ assertEquals(1, completionCandidates.size());
+ assertCompletionsPresent(completionCandidates, APPLE);
+
+ completionCandidates = this.completer.getCompletionCandidates("file:target" + File.separatorChar + "install-completer" + File.separatorChar
+ + "al");
+ assertCompletionsPresent(completionCandidates, ALPHA_SINGLE);
+
+ completionCandidates = this.completer.getCompletionCandidates("file:target" + File.separatorChar + "install-completer" + File.separatorChar
+ + "b");
+ assertCompletionsPresent(completionCandidates, BRAVO_SINGLE);
+ }
+
+ @Test
+ public void completionWithNoOptions() {
+ List<String> completionCandidates = this.completer.getCompletionCandidates("file:target" + File.separatorChar + "install-completer"
+ + File.separatorChar + "c");
+ assertCompletionsPresent(completionCandidates);
+
+ completionCandidates = this.completer.getCompletionCandidates("file:target" + File.separatorChar + "install-completer" + File.separatorChar
+ + "bravo" + File.separatorChar);
+ assertCompletionsPresent(completionCandidates);
+ }
+
+ private static void assertCompletionsPresent(List<String> actual, String... expected) {
+ assertEquals(expected.length, actual.size());
+ for (String string : expected) {
+ assertTrue("Expected completion candidate '" + string + "' was not present in completions " + actual, actual.contains(string));
+ }
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/converters/LongConverterTests.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/converters/LongConverterTests.java
new file mode 100644
index 00000000..c492ea40
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/converters/LongConverterTests.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.converters;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.virgo.kernel.shell.Converter;
+import org.eclipse.virgo.kernel.shell.internal.converters.LongConverter;
+import org.junit.Test;
+
+
+/**
+ */
+public class LongConverterTests {
+
+ private final Long testLong = 45L;
+
+ private final long testLongPrimitive = testLong.longValue();
+
+ @Test
+ public void testGetTypes() {
+ String[] types = LongConverter.getTypes();
+ List<String> typesList = Arrays.asList(types);
+ assertTrue(typesList.contains(Long.class.getName()));
+ assertTrue(typesList.contains(long.class.getName()));
+ }
+
+ @Test
+ public void testConvert() throws Exception {
+ LongConverter longConverter = new LongConverter();
+ assertEquals(testLong, longConverter.convert(Long.class, testLong.toString()));
+ assertEquals(testLong, longConverter.convert(long.class, testLong.toString()));
+ }
+
+ @Test
+ public void testConvertBadInput() throws Exception {
+ LongConverter longConverter = new LongConverter();
+ assertNull(longConverter.convert(Integer.class, testLong.toString()));
+ assertNull(longConverter.convert(int.class, testLong.toString()));
+ }
+
+ @Test
+ public void testFormat() throws Exception {
+ LongConverter longConverter = new LongConverter();
+ assertEquals(testLong.toString(), longConverter.format(testLong, Converter.LINE, null));
+ assertEquals(testLong.toString(), longConverter.format(testLongPrimitive, Converter.LINE, null));
+ }
+
+ @Test
+ public void testFormatNotALong() throws Exception {
+ LongConverter longConverter = new LongConverter();
+ assertNull(longConverter.format(new Object(), Converter.LINE, null));
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/converters/StringConverterTests.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/converters/StringConverterTests.java
new file mode 100644
index 00000000..532c0787
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/converters/StringConverterTests.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.converters;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import org.eclipse.virgo.kernel.shell.internal.converters.StringConverter;
+import org.junit.Test;
+
+
+
+/**
+ * <p>
+ * StringConverterTests for the basic function of {@link StringConverter} the format method is not used.
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Test class
+ *
+ */
+public class StringConverterTests {
+
+ private final String testString = "formattedString";
+
+ /**
+ * Test method for {@link StringConverter#getTypes()}.
+ */
+ @Test
+ public void testGetTypes() {
+ assertEquals(String.class.getName(), StringConverter.getTypes());
+ }
+
+ /**
+ * Test method for {@link StringConverter#convert(java.lang.Class, java.lang.Object)}.
+ * @throws Exception
+ */
+ @Test
+ public void testConvert() throws Exception {
+ StringConverter stringConverter = new StringConverter();
+ assertEquals(testString, stringConverter.convert(String.class, testString));
+ }
+
+ /**
+ * Test method for {@link StringConverter#convert(java.lang.Class, java.lang.Object)}.
+ * @throws Exception
+ */
+ @Test
+ public void testConvertBadType() throws Exception {
+ StringConverter stringConverter = new StringConverter();
+ assertEquals(null, stringConverter.convert(Integer.class, testString));
+ }
+
+ /**
+ * Test method for {@link StringConverter#format(java.lang.Object, int, org.eclipse.virgo.kernel.shell.Converter)}.
+ * @throws Exception
+ */
+ @Test
+ public void testFormat() throws Exception {
+ StringConverter stringConverter = new StringConverter();
+ assertEquals(testString, stringConverter.format(testString, 0, null));
+ }
+
+ /**
+ * Test method for {@link StringConverter#format(java.lang.Object, int, org.eclipse.virgo.kernel.shell.Converter)}.
+ * @throws Exception
+ */
+ @Test
+ public void testFormatNotAString() throws Exception {
+ StringConverter stringConverter = new StringConverter();
+ assertNull(stringConverter.format(new Object(), 0, null));
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/formatting/AbztractInstallArtifactCommandFormatterTests.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/formatting/AbztractInstallArtifactCommandFormatterTests.java
new file mode 100644
index 00000000..07346a6b
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/formatting/AbztractInstallArtifactCommandFormatterTests.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.formatting;
+
+import static org.eclipse.virgo.kernel.shell.internal.formatting.TestOutputComparator.assertOutputEquals;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+
+import org.eclipse.virgo.kernel.model.management.ManageableArtifact;
+import org.eclipse.virgo.kernel.shell.internal.formatting.AbstractInstallArtifactCommandFormatter;
+
+public class AbztractInstallArtifactCommandFormatterTests {
+
+ private final StubInstallArtifactCommandFormatter formatter = new StubInstallArtifactCommandFormatter();
+
+ @Test
+ public void list() {
+ List<ManageableArtifact> artifacts = new ArrayList<ManageableArtifact>();
+ artifacts.add(new StubManageableCompositeArtifact());
+ List<String> lines = this.formatter.formatList(artifacts);
+ assertOutputEquals(new File("src/test/resources/org/eclipse/virgo/kernel/shell/internal/formatting/abstract-list.txt"), lines);
+ }
+
+ private static class StubInstallArtifactCommandFormatter extends AbstractInstallArtifactCommandFormatter<ManageableArtifact> {
+
+ public List<String> formatExamine(ManageableArtifact artifact) {
+ throw new UnsupportedOperationException();
+ }
+
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/formatting/CompositeInstallArtifactCommandFormatterTests.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/formatting/CompositeInstallArtifactCommandFormatterTests.java
new file mode 100644
index 00000000..4d056cae
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/formatting/CompositeInstallArtifactCommandFormatterTests.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.formatting;
+
+import static org.eclipse.virgo.kernel.shell.internal.formatting.TestOutputComparator.assertOutputEquals;
+
+import java.io.File;
+import java.util.List;
+
+import org.eclipse.virgo.kernel.shell.internal.formatting.CompositeInstallArtifactCommandFormatter;
+import org.junit.Test;
+
+public class CompositeInstallArtifactCommandFormatterTests {
+
+ private final CompositeInstallArtifactCommandFormatter formatter = new CompositeInstallArtifactCommandFormatter();
+
+ @Test
+ public void examine() {
+ List<String> lines = this.formatter.formatExamine(new StubManageableCompositeArtifact());
+ assertOutputEquals(new File("src/test/resources/org/eclipse/virgo/kernel/shell/internal/formatting/composite-examine.txt"), lines);
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/formatting/ConfigInstallArtifactCommandFormatterTests.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/formatting/ConfigInstallArtifactCommandFormatterTests.java
new file mode 100644
index 00000000..871c8dce
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/formatting/ConfigInstallArtifactCommandFormatterTests.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.formatting;
+
+import static org.eclipse.virgo.kernel.shell.internal.formatting.TestOutputComparator.assertOutputEquals;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import javax.management.ObjectName;
+
+import org.junit.Test;
+
+import org.eclipse.virgo.kernel.model.management.ManageableArtifact;
+import org.eclipse.virgo.kernel.shell.internal.formatting.ConfigInstallArtifactCommandFormatter;
+import org.eclipse.virgo.teststubs.osgi.service.cm.StubConfiguration;
+import org.eclipse.virgo.teststubs.osgi.service.cm.StubConfigurationAdmin;
+
+public class ConfigInstallArtifactCommandFormatterTests {
+
+ private final StubConfigurationAdmin configurationAdmin = new StubConfigurationAdmin();
+
+ private final ConfigInstallArtifactCommandFormatter formatter = new ConfigInstallArtifactCommandFormatter(configurationAdmin);
+
+ @Test
+ public void examine() throws IOException {
+ StubConfiguration configuration = this.configurationAdmin.createConfiguration("testPid");
+ configuration.setBundleLocation("/a/location");
+ configuration.addProperty("key1", new Object[] { "value11111111111111111111111111111111111111111111111111111111111111111111111111111111a",
+ "value1b" });
+ configuration.addProperty("key2", "value2");
+
+ List<String> lines = this.formatter.formatExamine(new StubManageableArtifact());
+ assertOutputEquals(new File("src/test/resources/org/eclipse/virgo/kernel/shell/internal/formatting/config-examine.txt"), lines);
+ }
+
+ public class StubManageableArtifact implements ManageableArtifact {
+
+ public ObjectName[] getDependents() {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getName() {
+ return "testPid";
+ }
+
+ public Map<String, String> getProperties() {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getState() {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getType() {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getVersion() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void start() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void stop() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void uninstall() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean refresh() {
+ throw new UnsupportedOperationException();
+ }
+
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/formatting/PropertyFormatterTests.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/formatting/PropertyFormatterTests.java
new file mode 100644
index 00000000..b32f0d78
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/formatting/PropertyFormatterTests.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.formatting;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.List;
+
+import org.eclipse.virgo.kernel.shell.internal.formatting.PropertyFormatter;
+import org.junit.Test;
+
+
+
+/**
+ */
+public class PropertyFormatterTests {
+
+ @Test
+ public void formatSingleEntry() {
+ List<String> formatted = PropertyFormatter.formatPropertyValue("a single entry", 80);
+ assertEquals(1, formatted.size());
+ assertEquals("a single entry", formatted.get(0));
+
+ formatted = PropertyFormatter.formatPropertyValue("a single entry", 8);
+ assertEquals(1, formatted.size());
+ assertEquals("a single entry", formatted.get(0));
+ }
+
+ @Test
+ public void formatArrayEntry() {
+ List<String> formatted = PropertyFormatter.formatPropertyValue(new String[] {"alpha", "bravo", "charlie", "delta", "echo"}, 20);
+ assertEquals(2, formatted.size());
+ assertEquals("alpha, bravo, ", formatted.get(0));
+ assertEquals("charlie, delta, echo", formatted.get(1));
+
+ formatted = PropertyFormatter.formatPropertyValue(new String[] {"alpha", "bravo", "charlie", "delta", "echo"}, 5);
+ assertEquals(5, formatted.size());
+ assertEquals("alpha, ", formatted.get(0));
+ assertEquals("bravo, ", formatted.get(1));
+ assertEquals("charlie, ", formatted.get(2));
+ assertEquals("delta, ", formatted.get(3));
+ assertEquals("echo", formatted.get(4));
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/formatting/ServiceCommandFormatterTests.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/formatting/ServiceCommandFormatterTests.java
new file mode 100644
index 00000000..62111bce
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/formatting/ServiceCommandFormatterTests.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.formatting;
+
+import static org.eclipse.virgo.kernel.shell.internal.formatting.TestOutputComparator.assertOutputEquals;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Version;
+
+
+import org.eclipse.virgo.kernel.shell.internal.formatting.ServiceCommandFormatter;
+import org.eclipse.virgo.kernel.shell.state.QuasiLiveBundle;
+import org.eclipse.virgo.kernel.shell.state.QuasiLiveService;
+import org.eclipse.virgo.kernel.shell.stubs.StubQuasiLiveBundle;
+import org.eclipse.virgo.kernel.shell.stubs.StubQuasiLiveService;
+import org.eclipse.virgo.teststubs.osgi.framework.StubBundle;
+
+/**
+ * Tests for {@link ServiceCommandFormatter}
+ *
+ */
+public class ServiceCommandFormatterTests {
+
+ private final ServiceCommandFormatter serviceCommandFormatter = new ServiceCommandFormatter();
+
+ @Test
+ public void examine() throws Exception {
+ Bundle bundle = new StubBundle(2L, "bundle.symbolic.name", new Version("1.0.1.asdhjgf"), "/some/location");
+ QuasiLiveBundle liveBundle = new StubQuasiLiveBundle(2L, bundle);
+ StubQuasiLiveService service = new StubQuasiLiveService(1, liveBundle);
+
+ String[] obj1 = new String[] { "This is a string array....", "Second string" };
+ service.setProperty("propertyName1", obj1);
+
+ List<String> lines = serviceCommandFormatter.formatExamine(service);
+ assertOutputEquals(new File("src/test/resources/org/eclipse/virgo/kernel/shell/internal/formatting/service-examine.txt"), lines);
+ }
+
+ @Test
+ public void summary() throws Exception {
+ Bundle bundle1 = new StubBundle(2L, "bundle.symbolic.name1", new Version("2.0.1.asdhjgf"), "/some/location");
+ Bundle bundle2 = new StubBundle(4L, "bundle.symbolic.name2", new Version("4.0.1.asdhjgf"), "/some/location");
+ QuasiLiveBundle liveBundle1 = new StubQuasiLiveBundle(2L, bundle1);
+ QuasiLiveBundle liveBundle2 = new StubQuasiLiveBundle(4L, bundle2);
+ StubQuasiLiveService service1 = new StubQuasiLiveService(1, liveBundle1);
+ StubQuasiLiveService service2 = new StubQuasiLiveService(3476, liveBundle2);
+
+ service1.setProperty("objectClass", "object.class.obj.com.com.com.springsource.verylongclassnameinpackage.AgainLongName");
+
+ List<QuasiLiveService> services = new ArrayList<QuasiLiveService>(2);
+ services.add(service1);
+ services.add(service2);
+
+ List<String> lines = serviceCommandFormatter.formatList(services);
+ assertOutputEquals(new File("src/test/resources/org/eclipse/virgo/kernel/shell/internal/formatting/service-list.txt"), lines);
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/formatting/StubManageableCompositeArtifact.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/formatting/StubManageableCompositeArtifact.java
new file mode 100644
index 00000000..fd165b55
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/formatting/StubManageableCompositeArtifact.java
@@ -0,0 +1,182 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.formatting;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.eclipse.virgo.kernel.model.management.ManageableCompositeArtifact;
+
+public class StubManageableCompositeArtifact implements ManageableCompositeArtifact {
+
+ private volatile boolean atomicCalled = false;
+
+ private volatile boolean scopedCalled = false;
+
+ private volatile boolean namedCalled = false;
+
+ private volatile boolean stateCalled = false;
+
+ private volatile boolean typeCalled = false;
+
+ private volatile boolean versionCalled = false;
+
+ private volatile boolean startCalled = false;
+
+ private volatile boolean stopCalled = false;
+
+ private volatile boolean uninstallCalled = false;
+
+ private volatile boolean refreshCalled = false;
+
+ private volatile boolean dependentsCalled = false;
+
+ private volatile boolean propertiesCalled = false;
+
+ private volatile boolean shouldRefreshSucceed = true;
+
+ private volatile String state = "ACTIVE";
+
+ public void setShouldRefreshSucceed(boolean shouldRefreshSucceed) {
+ this.shouldRefreshSucceed = shouldRefreshSucceed;
+ }
+
+ public boolean isAtomic() {
+ this.atomicCalled = true;
+ return false;
+ }
+
+ public boolean isScoped() {
+ this.scopedCalled = true;
+ return false;
+ }
+
+ public ObjectName[] getDependents() {
+ this.dependentsCalled = true;
+
+ Set<ObjectName> objectNames = new HashSet<ObjectName>();
+ try {
+ objectNames.add(new ObjectName("test:artifact-type=test,name=com.springsource.test2,version=0.0.0"));
+ objectNames.add(new ObjectName("test:artifact-type=test,name=com.springsource.test3,version=0.0.0"));
+ } catch (MalformedObjectNameException e) {
+ } catch (NullPointerException e) {
+ }
+
+ return objectNames.toArray(new ObjectName[objectNames.size()]);
+ }
+
+ public String getName() {
+ this.namedCalled = true;
+ return "com.springsource.testName";
+ }
+
+ public Map<String, String> getProperties() {
+ this.propertiesCalled = true;
+
+ Map<String, String> properties = new HashMap<String, String>(2);
+ properties.put("key1", "value1");
+ properties.put("key2", "value2");
+
+ return properties;
+ }
+
+ public String getState() {
+ this.stateCalled = true;
+ return this.state;
+ }
+
+ public StubManageableCompositeArtifact setState(String state) {
+ this.state = state;
+ return this;
+ }
+
+ public String getType() {
+ this.typeCalled = true;
+ return "testType";
+ }
+
+ public String getVersion() {
+ this.versionCalled = true;
+ return "0.0.0";
+ }
+
+ public void start() {
+ this.startCalled = true;
+ }
+
+ public void stop() {
+ this.stopCalled = true;
+ }
+
+ public void uninstall() {
+ this.uninstallCalled = true;
+ }
+
+ public boolean refresh() {
+ this.refreshCalled = true;
+ return this.shouldRefreshSucceed;
+ }
+
+ public boolean getAtomicCalled() {
+ return atomicCalled;
+ }
+
+ public boolean getScopedCalled() {
+ return scopedCalled;
+ }
+
+ public boolean getNamedCalled() {
+ return namedCalled;
+ }
+
+ public boolean getStateCalled() {
+ return stateCalled;
+ }
+
+ public boolean getTypeCalled() {
+ return typeCalled;
+ }
+
+ public boolean getVersionCalled() {
+ return versionCalled;
+ }
+
+ public boolean getStartCalled() {
+ return startCalled;
+ }
+
+ public boolean getStopCalled() {
+ return stopCalled;
+ }
+
+ public boolean getUninstallCalled() {
+ return uninstallCalled;
+ }
+
+ public boolean getRefreshCalled() {
+ return refreshCalled;
+ }
+
+ public boolean getDependentsCalled() {
+ return dependentsCalled;
+ }
+
+ public boolean getPropertiesCalled() {
+ return propertiesCalled;
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/formatting/TestOutputComparator.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/formatting/TestOutputComparator.java
new file mode 100644
index 00000000..1cc14923
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/formatting/TestOutputComparator.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.formatting;
+
+import static org.junit.Assert.fail;
+import static org.junit.Assert.assertEquals;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.virgo.util.io.IOUtils;
+
+public final class TestOutputComparator {
+
+ public static void assertOutputEquals(File expectedFile, List<String> experimental) {
+
+ BufferedReader in = null;
+ Iterator<String> it = experimental.iterator();
+
+ try {
+ in = new BufferedReader(new FileReader(expectedFile));
+ String line;
+ while ((line = in.readLine()) != null) {
+ assertEquals(line, it.next());
+ }
+ } catch (FileNotFoundException e) {
+ fail(e.getMessage());
+ } catch (IOException e) {
+ fail(e.getMessage());
+ } finally {
+ IOUtils.closeQuietly(in);
+ }
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/help/SimpleFileHelpAccessorTests.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/help/SimpleFileHelpAccessorTests.java
new file mode 100644
index 00000000..45989cb8
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/internal/help/SimpleFileHelpAccessorTests.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.internal.help;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.virgo.kernel.shell.internal.help.HelpAccessor;
+import org.eclipse.virgo.kernel.shell.internal.help.SimpleFileHelpAccessor;
+import org.junit.Test;
+
+/**
+ * Tests for {@link SimpleFileHelpAccessor}.
+ * <p />
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ * Thread-safe
+ *
+ */
+public class SimpleFileHelpAccessorTests {
+
+ private final static String HELP_ACCESSOR_TEST_FILE_NAME = "org.eclipse.virgo.kernel.shell.internal.help.SimpleFileHelpAccessorTests.help";
+
+ private final URL HELP_ACCESSOR_TEST_HELP_FILE_URL;
+ {
+ URL url = null;
+ try {
+ url = new File("src/test/resources/helpAccessorTests.help").toURI().toURL();
+ } catch (MalformedURLException mue) {
+ assertTrue("Cannot define URL in test", false);
+ }
+ HELP_ACCESSOR_TEST_HELP_FILE_URL = url;
+ }
+
+ private class AccessorTestClass extends SimpleFileHelpAccessor {
+
+ protected URL helpResourceUrl(Class<?> clazz, String fileResourceName) {
+ assertEquals("File resource name not correctly formed from classname", HELP_ACCESSOR_TEST_FILE_NAME, fileResourceName);
+ return HELP_ACCESSOR_TEST_HELP_FILE_URL;
+ }
+ }
+
+ private class NoHelpAccessorTestClass extends SimpleFileHelpAccessor {
+
+ protected URL helpResourceUrl(Class<?> clazz, String fileResourceName) {
+ return null;
+ }
+ }
+
+ private HelpAccessor haTest = new AccessorTestClass();
+
+ @Test
+ public void readHelpFileSummary() throws Exception {
+ String helpSummary = haTest.getSummaryHelp(SimpleFileHelpAccessorTests.class);
+ assertEquals("First line not read correctly", "First line of help text", helpSummary);
+ }
+
+ @Test
+ public void readHelpFileDetails() throws Exception {
+ List<String> lines = haTest.getDetailedHelp(SimpleFileHelpAccessorTests.class);
+ assertEquals("Detail not read correctly", Arrays.asList("Line 1", " Line 2"), lines);
+ }
+
+ @Test
+ public void summaryWithNoHelpFile() throws Exception {
+ HelpAccessor missingHelp = new NoHelpAccessorTestClass();
+ assertNull(missingHelp.getSummaryHelp(Object.class));
+ }
+
+ @Test
+ public void detailWithNoHelpFile() throws Exception {
+ HelpAccessor missingHelp = new NoHelpAccessorTestClass();
+ assertTrue(missingHelp.getDetailedHelp(Object.class).isEmpty());
+ }
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/model/helper/DummyManagableArtifact.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/model/helper/DummyManagableArtifact.java
new file mode 100644
index 00000000..dd7e7565
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/model/helper/DummyManagableArtifact.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.model.helper;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.management.ObjectName;
+
+import org.eclipse.virgo.kernel.model.management.ManageableArtifact;
+
+/**
+ *
+ */
+public final class DummyManagableArtifact implements ManageableArtifact {
+
+ private final String version;
+
+ private final String type;
+
+ private final String name;
+
+ public DummyManagableArtifact(String type, String name, String version) {
+ this.type = type;
+ this.name = name;
+ this.version = version;
+ }
+
+ public void start() {
+ // do nothing
+ }
+
+ public void stop() {
+ // do nothing
+ }
+
+ public void uninstall() {
+ // do nothing
+ }
+
+ public boolean refresh() {
+ return true;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public ObjectName[] getDependents() {
+ return new ObjectName[0];
+ }
+
+ public Map<String, String> getProperties() {
+ HashMap<String, String> props = new HashMap<String, String>();
+ props.put("user.installed", "true");
+ return props;
+ }
+
+ public String getState() {
+ return "testState";
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/model/helper/StandardArtifactAccessorPointerTests.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/model/helper/StandardArtifactAccessorPointerTests.java
new file mode 100644
index 00000000..8e4f9c3b
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/model/helper/StandardArtifactAccessorPointerTests.java
@@ -0,0 +1,123 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.model.helper;
+
+import static org.junit.Assert.*;
+
+import org.eclipse.virgo.kernel.shell.model.helper.StandardArtifactAccessorPointer;
+import org.junit.Before;
+import org.junit.Test;
+
+
+/**
+ */
+public class StandardArtifactAccessorPointerTests {
+
+ private static final String TYPE = "foo";
+
+ private static final String NAME = "bar";
+
+ private static final String VERSION = "quo";
+
+ private static final String STATE = "moo";
+
+ private StandardArtifactAccessorPointer standardArtifactAccessorPointer;
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @Before
+ public void setUp() throws Exception {
+ this.standardArtifactAccessorPointer = new StandardArtifactAccessorPointer(TYPE, NAME, VERSION, STATE);
+ }
+
+ @Test(expected=IllegalArgumentException.class)
+ public void testConstructorNullType(){
+ new StandardArtifactAccessorPointer(null, NAME, VERSION, STATE);
+ }
+
+ @Test(expected=IllegalArgumentException.class)
+ public void testConstructorNullName(){
+ new StandardArtifactAccessorPointer(TYPE, null, VERSION, STATE);
+ }
+
+ @Test(expected=IllegalArgumentException.class)
+ public void testConstructorNullVersion(){
+ new StandardArtifactAccessorPointer(TYPE, NAME, null, STATE);
+ }
+
+ @Test(expected=IllegalArgumentException.class)
+ public void testConstructorNullState(){
+ new StandardArtifactAccessorPointer(TYPE, NAME, VERSION, null);
+ }
+
+ @Test
+ public void testGetName() {
+ assertEquals(NAME, this.standardArtifactAccessorPointer.getName());
+ }
+
+ @Test
+ public void testGetType() {
+ assertEquals(TYPE, this.standardArtifactAccessorPointer.getType());
+ }
+
+ @Test
+ public void testGetVersion() {
+ assertEquals(VERSION, this.standardArtifactAccessorPointer.getVersion());
+ }
+
+ @Test
+ public void testEqualsFalse() {
+ assertFalse(this.standardArtifactAccessorPointer.equals(new StandardArtifactAccessorPointer("foo", "bar", "123", "state")));
+ }
+
+ @Test
+ public void testEqualsTrue() {
+ assertTrue(this.standardArtifactAccessorPointer.equals(new StandardArtifactAccessorPointer(TYPE, NAME, VERSION, STATE)));
+ }
+
+ @Test
+ public void testEqualsSomthingElse() {
+ assertFalse(this.standardArtifactAccessorPointer.equals(new Object()));
+ }
+
+ @Test
+ public void testEqualsNull() {
+ assertFalse(this.standardArtifactAccessorPointer.equals(null));
+ }
+
+ @Test
+ public void testCompareFalse() {
+ assertTrue(0 != this.standardArtifactAccessorPointer.compareTo(new StandardArtifactAccessorPointer("foo", "bar", "123", "state")));
+ }
+
+ @Test
+ public void testCompareTrue() {
+ assertEquals(0, this.standardArtifactAccessorPointer.compareTo(new StandardArtifactAccessorPointer(TYPE, NAME, VERSION, STATE)));
+ }
+
+ @Test
+ public void testCompareNull() {
+ assertEquals(0, this.standardArtifactAccessorPointer.compareTo(null));
+ }
+
+ @Test
+ public void testHashNoMatch() {
+ assertFalse(this.standardArtifactAccessorPointer.hashCode() == new StandardArtifactAccessorPointer("foo", "bar", "123", "state").hashCode());
+ }
+
+ @Test
+ public void testHashMatch() {
+ assertEquals(this.standardArtifactAccessorPointer.hashCode(), new StandardArtifactAccessorPointer(TYPE, NAME, VERSION, STATE).hashCode());
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/model/helper/StandardArtifactAccessorTests.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/model/helper/StandardArtifactAccessorTests.java
new file mode 100644
index 00000000..fa749109
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/model/helper/StandardArtifactAccessorTests.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.model.helper;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+
+import org.eclipse.virgo.kernel.shell.model.helper.ArtifactAccessorPointer;
+import org.eclipse.virgo.kernel.shell.model.helper.StandardArtifactAccessor;
+import org.junit.Before;
+import org.junit.Test;
+
+
+/**
+ * Tests for {@link StandardArtifactAccessorTests}
+ *
+ */
+public class StandardArtifactAccessorTests {
+
+ private static final String TYPE_ATTRIBUTE = "Type";
+
+ private static final String NAME_ATTRIBUTE = "Name";
+
+ private static final String VERSION_ATTRIBUTE = "Version";
+
+ private static final String STATE_ATTRIBUTE = "State";
+
+ private StandardArtifactAccessor standardArtifactAccessor;
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @Before
+ public void setUp() throws Exception {
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(TYPE_ATTRIBUTE, TYPE_ATTRIBUTE);
+ attributes.put(NAME_ATTRIBUTE, NAME_ATTRIBUTE);
+ attributes.put(VERSION_ATTRIBUTE, VERSION_ATTRIBUTE);
+ attributes.put(STATE_ATTRIBUTE, STATE_ATTRIBUTE);
+ attributes.put("extra", "extra");
+ this.standardArtifactAccessor = new StandardArtifactAccessor(attributes, new HashMap<String, String>(), new HashSet<ArtifactAccessorPointer>());
+ }
+
+ /**
+ * Test method for {@link StandardArtifactAccessor#getType()}.
+ */
+ @Test
+ public void testGetType() {
+ assertEquals(TYPE_ATTRIBUTE, this.standardArtifactAccessor.getType());
+ }
+
+ /**
+ * Test method for {@link StandardArtifactAccessor#getName()}.
+ */
+ @Test
+ public void testGetName() {
+ assertEquals(NAME_ATTRIBUTE, this.standardArtifactAccessor.getName());
+ }
+
+ /**
+ * Test method for {@link StandardArtifactAccessor#getVersion()}.
+ */
+ @Test
+ public void testGetVersion() {
+ assertEquals(VERSION_ATTRIBUTE, this.standardArtifactAccessor.getVersion());
+ }
+
+ /**
+ * Test method for {@link StandardArtifactAccessor#getAttributes()}.
+ */
+ @Test
+ public void testGetAditionalAttributes() {
+ assertNotNull(this.standardArtifactAccessor.getAttributes());
+ assertEquals(2, this.standardArtifactAccessor.getAttributes().size());
+ assertTrue(this.standardArtifactAccessor.getAttributes().containsKey("extra"));
+ assertTrue(this.standardArtifactAccessor.getAttributes().containsKey("State"));
+ }
+
+ /**
+ * Test method for {@link StandardArtifactAccessor#getProperties()}.
+ */
+ @Test
+ public void testGetProperties() {
+ assertNotNull(this.standardArtifactAccessor.getProperties());
+ }
+
+ /**
+ * Test method for {@link StandardArtifactAccessor#getDependents()}.
+ */
+ @Test
+ public void testGetDependents() {
+ assertNotNull(this.standardArtifactAccessor.getDependents());
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/model/helper/StandardRamAccessorHelperTests.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/model/helper/StandardRamAccessorHelperTests.java
new file mode 100644
index 00000000..c9a19a21
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/model/helper/StandardRamAccessorHelperTests.java
@@ -0,0 +1,200 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.model.helper;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.lang.management.ManagementFactory;
+import java.util.List;
+
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.eclipse.virgo.kernel.shell.model.helper.ArtifactAccessor;
+import org.eclipse.virgo.kernel.shell.model.helper.ArtifactAccessorPointer;
+import org.eclipse.virgo.kernel.shell.model.helper.RamAccessorHelper;
+import org.eclipse.virgo.kernel.shell.model.helper.StandardRamAccessorHelper;
+import org.junit.Before;
+import org.junit.Test;
+
+
+/**
+ */
+public class StandardRamAccessorHelperTests {
+
+ private static final String TYPE = "test.type";
+
+ private static final String NAME = "test.name";
+
+ private static final String VERSION = "test.version";
+
+ private static final String TYPE_EXISTS = "test.type.exists";
+
+ private static final String NAME_EXISTS = "test.name.exists";
+
+ private static final String VERSION_EXISTS = "test.version.exists";
+
+ private static final String ARTIFACT_MBEAN_FORMAT = "org.eclipse.virgo.kernel:type=Model,artifact-type=%s,name=%s,version=%s";
+
+ private RamAccessorHelper ramAccessorHelper;
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @Before
+ public void setUp() throws Exception {
+ MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
+ ObjectName objectName = new ObjectName(String.format(ARTIFACT_MBEAN_FORMAT, TYPE_EXISTS, NAME_EXISTS, VERSION_EXISTS));
+ if(!mBeanServer.isRegistered(objectName)) {
+ DummyManagableArtifact dummyManagableArtifact = new DummyManagableArtifact(TYPE_EXISTS, NAME_EXISTS, VERSION_EXISTS);
+ mBeanServer.registerMBean(dummyManagableArtifact, objectName);
+ AttributeList attributeList = new AttributeList();
+ attributeList.add(new Attribute("type", TYPE_EXISTS));
+ attributeList.add(new Attribute("name", NAME_EXISTS));
+ attributeList.add(new Attribute("version", VERSION_EXISTS));
+ mBeanServer.setAttributes(objectName, attributeList);
+ }
+ ramAccessorHelper = new StandardRamAccessorHelper();
+ }
+
+ /**
+ * Test method for {@link RamAccessorHelper#start(String, String, String)}.
+ */
+ @Test
+ public void testStart() {
+ String message = this.ramAccessorHelper.start(TYPE_EXISTS, NAME_EXISTS, VERSION_EXISTS);
+ assertNotNull(message);
+ assertTrue(message.contains("successful"));
+ assertTrue(message.contains("start"));
+ }
+
+ /**
+ * Test method for {@link RamAccessorHelper#stop(String, String, String)}.
+ */
+ @Test
+ public void testStop() {
+ String message = this.ramAccessorHelper.stop(TYPE_EXISTS, NAME_EXISTS, VERSION_EXISTS);
+ assertNotNull(message);
+ assertTrue(message.contains("successful"));
+ assertTrue(message.contains("stop"));
+ }
+
+ /**
+ * Test method for {@link RamAccessorHelper#uninstall(String, String, String)}.
+ */
+ @Test
+ public void testUninstall() {
+ String message = this.ramAccessorHelper.uninstall(TYPE_EXISTS, NAME_EXISTS, VERSION_EXISTS);
+ assertNotNull(message);
+ assertTrue(message.contains("successful"));
+ assertTrue(message.contains("uninstall"));
+ }
+
+ /**
+ * Test method for {@link RamAccessorHelper#refresh(String, String, String)}.
+ */
+ @Test
+ public void testUpdateAndRefresh() {
+ String message = this.ramAccessorHelper.refresh(TYPE_EXISTS, NAME_EXISTS, VERSION_EXISTS);
+ assertNotNull(message);
+ assertTrue(message.contains("successful"));
+ assertTrue(message.contains("refresh"));
+ }
+
+ /**
+ * Test method for {@link RamAccessorHelper#start(String, String, String)}.
+ */
+ @Test
+ public void testStartFail() {
+ String message = this.ramAccessorHelper.start(TYPE, NAME, VERSION);
+ assertNotNull(message);
+ assertTrue(message.contains("error"));
+ assertTrue(message.contains("start"));
+ }
+
+ /**
+ * Test method for {@link RamAccessorHelper#stop(String, String, String)}.
+ */
+ @Test
+ public void testStopFail() {
+ String message = this.ramAccessorHelper.stop(TYPE, NAME, VERSION);
+ assertNotNull(message);
+ assertTrue(message.contains("error"));
+ assertTrue(message.contains("stop"));
+ }
+
+ /**
+ * Test method for {@link RamAccessorHelper#uninstall(String, String, String)}.
+ */
+ @Test
+ public void testUninstallFail() {
+ String message = this.ramAccessorHelper.uninstall(TYPE, NAME, VERSION);
+ assertNotNull(message);
+ assertTrue(message.contains("error"));
+ assertTrue(message.contains("uninstall"));
+ }
+
+ /**
+ * Test method for {@link RamAccessorHelper#refresh(String, String, String)}.
+ */
+ @Test
+ public void testUpdateAndRefreshFail() {
+ String message = this.ramAccessorHelper.refresh(TYPE, NAME, VERSION);
+ assertNotNull(message);
+ assertTrue(message.contains("error"));
+ assertTrue(message.contains("refresh"));
+ }
+
+ @Test
+ public void testGetTypes() {
+ List<String> types = this.ramAccessorHelper.getTypes();
+ assertNotNull(types);
+ assertEquals(1, types.size());
+ assertEquals(TYPE_EXISTS, types.get(0));
+ }
+
+ @Test
+ public void testGetArtifactsOfTypeExists() {
+ List<ArtifactAccessorPointer> artifactsOfType = this.ramAccessorHelper.getArtifactsOfType(TYPE_EXISTS);
+ assertNotNull(artifactsOfType);
+ assertEquals(1, artifactsOfType.size());
+ assertEquals(TYPE_EXISTS, artifactsOfType.get(0).getType());
+ }
+
+ @Test
+ public void testGetArtifactsOfTypeNotExist() {
+ List<ArtifactAccessorPointer> artifactsOfType = this.ramAccessorHelper.getArtifactsOfType(TYPE);
+ assertNotNull(artifactsOfType);
+ assertEquals(0, artifactsOfType.size());
+ }
+
+ @Test
+ public void testGetArtifactExist() {
+ ArtifactAccessor artifact = this.ramAccessorHelper.getArtifact(TYPE_EXISTS, NAME_EXISTS, VERSION_EXISTS);
+ assertNotNull(artifact);
+ assertEquals(TYPE_EXISTS, artifact.getType());
+ assertEquals(NAME_EXISTS, artifact.getName());
+ assertEquals(VERSION_EXISTS, artifact.getVersion());
+ }
+
+ @Test
+ public void testGetArtifactNotExist() {
+ ArtifactAccessor artifact = this.ramAccessorHelper.getArtifact(TYPE, NAME, VERSION);
+ assertNull(artifact);
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/state/internal/StandardQuasiLiveBundleTests.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/state/internal/StandardQuasiLiveBundleTests.java
new file mode 100644
index 00000000..23875a17
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/state/internal/StandardQuasiLiveBundleTests.java
@@ -0,0 +1,185 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.state.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.springframework.context.ApplicationContext;
+
+
+import org.eclipse.virgo.kernel.shell.state.QuasiLiveService;
+import org.eclipse.virgo.kernel.shell.state.internal.StandardQuasiLiveBundle;
+import org.eclipse.virgo.kernel.shell.stubs.StubQuasiFramework;
+import org.eclipse.virgo.kernel.shell.stubs.StubQuasiLiveBundle;
+import org.eclipse.virgo.teststubs.osgi.framework.StubBundle;
+import org.eclipse.virgo.teststubs.osgi.framework.StubBundleContext;
+import org.eclipse.virgo.teststubs.osgi.framework.StubServiceReference;
+import org.eclipse.virgo.teststubs.osgi.framework.StubServiceRegistration;
+
+/**
+ */
+public class StandardQuasiLiveBundleTests {
+
+ private StandardQuasiLiveBundle standardQuasiLiveBundle;
+
+ private StubBundle stubOsgiBundle;
+
+ private StubQuasiLiveBundle stubQuasiBundle;
+
+ private StubQuasiFramework stubQuasiFramework;
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @Before
+ public void setUp() throws Exception {
+ this.stubOsgiBundle = new StubBundle();
+ this.stubQuasiBundle = new StubQuasiLiveBundle(5, stubOsgiBundle);
+ this.stubQuasiFramework = new StubQuasiFramework();
+ this.standardQuasiLiveBundle = new StandardQuasiLiveBundle(stubQuasiFramework, stubQuasiBundle, stubOsgiBundle);
+ }
+
+ /**
+ * Test method for
+ * {@link org.eclipse.virgo.kernel.shell.state.internal.StandardQuasiLiveBundle#getExportedServices()}.
+ */
+ @Test
+ public void testGetExportedServices() {
+ this.registerFakeAppContext();
+ List<QuasiLiveService> exportedServices = this.standardQuasiLiveBundle.getExportedServices();
+ assertNotNull(exportedServices);
+ assertEquals(1, exportedServices.size());
+ }
+
+ /**
+ * Test method for
+ * {@link org.eclipse.virgo.kernel.shell.state.internal.StandardQuasiLiveBundle#getImportedServices()}.
+ */
+ @Test
+ public void testGetImportedServices() {
+ this.registerFakeAppContext();
+ List<QuasiLiveService> importedServices = this.standardQuasiLiveBundle.getImportedServices();
+ assertNotNull(importedServices);
+ assertEquals(0, importedServices.size());
+ }
+
+ /**
+ * Test method for {@link org.eclipse.virgo.kernel.shell.state.internal.StandardQuasiLiveBundle#getState()}.
+ */
+ @Test
+ public void testGetState() {
+ assertEquals("Starting", this.standardQuasiLiveBundle.getState());
+ this.stubOsgiBundle.setState(Bundle.RESOLVED);
+ assertEquals("Resolved", this.standardQuasiLiveBundle.getState());
+ }
+
+ /**
+ * Test method for {@link org.eclipse.virgo.kernel.shell.state.internal.StandardQuasiLiveBundle#getBundle()}.
+ */
+ @Test
+ public void testGetBundle() {
+ assertEquals(this.stubOsgiBundle, this.standardQuasiLiveBundle.getBundle());
+ }
+
+ /**
+ * Test method for {@link org.eclipse.virgo.kernel.shell.state.internal.StandardQuasiLiveBundle#getBundleId()}.
+ */
+ @Test
+ public void testGetBundleId() {
+ assertEquals(this.stubQuasiBundle.getBundleId(), this.standardQuasiLiveBundle.getBundleId());
+ }
+
+ /**
+ * Test method for {@link org.eclipse.virgo.kernel.shell.state.internal.StandardQuasiLiveBundle#getDependents()}.
+ */
+ @Test
+ public void testGetDependents() {
+ assertEquals(this.stubQuasiBundle.getDependents(), this.standardQuasiLiveBundle.getDependents());
+ }
+
+ /**
+ * Test method for {@link org.eclipse.virgo.kernel.shell.state.internal.StandardQuasiLiveBundle#getExportPackages()}.
+ */
+ @Test
+ public void testGetExportPackages() {
+ assertEquals(this.stubQuasiBundle.getExportPackages(), this.standardQuasiLiveBundle.getExportPackages());
+ }
+
+ /**
+ * Test method for {@link org.eclipse.virgo.kernel.shell.state.internal.StandardQuasiLiveBundle#getFragments()}.
+ */
+ @Test
+ public void testGetFragments() {
+ assertEquals(this.stubQuasiBundle.getFragments(), this.standardQuasiLiveBundle.getFragments());
+ }
+
+ /**
+ * Test method for {@link org.eclipse.virgo.kernel.shell.state.internal.StandardQuasiLiveBundle#getHosts()}.
+ */
+ @Test
+ public void testGetHosts() {
+ assertEquals(this.stubQuasiBundle.getHosts(), this.standardQuasiLiveBundle.getHosts());
+ }
+
+ /**
+ * Test method for {@link org.eclipse.virgo.kernel.shell.state.internal.StandardQuasiLiveBundle#getImportPackages()}.
+ */
+ @Test
+ public void testGetImportPackages() {
+ assertEquals(this.stubQuasiBundle.getImportPackages(), this.standardQuasiLiveBundle.getImportPackages());
+ }
+
+ /**
+ * Test method for {@link org.eclipse.virgo.kernel.shell.state.internal.StandardQuasiLiveBundle#getRequiredBundles()}
+ * .
+ */
+ @Test
+ public void testGetRequiredBundles() {
+ assertEquals(this.stubQuasiBundle.getRequiredBundles(), this.standardQuasiLiveBundle.getRequiredBundles());
+ }
+
+ /**
+ * Test method for {@link org.eclipse.virgo.kernel.shell.state.internal.StandardQuasiLiveBundle#getSymbolicName()}.
+ */
+ @Test
+ public void testGetSymbolicName() {
+ assertEquals(this.stubQuasiBundle.getSymbolicName(), this.standardQuasiLiveBundle.getSymbolicName());
+ }
+
+ /**
+ * Test method for {@link org.eclipse.virgo.kernel.shell.state.internal.StandardQuasiLiveBundle#getVersion()}.
+ */
+ @Test
+ public void testGetVersion() {
+ assertEquals(this.stubQuasiBundle.getVersion(), this.standardQuasiLiveBundle.getVersion());
+ }
+
+ /**
+ * Test method for {@link org.eclipse.virgo.kernel.shell.state.internal.StandardQuasiLiveBundle#isResolved()}.
+ */
+ @Test
+ public void testIsResolved() {
+ assertEquals(this.stubQuasiBundle.isResolved(), this.standardQuasiLiveBundle.isResolved());
+ }
+
+ private void registerFakeAppContext() {
+ this.stubOsgiBundle.addRegisteredService(new StubServiceReference(new StubServiceRegistration(new StubBundleContext(),
+ ApplicationContext.class.getName())));
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/state/internal/StandardQuasiLiveServiceTests.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/state/internal/StandardQuasiLiveServiceTests.java
new file mode 100644
index 00000000..5811f9f5
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/state/internal/StandardQuasiLiveServiceTests.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.state.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+
+
+import org.eclipse.virgo.kernel.shell.state.QuasiLiveBundle;
+import org.eclipse.virgo.kernel.shell.state.QuasiLiveService;
+import org.eclipse.virgo.kernel.shell.state.internal.StandardQuasiLiveService;
+import org.eclipse.virgo.kernel.shell.stubs.StubQuasiFramework;
+import org.eclipse.virgo.teststubs.osgi.framework.StubBundle;
+import org.eclipse.virgo.teststubs.osgi.framework.StubBundleContext;
+import org.eclipse.virgo.teststubs.osgi.framework.StubServiceReference;
+import org.eclipse.virgo.teststubs.osgi.framework.StubServiceRegistration;
+
+/**
+ */
+public class StandardQuasiLiveServiceTests {
+
+ private QuasiLiveService standardQuasiLiveService;
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @Before
+ public void setUp() throws Exception {
+ StubServiceRegistration serviceRegistration = new StubServiceRegistration(new StubBundleContext());
+ Dictionary<String, Object> properties = new Hashtable<String, Object>();
+ properties.put(Constants.OBJECTCLASS, new String[] { "one", "two" });
+ properties.put("Random", "foo");
+ serviceRegistration.setProperties(properties);
+ StubServiceReference stubServiceReference = new StubServiceReference(38l, 6, serviceRegistration);
+ stubServiceReference.setBundle(new StubBundle(4l, "Name", new Version("1.2.3"), "Location"));
+ stubServiceReference.addUsingBundles(new StubBundle(), new StubBundle());
+ StubQuasiFramework stubQuasiFramework = new StubQuasiFramework();
+ this.standardQuasiLiveService = new StandardQuasiLiveService(stubQuasiFramework, stubServiceReference);
+ }
+
+ /**
+ * Test method for {@link StandardQuasiLiveService#getServiceId()}.
+ */
+ @Test
+ public void testGetServiceId() {
+ assertEquals(38l, this.standardQuasiLiveService.getServiceId());
+ }
+
+ /**
+ * Test method for {@link StandardQuasiLiveService#getConsumers()}.
+ */
+ @Test
+ public void testGetConsumers() {
+ List<QuasiLiveBundle> result = this.standardQuasiLiveService.getConsumers();
+ assertNotNull(result);
+ assertEquals(2, result.size());
+ }
+
+ /**
+ * Test method for {@link StandardQuasiLiveService#getProvider()}.
+ */
+ @Test
+ public void testGetProvider() {
+ assertEquals(4l, this.standardQuasiLiveService.getProvider().getBundleId());
+ }
+
+ /**
+ * Test method for {@link StandardQuasiLiveService#getProperties()}.
+ */
+ @Test
+ public void testGetProperties() {
+ Map<String, Object> propertyMap = this.standardQuasiLiveService.getProperties();
+ assertNotNull(propertyMap);
+ assertEquals(4, propertyMap.size());
+ assertNotNull(propertyMap.get(Constants.SERVICE_ID));
+ assertEquals("foo", propertyMap.get("Random"));
+ }
+
+ /**
+ * Test method for
+ * {@link StandardQuasiLiveService#compareTo(QuasiLiveService)}
+ * .
+ */
+ @Test
+ public void testCompareTo() {
+ int compareTo = this.standardQuasiLiveService.compareTo(this.standardQuasiLiveService);
+ assertEquals(0, compareTo);
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/state/internal/StandardQuasiPackageTests.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/state/internal/StandardQuasiPackageTests.java
new file mode 100644
index 00000000..5a246d94
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/state/internal/StandardQuasiPackageTests.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.state.internal;
+
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiExportPackage;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiImportPackage;
+import org.eclipse.virgo.kernel.shell.state.internal.StandardQuasiPackage;
+import org.eclipse.virgo.kernel.shell.stubs.StubQuasiExportPackage;
+import org.eclipse.virgo.kernel.shell.stubs.StubQuasiImportPackage;
+
+
+/**
+ */
+public class StandardQuasiPackageTests {
+
+ private final String TEST_PACKAGE_NAME = "test.package";
+
+ private StandardQuasiPackage standardQuasiPackage;
+
+ @Before
+ public void setUp() throws Exception {
+ List<QuasiExportPackage> exports = new ArrayList<QuasiExportPackage>();
+ exports.add(new StubQuasiExportPackage(TEST_PACKAGE_NAME));
+ List<QuasiImportPackage> imports = new ArrayList<QuasiImportPackage>();
+ imports.add(new StubQuasiImportPackage(TEST_PACKAGE_NAME));
+ this.standardQuasiPackage = new StandardQuasiPackage(exports, imports, TEST_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testGetExporters() {
+ assertNotNull(this.standardQuasiPackage.getExporters());
+ assertEquals(1, this.standardQuasiPackage.getExporters().size());
+ }
+
+ @Test
+ public void testGetImporters() {
+ assertNotNull(this.standardQuasiPackage.getImporters());
+ assertEquals(1, this.standardQuasiPackage.getImporters().size());
+ }
+
+ @Test
+ public void testGetPackageName() {
+ assertNotNull(this.standardQuasiPackage.getPackageName());
+ assertEquals(TEST_PACKAGE_NAME, this.standardQuasiPackage.getPackageName());
+ }
+
+ @Test
+ public void testGetExportersNull() {
+ this.standardQuasiPackage = new StandardQuasiPackage(null, new ArrayList<QuasiImportPackage>(), TEST_PACKAGE_NAME);
+ assertNotNull(this.standardQuasiPackage.getExporters());
+ }
+
+ @Test
+ public void testGetImportersNull() {
+ this.standardQuasiPackage = new StandardQuasiPackage(new ArrayList<QuasiExportPackage>(), null, TEST_PACKAGE_NAME);
+ assertNotNull(this.standardQuasiPackage.getImporters());
+ }
+
+ @Test(expected=IllegalArgumentException.class)
+ public void testGetPackageNameNull() {
+ this.standardQuasiPackage = new StandardQuasiPackage(new ArrayList<QuasiExportPackage>(), new ArrayList<QuasiImportPackage>(), null);
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/state/internal/StandardStateServiceTests.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/state/internal/StandardStateServiceTests.java
new file mode 100644
index 00000000..a6096e93
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/state/internal/StandardStateServiceTests.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.state.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.io.File;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiBundle;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiFrameworkFactory;
+import org.eclipse.virgo.kernel.shell.state.QuasiLiveService;
+import org.eclipse.virgo.kernel.shell.state.internal.StandardStateService;
+import org.eclipse.virgo.kernel.shell.stubs.StubQuasiFrameworkFactory;
+
+import org.eclipse.virgo.teststubs.osgi.framework.StubBundleContext;
+
+/**
+ * <p>
+ * Tests for {@link StandardStateService}
+ * </p>
+ *
+ * <strong>Concurrent Semantics</strong><br />
+ *
+ * Tests
+ *
+ */
+public class StandardStateServiceTests {
+
+ private final static File TEST_DUMP_FILE = new File("src/test/resources/fakeDump");
+
+ private StandardStateService standardStateService;
+
+ private StubBundleContext stubBundleContext;
+
+ private QuasiFrameworkFactory stubQuasiFrameworkFactory;
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @Before
+ public void setUp() throws Exception {
+ this.stubBundleContext = new StubBundleContext();
+ this.stubQuasiFrameworkFactory = new StubQuasiFrameworkFactory();
+ this.standardStateService = new StandardStateService(this.stubQuasiFrameworkFactory, this.stubBundleContext);
+ }
+
+ @Test
+ public void getAllBundlesNullDump() {
+ List<QuasiBundle> result = this.standardStateService.getAllBundles(null);
+ assertNotNull(result);
+ assertEquals(1, result.size());
+ }
+
+ @Test
+ public void getAllBundlesFromDump() {
+ List<QuasiBundle> result = this.standardStateService.getAllBundles(TEST_DUMP_FILE);
+ assertNotNull(result);
+ assertEquals(1, result.size());
+ }
+
+ @Test
+ public void getBundleNullDumpExists() {
+ QuasiBundle quasiBundle = this.standardStateService.getBundle(null, 4);
+ assertNotNull(quasiBundle);
+ assertEquals("fake.test.bundle", quasiBundle.getSymbolicName());
+ }
+
+ @Test
+ public void getBundleFromDumpExists() {
+ QuasiBundle quasiBundle = this.standardStateService.getBundle(TEST_DUMP_FILE, 4);
+ assertNotNull(quasiBundle);
+ assertEquals("fake.test.bundle", quasiBundle.getSymbolicName());
+ }
+
+ @Test
+ public void getBundleNullDumpNoExists() {
+ QuasiBundle quasiBundle = this.standardStateService.getBundle(null, 5);
+ assertNull(quasiBundle);
+ }
+
+ @Test
+ public void getBundleFromDumpNoExists() {
+ QuasiBundle quasiBundle = this.standardStateService.getBundle(TEST_DUMP_FILE, 5);
+ assertNull(quasiBundle);
+ }
+
+ @Test
+ public void getAllServices() {
+ List<QuasiLiveService> allServices = this.standardStateService.getAllServices(new File(""));
+ assertNotNull(allServices);
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/stubs/StubQuasiExportPackage.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/stubs/StubQuasiExportPackage.java
new file mode 100644
index 00000000..985ea615
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/stubs/StubQuasiExportPackage.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.stubs;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.osgi.framework.Version;
+
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiBundle;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiExportPackage;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiImportPackage;
+import org.eclipse.virgo.teststubs.osgi.framework.StubBundle;
+
+
+/**
+ */
+public class StubQuasiExportPackage implements QuasiExportPackage {
+
+ private final String packageName;
+
+ public StubQuasiExportPackage(String packageName) {
+ this.packageName = packageName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<QuasiImportPackage> getConsumers() {
+ return new ArrayList<QuasiImportPackage>();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public QuasiBundle getExportingBundle() {
+ return new StubQuasiLiveBundle(5, new StubBundle());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getPackageName() {
+ return this.packageName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Version getVersion() {
+ return Version.emptyVersion;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<String, Object> getAttributes() {
+ return new HashMap<String, Object>();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<String, Object> getDirectives() {
+ return new HashMap<String, Object>();
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/stubs/StubQuasiFramework.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/stubs/StubQuasiFramework.java
new file mode 100644
index 00000000..38420f99
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/stubs/StubQuasiFramework.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.stubs;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Version;
+
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiBundle;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiFramework;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiResolutionFailure;
+import org.eclipse.virgo.teststubs.osgi.framework.StubBundle;
+import org.eclipse.virgo.teststubs.osgi.framework.StubBundleContext;
+import org.eclipse.virgo.teststubs.osgi.framework.StubServiceReference;
+import org.eclipse.virgo.teststubs.osgi.framework.StubServiceRegistration;
+import org.eclipse.virgo.util.osgi.manifest.BundleManifest;
+
+
+/**
+ * <p>
+ * This <code>StubQuasiFramework</code> is a pretend framework containing
+ * one bundle with an id of 4
+ * <p />
+ *
+ */
+public class StubQuasiFramework implements QuasiFramework{
+
+ private final StubBundle stubBundle;
+ private final StubBundleContext stubBundleContext;
+
+ public StubQuasiFramework() {
+ this.stubBundle = new StubBundle(4L, "test.symbolic.name", new Version("0"), "");
+ this.stubBundleContext = new StubBundleContext(stubBundle);
+ this.stubBundleContext.addInstalledBundle(stubBundle);
+ this.stubBundle.addRegisteredService(new StubServiceReference(new StubServiceRegistration(this.stubBundleContext)));
+ }
+
+ public void commit() throws BundleException {
+ }
+
+ public QuasiBundle getBundle(long bundleId) {
+ if(bundleId == 4){
+ return new StubQuasiLiveBundle(bundleId, this.stubBundle);
+ }else{
+ return null;
+ }
+ }
+
+ public List<QuasiBundle> getBundles() {
+ List<QuasiBundle> bundles = new ArrayList<QuasiBundle>();
+
+
+ bundles.add(new StubQuasiLiveBundle(4, this.stubBundle));
+ return bundles;
+ }
+
+ public QuasiBundle install(URI location, BundleManifest bundleManifest) throws BundleException {
+ return new StubQuasiLiveBundle(6, null);
+ }
+
+ public List<QuasiResolutionFailure> resolve() {
+ return new ArrayList<QuasiResolutionFailure>();
+ }
+
+ public List<QuasiResolutionFailure> diagnose(long bundleId) {
+ return new ArrayList<QuasiResolutionFailure>();
+ }
+
+ public QuasiBundle getBundle(String name, Version version) {
+ return null;
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/stubs/StubQuasiFrameworkFactory.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/stubs/StubQuasiFrameworkFactory.java
new file mode 100644
index 00000000..ef3c6b3a
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/stubs/StubQuasiFrameworkFactory.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.stubs;
+
+import java.io.File;
+
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiFramework;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiFrameworkFactory;
+
+/**
+ */
+public class StubQuasiFrameworkFactory implements QuasiFrameworkFactory {
+
+ public QuasiFramework create() {
+ return new StubQuasiFramework();
+ }
+
+ public QuasiFramework create(File arg0) {
+ return new StubQuasiFramework();
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/stubs/StubQuasiImportPackage.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/stubs/StubQuasiImportPackage.java
new file mode 100644
index 00000000..a92d0d28
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/stubs/StubQuasiImportPackage.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.stubs;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiBundle;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiExportPackage;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiImportPackage;
+import org.eclipse.virgo.teststubs.osgi.framework.StubBundle;
+import org.eclipse.virgo.util.osgi.VersionRange;
+
+
+/**
+ */
+public class StubQuasiImportPackage implements QuasiImportPackage {
+
+ private final String packageName;
+
+ public StubQuasiImportPackage(String packageName) {
+ this.packageName = packageName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public QuasiBundle getImportingBundle() {
+ return new StubQuasiLiveBundle(5, new StubBundle());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getPackageName() {
+ return this.packageName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public QuasiExportPackage getProvider() {
+ return new StubQuasiExportPackage(packageName);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public VersionRange getVersionConstraint() {
+ return VersionRange.NATURAL_NUMBER_RANGE;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isResolved() {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<String, Object> getAttributes() {
+ return new HashMap<String, Object>();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<String, Object> getDirectives() {
+ return new HashMap<String, Object>();
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/stubs/StubQuasiLiveBundle.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/stubs/StubQuasiLiveBundle.java
new file mode 100644
index 00000000..cf9e789e
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/stubs/StubQuasiLiveBundle.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.stubs;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Version;
+
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiBundle;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiExportPackage;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiImportPackage;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiRequiredBundle;
+import org.eclipse.virgo.kernel.shell.state.QuasiLiveBundle;
+import org.eclipse.virgo.kernel.shell.state.QuasiLiveService;
+
+public class StubQuasiLiveBundle implements QuasiLiveBundle {
+
+ public static final String TEST_NAME = "fake.test.bundle";
+
+ private final Bundle bundle;
+
+ private final long id;
+
+ public StubQuasiLiveBundle(long id, Bundle bundle) {
+ this.bundle = bundle;
+ this.id = id;
+ }
+
+ public Bundle getBundle() {
+ return this.bundle;
+ }
+
+ public long getBundleId() {
+ return this.id;
+ }
+
+ public List<QuasiBundle> getDependents() {
+ return new ArrayList<QuasiBundle>();
+ }
+
+ public List<QuasiExportPackage> getExportPackages() {
+ return new ArrayList<QuasiExportPackage>();
+ }
+
+ public List<QuasiBundle> getFragments() {
+ return new ArrayList<QuasiBundle>();
+ }
+
+ public List<QuasiBundle> getHosts() {
+ return new ArrayList<QuasiBundle>();
+ }
+
+ public List<QuasiImportPackage> getImportPackages() {
+ return new ArrayList<QuasiImportPackage>();
+ }
+
+ public List<QuasiRequiredBundle> getRequiredBundles() {
+ return new ArrayList<QuasiRequiredBundle>();
+ }
+
+ public String getSymbolicName() {
+ return TEST_NAME;
+ }
+
+ public Version getVersion() {
+ return new Version("1.2.3.test");
+ }
+
+ public boolean isResolved() {
+ return false;
+ }
+
+ public void uninstall() {
+ }
+
+ public List<QuasiLiveService> getExportedServices() {
+ return new ArrayList<QuasiLiveService>();
+ }
+
+ public List<QuasiLiveService> getImportedServices() {
+ return new ArrayList<QuasiLiveService>();
+ }
+
+ public String getState() {
+ return "Not A State";
+ }
+
+ public File getBundleFile() {
+ return null;
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/stubs/StubQuasiLiveService.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/stubs/StubQuasiLiveService.java
new file mode 100644
index 00000000..b527537b
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/stubs/StubQuasiLiveService.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.stubs;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.virgo.kernel.shell.state.QuasiLiveBundle;
+import org.eclipse.virgo.kernel.shell.state.QuasiLiveService;
+
+
+public class StubQuasiLiveService implements QuasiLiveService {
+
+ private Map<String, Object> properties = new HashMap<String,Object>();
+
+ private long serviceId;
+
+ private QuasiLiveBundle provider;
+
+ public StubQuasiLiveService(long serviceId, QuasiLiveBundle provider) {
+ this.serviceId = serviceId;
+ this.provider = provider;
+ }
+
+ public List<QuasiLiveBundle> getConsumers() {
+ return new ArrayList<QuasiLiveBundle>();
+ }
+
+ public boolean setProperty(String name, Object value) {
+ Object oldValue = this.properties.put(name, value);
+ return (oldValue!=null);
+ }
+
+ public QuasiLiveBundle getProvider() {
+ return provider;
+ }
+
+ public long getServiceId() {
+ return this.serviceId;
+ }
+
+ public int compareTo(QuasiLiveService o) {
+ return 0;
+ }
+
+ public Map<String, Object> getProperties() {
+ Map<String, Object> map = new HashMap<String, Object>();
+ map.putAll(this.properties);
+ return map;
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/stubs/StubQuasiPackage.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/stubs/StubQuasiPackage.java
new file mode 100644
index 00000000..b9069665
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/stubs/StubQuasiPackage.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.stubs;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiExportPackage;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiImportPackage;
+import org.eclipse.virgo.kernel.shell.state.QuasiPackage;
+
+
+/**
+ */
+public class StubQuasiPackage implements QuasiPackage {
+
+ private String packageName;
+
+ public StubQuasiPackage(String packageName) {
+ this.packageName = packageName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<QuasiExportPackage> getExporters() {
+ return new ArrayList<QuasiExportPackage>();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<QuasiImportPackage> getImporters() {
+ return new ArrayList<QuasiImportPackage>();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getPackageName() {
+ return this.packageName;
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/stubs/StubStateService.java b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/stubs/StubStateService.java
new file mode 100644
index 00000000..458f44be
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/java/org/eclipse/virgo/kernel/shell/stubs/StubStateService.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware Inc. - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.kernel.shell.stubs;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiBundle;
+import org.eclipse.virgo.kernel.osgi.quasi.QuasiResolutionFailure;
+import org.eclipse.virgo.kernel.shell.state.QuasiLiveService;
+import org.eclipse.virgo.kernel.shell.state.QuasiPackage;
+import org.eclipse.virgo.kernel.shell.state.StateService;
+import org.eclipse.virgo.teststubs.osgi.framework.StubBundle;
+
+public class StubStateService implements StateService {
+
+ public static final long STUB_STATE_BUNDLE_ID = 5;
+ public static final long STUB_STATE_NON_BUNDLE_ID = 6;
+ public static final long STUB_STATE_SERVICE_ID = 55;
+
+ private StubQuasiLiveBundle stubQuasiBundle = new StubQuasiLiveBundle(STUB_STATE_BUNDLE_ID, new StubBundle());
+
+ public List<QuasiBundle> getAllBundles(File source) {
+ return new ArrayList<QuasiBundle>();
+ }
+
+ public List<QuasiLiveService> getAllServices(File source) {
+ return new ArrayList<QuasiLiveService>();
+ }
+
+ public QuasiBundle getBundle(File source, long bundleId) {
+ if (bundleId == stubQuasiBundle.getBundleId()) {
+ return this.stubQuasiBundle;
+ } else {
+ return null;
+ }
+ }
+
+ public List<QuasiResolutionFailure> getResolverReport(File source, long bundleId) {
+ return new ArrayList<QuasiResolutionFailure>();
+ }
+
+ public QuasiLiveService getService(File source, long serviceId) {
+ return new StubQuasiLiveService(STUB_STATE_SERVICE_ID, this.stubQuasiBundle);
+ }
+
+ public QuasiBundle installBundle(File source, String location) {
+ return this.stubQuasiBundle;
+ }
+
+ public QuasiPackage getPackages(File source, String packageName) {
+ return new StubQuasiPackage(packageName);
+ }
+
+ public List<QuasiBundle> search(File source, String term) {
+ ArrayList<QuasiBundle> arrayList = new ArrayList<QuasiBundle>();
+ if (term.contains("*")) {
+ arrayList.add(this.stubQuasiBundle);
+ }
+ return arrayList;
+ }
+
+}
diff --git a/org.eclipse.virgo.kernel.shell/src/test/resources/helpAccessorTests.help b/org.eclipse.virgo.kernel.shell/src/test/resources/helpAccessorTests.help
new file mode 100644
index 00000000..c44fd7e7
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/resources/helpAccessorTests.help
@@ -0,0 +1,7 @@
+# rubbish
+First line of help text
+# more rubbish
+Line 1
+#
+ Line 2
+# \ No newline at end of file
diff --git a/org.eclipse.virgo.kernel.shell/src/test/resources/org/eclipse/virgo/kernel/shell/internal/formatting/abstract-list.txt b/org.eclipse.virgo.kernel.shell/src/test/resources/org/eclipse/virgo/kernel/shell/internal/formatting/abstract-list.txt
new file mode 100644
index 00000000..661a6150
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/resources/org/eclipse/virgo/kernel/shell/internal/formatting/abstract-list.txt
@@ -0,0 +1,2 @@
+Name Version State
+com.springsource.testName 0.0.0 ACTIVE
diff --git a/org.eclipse.virgo.kernel.shell/src/test/resources/org/eclipse/virgo/kernel/shell/internal/formatting/composite-examine.txt b/org.eclipse.virgo.kernel.shell/src/test/resources/org/eclipse/virgo/kernel/shell/internal/formatting/composite-examine.txt
new file mode 100644
index 00000000..fd61e635
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/resources/org/eclipse/virgo/kernel/shell/internal/formatting/composite-examine.txt
@@ -0,0 +1,7 @@
+State: ACTIVE
+Scoped: false
+Atomic: false
+
+Children:
+ test com.springsource.test2 0.0.0
+ test com.springsource.test3 0.0.0
diff --git a/org.eclipse.virgo.kernel.shell/src/test/resources/org/eclipse/virgo/kernel/shell/internal/formatting/config-examine.txt b/org.eclipse.virgo.kernel.shell/src/test/resources/org/eclipse/virgo/kernel/shell/internal/formatting/config-examine.txt
new file mode 100644
index 00000000..49171efe
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/resources/org/eclipse/virgo/kernel/shell/internal/formatting/config-examine.txt
@@ -0,0 +1,13 @@
+Factory pid: testPid
+Bundle Location: /a/location
+
+Properties:
+ key1:
+ value11111111111111111111111111111111111111111111111111111111111111111111111111111111a,
+ value1b
+ key2:
+ value2
+ service.factoryPid:
+ testPid
+ service.pid:
+ testPid
diff --git a/org.eclipse.virgo.kernel.shell/src/test/resources/org/eclipse/virgo/kernel/shell/internal/formatting/service-examine.txt b/org.eclipse.virgo.kernel.shell/src/test/resources/org/eclipse/virgo/kernel/shell/internal/formatting/service-examine.txt
new file mode 100644
index 00000000..66bc6c97
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/resources/org/eclipse/virgo/kernel/shell/internal/formatting/service-examine.txt
@@ -0,0 +1,8 @@
+Properties:
+ propertyName1:
+ This is a string array...., Second string
+
+Publisher: fake.test.bundle 1.2.3.test [2]
+
+Consumer(s):
+ None
diff --git a/org.eclipse.virgo.kernel.shell/src/test/resources/org/eclipse/virgo/kernel/shell/internal/formatting/service-list.txt b/org.eclipse.virgo.kernel.shell/src/test/resources/org/eclipse/virgo/kernel/shell/internal/formatting/service-list.txt
new file mode 100644
index 00000000..54ce0dba
--- /dev/null
+++ b/org.eclipse.virgo.kernel.shell/src/test/resources/org/eclipse/virgo/kernel/shell/internal/formatting/service-list.txt
@@ -0,0 +1,3 @@
+Id Object Class(es) Providing Bundle
+1 o.c.o.c.c.c.s.verylongclassnameinpackage.AgainLongName 2
+3476 <none> 4

Back to the top