Move ServiceMix Kernel trunk into Felix

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@768912 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/karaf/BUILDING.txt b/karaf/BUILDING.txt
new file mode 100644
index 0000000..7a7963e
--- /dev/null
+++ b/karaf/BUILDING.txt
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+Building Apache ServiceMix Kernel
+===================================
+
+Initial Setup
+-------------
+
+1) Install J2SE 5.0 SDK, which can be downloaded from 
+   http://java.sun.com/j2se/1.5.0/download.jsp. Use version of 1.5.0_06 JDK.
+
+2) Make sure that your JAVA_HOME environment variable is set to the newly installed 
+   JDK location, and that your PATH includes %JAVA_HOME%\bin (windows) or 
+   $JAVA_HOME$/bin (unix).
+
+3) Install Maven 2.0.7, which can be downloaded from 
+   http://maven.apache.org/download.html. Make sure that your PATH includes 
+   the MVN_HOME/bin directory. 
+
+
+Building
+--------
+
+1) Change to the top level directory of Apache ServiceMix Kernel source distribution.
+2) Run
+         $> mvn
+   This will compile Apache ServiceMix Kernel and run all of the tests in the 
+   Apache ServiceMix Kernel source distribution. Alternatively, you can run
+         $> mvn -Pfastinstall
+   This will compile Apache ServiceMix Kernel without running the tests and takes less
+   time to build.
+   Depending on the load of remote Maven 2.0 repositories, you may have 
+   to run "mvn" several times until the required dependencies are 
+   all located in your local maven repository. It usually takes some time for 
+   maven to download required dependencies in the first build.
+3) The distributions will be available under "assembly/target" directory.
+
diff --git a/karaf/LICENSE.txt b/karaf/LICENSE.txt
new file mode 100644
index 0000000..6b0b127
--- /dev/null
+++ b/karaf/LICENSE.txt
@@ -0,0 +1,203 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.
+
diff --git a/karaf/NOTICE.txt b/karaf/NOTICE.txt
new file mode 100644
index 0000000..15b77cc
--- /dev/null
+++ b/karaf/NOTICE.txt
@@ -0,0 +1,9 @@
+   =========================================================================

+   ==  NOTICE file for use with the Apache License, Version 2.0,          ==

+   ==  in this case for the Apache ServiceMix distribution.               ==

+   =========================================================================

+

+   This product contains software developed by

+   The Apache Software Foundation (http://www.apache.org/).

+

+

diff --git a/karaf/README.txt b/karaf/README.txt
new file mode 100644
index 0000000..07740ef
--- /dev/null
+++ b/karaf/README.txt
@@ -0,0 +1,76 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one or more

+ * contributor license agreements.  See the NOTICE file distributed with

+ * this work for additional information regarding copyright ownership.

+ * The ASF licenses this file to You under the Apache License, Version 2.0

+ * (the "License"); you may not use this file except in compliance with

+ * the License.  You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+Welcome to Apache ServiceMix Kernel 

+====================================

+Apache ServiceMix Kernel is a small OSGi based kernel which provides a 

+lightweight container onto which various bundles can be deployed.

+

+The following features are included:

+    * Hot deployment: ServiceMix Kernel supports hot deployment of OSGi bundles by monitoring

+      jar files inside the [home]/deploy directory. Each time a jar is copied in this folder,

+      it will be installed inside the runtime. You can then update or delete it and changes will

+      be handled automatically. In addition, the Kernel also supports exploded bundles and custom

+      deployers (a spring one is included by default).

+    * Dynamic configuration: Services are usually configured through the ConfigurationAdmin OSGi

+      service. Such configuration can be defined in ServiceMix Kernel using property files inside

+      the [home]/etc directory. These configurations are monitored and changes on the properties

+      files will be propagated to the services.

+    * Logging System: using a centralized logging back end supported by Log4J, ServiceMix Kernel

+      supports a number of different APIs (JDK 1.4, JCL, SLF4J, Avalon, Tomcat, OSGi)

+    * Provisioning: Provisioning of libraries or applications can be done through a number of

+      different ways, by which they will be downloaded locally, installed and started.

+    * Native OS integration: ServiceMix Kernel can be integrated into your own Operating System as

+      a service so that the lifecycle will be bound to your Operating System.

+    * Extensible Shell console: ServiceMix features a nice text console where you can manage the

+      services, install new applications or libraries and manage their state. This shell is easily

+      extensible by deploying new commands dynamically along with new features or applications.

+    * Remote access: use any SSH client to connect to the kernel and issue commands in the console

+    * Security framework based on JAAS

+    * Managing instances: ServiceMix Kernel provides simple commands for managing instances of

+      ServiceMix Kernel. You can easily create, delete, start and stop instances of ServiceMix

+      Kernel through the console.

+

+Getting Started

+===============

+For an Apache ServiceMix Kernel source distribution, please read 

+BUILDING.txt for instructions on building Apache ServiceMix Kernel. 

+

+For an Apache ServiceMix Kernel binary distribution, please read 

+RELEASE-NOTES.txt for installation instructions and list of supported 

+and unsupported features.

+

+Alternatively, you can also find out how to get started here:

+    http://servicemix.apache.org/kernel/

+

+If you need more help try talking to us on our mailing lists

+    http://servicemix.apache.org/mailing-lists.html

+

+If you find any issues with ServiceMix Kernel, please submit reports 

+with JIRA here:

+    http://issues.apache.org/activemq/browse/SMX4KNL

+

+We welcome contributions, and encourage you to get involved in the 

+ServiceMix community. If you'd like to learn more about how you can 

+contribute, please see:

+    http://servicemix.apache.org/contributing.html

+

+Many thanks for using Apache ServiceMix.

+

+

+The ServiceMix Team

+http://servicemix.apache.org/team.html

diff --git a/karaf/RELEASE-NOTES.txt b/karaf/RELEASE-NOTES.txt
new file mode 100644
index 0000000..41fc751
--- /dev/null
+++ b/karaf/RELEASE-NOTES.txt
@@ -0,0 +1,373 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one or more

+ * contributor license agreements.  See the NOTICE file distributed with

+ * this work for additional information regarding copyright ownership.

+ * The ASF licenses this file to You under the Apache License, Version 2.0

+ * (the "License"); you may not use this file except in compliance with

+ * the License.  You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+

+                    Apache ServiceMix Kernel 1.1.0

+                    ==============================

+

+  Overview

+  --------

+

+ The Apache ServiceMix Kernel 1.1.0 release brings a lot of new features enhancements and bug fixes:

+  * remote connection using SSH protocol

+  * provisioning enhancements: versioning / hot deployment of features

+  * new commands, including OSGi related commands for the Configuration Admin and Package Admin services

+  * improved spring integration: upgrade to spring 2.5.6 and spring-dm 1.2.0-m2, the osgi/list command

+       now displays spring applications status

+  * container level locking for master / slave deployments

+  * support for JAXP 1.4 on all platforms

+  * improved JMX support for managing the OSGi framework and features

+ Note that the commands syntax has changed due to the upgrade to the latest gshell version.

+

+  Known issues

+  ============

+

+     * [SMX4KNL-141] - The config/edit command changes does not takes precedence over configuration files in the etc folder at restart

+     * [SMX4KNL-183] - features/uninstall behaves different in version selection than features/install

+     * [SMX4KNL-189] - Shell completion works only in the root shell

+     * [SMX4KNL-200] - The client jar / ssh daemon should support direct commands

+     * [SMX4KNL-227] - Full support of fragment bundles

+     * [SMX4KNL-228] - Warning messages when using OpenSSH 5.1 to connect to ServiceMix Kernel

+     * [SMX4KNL-231] - Unable to log into ServiceMix Kernel using OpenSolaris SSH client

+     * [SMX4KNL-232] - Unable to log into ServiceMix Kernel using Windows putty SSH client

+

+  Changelog

+  ---------

+

+  The following list shows the bug fixes and enhancements included in this release:

+

+ ** Bug

+     * [SMX4KNL-72] - If there is no etc/startup.properties, the kernel hangs without displaying any error

+     * [SMX4KNL-79] - When starting the kernel, a log entry states "Can not install feature ''"

+     * [SMX4KNL-86] - When running integration tests, the container classpath contains all the test bundles which may cause problems

+     * [SMX4KNL-87] - Problems with batch files on windows

+     * [SMX4KNL-95] - kernel build failed in testing/itests

+     * [SMX4KNL-96] - package missing for felix.config.properties

+     * [SMX4KNL-97] - Dissociate the name and the location of ServiceMix Kernel instances managed by the admin shell

+     * [SMX4KNL-100] - The client does not close when running "osgi shutdown" command

+     * [SMX4KNL-102] - The file monitor should use ${servicemix.base} for default polling locations

+     * [SMX4KNL-104] - When using a remote connection, errors are not reported correctly

+     * [SMX4KNL-105] - Features are reinstalled on restart of servicemix

+     * [SMX4KNL-112] - gshell pom needs to include gshell-config and gshell-packages modules

+     * [SMX4KNL-115] - config.properties for SMX-Kernel needs to be updated

+     * [SMX4KNL-117] - The Smx testing platform should take into account the boot delegation packages specified in the configuration file

+     * [SMX4KNL-118] - The configuration file for felix comes from 3 different places in the svn tree, only one copy should be used

+     * [SMX4KNL-122] - When using the client and trying to connect to another instance using the "admin connect" command, the console hangs

+     * [SMX4KNL-123] - XML parsing does not work on non Sun JVMs and Sun's SAAJ bundle requires Sun's JAXP implementation

+     * [SMX4KNL-124] - Issuing command "log d" fails with NullPointerException on AIX.

+     * [SMX4KNL-126] - The user is no more authenticated with the new gshell integration

+     * [SMX4KNL-128] - Remove OBR support from default distribution

+     * [SMX4KNL-132] - osgi/list command should display the spring application state

+     * [SMX4KNL-133] - jaxp-ri bundle miss javax.xml.datatype.DatatypeFactory factoryId under META-INF/services

+     * [SMX4KNL-134] - XPathFactoryFinder in jaxp api should use factoryId to load the spi class in osgi enviroment

+     * [SMX4KNL-135] - Remote shell missing help resources

+     * [SMX4KNL-138] - No command history with GShell console

+     * [SMX4KNL-140] - GShell commands references not cleaned up when bundle uninstalled

+     * [SMX4KNL-142] - Starting a new instance that was created with admin on windows fails to start

+     * [SMX4KNL-145] - java.lang.IllegalStateException: Streams not registered for thread

+     * [SMX4KNL-148] - OPS4J maven repo missing form default search list

+     * [SMX4KNL-149] - Build failure due to new sshd snapshot

+     * [SMX4KNL-150] - GShell group name variable doesn't resolve

+     * [SMX4KNL-151] - Update displayed version in GShell to be 1.1.0-SNAPSHOT for trunk

+     * [SMX4KNL-153] - Stopping one of the "core" bundles of the servicemix engine block the server

+     * [SMX4KNL-155] - Error changing manifest while bundle is deployed

+     * [SMX4KNL-162] - The default jaas realm uses the config admin to store clear password

+     * [SMX4KNL-164] - features/removeUrl does not remove the repository

+     * [SMX4KNL-165] - Initial provisioning using features is very slow especially when using snapshots

+     * [SMX4KNL-170] - Unknown protocol: org.apache.servicemix.kernel.gshell

+     * [SMX4KNL-172] - the new command optional/cat from gshell can't support mvn/http protocol

+     * [SMX4KNL-174] - NoClassDefFoundError jline/ConsoleReader when invoking servicemix-client

+     * [SMX4KNL-176] - 'features/install xxx' tries to install version 0.0.0 instead of the latest one

+     * [SMX4KNL-177] - Some of the Optional commands have moved to different packages in the latest snapshot of geronimo gshell

+     * [SMX4KNL-178] - Remove debug log statements when booting

+     * [SMX4KNL-180] - features/install xxx barfs when using non osgi compliant versions

+     * [SMX4KNL-181] - osgi/install -s throws a NPE if the bundle can not be resolved

+     * [SMX4KNL-182] - Upon restart, the list of previously  installed features is not available anymore

+     * [SMX4KNL-185] - Features JMX view does not reload persistent state on restart

+     * [SMX4KNL-187] - Features JMX view making too much log noise

+     * [SMX4KNL-188] - Gshell itests fail on windows

+     * [SMX4KNL-190] - Deployment / Startup of spring xml configurations doesn't work correctly

+     * [SMX4KNL-192] - ServiceMix Kernel startup blocks

+     * [SMX4KNL-198] - The console / server / client arguments to servicemix shell script are broken

+     * [SMX4KNL-199] - Missing resource bundle for obr shell

+     * [SMX4KNL-201] - The client jar does not exit when running with --help argument

+     * [SMX4KNL-202] - Startup of a pending to deploy Spring config file fails when all required bundles got installed

+     * [SMX4KNL-204] - OsgiConfiguration.unregister() throw NPE when exit smx

+     * [SMX4KNL-205] - "ld | grep WARN" does not filter while "log/display | grep WARN" does

+     * [SMX4KNL-207] - features/install should install latest feature version for any dependency that does not explicitly specify a dependency

+     * [SMX4KNL-208] - Bundle#loadClass sometimes return null instead of throwing a CNFE

+     * [SMX4KNL-212] - Exceptions are displayed in the console when trying to load default xml catalogs

+     * [SMX4KNL-215] - Don't attempt to stop fragments in filemonitor

+     * [SMX4KNL-218] - Can't find bundle for base name org.apache.servicemix.kernel.gshell.wrapper.InstallCommand, locale fr_BE

+     * [SMX4KNL-220] - The org.apache.servicemix.kernel.management bundle should not use DynamicImport-Package=*

+

+ ** Improvement

+     * [SMX4KNL-36] - Investigate having a different bootstrap mechanism for a remote client to not start all the bundles installed (maybe by not using osgi)

+     * [SMX4KNL-62] - Enhance admin shell create command to allocate unique ports to new instances.

+     * [SMX4KNL-74] - When using the spring deployer, allow the customization of the OSGi manifest entries

+     * [SMX4KNL-78] - Small refactoring of the Feature interface

+     * [SMX4KNL-85] - Extend GShell#waitForFrameworkToStart to wait 60 seconds instead of 5 seconds.

+     * [SMX4KNL-101] - Reduce the amount of logging issued by mina

+     * [SMX4KNL-106] - Support for container level lock to support master/slave deployments

+     * [SMX4KNL-114] - prompt should print username@instance-name when using remote shell

+     * [SMX4KNL-119] - Use boot delegation instead of listing sun packages for jaxp / url handlers

+     * [SMX4KNL-120] - The ServiceMix Kernel testing platform should use the servicemix kernel main jar instead of the felix one

+     * [SMX4KNL-121] - Improve the Main class to easily embed the whole ServiceMix Kernel distribution in another web application

+     * [SMX4KNL-125] - Show command environment in kernel shell

+     * [SMX4KNL-127] - Add the update command in the osgi shell

+     * [SMX4KNL-130] - Support configurable lock directory for container level locking (for master/slave deployments).

+     * [SMX4KNL-136] - Upgrade to pax logging 1.2.0

+     * [SMX4KNL-154] - some Action moved from to another package cause kernel start up failed

+     * [SMX4KNL-158] - Move jline into its own bundle instead of using a private package in gshell-core

+     * [SMX4KNL-169] - Use the start level to implement the container level locking

+     * [SMX4KNL-184] - Align the commands name with the gshell ones

+     * [SMX4KNL-186] - features/uninstall should select the right version if only one version has been installed

+     * [SMX4KNL-191] - Upgrade to pax-logging 1.3.0

+     * [SMX4KNL-203] - When installing a feature, the service should first install all bundles, then start them all in order

+     * [SMX4KNL-206] - Felix version in servicemix-kernel-1.1.0-snapshot doesn't seem to support fragment bundles.

+     * [SMX4KNL-216] - Display fragments informations in the osgi list command

+     * [SMX4KNL-230] - Log statements using java.util.logging are logged into both stderr and data/log/servicemix.log file

+

+ ** New Feature

+     * [SMX4KNL-28] - Create a config command to administer the ConfigAdmin service

+     * [SMX4KNL-33] - Enhance admin shell to provide commands to start / stop / list / connect to known ServiceMix instances

+     * [SMX4KNL-60] - Versionning of features

+     * [SMX4KNL-76] - support to install/uninstall different version of features

+     * [SMX4KNL-90] - Create new commands to leverage the PackageAdmin OSGi service

+     * [SMX4KNL-94] - Provide a JMX frontend on top of the features service

+     * [SMX4KNL-107] - Create a new "admin connect" command to easily connect to a named instance of servicemix

+     * [SMX4KNL-108] - Add a new 'log de' command that displays the last exception from the log

+     * [SMX4KNL-109] - Include the pax wrapper url handler in the kernel for ease of use of non osgi third party dependencies

+     * [SMX4KNL-111] - Add a "starting" state to the admin list command

+     * [SMX4KNL-113] - Upgrade to Felix 1.2.1

+     * [SMX4KNL-116] - Allow repository descriptors to reference other repository descriptors

+     * [SMX4KNL-131] - Include JAXP 1.4 API

+     * [SMX4KNL-143] - Provide a way to make BouncyCastle work in ServiceMix Kernel

+     * [SMX4KNL-144] - Use SSH as a remoting protocol to connect to a servicemix kernel

+     * [SMX4KNL-147] - Upgrade to spring-DM 1.2.0-m2

+     * [SMX4KNL-152] - The version number displayed in the console should be extract from resources (using maven filtering + properties file) but the branding should be easy to change so that people embedding the Kernel can define their own

+     * [SMX4KNL-156] - Move core management feature to the kernel

+     * [SMX4KNL-157] - Add a JAAS realm for authenticating users from SSH and JMX

+     * [SMX4KNL-163] - Provide default jdbc lock impl for master/slave deployments

+     * [SMX4KNL-167] - Upgrade to spring 2.5.6

+     * [SMX4KNL-171] - Include RFC0139 (JMX management of OSGi)

+     * [SMX4KNL-179] - Upgrade to felix 1.5.0-SNAPSHOT

+     * [SMX4KNL-214] - Hot deployment of features through the deploy folder

+

+ ** Task

+     * [SMX4KNL-43] - Upgrade to latest gshell

+     * [SMX4KNL-93] - Extract the admin commands in their own module

+     * [SMX4KNL-98] - Use dependency management section for all dependencies

+     * [SMX4KNL-99] - Remove ant from the kernel distribution and replace its use in the filemonitor

+     * [SMX4KNL-129] - Make sure aliases and links commands work with the new gshell integration

+     * [SMX4KNL-166] - Move the embedded smx demo into trunk

+     * [SMX4KNL-168] - Downgrade to junit 3.8

+     * [SMX4KNL-196] - gshell-core source jar should use the shade plugin to include the gshell sources

+     * [SMX4KNL-197] - The client source jar should include the slf4j sources using the shade plugin

+     * [SMX4KNL-211] - Remove one of jmock or easymock from the kernel

+

+

+

+

+                    Apache ServiceMix Kernel 1.0.0

+                    ==============================

+

+  Overview

+  --------

+

+ This release is the first GA release of ServiceMix Kernel.  A few bugs and enhancements have been done 

+ to the Kernel since the second release candidate. The most two important fixes from a user point of view

+ are SMX4KNL-70 which makes sure the bundles provided in the distribution are used first instead of the ones

+ from the user's local maven repository and SMx4KNL-77 which allows artifacts in the /deploy folder to be 

+ started when the needed dependencies have been installed successfully (the previous behavior was to fail

+ if there were missing bundles when the artifact is processed).

+ See the change log below for more informations.

+

+  Changelog

+  ---------

+

+  The following list shows the bug fixes and enhancements included in this release:

+

+ ** Bug

+     * [SMX4KNL-70] - Bundles in /system folder should take precedence over local Maven repository

+     * [SMX4KNL-79] - When starting the kernel, a log entry states "Can not install feature ''"

+     * [SMX4KNL-80] - "features list" output has a "version" column but no infos

+     * [SMX4KNL-81] - The wrapper feature can not be installed out of the box

+     * [SMX4KNL-82] - The installation state of a feature is not displayed correctly after a restart when using the "features list" command

+     * [SMX4KNL-83] - When using the wrapper command, ServiceMix Kernel does not start correctly

+

+ ** Improvement

+     * [SMX4KNL-69] - Add installation status for the 'features list' result.

+     * [SMX4KNL-71] - Export the gshell CommandExecutor in the OSGi registry

+     * [SMX4KNL-73] - Require work around for blocking in.read() call in ProxyIO for automated testing.

+     * [SMX4KNL-75] - Modify GShell argument processing to execute multiple commands.

+     * [SMX4KNL-77] - The deployer should keep a list of installed bundles that failed to start and retry those when new bundles have been resolved

+     * [SMX4KNL-78] - Small refactoring of the Feature interface

+

+

+

+                  Apache ServiceMix Kernel 1.0.0-rc2

+                  ==================================

+

+Overview

+--------

+

+This second Release Candidate of Apache ServiceMix Kernel includes a few bug fixes and a few new features.

+The main change is that the system folder that contains the OSGi bundles to install in the runtime is now

+organized as a maven 2 repository, though it should not directly affect users.  A more detailed changelog

+is following. 

+    

+Changelog

+---------

+    

+The following list shows the bug fixes and enhancements included in this release:

+

+** Bug

+    * [SMX4KNL-34] - snapshot jar name mismatch in startup.properties and in the system folder

+    * [SMX4KNL-52] - Deployment of pain spring files does not work when using xml extensions because these are not available in the classpath

+    * [SMX4KNL-53] - During starting, files are redeployed several times, one each time a new Deployer is registered in OSGi

+    * [SMX4KNL-54] - Kernel does not start if system property "felix.cache.profiledir" is not defined

+    * [SMX4KNL-56] - Kernel does not start on Windows if classpath contains spaces

+    * [SMX4KNL-58] - Hot-deploy capability of FileMonitor does not update bundles properly on Windows.

+    * [SMX4KNL-63] - Possible deadlock at startup caused by the filedeployer not running in its own thread the first time

+    * [SMX4KNL-64] - The list of repositories for the features shell is not persisted across restart

+    * [SMX4KNL-65] - After copying or moving the kernel, it does not start in a very clean way anymore

+    * [SMX4KNL-68] - failed to start smx4

+

+** Improvement

+    * [SMX4KNL-51] - Add a configuration file for the maven url handler so that adding default repositories is easy enough

+    * [SMX4KNL-55] - Use maven shade plugin on the main module so that sources jar is correct

+    * [SMX4KNL-66] - When the file monitor loads configuration for the config admin, allow the use of system properties using ${xxx}

+

+** New Feature

+    * [SMX4KNL-61] - Organize the system folder as a maven 2 repository

+    * [SMX4KNL-67] - Allow the features service to obtain a list of features to install at startup

+

+** Task

+    * [SMX4KNL-57] - Extract bundles from the svn tree

+    * [SMX4KNL-59] - Upgrade to spring 2.5.5 / spring-dm 1.1.0

+

+

+

+                  Apache ServiceMix Kernel 1.0-rc1

+                  ================================

+

+This first Release Candidate of Apache ServiceMix Kernel includes a security framework based on

+JAAS allowing authentication using JAAS realms deployed at runtime and also allow keystores and

+trustores to be deployed and accessed through OSGi.  This allow the remote console to be secured

+correctly (if the console is activated in a production environment, we strongly recommand to 

+deploy a custom JAAS realm and new keystores when using the SSL connection).  A few bugs have been

+fixed too.

+

+A release candidate (RC) is a distribution that has not been proven completely stable, but the 

+feature set is the one that will be available in the final release.   The number of RCs has not 

+been fixed and it will depend on the feedback we obtain from this release, so please give it a try

+and report any problems you can find.

+

+** Bug

+    * [SMX4KNL-38] - Fix NullPointerException instead of Command not found in the console

+    * [SMX4KNL-40] - Remote console does not display output

+    * [SMX4KNL-41] - When using the remote command on the client from the command line, the process does not exit correctly

+    * [SMX4KNL-44] - Changed bundles restarted twice

+    * [SMX4KNL-45] - The "log display" command does not display anything when running from an instance that has been created using the "admin create" command

+    * [SMX4KNL-46] - After using the 'admin create' command, cpu goes to 100% until another command is entered

+    * [SMX4KNL-48] - ulimit error on MacOS X Leopard 10.5

+    * [SMX4KNL-50] - Kernel does not start on Windows

+

+** Improvement

+    * [SMX4KNL-39] - Make bundle locations for SMX configurable

+    * [SMX4KNL-49] - Upgrade to Spring 2.5.4, Spring-DM 1.1.0-m2, PaxLogging 1.1.1

+

+** New Feature

+    * [SMX4KNL-35] - Secure the connection between the client and the kernel in some way

+    * [SMX4KNL-37] - JAAS support

+

+

+                  Apache ServiceMix Kernel 1.0-m3

+                  ================================

+

+This third milestone of Apache ServiceMix Kernel brings a lot of new features:

+  * a provisioning system to install applications easily

+  * a log shell to visualize the logging output and change log levels

+  * pipe support on commands

+  * a bunch of new commands: history, grep, cat, ava, exec, sleep

+

+Note that this milestone does not include the latest spring version because 

+the latest ones have wrong OSGi manifest headers and do not work.

+

+** Bug

+    * [SMX4KNL-22] - The console can not be reloaded at runtime

+    * [SMX4KNL-29] - Shell commands are not unregistered automatically when the last command is unregistered

+    * [SMX4KNL-31] - Aliases do not work when inside a subshell

+

+** Improvement

+    * [SMX4KNL-5] - Show gshell sub-shell name in prompt

+    * [SMX4KNL-6] - Error Message improvement on Gshell console.

+    * [SMX4KNL-10] - Handle dependant features correctly

+    * [SMX4KNL-21] - Allow pipes in command syntax

+    * [SMX4KNL-25] - Feature commands enhancement.

+    * [SMX4KNL-32] - Lazy load feature repositories to avoid delay when the url can not be accessed or things like that

+

+** New Feature

+    * [SMX4KNL-1] - Implements a log command

+    * [SMX4KNL-11] - Provisioning system

+    * [SMX4KNL-20] - Adding a new OBR command to reload the repository url's

+    * [SMX4KNL-23] - Add a grep command

+    * [SMX4KNL-24] - Add a few utils commands: cat, java, exec, sleep

+    * [SMX4KNL-26] - Spring URL handler to wrap xml spring files into bundles for direct installation.

+    * [SMX4KNL-27] - Include an implementation of the Preferences service

+    * [SMX4KNL-30] - Create an history command to be able to browse previous commands easily

+

+

+                  Apache ServiceMix Kernel 1.0-m2

+                  ================================

+

+This is the second milestone of ServiceMix Kernel, but mostly a bug fix release

+compared to the first milestone.

+

+** Bug

+    * [SMX4KNL-13] - startup issue in recognizing new files in deploy folder

+    * [SMX4KNL-15] - Display of memory size using the info command on Windows is ugly

+    * [SMX4KNL-16] - Bad error message when startup.properties lists a unknown file (the file name is not displayed, but 'null' instead)

+    * [SMX4KNL-18] - No need for DynamicImport-Package=* in filemonitor

+    * [SMX4KNL-19] - Performance problems when using the OSGi classloaders in a certain way

+

+** Improvement

+    * [SMX4KNL-4] - Add a start option on the 'osgi install' command so that the bundle is automatically started

+

+** Task

+    * [SMX4KNL-17] - Remove all the warnings when building the distribution tar.gz

+

+See the README.txt file for more general informations about ServiceMix Kernel.

+

+

+                  Apache ServiceMix Kernel 1.0-m1

+                  ================================

+

+See the README.txt file for more general informations about ServiceMix Kernel.

+

+This is the first milestone of ServiceMix Kernel.  All the features are not 

+fully implemented yet and things may be changed until the final 1.0 release.

+Please refer to the web site for more informations and feel free to ask any

+questions on the ServiceMix mailing lists or simply to provide feedback 

+(we appreciate it very much).

+

+Thanks you for downloading ServiceMix Kernel.  Enjoy !

+

+The ServiceMix Team

+http://servicemix.apache.org/team.html

+

diff --git a/karaf/assembly/pom.xml b/karaf/assembly/pom.xml
new file mode 100644
index 0000000..936d36a
--- /dev/null
+++ b/karaf/assembly/pom.xml
@@ -0,0 +1,409 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <!--
+
+        Licensed to the Apache Software Foundation (ASF) under one or more
+        contributor license agreements.  See the NOTICE file distributed with
+        this work for additional information regarding copyright ownership.
+        The ASF licenses this file to You under the Apache License, Version 2.0
+        (the "License"); you may not use this file except in compliance with
+        the License.  You may obtain a copy of the License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software
+        distributed under the License is distributed on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        See the License for the specific language governing permissions and
+        limitations under the License.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.servicemix.kernel</groupId>
+        <artifactId>kernel</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.servicemix.kernel</groupId>
+    <artifactId>apache-servicemix-kernel</artifactId>
+    <packaging>pom</packaging>
+    <version>1.2.0-SNAPSHOT</version>
+    <name>Apache ServiceMix Kernel :: Assembly</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel</groupId>
+            <artifactId>org.apache.servicemix.kernel.main</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel</groupId>
+            <artifactId>org.apache.servicemix.kernel.client</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel</groupId>
+            <artifactId>org.apache.servicemix.kernel.filemonitor</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel</groupId>
+            <artifactId>org.apache.servicemix.kernel.spring</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel.gshell</groupId>
+            <artifactId>org.apache.servicemix.kernel.gshell.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel.gshell</groupId>
+            <artifactId>org.apache.servicemix.kernel.gshell.admin</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel.gshell</groupId>
+            <artifactId>org.apache.servicemix.kernel.gshell.obr</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel.gshell</groupId>
+            <artifactId>org.apache.servicemix.kernel.gshell.osgi</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel.gshell</groupId>
+            <artifactId>org.apache.servicemix.kernel.gshell.log</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel.gshell</groupId>
+            <artifactId>org.apache.servicemix.kernel.gshell.features</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel.gshell</groupId>
+            <artifactId>org.apache.servicemix.kernel.gshell.config</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel.gshell</groupId>
+            <artifactId>org.apache.servicemix.kernel.gshell.packages</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel.jaas</groupId>
+            <artifactId>org.apache.servicemix.kernel.jaas.boot</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel.jaas</groupId>
+            <artifactId>org.apache.servicemix.kernel.jaas.config</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel.jaas</groupId>
+            <artifactId>org.apache.servicemix.kernel.jaas.modules</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel</groupId>
+            <artifactId>org.apache.servicemix.kernel.management</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.osgi</groupId>
+            <artifactId>spring-osgi-extender</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.osgi</groupId>
+            <artifactId>spring-osgi-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.osgi</groupId>
+            <artifactId>spring-osgi-io</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-beans</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-aop</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.bundlerepository</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.specs</groupId>
+            <artifactId>org.apache.servicemix.specs.jaxp-api-1.4</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.jaxp-ri</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.mina</groupId>
+            <artifactId>mina-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.aopalliance</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.cglib</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.commons-jexl</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.commons-vfs</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.oro</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.commons-codec</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.commons-httpclient</artifactId>
+        </dependency>
+        <dependency>
+	    <groupId>org.apache.servicemix.bundles</groupId>
+	    <artifactId>org.apache.servicemix.bundles.jline</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.configadmin</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.prefs</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.logging</groupId>
+            <artifactId>pax-logging-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.logging</groupId>
+            <artifactId>pax-logging-service</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.url</groupId>
+            <artifactId>pax-url-mvn</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.url</groupId>
+            <artifactId>pax-url-wrap</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.geronimo.specs</groupId>
+            <artifactId>geronimo-servlet_2.5_spec</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.geronimo.specs</groupId>
+            <artifactId>geronimo-annotation_1.0_spec</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sshd</groupId>
+            <artifactId>sshd-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>jmx</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.oracle.osgi</groupId>
+            <artifactId>jmx-impl</artifactId>
+        </dependency>
+    </dependencies>
+    <build>
+        <resources>
+            <resource>
+                <directory>${pom.basedir}/src/main/filtered-resources</directory>
+                <filtering>true</filtering>
+                <includes>
+                    <include>**/*</include>
+                </includes>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-resources-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>filter</id>
+                        <phase>generate-resources</phase>
+                        <goals>
+                            <goal>resources</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>copy</id>
+                        <phase>generate-resources</phase>
+                        <goals>
+                            <goal>copy</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>org.apache.servicemix.kernel</groupId>
+                                    <artifactId>org.apache.servicemix.kernel.main</artifactId>
+                                    <outputDirectory>target/dependencies</outputDirectory>
+                                    <destFileName>servicemix.jar</destFileName>
+                                </artifactItem>
+                                <artifactItem>
+                                    <groupId>org.apache.servicemix.kernel</groupId>
+                                    <artifactId>org.apache.servicemix.kernel.client</artifactId>
+                                    <outputDirectory>target/dependencies</outputDirectory>
+                                    <destFileName>servicemix-client.jar</destFileName>
+                                </artifactItem>
+                                <artifactItem>
+                                    <groupId>org.apache.servicemix.kernel.jaas</groupId>
+                                    <artifactId>org.apache.servicemix.kernel.jaas.boot</artifactId>
+                                    <outputDirectory>target/dependencies</outputDirectory>
+                                    <destFileName>servicemix-jaas-boot.jar</destFileName>
+                                </artifactItem>
+                            </artifactItems>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>attach-artifacts</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>attach-artifact</goal>
+                        </goals>
+                        <configuration>
+                            <artifacts>
+                                <artifact>
+                                    <file>target/classes/features.xml</file>
+                                    <type>xml</type>
+                                    <classifier>features</classifier>
+                                </artifact>
+                            </artifacts>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>unix-bin</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                        <configuration>
+                            <descriptors>
+                                <descriptor>src/main/descriptors/unix-bin.xml</descriptor>
+                            </descriptors>
+                            <finalName>${pom.artifactId}-${pom.version}</finalName>
+                            <tarLongFileMode>gnu</tarLongFileMode>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>windows-bin</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                        <configuration>
+                            <descriptors>
+                                <descriptor>src/main/descriptors/windows-bin.xml</descriptor>
+                            </descriptors>
+                            <finalName>${pom.artifactId}-${pom.version}</finalName>
+                            <appendAssemblyId>true</appendAssemblyId>
+                            <assemblyId/>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>unix-src</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                        <configuration>
+                            <descriptors>
+                                <descriptor>src/main/descriptors/unix-src.xml</descriptor>
+                            </descriptors>
+                            <tarLongFileMode>gnu</tarLongFileMode>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>windows-src</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                        <configuration>
+                            <descriptors>
+                                <descriptor>src/main/descriptors/windows-src.xml</descriptor>
+                            </descriptors>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <profiles>
+        <profile>
+            <id>assembly-src</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-assembly-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>unix-src</id>
+                                <phase>package</phase>
+                                <goals>
+                                    <goal>attached</goal>
+                                </goals>
+                                <configuration>
+                                    <descriptors>
+                                        <descriptor>src/main/descriptors/unix-src.xml</descriptor>
+                                    </descriptors>
+                                </configuration>
+                            </execution>
+                            <execution>
+                                <id>windows-src</id>
+                                <phase>package</phase>
+                                <goals>
+                                    <goal>attached</goal>
+                                </goals>
+                                <configuration>
+                                    <descriptors>
+                                        <descriptor>src/main/descriptors/windows-src.xml</descriptor>
+                                    </descriptors>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+</project>
diff --git a/karaf/assembly/src/main/descriptors/unix-bin.xml b/karaf/assembly/src/main/descriptors/unix-bin.xml
new file mode 100644
index 0000000..3dd8246
--- /dev/null
+++ b/karaf/assembly/src/main/descriptors/unix-bin.xml
@@ -0,0 +1,290 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+   
+    http://www.apache.org/licenses/LICENSE-2.0
+   
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<assembly>
+    <id></id> <!-- intentionally left blank -> http://jira.codehaus.org/browse/MASSEMBLY-301 -->
+    <formats>
+        <format>tar.gz</format>
+    </formats>
+    <fileSets>
+
+        <!-- Copy license and other files from root -->
+        <fileSet>
+            <directory>..</directory>
+            <outputDirectory>/</outputDirectory>
+            <includes>
+                <include>README.txt</include>
+                <include>RELEASE*.txt</include>
+            </includes>
+            <lineEnding>unix</lineEnding>
+        </fileSet>
+
+        <!-- Copy over everything that needs to get unix line endings -->
+        <fileSet>
+            <directory>src/main/distribution/text</directory>
+            <outputDirectory>/</outputDirectory>
+            <lineEnding>unix</lineEnding>
+        </fileSet>        
+        <fileSet>
+            <directory>src/main/distribution/unix-text</directory>
+            <outputDirectory>/</outputDirectory>
+            <lineEnding>unix</lineEnding>
+        </fileSet>        
+        <fileSet>
+            <directory>target/classes/etc</directory>
+            <outputDirectory>/etc/</outputDirectory>
+            <lineEnding>unix</lineEnding>
+        </fileSet>
+
+        <!-- Copy over the examples -->
+        <fileSet>
+            <directory>../demos</directory>
+            <outputDirectory>/demos/</outputDirectory>
+            <lineEnding>unix</lineEnding>
+            <excludes>
+                <exclude>**/target/**</exclude>
+            </excludes>
+        </fileSet>
+
+        <!-- Copy over files that should not get the line endings converted -->
+        <fileSet>
+            <directory>src/main/distribution/binary</directory>
+            <outputDirectory>/</outputDirectory>
+        </fileSet>
+
+        <!-- Copy over the files that should not get the line endings converted but need to be chmod to 755 -->
+        <fileSet>
+            <directory>src/main/distribution/unix-binary</directory>
+            <outputDirectory>/</outputDirectory>
+            <fileMode>0755</fileMode>
+        </fileSet>
+        
+        <!-- Copy over the files that need unix line endings and also chmod to 755 -->
+        <fileSet>
+            <directory>src/main/distribution/unix-shell</directory>
+            <outputDirectory>/</outputDirectory>
+            <lineEnding>unix</lineEnding>
+            <fileMode>0755</fileMode>
+        </fileSet>
+
+        <!-- Copy over jar files -->
+        <fileSet>
+            <directory>target/dependencies</directory>
+            <outputDirectory>/lib/</outputDirectory>
+        </fileSet>
+
+    </fileSets>
+
+    <files>
+        <file>
+            <source>${basedir}/../etc/config.properties</source>          
+            <outputDirectory>/etc/</outputDirectory>
+            <destName>config.properties</destName>
+            <fileMode>0644</fileMode>
+            <lineEnding>unix</lineEnding>
+        </file>
+        <file>
+            <source>${basedir}/target/maven-shared-archive-resources/META-INF/LICENSE</source>
+            <outputDirectory>/</outputDirectory>
+            <destName>LICENSE.txt</destName>
+            <fileMode>0644</fileMode>
+            <lineEnding>unix</lineEnding>
+        </file>
+        <file>
+            <source>${basedir}/target/maven-shared-archive-resources/META-INF/NOTICE</source>
+            <outputDirectory>/</outputDirectory>
+            <destName>NOTICE.txt</destName>
+            <fileMode>0644</fileMode>
+            <lineEnding>unix</lineEnding>
+        </file>
+        <file>
+            <source>${basedir}/target/classes/features.xml</source>
+            <outputDirectory>/system/org/apache/servicemix/kernel/apache-servicemix-kernel/${version}</outputDirectory>
+            <destName>apache-servicemix-kernel-${version}-features.xml</destName>
+            <fileMode>0644</fileMode>
+            <lineEnding>unix</lineEnding>
+        </file>
+    </files>
+
+    <dependencySets>
+
+        <dependencySet>
+            <outputDirectory>/system</outputDirectory>
+            <unpack>false</unpack>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputFileNameMapping>org/apache/felix/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+            <includes>
+                <include>org.apache.felix:org.osgi.compendium</include>
+                <include>org.apache.felix:org.apache.felix.configadmin</include>
+                <include>org.apache.felix:org.apache.felix.prefs</include>
+            </includes>
+        </dependencySet>
+        <dependencySet>
+            <outputDirectory>/system</outputDirectory>
+            <unpack>false</unpack>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputFileNameMapping>org/ops4j/pax/logging/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+            <includes>
+                <include>org.ops4j.pax.logging:pax-logging-api</include>
+                <include>org.ops4j.pax.logging:pax-logging-service</include>
+            </includes>
+        </dependencySet>
+        <dependencySet>
+            <outputDirectory>/system</outputDirectory>
+            <unpack>false</unpack>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputFileNameMapping>org/ops4j/pax/url/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+            <includes>
+                <include>org.ops4j.pax.url:pax-url-mvn</include>
+                <include>org.ops4j.pax.url:pax-url-wrap</include>
+            </includes>
+        </dependencySet>
+        <dependencySet>
+            <outputDirectory>/system</outputDirectory>
+            <unpack>false</unpack>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputFileNameMapping>org/springframework/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+            <includes>
+                <include>org.springframework:spring-aop</include>
+                <include>org.springframework:spring-beans</include>
+                <include>org.springframework:spring-context</include>
+                <include>org.springframework:spring-core</include>
+            </includes>
+        </dependencySet>
+        <dependencySet>
+            <outputDirectory>/system</outputDirectory>
+            <unpack>false</unpack>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputFileNameMapping>org/springframework/osgi/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+            <includes>
+                <include>org.springframework.osgi:spring-osgi-core</include>
+                <include>org.springframework.osgi:spring-osgi-extender</include>
+                <include>org.springframework.osgi:spring-osgi-io</include>
+            </includes>
+        </dependencySet>
+        <dependencySet>
+            <outputDirectory>/system</outputDirectory>
+            <unpack>false</unpack>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputFileNameMapping>org/apache/geronimo/specs/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+            <includes>
+                <include>org.apache.geronimo.specs:geronimo-servlet_2.5_spec</include>
+                <include>org.apache.geronimo.specs:geronimo-annotation_1.0_spec</include>
+            </includes>
+        </dependencySet>
+        <dependencySet>
+            <outputDirectory>/system</outputDirectory>
+            <unpack>false</unpack>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputFileNameMapping>org/apache/servicemix/bundles/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+            <includes>
+                <include>org.apache.servicemix.bundles:org.apache.servicemix.bundles.aopalliance</include>
+                <include>org.apache.servicemix.bundles:org.apache.servicemix.bundles.cglib</include>
+                <include>org.apache.servicemix.bundles:org.apache.servicemix.bundles.jaxp-ri</include>
+                <include>org.apache.servicemix.bundles:org.apache.servicemix.bundles.oro</include>
+                <include>org.apache.servicemix.bundles:org.apache.servicemix.bundles.commons-jexl</include>
+                <include>org.apache.servicemix.bundles:org.apache.servicemix.bundles.commons-vfs</include>
+                <include>org.apache.servicemix.bundles:org.apache.servicemix.bundles.commons-codec</include>
+                <include>org.apache.servicemix.bundles:org.apache.servicemix.bundles.commons-httpclient</include>
+                <include>org.apache.servicemix.bundles:org.apache.servicemix.bundles.jline</include>
+            </includes>
+        </dependencySet>
+        <dependencySet>
+            <outputDirectory>/system</outputDirectory>
+            <unpack>false</unpack>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputFileNameMapping>org/apache/servicemix/specs/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+            <includes>
+                <include>org.apache.servicemix.specs:org.apache.servicemix.specs.jaxp-api-1.4</include>
+            </includes>
+        </dependencySet>
+        <dependencySet>
+            <outputDirectory>/system</outputDirectory>
+            <unpack>false</unpack>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputFileNameMapping>org/apache/servicemix/kernel/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+            <includes>
+                <include>org.apache.servicemix.kernel:org.apache.servicemix.kernel.filemonitor</include>
+                <include>org.apache.servicemix.kernel:org.apache.servicemix.kernel.spring</include>
+                <include>org.apache.servicemix.kernel:org.apache.servicemix.kernel.management</include>
+            </includes>
+        </dependencySet>
+        <dependencySet>
+            <outputDirectory>/system</outputDirectory>
+            <unpack>false</unpack>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputFileNameMapping>org/apache/servicemix/kernel/gshell/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+            <includes>
+                <include>org.apache.servicemix.kernel.gshell:org.apache.servicemix.kernel.gshell.core</include>
+                <include>org.apache.servicemix.kernel.gshell:org.apache.servicemix.kernel.gshell.admin</include>
+                <include>org.apache.servicemix.kernel.gshell:org.apache.servicemix.kernel.gshell.osgi</include>
+                <include>org.apache.servicemix.kernel.gshell:org.apache.servicemix.kernel.gshell.log</include>
+                <include>org.apache.servicemix.kernel.gshell:org.apache.servicemix.kernel.gshell.features</include>
+                <include>org.apache.servicemix.kernel.gshell:org.apache.servicemix.kernel.gshell.config</include>
+                <include>org.apache.servicemix.kernel.gshell:org.apache.servicemix.kernel.gshell.packages</include>
+            </includes>
+        </dependencySet>
+        <dependencySet>
+            <outputDirectory>/system</outputDirectory>
+            <unpack>false</unpack>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputFileNameMapping>org/apache/servicemix/kernel/jaas/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+            <includes>
+                <include>org.apache.servicemix.kernel.jaas:org.apache.servicemix.kernel.jaas.config</include>
+                <include>org.apache.servicemix.kernel.jaas:org.apache.servicemix.kernel.jaas.modules</include>
+            </includes>
+        </dependencySet>
+        <dependencySet>
+            <outputDirectory>/system</outputDirectory>
+            <unpack>false</unpack>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputFileNameMapping>org/apache/sshd/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+            <includes>
+                <include>org.apache.sshd:sshd-core</include>
+            </includes>
+        </dependencySet>
+        <dependencySet>
+            <outputDirectory>/system</outputDirectory>
+            <unpack>false</unpack>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputFileNameMapping>org/apache/mina/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+            <includes>
+                <include>org.apache.mina:mina-core</include>
+            </includes>
+        </dependencySet>
+        <dependencySet>
+            <outputDirectory>/system</outputDirectory>
+            <unpack>false</unpack>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputFileNameMapping>org/osgi/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+            <includes>
+                <include>org.osgi:jmx</include>
+            </includes>
+        </dependencySet>
+        <dependencySet>
+            <outputDirectory>/system</outputDirectory>
+            <unpack>false</unpack>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputFileNameMapping>com/oracle/osgi/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+            <includes>
+                <include>com.oracle.osgi:jmx-impl</include>
+            </includes>
+        </dependencySet>
+
+    </dependencySets>
+
+</assembly>
diff --git a/karaf/assembly/src/main/descriptors/unix-src.xml b/karaf/assembly/src/main/descriptors/unix-src.xml
new file mode 100644
index 0000000..9227d56
--- /dev/null
+++ b/karaf/assembly/src/main/descriptors/unix-src.xml
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<assembly>
+    <id>src</id>
+    <formats>
+        <format>tar.gz</format>
+    </formats>
+    <fileSets>
+        <!-- Copy license and other files from root -->
+        <fileSet>
+            <directory>${basedir}/..</directory>
+            <outputDirectory>/</outputDirectory>
+            <includes>
+                <include>BUILDING.txt</include>
+                <include>README.txt</include>
+                <include>RELEASE*.txt</include>
+            </includes>
+            <lineEnding>unix</lineEnding>
+        </fileSet>
+
+        <!-- Binary Files -->
+        <fileSet>
+            <directory>${basedir}/..</directory>
+            <outputDirectory>src</outputDirectory>
+            <includes>
+                <include>**/*.jpeg</include>
+                <include>**/*.jpg</include>
+                <include>**/*.gif</include>
+                <include>**/*.png</include>
+                <include>**/*.exe</include>
+                <include>**/*.dll</include>
+                <include>**/*.jar</include>
+                <include>**/*.so</include>
+                <include>**/*.ks</include>
+                <include>**/*.ts</include>
+                <include>**/*.keystore</include>
+                <include>**/*.bin</include>
+                <include>**/*.jnilib</include>
+                <include>**/*.cert</include>
+                <include>apache-servicemix/src/main/release/bin/*/wrapper</include>
+            </includes>
+            <excludes>
+                <exclude>**/eclipse-classes/**</exclude>
+                <exclude>**/target/**</exclude>
+            </excludes>
+        </fileSet>
+
+        <!-- Text Files -->
+        <fileSet>
+            <directory>${basedir}/..</directory>
+            <outputDirectory>src</outputDirectory>
+            <includes>
+                <include>**/*</include>
+            </includes>
+            <excludes>
+                <exclude>**/*.jpeg</exclude>
+                <exclude>**/*.jpg</exclude>
+                <exclude>**/*.gif</exclude>
+                <exclude>**/*.png</exclude>
+                <exclude>**/*.exe</exclude>
+                <exclude>**/*.dll</exclude>
+                <exclude>**/*.jar</exclude>
+                <exclude>**/*.so</exclude>
+                <exclude>**/*.ks</exclude>
+                <exclude>**/*.ts</exclude>
+                <exclude>**/*.keystore</exclude>
+                <exclude>**/*.bin</exclude>
+                <exclude>**/*.jnilib</exclude>
+                <exclude>**/*.cert</exclude>
+                <exclude>apache-servicemix/src/main/release/bin/*/wrapper</exclude>
+                <exclude>**/target/**</exclude>
+                <exclude>**/build/**</exclude>
+                <exclude>activemq-data/**</exclude>
+                <exclude>*/activemq-data/**</exclude>
+                <exclude>**/eclipse-classes/**</exclude>
+                <exclude>**/.*</exclude>
+                <exclude>**/.*/**</exclude>
+
+                <exclude>**/surefire*</exclude>
+                <exclude>**/svn-commit*</exclude>
+
+                <exclude>**/*.iml</exclude>
+                <exclude>**/*.ipr</exclude>
+                <exclude>**/*.iws</exclude>
+
+                <exclude>**/cobertura.ser</exclude>
+
+            </excludes>
+            <lineEnding>unix</lineEnding>
+        </fileSet>
+    </fileSets>
+    <files>
+        <file>
+            <source>${basedir}/target/maven-shared-archive-resources/META-INF/LICENSE</source>
+            <outputDirectory>/</outputDirectory>
+            <destName>LICENSE.txt</destName>
+            <fileMode>0644</fileMode>
+            <lineEnding>unix</lineEnding>
+        </file>
+        <file>
+            <source>${basedir}/target/maven-shared-archive-resources/META-INF/NOTICE</source>
+            <outputDirectory>/</outputDirectory>
+            <destName>NOTICE.txt</destName>
+            <fileMode>0644</fileMode>
+            <lineEnding>unix</lineEnding>
+        </file>
+    </files>
+</assembly>
diff --git a/karaf/assembly/src/main/descriptors/windows-bin.xml b/karaf/assembly/src/main/descriptors/windows-bin.xml
new file mode 100644
index 0000000..0901795
--- /dev/null
+++ b/karaf/assembly/src/main/descriptors/windows-bin.xml
@@ -0,0 +1,282 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<assembly>
+    <id></id> <!-- intentionally left blank -> http://jira.codehaus.org/browse/MASSEMBLY-301 -->
+    <formats>
+        <format>zip</format>
+    </formats>
+    <fileSets>
+
+
+      <!-- Copy license and other files from root -->
+      <fileSet>
+          <directory>..</directory>
+          <outputDirectory>/</outputDirectory>
+          <includes>
+              <include>README.txt</include>
+              <include>RELEASE*.txt</include>
+          </includes>
+          <lineEnding>dos</lineEnding>
+      </fileSet>
+
+      <!-- Copy over everything that needs to get dos line endings -->
+      <fileSet>
+          <directory>src/main/distribution/text</directory>
+          <outputDirectory>/</outputDirectory>
+          <lineEnding>dos</lineEnding>
+      </fileSet>        
+      <fileSet>
+          <directory>src/main/distribution/windows-text</directory>
+          <outputDirectory>/</outputDirectory>
+          <lineEnding>dos</lineEnding>
+      </fileSet>        
+      <fileSet>
+          <directory>target/classes/etc</directory>
+          <outputDirectory>/etc/</outputDirectory>
+          <lineEnding>dos</lineEnding>
+      </fileSet>
+
+        <!-- Copy over the examples -->
+        <fileSet>
+            <directory>../demos</directory>
+            <outputDirectory>/demos/</outputDirectory>
+            <lineEnding>dos</lineEnding>
+            <excludes>
+                <exclude>**/target/**</exclude>
+            </excludes>
+        </fileSet>
+
+      <!-- Copy over files that should not get the line endings converted -->
+      <fileSet>
+          <directory>src/main/distribution/binary</directory>
+          <outputDirectory>/</outputDirectory>
+      </fileSet>
+
+      <!-- Copy over the files that should not get the line endings converted but need to be chmod to 755 -->
+      <fileSet>
+          <directory>src/main/distribution/windows-binary</directory>
+          <outputDirectory>/</outputDirectory>
+      </fileSet>
+      
+      <!-- Copy over jar files -->
+      <fileSet>
+          <directory>target/dependencies</directory>
+          <outputDirectory>/lib/</outputDirectory>
+      </fileSet>
+
+    </fileSets>
+
+    <files>
+        <file>
+            <source>${basedir}/../etc/config.properties</source>          
+            <outputDirectory>/etc/</outputDirectory>
+            <destName>config.properties</destName>
+            <fileMode>0644</fileMode>
+            <lineEnding>dos</lineEnding>
+        </file>
+        <file>
+            <source>${basedir}/target/maven-shared-archive-resources/META-INF/LICENSE</source>
+            <outputDirectory>/</outputDirectory>
+            <destName>LICENSE.txt</destName>
+            <fileMode>0644</fileMode>
+            <lineEnding>dos</lineEnding>
+        </file>
+        <file>
+            <source>${basedir}/target/maven-shared-archive-resources/META-INF/NOTICE</source>
+            <outputDirectory>/</outputDirectory>
+            <destName>NOTICE.txt</destName>
+            <fileMode>0644</fileMode>
+            <lineEnding>dos</lineEnding>
+        </file>
+        <file>
+            <source>${basedir}/target/classes/features.xml</source>
+            <outputDirectory>/system/org/apache/servicemix/kernel/apache-servicemix-kernel/${version}</outputDirectory>
+            <destName>apache-servicemix-kernel-${version}-features.xml</destName>
+            <fileMode>0644</fileMode>
+            <lineEnding>dos</lineEnding>
+        </file>
+    </files>
+
+    <dependencySets>
+
+        <dependencySet>
+            <outputDirectory>/system</outputDirectory>
+            <unpack>false</unpack>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputFileNameMapping>org/apache/felix/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+            <includes>
+                <include>org.apache.felix:org.osgi.compendium</include>
+                <include>org.apache.felix:org.apache.felix.configadmin</include>
+                <include>org.apache.felix:org.apache.felix.prefs</include>
+            </includes>
+        </dependencySet>
+        <dependencySet>
+            <outputDirectory>/system</outputDirectory>
+            <unpack>false</unpack>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputFileNameMapping>org/ops4j/pax/logging/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+            <includes>
+                <include>org.ops4j.pax.logging:pax-logging-api</include>
+                <include>org.ops4j.pax.logging:pax-logging-service</include>
+            </includes>
+        </dependencySet>
+        <dependencySet>
+            <outputDirectory>/system</outputDirectory>
+            <unpack>false</unpack>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputFileNameMapping>org/ops4j/pax/url/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+            <includes>
+                <include>org.ops4j.pax.url:pax-url-mvn</include>
+                <include>org.ops4j.pax.url:pax-url-wrap</include>
+            </includes>
+        </dependencySet>
+        <dependencySet>
+            <outputDirectory>/system</outputDirectory>
+            <unpack>false</unpack>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputFileNameMapping>org/springframework/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+            <includes>
+                <include>org.springframework:spring-aop</include>
+                <include>org.springframework:spring-beans</include>
+                <include>org.springframework:spring-context</include>
+                <include>org.springframework:spring-core</include>
+            </includes>
+        </dependencySet>
+        <dependencySet>
+            <outputDirectory>/system</outputDirectory>
+            <unpack>false</unpack>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputFileNameMapping>org/springframework/osgi/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+            <includes>
+                <include>org.springframework.osgi:spring-osgi-core</include>
+                <include>org.springframework.osgi:spring-osgi-extender</include>
+                <include>org.springframework.osgi:spring-osgi-io</include>
+            </includes>
+        </dependencySet>
+        <dependencySet>
+            <outputDirectory>/system</outputDirectory>
+            <unpack>false</unpack>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputFileNameMapping>org/apache/geronimo/specs/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+            <includes>
+                <include>org.apache.geronimo.specs:geronimo-servlet_2.5_spec</include>
+                <include>org.apache.geronimo.specs:geronimo-annotation_1.0_spec</include>
+            </includes>
+        </dependencySet>
+        <dependencySet>
+            <outputDirectory>/system</outputDirectory>
+            <unpack>false</unpack>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputFileNameMapping>org/apache/servicemix/bundles/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+            <includes>
+                <include>org.apache.servicemix.bundles:org.apache.servicemix.bundles.aopalliance</include>
+                <include>org.apache.servicemix.bundles:org.apache.servicemix.bundles.cglib</include>
+                <include>org.apache.servicemix.bundles:org.apache.servicemix.bundles.jaxp-ri</include>
+                <include>org.apache.servicemix.bundles:org.apache.servicemix.bundles.oro</include>
+                <include>org.apache.servicemix.bundles:org.apache.servicemix.bundles.commons-jexl</include>
+                <include>org.apache.servicemix.bundles:org.apache.servicemix.bundles.commons-vfs</include>
+                <include>org.apache.servicemix.bundles:org.apache.servicemix.bundles.commons-codec</include>
+                <include>org.apache.servicemix.bundles:org.apache.servicemix.bundles.commons-httpclient</include>
+                <include>org.apache.servicemix.bundles:org.apache.servicemix.bundles.jline</include>
+            </includes>
+        </dependencySet>
+        <dependencySet>
+            <outputDirectory>/system</outputDirectory>
+            <unpack>false</unpack>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputFileNameMapping>org/apache/servicemix/specs/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+            <includes>
+                <include>org.apache.servicemix.specs:org.apache.servicemix.specs.jaxp-api-1.4</include>
+            </includes>
+        </dependencySet>
+        <dependencySet>
+            <outputDirectory>/system</outputDirectory>
+            <unpack>false</unpack>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputFileNameMapping>org/apache/servicemix/kernel/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+            <includes>
+                <include>org.apache.servicemix.kernel:org.apache.servicemix.kernel.filemonitor</include>
+                <include>org.apache.servicemix.kernel:org.apache.servicemix.kernel.spring</include>
+                <include>org.apache.servicemix.kernel:org.apache.servicemix.kernel.management</include>
+            </includes>
+        </dependencySet>
+        <dependencySet>
+            <outputDirectory>/system</outputDirectory>
+            <unpack>false</unpack>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputFileNameMapping>org/apache/servicemix/kernel/gshell/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+            <includes>
+                <include>org.apache.servicemix.kernel.gshell:org.apache.servicemix.kernel.gshell.core</include>
+                <include>org.apache.servicemix.kernel.gshell:org.apache.servicemix.kernel.gshell.admin</include>
+                <include>org.apache.servicemix.kernel.gshell:org.apache.servicemix.kernel.gshell.osgi</include>
+                <include>org.apache.servicemix.kernel.gshell:org.apache.servicemix.kernel.gshell.log</include>
+                <include>org.apache.servicemix.kernel.gshell:org.apache.servicemix.kernel.gshell.features</include>
+                <include>org.apache.servicemix.kernel.gshell:org.apache.servicemix.kernel.gshell.config</include>
+                <include>org.apache.servicemix.kernel.gshell:org.apache.servicemix.kernel.gshell.packages</include>
+            </includes>
+        </dependencySet>
+        <dependencySet>
+            <outputDirectory>/system</outputDirectory>
+            <unpack>false</unpack>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputFileNameMapping>org/apache/servicemix/kernel/jaas/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+            <includes>
+                <include>org.apache.servicemix.kernel.jaas:org.apache.servicemix.kernel.jaas.config</include>
+                <include>org.apache.servicemix.kernel.jaas:org.apache.servicemix.kernel.jaas.modules</include>
+            </includes>
+        </dependencySet>
+        <dependencySet>
+            <outputDirectory>/system</outputDirectory>
+            <unpack>false</unpack>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputFileNameMapping>org/apache/sshd/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+            <includes>
+                <include>org.apache.sshd:sshd-core</include>
+            </includes>
+        </dependencySet>
+        <dependencySet>
+            <outputDirectory>/system</outputDirectory>
+            <unpack>false</unpack>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputFileNameMapping>org/apache/mina/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+            <includes>
+                <include>org.apache.mina:mina-core</include>
+            </includes>
+        </dependencySet>
+        <dependencySet>
+            <outputDirectory>/system</outputDirectory>
+            <unpack>false</unpack>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputFileNameMapping>org/osgi/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+            <includes>
+                <include>org.osgi:jmx</include>
+            </includes>
+        </dependencySet>
+        <dependencySet>
+            <outputDirectory>/system</outputDirectory>
+            <unpack>false</unpack>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputFileNameMapping>com/oracle/osgi/${artifact.artifactId}/${artifact.baseVersion}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+            <includes>
+                <include>com.oracle.osgi:jmx-impl</include>
+            </includes>
+        </dependencySet>
+
+    </dependencySets>
+
+</assembly>
diff --git a/karaf/assembly/src/main/descriptors/windows-src.xml b/karaf/assembly/src/main/descriptors/windows-src.xml
new file mode 100644
index 0000000..4d0c6ae
--- /dev/null
+++ b/karaf/assembly/src/main/descriptors/windows-src.xml
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<assembly>
+    <id>src</id>
+    <formats>
+        <format>zip</format>
+    </formats>
+    <fileSets>
+        <!-- Copy license and other files from root -->
+        <fileSet>
+            <directory>${basedir}/..</directory>
+            <outputDirectory>/</outputDirectory>
+            <includes>
+                <include>BUILDING.txt</include>
+                <include>README.txt</include>
+                <include>RELEASE*.txt</include>
+            </includes>
+            <lineEnding>dos</lineEnding>
+        </fileSet>
+
+        <!-- Binary Files -->
+        <fileSet>
+            <directory>${basedir}/..</directory>
+            <outputDirectory>src</outputDirectory>
+            <includes>
+                <include>**/*.jpeg</include>
+                <include>**/*.jpg</include>
+                <include>**/*.gif</include>
+                <include>**/*.png</include>
+                <include>**/*.exe</include>
+                <include>**/*.dll</include>
+                <include>**/*.jar</include>
+                <include>**/*.so</include>
+                <include>**/*.ks</include>
+                <include>**/*.ts</include>
+                <include>**/*.keystore</include>
+                <include>**/*.bin</include>
+                <include>**/*.jnilib</include>
+                <include>**/*.cert</include>
+                <include>apache-servicemix/src/main/release/bin/*/wrapper</include>
+            </includes>
+            <excludes>
+                <exclude>**/eclipse-classes/**</exclude>
+                <exclude>**/target/**</exclude>
+            </excludes>
+        </fileSet>
+
+        <!-- Text Files -->
+        <fileSet>
+            <directory>${basedir}/..</directory>
+            <outputDirectory>src</outputDirectory>
+            <includes>
+                <include>**/*</include>
+            </includes>
+            <excludes>
+                <exclude>**/*.jpeg</exclude>
+                <exclude>**/*.jpg</exclude>
+                <exclude>**/*.gif</exclude>
+                <exclude>**/*.png</exclude>
+                <exclude>**/*.exe</exclude>
+                <exclude>**/*.dll</exclude>
+                <exclude>**/*.jar</exclude>
+                <exclude>**/*.so</exclude>
+                <exclude>**/*.ks</exclude>
+                <exclude>**/*.ts</exclude>
+                <exclude>**/*.keystore</exclude>
+                <exclude>**/*.bin</exclude>
+                <exclude>**/*.jnilib</exclude>
+                <exclude>**/*.cert</exclude>
+                <exclude>apache-servicemix/src/main/release/bin/*/wrapper</exclude>
+
+                <exclude>**/target/**</exclude>
+                <exclude>**/build/**</exclude>
+                <exclude>activemq-data/**</exclude>
+                <exclude>*/activemq-data/**</exclude>
+                <exclude>**/eclipse-classes/**</exclude>
+                <exclude>**/.*</exclude>
+                <exclude>**/.*/**</exclude>
+
+                <exclude>**/surefire*</exclude>
+                <exclude>**/svn-commit*</exclude>
+
+                <exclude>**/*.iml</exclude>
+                <exclude>**/*.ipr</exclude>
+                <exclude>**/*.iws</exclude>
+
+                <exclude>**/cobertura.ser</exclude>
+
+            </excludes>
+            <lineEnding>dos</lineEnding>
+        </fileSet>
+    </fileSets>
+    <files>
+        <file>
+            <source>${basedir}/target/maven-shared-archive-resources/META-INF/LICENSE</source>
+            <outputDirectory>/</outputDirectory>
+            <destName>LICENSE.txt</destName>
+            <fileMode>0644</fileMode>
+            <lineEnding>unix</lineEnding>
+        </file>
+        <file>
+            <source>${basedir}/target/maven-shared-archive-resources/META-INF/NOTICE</source>
+            <outputDirectory>/</outputDirectory>
+            <destName>NOTICE.txt</destName>
+            <fileMode>0644</fileMode>
+            <lineEnding>unix</lineEnding>
+        </file>
+    </files>
+</assembly>
diff --git a/karaf/assembly/src/main/distribution/text/etc/java.util.logging.properties b/karaf/assembly/src/main/distribution/text/etc/java.util.logging.properties
new file mode 100644
index 0000000..b7b50c5
--- /dev/null
+++ b/karaf/assembly/src/main/distribution/text/etc/java.util.logging.properties
@@ -0,0 +1,23 @@
+################################################################################
+#
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+################################################################################
+
+# Empty java.util.logging.properties to prevent the log to stderr, so that
+# all logs will be delegated to pax logging JUL handler only
+
+
diff --git a/karaf/assembly/src/main/distribution/text/etc/org.apache.servicemix.shell.cfg b/karaf/assembly/src/main/distribution/text/etc/org.apache.servicemix.shell.cfg
new file mode 100644
index 0000000..98bbd57
--- /dev/null
+++ b/karaf/assembly/src/main/distribution/text/etc/org.apache.servicemix.shell.cfg
@@ -0,0 +1,23 @@
+################################################################################
+#
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+################################################################################
+
+#
+sshPort=8101
+sshRealm=servicemix
+hostKey=${servicemix.base}/etc/host.key
diff --git a/karaf/assembly/src/main/distribution/text/etc/org.ops4j.pax.logging.cfg b/karaf/assembly/src/main/distribution/text/etc/org.ops4j.pax.logging.cfg
new file mode 100644
index 0000000..24ddea5
--- /dev/null
+++ b/karaf/assembly/src/main/distribution/text/etc/org.ops4j.pax.logging.cfg
@@ -0,0 +1,36 @@
+################################################################################
+#
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+################################################################################
+
+# Root logger
+log4j.rootLogger=INFO, out, osgi:VmLogAppender
+
+# Logger infos
+log4j.logger.org.apache.geronimo.gshell.remote=WARN
+
+# CONSOLE appender not used by default
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} | %-5.5p | %-16.16t | %-32.32c{1} | %-32.32C %4L | %m%n
+
+# File appender
+log4j.appender.out=org.apache.log4j.FileAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.out.layout.ConversionPattern=%d{ABSOLUTE} | %-5.5p | %-16.16t | %-32.32c{1} | %-32.32C %4L | %m%n
+log4j.appender.out.file=${servicemix.base}/data/log/servicemix.log
+log4j.appender.out.append=true
diff --git a/karaf/assembly/src/main/distribution/text/etc/org.ops4j.pax.url.mvn.cfg b/karaf/assembly/src/main/distribution/text/etc/org.ops4j.pax.url.mvn.cfg
new file mode 100644
index 0000000..6e50c3e
--- /dev/null
+++ b/karaf/assembly/src/main/distribution/text/etc/org.ops4j.pax.url.mvn.cfg
@@ -0,0 +1,73 @@
+################################################################################
+#
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+################################################################################
+
+#
+# If set to true, the following property will not allow any certificate to be used
+# when accessing maven repositories through SSL
+#
+#org.ops4j.pax.url.mvn.certificateCheck=
+
+#
+# Path to the local maven settings file.
+# The repositories defined in this file will be automatically added to the list
+# of default repositories if the 'org.ops4j.pax.url.mvn.repositories' property
+# below is not set.
+# The following locations are checked for the existence of the settings.xml file
+#   * 1. looks for the specified url
+#   * 2. if not found looks for ${user.home}/.m2/settings.xml
+#   * 3. if not found looks for ${maven.home}/conf/settings.xml
+#   * 4. if not found looks for ${M2_HOME}/conf/settings.xml
+#
+#org.ops4j.pax.url.mvn.settings=
+
+#
+# Path to the local maven repository which is used to avoid downloading
+# artifacts when they already exist locally.
+# The value of this property will be extracted from the settings.xml file
+# above, or defaulted to:
+#     System.getProperty( "user.home" ) + "/.m2/repository"
+#
+#org.ops4j.pax.url.mvn.localRepository=
+
+#
+# Comma separated list of repositories scanned when resolving an artifact.
+# Those repositories will be checked before iterating through the
+     below list of repositories and even before the local repository
+# A repository url can be appended with zero or more of the following flags:
+#    @snapshots  : the repository contains snaphots
+#    @noreleases : the repository does not contain any released artifacts
+#
+# The following property value will add the system folder as a repo.
+#
+org.ops4j.pax.url.mvn.defaultRepositories=file:${servicemix.home}/system@snapshots
+
+#
+# Comma separated list of repositories scanned when resolving an artifact.
+# The default list includes the following repositories:
+#    http://repo1.maven.org/maven2
+#    http://repository.ops4j.org/maven2
+# To add repositories to the default ones, prepend '+' to the list of repositories
+# to add.
+# A repository url can be appended with zero or more of the following flags:
+#    @snapshots  : the repository contains snaphots
+#    @noreleases : the repository does not contain any released artifacts
+#
+# The following property value will add the system folder as a repo.
+#
+org.ops4j.pax.url.mvn.repositories=http://repo1.maven.org/maven2,http://people.apache.org/repo/m2-snapshot-repository@snapshots@noreleases,http://repository.ops4j.org/maven2,http://svn.apache.org/repos/asf/servicemix/m2-repo
diff --git a/karaf/assembly/src/main/distribution/text/etc/system.properties b/karaf/assembly/src/main/distribution/text/etc/system.properties
new file mode 100644
index 0000000..d82ce7c
--- /dev/null
+++ b/karaf/assembly/src/main/distribution/text/etc/system.properties
@@ -0,0 +1,22 @@
+################################################################################
+#
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+################################################################################
+
+org.ops4j.pax.logging.DefaultServiceLog.level=ERROR
+servicemix.name=root
+xml.catalog.files=
diff --git a/karaf/assembly/src/main/distribution/text/etc/users.properties b/karaf/assembly/src/main/distribution/text/etc/users.properties
new file mode 100644
index 0000000..0348fae
--- /dev/null
+++ b/karaf/assembly/src/main/distribution/text/etc/users.properties
@@ -0,0 +1,21 @@
+################################################################################
+#
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+################################################################################
+
+#
+smx=smx,admin
diff --git a/karaf/assembly/src/main/distribution/unix-shell/bin/servicemix b/karaf/assembly/src/main/distribution/unix-shell/bin/servicemix
new file mode 100755
index 0000000..6f5d30d
--- /dev/null
+++ b/karaf/assembly/src/main/distribution/unix-shell/bin/servicemix
@@ -0,0 +1,292 @@
+#!/bin/sh
+#
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+# $Id: servicemix 979 2005-11-30 22:50:55Z bsnyder $
+#
+
+DIRNAME=`dirname $0`
+PROGNAME=`basename $0`
+
+#
+# Check/Set up some easily accessible MIN/MAX params for JVM mem usage
+#
+
+if [ "x$JAVA_MIN_MEM" = "x" ]; then
+    JAVA_MIN_MEM=128M
+    export JAVA_MIN_MEM
+fi
+
+if [ "x$JAVA_MAX_MEM" = "x" ]; then
+    JAVA_MAX_MEM=512M
+    export JAVA_MAX_MEM
+fi
+
+warn() {
+    echo "${PROGNAME}: $*"
+}
+
+die() {
+    warn "$*"
+    exit 1
+}
+
+maybeSource() {
+    file="$1"
+    if [ -f "$file" ] ; then
+        . $file
+    fi
+}
+
+detectOS() {
+    # OS specific support (must be 'true' or 'false').
+    cygwin=false;
+    darwin=false;
+    aix=false;
+    os400=false;
+    case "`uname`" in
+        CYGWIN*)
+            cygwin=true
+            ;;
+        Darwin*)
+            darwin=true
+            ;;
+        AIX*)
+            aix=true
+            ;;
+        OS400*)
+            os400=true
+            ;;
+    esac
+    # For AIX, set an environment variable
+    if $aix; then
+         export LDR_CNTRL=MAXDATA=0xB0000000@DSA
+         export IBM_JAVA_HEAPDUMP_TEXT=true
+         echo $LDR_CNTRL
+    fi
+}
+
+unlimitFD() {
+    # Use the maximum available, or set MAX_FD != -1 to use that
+    if [ "x$MAX_FD" = "x" ]; then
+        MAX_FD="maximum"
+    fi
+
+    # Increase the maximum file descriptors if we can
+    if [ "$os400" = "false" ] && [ "$cygwin" = "false" ]; then
+        MAX_FD_LIMIT=`ulimit -H -n`
+        if [ "$MAX_FD_LIMIT" != 'unlimited' ]; then 
+            if [ $? -eq 0 ]; then
+                if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ]; then
+                    # use the system max
+                    MAX_FD="$MAX_FD_LIMIT"
+                fi
+
+                ulimit -n $MAX_FD > /dev/null
+                # echo "ulimit -n" `ulimit -n`
+                if [ $? -ne 0 ]; then
+                    warn "Could not set maximum file descriptor limit: $MAX_FD"
+                fi
+            else
+                warn "Could not query system maximum file descriptor limit: $MAX_FD_LIMIT"
+            fi
+        fi
+    fi
+}
+
+locateHome() {
+    if [ "x$SERVICEMIX_HOME" != "x" ]; then
+        warn "Ignoring predefined value for SERVICEMIX_HOME"
+    fi
+
+    SERVICEMIX_HOME=`cd $DIRNAME/..; pwd`
+    if [ ! -d "$SERVICEMIX_HOME" ]; then
+        die "SERVICEMIX_HOME is not valid: $SERVICEMIX_HOME"
+    fi
+}
+
+locateBase() {
+    if [ "x$SERVICEMIX_BASE" != "x" ]; then
+        if [ ! -d "$SERVICEMIX_BASE" ]; then
+            die "SERVICEMIX_BASE is not valid: $SERVICEMIX_BASE"
+        fi
+    else
+        SERVICEMIX_BASE=$SERVICEMIX_HOME
+    fi
+}
+
+setupNativePath() {
+    # Support for loading native libraries
+    LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:$SERVICEMIX_BASE/lib:$SERVICEMIX_HOME/lib"
+
+    # For Cygwin, set PATH from LD_LIBRARY_PATH
+    if $cygwin; then
+        LD_LIBRARY_PATH=`cygpath --path --windows "$LD_LIBRARY_PATH"`
+        PATH="$PATH;$LD_LIBRARY_PATH"
+        export PATH
+    fi
+    export LD_LIBRARY_PATH
+}
+
+locateJava() {
+    # Setup the Java Virtual Machine
+    if $cygwin ; then
+        [ -n "$JAVA" ] && JAVA=`cygpath --unix "$JAVA"`
+        [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+    fi
+
+    if [ "x$JAVA" = "x" ]; then
+        if [ "x$JAVA_HOME" = "x" ] && [ "$darwin" = "true" ]; then
+            JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Home
+        fi
+        if [ "x$JAVA_HOME" != "x" ]; then
+            if [ ! -d "$JAVA_HOME" ]; then
+                die "JAVA_HOME is not valid: $JAVA_HOME"
+            fi
+            JAVA="$JAVA_HOME/bin/java"
+        else
+            warn "JAVA_HOME not set; results may vary"
+            JAVA="java"
+        fi
+    fi
+}
+
+detectJVM() {
+   #echo "`$JAVA -version`"
+   # This service should call `java -version`,
+   # read stdout, and look for hints
+   if $JAVA -version 2>&1 | grep "^IBM" ; then
+       JVM_VENDOR="IBM"
+   # on OS/400, java -version does not contain IBM explicitly
+   elif $os400; then
+       JVM_VENDOR="IBM"
+   else
+       JVM_VENDOR="SUN"
+   fi
+   # echo "JVM vendor is $JVM_VENDOR"
+}
+
+setupDebugOptions() {
+    if [ "x$JAVA_OPTS" = "x" ]; then
+        JAVA_OPTS="$DEFAULT_JAVA_OPTS"
+    fi
+    export JAVA_OPTS
+
+    # Set Debug options if enabled
+    if [ "x$SERVICEMIX_DEBUG" != "x" ]; then
+        # Use the defaults if JAVA_DEBUG_OPTS was not set
+        if [ "x$JAVA_DEBUG_OPTS" = "x" ]; then
+            JAVA_DEBUG_OPTS="$DEFAULT_JAVA_DEBUG_OPTS"
+        fi
+
+        JAVA_OPTS="$JAVA_DEBUG_OPTS $JAVA_OPTS"
+        warn "Enabling Java debug options: $JAVA_DEBUG_OPTS"
+    fi
+}
+
+setupDefaults() {
+    DEFAULT_JAVA_OPTS="-Xms$JAVA_MIN_MEM -Xmx$JAVA_MAX_MEM "
+
+    #Set the JVM_VENDOR specific JVM flags
+    if [ "$JVM_VENDOR" = "SUN" ]; then
+        DEFAULT_JAVA_OPTS="-server $DEFAULT_JAVA_OPTS -Dcom.sun.management.jmxremote"
+    elif [ "$JVM_VENDOR" = "IBM" ]; then
+        if $os400; then
+            DEFAULT_JAVA_OPTS="$DEFAULT_JAVA_OPTS"
+        elif $aix; then
+            DEFAULT_JAVA_OPTS="-Xverify:none -Xlp $DEFAULT_JAVA_OPTS"
+        else
+            DEFAULT_JAVA_OPTS="-Xverify:none $DEFAULT_JAVA_OPTS"
+        fi
+    fi
+
+    # Add the jars in the lib dir
+    for file in $SERVICEMIX_HOME/lib/*.jar
+    do
+        if [ -z "$CLASSPATH" ]; then
+            CLASSPATH="$file"
+        else
+            CLASSPATH="$CLASSPATH:$file"
+        fi
+    done
+    DEFAULT_JAVA_DEBUG_OPTS="-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005"
+
+    ##
+    ## TODO: Move to conf/profiler/yourkit.{sh|cmd}
+    ##
+    # Uncomment to enable YourKit profiling
+    #DEFAULT_JAVA_DEBUG_OPTS="-Xrunyjpagent"
+}
+
+init() {
+    # Determine if there is special OS handling we must perform
+    detectOS
+
+    # Unlimit the number of file descriptors if possible
+    unlimitFD
+
+    # Locate the ServiceMix home directory
+    locateHome
+
+    # Locate the ServiceMix base directory
+    locateBase
+
+    # Setup the native library path
+    setupNativePath
+
+    # Locate the Java VM to execute
+    locateJava
+
+    # Determine the JVM vendor
+    detectJVM
+
+    # Setup default options
+    setupDefaults
+
+    # Install debug options
+    setupDebugOptions
+
+}
+
+run() {
+    OPTS="-Dservicemix.startLocalConsole=true -Dservicemix.startRemoteShell=true"
+    case "$1" in
+        'console')
+            shift
+            ;;
+        'server')
+            OPTS="-Dservicemix.startLocalConsole=false -Dservicemix.startRemoteShell=true"
+            shift
+            ;;
+        'client')
+            OPTS="-Dservicemix.startLocalConsole=true -Dservicemix.startRemoteShell=false"
+            shift
+            ;;
+    esac
+
+    if $cygwin; then
+        SERVICEMIX_HOME=`cygpath --path --windows "$SERVICEMIX_HOME"`
+        SERVICEMIX_BASE=`cygpath --path --windows "$SERVICEMIX_BASE"`
+    fi
+    exec $JAVA $JAVA_OPTS -Dservicemix.home="$SERVICEMIX_HOME" -Dservicemix.base="$SERVICEMIX_BASE" -Djava.util.logging.config.file=$SERVICEMIX_BASE/etc/java.util.logging.properties $OPTS -classpath "$CLASSPATH" org.apache.servicemix.kernel.main.Main $*
+}
+
+main() {
+    init
+    run $@
+}
+
+main $@
diff --git a/karaf/assembly/src/main/distribution/windows-text/bin/servicemix.bat b/karaf/assembly/src/main/distribution/windows-text/bin/servicemix.bat
new file mode 100755
index 0000000..f7aa2d1
--- /dev/null
+++ b/karaf/assembly/src/main/distribution/windows-text/bin/servicemix.bat
@@ -0,0 +1,166 @@
+@echo off
+rem
+rem
+rem    Licensed to the Apache Software Foundation (ASF) under one or more
+rem    contributor license agreements.  See the NOTICE file distributed with
+rem    this work for additional information regarding copyright ownership.
+rem    The ASF licenses this file to You under the Apache License, Version 2.0
+rem    (the "License"); you may not use this file except in compliance with
+rem    the License.  You may obtain a copy of the License at
+rem
+rem       http://www.apache.org/licenses/LICENSE-2.0
+rem
+rem    Unless required by applicable law or agreed to in writing, software
+rem    distributed under the License is distributed on an "AS IS" BASIS,
+rem    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+rem    See the License for the specific language governing permissions and
+rem    limitations under the License.
+rem
+rem 
+rem $Id: servicemix.bat 979 2005-11-30 22:50:55Z bsnyder $
+rem 
+
+if not "%ECHO%" == "" echo %ECHO%
+
+setlocal
+set DIRNAME=%~dp0%
+set PROGNAME=%~nx0%
+set ARGS=%*
+
+title ServiceMix
+
+goto BEGIN
+
+:warn
+    echo %PROGNAME%: %*
+goto :EOF
+
+:BEGIN
+
+rem # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+if not "%SERVICEMIX_HOME%" == "" (
+    call :warn Ignoring predefined value for SERVICEMIX_HOME
+)
+set SERVICEMIX_HOME=%DIRNAME%..
+if not exist "%SERVICEMIX_HOME%" (
+    call :warn SERVICEMIX_HOME is not valid: %SERVICEMIX_HOME%
+    goto END
+)
+
+if not "%SERVICEMIX_BASE%" == "" (
+    if not exist "%SERVICEMIX_BASE%" (
+       call :warn SERVICEMIX_BASE is not valid: %SERVICEMIX_BASE%
+       goto END
+    )
+)
+if "%SERVICEMIX_BASE%" == "" (
+  set SERVICEMIX_BASE=%SERVICEMIX_HOME%
+)
+
+set LOCAL_CLASSPATH=%CLASSPATH%
+set DEFAULT_JAVA_OPTS=-server -Xmx512M -Dderby.system.home="%SERVICEMIX_BASE%\data\derby" -Dderby.storage.fileSyncTransactionLog=true -Dcom.sun.management.jmxremote
+set CLASSPATH=%LOCAL_CLASSPATH%;%SERVICEMIX_BASE%\conf
+set DEFAULT_JAVA_DEBUG_OPTS=-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005
+
+if "%LOCAL_CLASSPATH%" == "" goto :SERVICEMIX_CLASSPATH_EMPTY
+    set CLASSPATH=%LOCAL_CLASSPATH%;%SERVICEMIX_BASE%\conf
+    goto :SERVICEMIX_CLASSPATH_END
+:SERVICEMIX_CLASSPATH_EMPTY
+    set CLASSPATH=%SERVICEMIX_BASE%\conf
+:SERVICEMIX_CLASSPATH_END
+
+rem Setup Servicemix Home
+if exist "%SERVICEMIX_HOME%\conf\servicemix-rc.cmd" call %SERVICEMIX_HOME%\conf\servicemix-rc.cmd
+if exist "%HOME%\servicemix-rc.cmd" call %HOME%\servicemix-rc.cmd
+
+rem Support for loading native libraries
+set PATH=%PATH%;%SERVICEMIX_BASE%\lib;%SERVICEMIX_HOME%\lib
+
+rem Setup the Java Virtual Machine
+if not "%JAVA%" == "" goto :Check_JAVA_END
+    set JAVA=java
+    if "%JAVA_HOME%" == "" call :warn JAVA_HOME not set; results may vary
+    if not "%JAVA_HOME%" == "" set JAVA=%JAVA_HOME%\bin\java
+    if not exist "%JAVA_HOME%" (
+        call :warn JAVA_HOME is not valid: "%JAVA_HOME%"
+        goto END
+    )
+:Check_JAVA_END
+
+if "%JAVA_OPTS%" == "" set JAVA_OPTS=%DEFAULT_JAVA_OPTS%
+
+if "%SERVICEMIX_DEBUG%" == "" goto :SERVICEMIX_DEBUG_END
+    rem Use the defaults if JAVA_DEBUG_OPTS was not set
+    if "%JAVA_DEBUG_OPTS%" == "" set JAVA_DEBUG_OPTS=%DEFAULT_JAVA_DEBUG_OPTS%
+    
+    set "JAVA_OPTS=%JAVA_DEBUG_OPTS% %JAVA_OPTS%"
+    call :warn Enabling Java debug options: %JAVA_DEBUG_OPTS%
+:SERVICEMIX_DEBUG_END
+
+if "%SERVICEMIX_PROFILER%" == "" goto :SERVICEMIX_PROFILER_END
+    set SERVICEMIX_PROFILER_SCRIPT=%SERVICEMIX_HOME%\conf\profiler\%SERVICEMIX_PROFILER%.cmd
+    
+    if exist "%SERVICEMIX_PROFILER_SCRIPT%" goto :SERVICEMIX_PROFILER_END
+    call :warn Missing configuration for profiler '%SERVICEMIX_PROFILER%': %SERVICEMIX_PROFILER_SCRIPT%
+    goto END
+:SERVICEMIX_PROFILER_END
+
+rem Setup the classpath
+pushd "%SERVICEMIX_HOME%\lib"
+for %%G in (*.*) do call:APPEND_TO_CLASSPATH %%G
+popd
+goto CLASSPATH_END
+
+: APPEND_TO_CLASSPATH
+set filename=%~1
+set suffix=%filename:~-4%
+if %suffix% equ .jar set CLASSPATH=%CLASSPATH%;%SERVICEMIX_HOME%\lib\%filename%
+goto :EOF
+
+:CLASSPATH_END
+
+rem Execute the JVM or the load the profiler
+if "%SERVICEMIX_PROFILER%" == "" goto :RUN
+    rem Execute the profiler if it has been configured
+    call :warn Loading profiler script: %SERVICEMIX_PROFILER_SCRIPT%
+    call %SERVICEMIX_PROFILER_SCRIPT%
+
+:RUN
+    SET OPTS=-Dservicemix.startLocalConsole=true -Dservicemix.startRemoteShell=true
+    SET SHIFT=false
+    if "%1" == "console" goto :EXECUTE_CONSOLE
+    if "%1" == "server" goto :EXECUTE_SERVER
+    if "%1" == "client" goto :EXECUTE_CLIENT
+    goto :EXECUTE
+
+:EXECUTE_CONSOLE
+    SET SHIFT=true
+    goto :EXECUTE    
+
+:EXECUTE_SERVER
+    SET OPTS="-Dservicemix.startLocalConsole=false -Dservicemix.startRemoteShell=true"
+    SET SHIFT=true
+    goto :EXECUTE
+
+:EXECUTE_CLIENT
+    SET OPTS="-Dservicemix.startLocalConsole=true -Dservicemix.startRemoteShell=false"
+    SET SHIFT=true
+    goto :EXECUTE
+
+:EXECUTE
+    if "%SHIFT%" == "true" SET ARGS=%2 %3 %4 %5 %6 %7 %8
+    if not "%SHIFT%" == "true" SET ARGS=%1 %2 %3 %4 %5 %6 %7 %8    
+    rem Execute the Java Virtual Machine
+    "%JAVA%" %JAVA_OPTS% %OPTS% -classpath "%CLASSPATH%" -Dservicemix.home="%SERVICEMIX_HOME%" -Dservicemix.base="%SERVICEMIX_BASE%" -Djava.util.logging.config.file=%SERVICEMIX_BASE%\etc\java.util.logging.properties org.apache.servicemix.kernel.main.Main %ARGS%
+
+rem # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+:END
+
+endlocal
+
+if not "%PAUSE%" == "" pause
+
+:END_NO_PAUSE
+
diff --git a/karaf/assembly/src/main/filtered-resources/etc/org.apache.servicemix.features.cfg b/karaf/assembly/src/main/filtered-resources/etc/org.apache.servicemix.features.cfg
new file mode 100644
index 0000000..2e22aec
--- /dev/null
+++ b/karaf/assembly/src/main/filtered-resources/etc/org.apache.servicemix.features.cfg
@@ -0,0 +1,28 @@
+################################################################################

+#

+#    Licensed to the Apache Software Foundation (ASF) under one or more

+#    contributor license agreements.  See the NOTICE file distributed with

+#    this work for additional information regarding copyright ownership.

+#    The ASF licenses this file to You under the Apache License, Version 2.0

+#    (the "License"); you may not use this file except in compliance with

+#    the License.  You may obtain a copy of the License at

+#

+#       http://www.apache.org/licenses/LICENSE-2.0

+#

+#    Unless required by applicable law or agreed to in writing, software

+#    distributed under the License is distributed on an "AS IS" BASIS,

+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+#    See the License for the specific language governing permissions and

+#    limitations under the License.

+#

+################################################################################

+

+#

+# Comma separated list of features repositories to register by default

+#

+featuresRepositories=mvn:org.apache.servicemix.kernel/apache-servicemix-kernel/${version}/xml/features

+

+#

+# Comma separated list of features to install at startup

+#

+featuresBoot=

diff --git a/karaf/assembly/src/main/filtered-resources/etc/startup.properties b/karaf/assembly/src/main/filtered-resources/etc/startup.properties
new file mode 100644
index 0000000..06519d6
--- /dev/null
+++ b/karaf/assembly/src/main/filtered-resources/etc/startup.properties
@@ -0,0 +1,76 @@
+################################################################################
+#
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+################################################################################
+
+# This file allows you to control the start level of each bundle.
+#
+
+#
+# Startup core services like logging
+#
+org/ops4j/pax/url/pax-url-mvn/${pax.url.version}/pax-url-mvn-${pax.url.version}.jar=5
+org/ops4j/pax/url/pax-url-wrap/${pax.url.version}/pax-url-wrap-${pax.url.version}.jar=5
+org/ops4j/pax/logging/pax-logging-api/${pax.logging.version}/pax-logging-api-${pax.logging.version}.jar=8
+org/ops4j/pax/logging/pax-logging-service/${pax.logging.version}/pax-logging-service-${pax.logging.version}.jar=8
+org/apache/geronimo/specs/geronimo-servlet_2.5_spec/${geronimo.servlet.version}/geronimo-servlet_2.5_spec-${geronimo.servlet.version}.jar=10
+org/apache/servicemix/specs/org.apache.servicemix.specs.jaxp-api-1.4/${servicemix.specs.version}/org.apache.servicemix.specs.jaxp-api-1.4-${servicemix.specs.version}.jar=10
+org/apache/servicemix/bundles/org.apache.servicemix.bundles.jaxp-ri/${jaxp.ri.version}/org.apache.servicemix.bundles.jaxp-ri-${jaxp.ri.version}.jar=10
+org/apache/felix/org.osgi.compendium/${felix.compendium.version}/org.osgi.compendium-${felix.compendium.version}.jar=10
+org/apache/felix/org.apache.felix.configadmin/${felix.configadmin.version}/org.apache.felix.configadmin-${felix.configadmin.version}.jar=10
+org/apache/geronimo/specs/geronimo-annotation_1.0_spec/${geronimo.annotation.version}/geronimo-annotation_1.0_spec-${geronimo.annotation.version}.jar=10
+org/apache/felix/org.apache.felix.prefs/${felix.prefs.version}/org.apache.felix.prefs-${felix.prefs.version}.jar=10
+org/apache/servicemix/kernel/org.apache.servicemix.kernel.filemonitor/${pom.version}/org.apache.servicemix.kernel.filemonitor-${pom.version}.jar=15
+
+#
+# The rest of the services..
+#
+org/apache/servicemix/bundles/org.apache.servicemix.bundles.jline/${jline.version}/org.apache.servicemix.bundles.jline-${jline.version}.jar=30
+org/apache/servicemix/bundles/org.apache.servicemix.bundles.aopalliance/${aopalliance.version}/org.apache.servicemix.bundles.aopalliance-${aopalliance.version}.jar=30
+org/apache/servicemix/bundles/org.apache.servicemix.bundles.cglib/${cglib.version}/org.apache.servicemix.bundles.cglib-${cglib.version}.jar=30
+org/apache/servicemix/bundles/org.apache.servicemix.bundles.oro/${oro.version}/org.apache.servicemix.bundles.oro-${oro.version}.jar=30
+org/apache/servicemix/bundles/org.apache.servicemix.bundles.commons-codec/${commons.codec.version}/org.apache.servicemix.bundles.commons-codec-${commons.codec.version}.jar=30
+org/apache/servicemix/bundles/org.apache.servicemix.bundles.commons-httpclient/${commons.httpclient.version}/org.apache.servicemix.bundles.commons-httpclient-${commons.httpclient.version}.jar=30
+org/apache/servicemix/bundles/org.apache.servicemix.bundles.commons-jexl/${commons.jexl.version}/org.apache.servicemix.bundles.commons-jexl-${commons.jexl.version}.jar=30
+org/apache/servicemix/bundles/org.apache.servicemix.bundles.commons-vfs/${commons.vfs.version}/org.apache.servicemix.bundles.commons-vfs-${commons.vfs.version}.jar=30
+org/springframework/spring-aop/${spring.version}/spring-aop-${spring.version}.jar=30
+org/springframework/spring-beans/${spring.version}/spring-beans-${spring.version}.jar=30
+org/springframework/spring-context/${spring.version}/spring-context-${spring.version}.jar=30
+org/springframework/spring-core/${spring.version}/spring-core-${spring.version}.jar=30
+org/springframework/osgi/spring-osgi-core/${spring.osgi.version}/spring-osgi-core-${spring.osgi.version}.jar=30
+org/springframework/osgi/spring-osgi-extender/${spring.osgi.version}/spring-osgi-extender-${spring.osgi.version}.jar=30
+org/springframework/osgi/spring-osgi-io/${spring.osgi.version}/spring-osgi-io-${spring.osgi.version}.jar=30
+org/apache/servicemix/kernel/org.apache.servicemix.kernel.spring/${pom.version}/org.apache.servicemix.kernel.spring-${pom.version}.jar=30
+org/apache/servicemix/kernel/org.apache.servicemix.kernel.management/${pom.version}/org.apache.servicemix.kernel.management-${pom.version}.jar=30
+org/apache/servicemix/kernel/gshell/org.apache.servicemix.kernel.gshell.admin/${pom.version}/org.apache.servicemix.kernel.gshell.admin-${pom.version}.jar=30
+org/apache/servicemix/kernel/gshell/org.apache.servicemix.kernel.gshell.osgi/${pom.version}/org.apache.servicemix.kernel.gshell.osgi-${pom.version}.jar=30
+org/apache/servicemix/kernel/gshell/org.apache.servicemix.kernel.gshell.features/${pom.version}/org.apache.servicemix.kernel.gshell.features-${pom.version}.jar=30
+org/apache/servicemix/kernel/gshell/org.apache.servicemix.kernel.gshell.log/${pom.version}/org.apache.servicemix.kernel.gshell.log-${pom.version}.jar=30
+org/apache/servicemix/kernel/gshell/org.apache.servicemix.kernel.gshell.config/${pom.version}/org.apache.servicemix.kernel.gshell.config-${pom.version}.jar=30
+org/apache/servicemix/kernel/gshell/org.apache.servicemix.kernel.gshell.packages/${pom.version}/org.apache.servicemix.kernel.gshell.packages-${pom.version}.jar=30
+org/apache/servicemix/kernel/jaas/org.apache.servicemix.kernel.jaas.config/${pom.version}/org.apache.servicemix.kernel.jaas.config-${pom.version}.jar=30
+org/apache/servicemix/kernel/jaas/org.apache.servicemix.kernel.jaas.modules/${pom.version}/org.apache.servicemix.kernel.jaas.modules-${pom.version}.jar=30
+org/apache/mina/mina-core/${mina.version}/mina-core-${mina.version}.jar=30
+org/apache/sshd/sshd-core/${sshd.version}/sshd-core-${sshd.version}.jar=30
+org/osgi/jmx/${osgi.jmx.version}/jmx-${osgi.jmx.version}.jar=30
+com/oracle/osgi/jmx-impl/${osgi.jmx.version}/jmx-impl-${osgi.jmx.version}.jar=30
+
+#
+# Start console last
+#
+org/apache/servicemix/kernel/gshell/org.apache.servicemix.kernel.gshell.core/${pom.version}/org.apache.servicemix.kernel.gshell.core-${pom.version}.jar=40
+
diff --git a/karaf/assembly/src/main/filtered-resources/features.xml b/karaf/assembly/src/main/filtered-resources/features.xml
new file mode 100644
index 0000000..8316b3f
--- /dev/null
+++ b/karaf/assembly/src/main/filtered-resources/features.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+      Licensed to the Apache Software Foundation (ASF) under one or more
+      contributor license agreements.  See the NOTICE file distributed with
+      this work for additional information regarding copyright ownership.
+      The ASF licenses this file to You under the Apache License, Version 2.0
+      (the "License"); you may not use this file except in compliance with
+      the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+      Unless required by applicable law or agreed to in writing, software
+      distributed under the License is distributed on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+      See the License for the specific language governing permissions and
+      limitations under the License.
+-->
+<features>
+    <feature name="wrapper" version="${version}">
+        <bundle>mvn:org.apache.servicemix.kernel.gshell/org.apache.servicemix.kernel.gshell.wrapper/${version}</bundle>
+    </feature>
+    <feature name="obr" version="${version}">
+        <bundle>mvn:org.apache.felix/org.apache.felix.bundlerepository/${felix.bundlerepository.version}</bundle>
+        <bundle>mvn:org.apache.servicemix.kernel.gshell/org.apache.servicemix.kernel.gshell.obr/${version}</bundle>
+    </feature>
+</features>
diff --git a/karaf/client/pom.xml b/karaf/client/pom.xml
new file mode 100644
index 0000000..13534f1
--- /dev/null
+++ b/karaf/client/pom.xml
@@ -0,0 +1,136 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <!--
+
+        Licensed to the Apache Software Foundation (ASF) under one or more
+        contributor license agreements.  See the NOTICE file distributed with
+        this work for additional information regarding copyright ownership.
+        The ASF licenses this file to You under the Apache License, Version 2.0
+        (the "License"); you may not use this file except in compliance with
+        the License.  You may obtain a copy of the License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software
+        distributed under the License is distributed on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        See the License for the specific language governing permissions and
+        limitations under the License.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.servicemix.kernel</groupId>
+        <artifactId>kernel</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.servicemix.kernel</groupId>
+    <artifactId>org.apache.servicemix.kernel.client</artifactId>
+    <packaging>bundle</packaging>
+    <version>1.2.0-SNAPSHOT</version>
+    <name>Apache ServiceMix Kernel :: Client</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel.gshell</groupId>
+            <artifactId>org.apache.servicemix.kernel.gshell.core</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-jdk14</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-nop</artifactId>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <_donotcopy>(CVS|.svn|config.properties)</_donotcopy>
+                        <Main-Class>org.apache.servicemix.kernel.client.Main</Main-Class>
+                        <Class-Path>
+                            ../system/com/google/code/sshd/sshd/${sshd.version}/sshd-${sshd.version}.jar
+                            ../system/org/apache/servicemix/kernel/gshell/org.apache.servicemix.kernel.gshell.core/${pom.version}/org.apache.servicemix.kernel.gshell.core-${pom.version}.jar
+                            ../system/org/apache/servicemix/bundles/org.apache.servicemix.bundles.mina/${mina.version}/org.apache.servicemix.bundles.mina-${mina.version}.jar
+                            ../system/org/apache/servicemix/bundles/org.apache.servicemix.bundles.jline/${jline.version}/org.apache.servicemix.bundles.jline-${jline.version}.jar
+                        </Class-Path>
+                        <Bundle-Name>Apache ServiceMix Shell Client</Bundle-Name>
+                        <Bundle-Description>Shell client bundle for Apache ServiceMix Kernel.</Bundle-Description>
+                        <Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName>
+                        <Export-Package>org.apache.servicemix.kernel.client</Export-Package>
+                        <Private-Package>
+                            org.apache.servicemix.kernel.client;-split-package:=merge-first,
+                            org.slf4j;-split-package:=merge-first,
+                            org.slf4j.spi;-split-package:=merge-first,
+                            org.slf4j.helpers;-split-package:=merge-first,
+                            org.slf4j.impl;-split-package:=merge-first,
+                            META-INF;-split-package:=merge-first
+                        </Private-Package>
+                        <Import-Package>!*</Import-Package>
+                    </instructions>
+                    <unpackBundle>true</unpackBundle>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                        <configuration>
+                            <artifactSet>
+                                <includes>
+                                    <include>${project.groupId}:${project.artifactId}</include>
+                                    <include>org.slf4j:slf4j-api</include>
+                                    <include>org.slf4j:slf4j-nop</include>
+                                </includes>
+                            </artifactSet>
+                            <filters>
+                                <filter>
+                                    <artifact>org.slf4j:slf4j-api</artifact>
+                                    <excludes>
+                                        <exclude>org/slf4j/**</exclude>
+                                    </excludes>
+                                </filter>
+                                <filter>
+                                    <artifact>org.slf4j:slf4j-nop</artifact>
+                                    <excludes>
+                                        <exclude>org/slf4j/**</exclude>
+                                    </excludes>
+                                </filter>
+                            </filters>
+                            <createSourcesJar>${createSourcesJar}</createSourcesJar>
+                            <promoteTransitiveDependencies>true</promoteTransitiveDependencies>
+                            <createDependencyReducedPom>true</createDependencyReducedPom>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+                <filtering>true</filtering>
+            </resource>
+        </resources>
+    </build>
+    
+
+</project>
diff --git a/karaf/client/src/main/java/org/apache/servicemix/kernel/client/Main.java b/karaf/client/src/main/java/org/apache/servicemix/kernel/client/Main.java
new file mode 100644
index 0000000..886acaf
--- /dev/null
+++ b/karaf/client/src/main/java/org/apache/servicemix/kernel/client/Main.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.client;
+
+import org.apache.sshd.ClientChannel;
+import org.apache.sshd.ClientSession;
+import org.apache.sshd.SshClient;
+import org.apache.sshd.client.future.ConnectFuture;
+
+import jline.ConsoleReader;
+
+/**
+ * A very simple
+ */
+public class Main {
+
+    public static void main(String[] args) throws Exception {
+        String host = "localhost";
+        int port = 8101;
+        String user = "smx";
+        String password = "smx";
+        StringBuilder sb = new StringBuilder();
+
+        for (int i = 0; i < args.length; i++) {
+            if (args[i].charAt(0) == '-') {
+                if (args[i].equals("-a")) {
+                    port = Integer.parseInt(args[++i]);
+                } else if (args[i].equals("-h")) {
+                    host = args[++i];
+                } else if (args[i].equals("-u")) {
+                    user = args[++i];
+                } else if (args[i].equals("-p")) {
+                    password = args[++i];
+                } else if (args[i].equals("--help")) {
+                    System.out.println("Apache ServiceMix Kernel client");
+                    System.out.println("  -a [port]     specify the port to connect to");
+                    System.out.println("  -h [host]     specify the host to connect to");
+                    System.out.println("  -u [user]     specify the user name");
+                    System.out.println("  -p [password] specify the password");
+                    System.out.println("  --help        shows this help message");
+                    System.out.println("  [commands]    commands to run");
+                    System.out.println("If no commands are specified, the client will be put in an interactive mode");
+                    System.exit(0);
+                } else {
+                    System.err.println("Unknown option: " + args[i]);
+                    System.err.println("Run with --help for usage");
+                    System.exit(1);
+                }
+            } else {
+                sb.append(args[i]);
+                sb.append(' ');
+            }
+        }
+
+        // TODO: implement sending a direct command
+
+        SshClient client = null;
+        try {
+            client = SshClient.setUpDefaultClient();
+            client.start();
+            ConnectFuture future = client.connect(host, port);
+            future.await();
+            ClientSession session = future.getSession();
+            session.authPassword(user, password);
+            ClientChannel channel = session.createChannel("shell");
+            channel.setIn(new ConsoleReader().getInput());
+            channel.setOut(System.out);
+            channel.setErr(System.err);
+            channel.open();
+            channel.waitFor(ClientChannel.CLOSED, 0);
+        } catch (Throwable t) {
+            t.printStackTrace();
+            System.exit(1);
+        } finally {
+            try {
+                client.stop();
+            } catch (Throwable t) { }
+        }
+        System.exit(0);
+    }
+
+}
diff --git a/karaf/client/src/main/resources/client.login.conf b/karaf/client/src/main/resources/client.login.conf
new file mode 100644
index 0000000..dc2b0ba
--- /dev/null
+++ b/karaf/client/src/main/resources/client.login.conf
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+//
+// $Rev: 580717 $ $Date: 2007-09-30 14:47:55 +0200 (Sun, 30 Sep 2007) $
+//
+
+RshClient {
+    org.apache.geronimo.gshell.remote.client.auth.RemoteLoginModule required;
+};
diff --git a/karaf/demos/pom.xml b/karaf/demos/pom.xml
new file mode 100644
index 0000000..9665c6c
--- /dev/null
+++ b/karaf/demos/pom.xml
@@ -0,0 +1,40 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <!--
+
+        Licensed to the Apache Software Foundation (ASF) under one or more
+        contributor license agreements.  See the NOTICE file distributed with
+        this work for additional information regarding copyright ownership.
+        The ASF licenses this file to You under the Apache License, Version 2.0
+        (the "License"); you may not use this file except in compliance with
+        the License.  You may obtain a copy of the License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software
+        distributed under the License is distributed on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        See the License for the specific language governing permissions and
+        limitations under the License.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.servicemix.kernel</groupId>
+        <artifactId>kernel</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.servicemix.kernel</groupId>
+    <artifactId>org.apache.servicemix.kernel.demos</artifactId>
+    <packaging>pom</packaging>
+    <version>1.2.0-SNAPSHOT</version>
+    <name>Apache ServiceMix Kernel :: Demos</name>
+
+    <modules>
+        <module>smx4web</module>
+    </modules>
+
+</project>
diff --git a/karaf/demos/smx4web/README.txt b/karaf/demos/smx4web/README.txt
new file mode 100644
index 0000000..a41aad9
--- /dev/null
+++ b/karaf/demos/smx4web/README.txt
@@ -0,0 +1,28 @@
+################################################################################
+#
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+################################################################################
+
+This is an example showing how to embed ServiceMix Kernel in a web application.
+You can either:
+  * build the web app using "mvn package" and deploy the web application to your favorite web container
+  * run the web app from the command line using the "mvn package jetty:run" command
+  
+Once the web application is started, you can use the Apache ServiceMix Kernel client to connect to the running server:
+  cd [smx-kernel-install-dir]
+  java -jar lib/servicemix-client.jar
+  
diff --git a/karaf/demos/smx4web/pom.xml b/karaf/demos/smx4web/pom.xml
new file mode 100644
index 0000000..ae8a45a
--- /dev/null
+++ b/karaf/demos/smx4web/pom.xml
@@ -0,0 +1,283 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.servicemix.kernel</groupId>
+    <artifactId>org.apache.servicemix.kernel.demos</artifactId>
+    <version>1.2.0-SNAPSHOT</version>
+  </parent>
+
+  <groupId>org.apache.servicemix.kernel.demos</groupId>
+  <artifactId>smx4web</artifactId>
+  <packaging>war</packaging>
+  <name>Apache ServiceMix Kernel :: Demos :: smx4web</name>
+  
+  <properties>
+    <jetty.port>8080</jetty.port>
+    <jetty.version>6.1.12rc1</jetty.version>
+    <geronimo.servlet.version>1.1.2</geronimo.servlet.version>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.servicemix.kernel</groupId>
+      <artifactId>org.apache.servicemix.kernel.main</artifactId>
+    </dependency>
+    <dependency>
+        <groupId>org.apache.servicemix.kernel</groupId>
+        <artifactId>apache-servicemix-kernel</artifactId>
+        <type>zip</type>
+        <exclusions>
+            <exclusion>
+                <groupId>org.apache.servicemix.kernel</groupId>
+                <artifactId>org.apache.servicemix.kernel.client</artifactId>
+            </exclusion>
+            <exclusion>
+                <groupId>org.apache.servicemix.kernel</groupId>
+                <artifactId>org.apache.servicemix.kernel.filemonitor</artifactId>
+            </exclusion>
+            <exclusion>
+                <groupId>org.apache.servicemix.kernel</groupId>
+                <artifactId>org.apache.servicemix.kernel.spring</artifactId>
+            </exclusion>
+            <exclusion>
+                <groupId>org.apache.servicemix.kernel.gshell</groupId>
+                <artifactId>org.apache.servicemix.kernel.gshell.core</artifactId>
+            </exclusion>
+            <exclusion>
+                <groupId>org.apache.servicemix.kernel.gshell</groupId>
+                <artifactId>org.apache.servicemix.kernel.gshell.admin</artifactId>
+            </exclusion>
+            <exclusion>
+                <groupId>org.apache.servicemix.kernel.gshell</groupId>
+                <artifactId>org.apache.servicemix.kernel.gshell.obr</artifactId>
+            </exclusion>
+            <exclusion>
+                <groupId>org.apache.servicemix.kernel.gshell</groupId>
+                <artifactId>org.apache.servicemix.kernel.gshell.osgi</artifactId>
+            </exclusion>
+            <exclusion>
+                <groupId>org.apache.servicemix.kernel.gshell</groupId>
+                <artifactId>org.apache.servicemix.kernel.gshell.log</artifactId>
+            </exclusion>
+            <exclusion>
+                <groupId>org.apache.servicemix.kernel.gshell</groupId>
+                <artifactId>org.apache.servicemix.kernel.gshell.features</artifactId>
+            </exclusion>
+            <exclusion>
+                <groupId>org.apache.servicemix.kernel.gshell</groupId>
+                <artifactId>org.apache.servicemix.kernel.gshell.config</artifactId>
+            </exclusion>
+            <exclusion>
+                <groupId>org.apache.servicemix.kernel.gshell</groupId>
+                <artifactId>org.apache.servicemix.kernel.gshell.packages</artifactId>
+            </exclusion>
+            <exclusion>
+                <groupId>org.apache.servicemix.kernel.jaas</groupId>
+                <artifactId>org.apache.servicemix.kernel.jaas.config</artifactId>
+            </exclusion>
+            <exclusion>
+                <groupId>org.apache.servicemix.kernel.jaas</groupId>
+                <artifactId>org.apache.servicemix.kernel.jaas.keystore</artifactId>
+            </exclusion>
+            <exclusion>
+                <groupId>org.springframework.osgi</groupId>
+                <artifactId>spring-osgi-extender</artifactId>
+            </exclusion>
+            <exclusion>
+                <groupId>org.springframework.osgi</groupId>
+                <artifactId>spring-osgi-core</artifactId>
+            </exclusion>
+            <exclusion>
+                <groupId>org.springframework.osgi</groupId>
+                <artifactId>spring-osgi-io</artifactId>
+            </exclusion>
+            <exclusion>
+                <groupId>org.springframework</groupId>
+                <artifactId>spring-context</artifactId>
+            </exclusion>
+            <exclusion>
+                <groupId>org.springframework</groupId>
+                <artifactId>spring-beans</artifactId>
+            </exclusion>
+            <exclusion>
+                <groupId>org.springframework</groupId>
+                <artifactId>spring-core</artifactId>
+            </exclusion>
+            <exclusion>
+                <groupId>org.springframework</groupId>
+                <artifactId>spring-aop</artifactId>
+            </exclusion>
+            <exclusion>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>org.apache.felix.bundlerepository</artifactId>
+            </exclusion>
+            <exclusion>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>org.apache.felix.configadmin</artifactId>
+            </exclusion>
+            <exclusion>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>org.apache.felix.prefs</artifactId>
+            </exclusion>
+            <exclusion>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>org.osgi.compendium</artifactId>
+            </exclusion>
+            <exclusion>
+                <groupId>org.apache.servicemix.bundles</groupId>
+                <artifactId>org.apache.servicemix.bundles.mina</artifactId>
+            </exclusion>
+            <exclusion>
+                <groupId>org.apache.servicemix.bundles</groupId>
+                <artifactId>org.apache.servicemix.bundles.aopalliance</artifactId>
+            </exclusion>
+            <exclusion>
+                <groupId>org.apache.servicemix.bundles</groupId>
+                <artifactId>org.apache.servicemix.bundles.asm</artifactId>
+            </exclusion>
+            <exclusion>
+                <groupId>org.apache.servicemix.bundles</groupId>
+                <artifactId>org.apache.servicemix.bundles.cglib</artifactId>
+            </exclusion>
+            <exclusion>
+                <groupId>org.apache.servicemix.bundles</groupId>
+                <artifactId>org.apache.servicemix.bundles.ant</artifactId>
+            </exclusion>
+            <exclusion>
+                <groupId>org.ops4j.pax.logging</groupId>
+                <artifactId>pax-logging-service</artifactId>
+            </exclusion>
+            <exclusion>
+                <groupId>org.ops4j.pax.logging</groupId>
+                <artifactId>pax-logging-api</artifactId>
+            </exclusion>
+            <exclusion>
+                <groupId>org.ops4j.pax.url</groupId>
+                <artifactId>pax-url-mvn</artifactId>
+            </exclusion>
+        </exclusions>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-servlet_2.5_spec</artifactId>
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <source>1.5</source>
+          <target>1.5</target>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-war-plugin</artifactId>
+        <version>2.1-beta-1</version>
+        <configuration>
+          <warSourceDirectory>src/main/webapp/</warSourceDirectory>
+          <webResources>
+            <resource>
+              <directory>target/kernel</directory>
+            </resource>
+          </webResources>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.mortbay.jetty</groupId>
+        <artifactId>maven-jetty-plugin</artifactId>
+        <version>${jetty.version}</version>
+        <configuration>
+          <connectors>
+            <connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
+              <port>${jetty.port}</port>
+              <maxIdleTime>60000</maxIdleTime>
+            </connector>
+          </connectors>
+          <systemProperties>
+            <!-- enable easy connection to JConsole -->
+            <systemProperty>
+              <name>com.sun.management.jmxremote</name>
+              <value></value>
+            </systemProperty>
+          </systemProperties>
+          <scanIntervalSeconds>10</scanIntervalSeconds>
+          <webAppSourceDirectory>${project.build.directory}/${project.build.finalName}</webAppSourceDirectory>
+        </configuration>
+      </plugin>
+      <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-dependency-plugin</artifactId>
+          <version>2.0</version>
+          <executions>
+              <execution>
+                  <id>unpack-unix</id>
+                  <phase>generate-resources</phase>
+                  <goals>
+                      <goal>unpack</goal>
+                  </goals>
+                  <configuration>
+                      <artifactItems>
+                          <artifactItem>
+                              <groupId>org.apache.servicemix.kernel</groupId>
+                              <artifactId>apache-servicemix-kernel</artifactId>
+                              <type>zip</type>
+                              <overWrite>true</overWrite>
+                              <outputDirectory>${project.build.directory}/kernel/WEB-INF</outputDirectory>
+                              <excludes>**/lib/*,**/*.txt,**/bin/*,**/demos/**,**/lib,**/bin,**/demos</excludes>
+                          </artifactItem>
+                      </artifactItems>
+                  </configuration>
+              </execution>
+        </executions>
+      </plugin>
+      <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-antrun-plugin</artifactId>
+          <version>1.3</version>
+          <executions>
+              <execution>
+                  <id>copy-kernel</id>
+                  <phase>process-resources</phase>
+                  <goals>
+                      <goal>run</goal>
+                  </goals>
+                  <configuration>
+                      <tasks>
+                          <move todir="${project.build.directory}/kernel/WEB-INF/servicemix">
+                              <fileset dir="${project.build.directory}/kernel/WEB-INF/apache-servicemix-kernel-${pom.version}"/>
+                          </move>
+                      </tasks>
+                  </configuration>
+              </execution>
+          </executions>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/karaf/demos/smx4web/src/main/java/org/apache/servicemix/smx4webex/WebAppListener.java b/karaf/demos/smx4web/src/main/java/org/apache/servicemix/smx4webex/WebAppListener.java
new file mode 100644
index 0000000..11e9bbb
--- /dev/null
+++ b/karaf/demos/smx4web/src/main/java/org/apache/servicemix/smx4webex/WebAppListener.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.smx4webex;
+
+import java.io.File;
+
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+import org.apache.servicemix.kernel.main.Main;
+
+public class WebAppListener implements ServletContextListener {
+	
+	private Main main;
+	
+	public void contextInitialized(ServletContextEvent sce) {
+		try {
+			System.err.println("contextInitialized");
+			String root = new File(sce.getServletContext().getRealPath("/") + "WEB-INF/servicemix").getAbsolutePath();
+			System.err.println("Root: " + root);
+			System.setProperty("servicemix.home", root);
+			System.setProperty("servicemix.base", root);
+			System.setProperty("servicemix.startLocalConsole", "false");
+			System.setProperty("servicemix.startRemoteShell", "true");
+			main = new Main(new String[0]);
+			main.launch();
+		} catch (Exception e) {
+			main = null;
+			e.printStackTrace();
+		}
+	}
+
+	public void contextDestroyed(ServletContextEvent sce) {
+		try {
+			System.err.println("contextDestroyed");
+			if (main != null) {
+				main.destroy(false);
+			}
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+}
diff --git a/karaf/demos/smx4web/src/main/webapp/WEB-INF/web.xml b/karaf/demos/smx4web/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..30f7072
--- /dev/null
+++ b/karaf/demos/smx4web/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+   
+    http://www.apache.org/licenses/LICENSE-2.0
+   
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<web-app version="2.4"
+         xmlns="http://java.sun.com/xml/ns/j2ee"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
+                             http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
+
+  <description>ServiceMix 4 Embedded Example</description>
+  <display-name>ServiceMix 4 Embedded Example</display-name>
+
+  <listener>
+    <listener-class>org.apache.servicemix.smx4webex.WebAppListener</listener-class>
+  </listener>
+
+  <welcome-file-list>
+    <welcome-file>index.jsp</welcome-file>
+  </welcome-file-list>
+		
+</web-app>
diff --git a/karaf/demos/smx4web/src/main/webapp/index.jsp b/karaf/demos/smx4web/src/main/webapp/index.jsp
new file mode 100644
index 0000000..3734ee9
--- /dev/null
+++ b/karaf/demos/smx4web/src/main/webapp/index.jsp
@@ -0,0 +1,34 @@
+<%--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+   
+    http://www.apache.org/licenses/LICENSE-2.0
+   
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+--%>
+<html>
+<head>
+<title>Apache ServiceMix Kernel</title>
+</head>
+<body>
+
+<h2>Welcome!</h2>
+
+<p>
+Welcome to Apache ServiceMix Kernel web application demo
+</p>
+
+<p>
+You can find more information about ServiceMix Kernel on the <a href="http://servicemix.apache.org/kernel">Apache ServiceMix Kernel Site</a>
+</p>
+</body>
+</html>
+	
diff --git a/karaf/etc/config.properties b/karaf/etc/config.properties
new file mode 100644
index 0000000..3146515
--- /dev/null
+++ b/karaf/etc/config.properties
@@ -0,0 +1,281 @@
+################################################################################
+#
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+################################################################################
+
+#
+# Framework config properties.
+#
+org.osgi.framework.system.packages=org.osgi.framework; version=1.4.0, \
+ org.osgi.framework.hooks.service; version=1.4.0, \
+ org.osgi.service.packageadmin; version=1.2.0, \
+ org.osgi.service.startlevel; version=1.1.0, \
+ org.osgi.service.url; version=1.0.0, \
+ org.apache.servicemix.kernel.main.spi; version=1.0.0, \
+ org.apache.servicemix.kernel.jaas.boot, \
+ org.osgi.util.tracker; version=1.3.3, \
+ org.apache.servicemix.kernel.version, \
+ ${jre-${java.specification.version}}
+org.osgi.framework.bootdelegation=sun.*,com.sun.management*
+
+# To enable the use of the startup.properties file to control the start level:
+felix.auto.start=startup.properties
+#felix.auto.start=all
+
+org.osgi.framework.startlevel=100
+felix.startlevel.bundle=60
+#framework.service.urlhandlers=false
+
+# Only works on Felix 1.4+
+felix.fragment.validation=warning
+# felix.log.level=1
+
+#
+# Bundle config properties.
+#
+obr.repository.url=http://svn.apache.org/repos/asf/servicemix/smx4/obr-repo/repository.xml
+
+#
+# FileMonitor properties
+#
+org.apache.servicemix.filemonitor.configDir        = ${servicemix.base}/etc
+org.apache.servicemix.filemonitor.monitorDir       = ${servicemix.base}/deploy
+org.apache.servicemix.filemonitor.generatedJarDir  = ${servicemix.base}/data/generated-bundles
+org.apache.servicemix.filemonitor.scanInterval     = 500
+
+
+#
+# Java platform package export properties.
+#
+jre-1.5= \
+ javax.accessibility; \
+ javax.activity; \
+ javax.crypto; \
+ javax.crypto.interfaces; \
+ javax.crypto.spec; \
+ javax.imageio; \
+ javax.imageio.event; \
+ javax.imageio.metadata; \
+ javax.imageio.plugins.bmp; \
+ javax.imageio.plugins.jpeg; \
+ javax.imageio.spi; \
+ javax.imageio.stream; \
+ javax.management; \
+ javax.management.loading; \
+ javax.management.modelmbean; \
+ javax.management.monitor; \
+ javax.management.openmbean; \
+ javax.management.relation; \
+ javax.management.remote; \
+ javax.management.remote.rmi; \
+ javax.management.timer; \
+ javax.naming; \
+ javax.naming.directory; \
+ javax.naming.event; \
+ javax.naming.ldap; \
+ javax.naming.spi; \
+ javax.net; \
+ javax.net.ssl; \
+ javax.print; \
+ javax.print.attribute; \
+ javax.print.attribute.standard; \
+ javax.print.event; \
+ javax.rmi; \
+ javax.rmi.CORBA; \
+ javax.rmi.ssl; \
+ javax.security.auth; \
+ javax.security.auth.callback; \
+ javax.security.auth.kerberos; \
+ javax.security.auth.login; \
+ javax.security.auth.spi; \
+ javax.security.auth.x500; \
+ javax.security.cert; \
+ javax.security.sasl; \
+ javax.sound.midi; \
+ javax.sound.midi.spi; \
+ javax.sound.sampled; \
+ javax.sound.sampled.spi; \
+ javax.sql; \
+ javax.sql.rowset; \
+ javax.sql.rowset.serial; \
+ javax.sql.rowset.spi; \
+ javax.swing; \
+ javax.swing.border; \
+ javax.swing.colorchooser; \
+ javax.swing.event; \
+ javax.swing.filechooser; \
+ javax.swing.plaf; \
+ javax.swing.plaf.basic; \
+ javax.swing.plaf.metal; \
+ javax.swing.plaf.multi; \
+ javax.swing.plaf.synth; \
+ javax.swing.table; \
+ javax.swing.text; \
+ javax.swing.text.html; \
+ javax.swing.text.html.parser; \
+ javax.swing.text.rtf; \
+ javax.swing.tree; \
+ javax.swing.undo; \
+ org.ietf.jgss; \
+ org.omg.CORBA; \
+ org.omg.CORBA_2_3; \
+ org.omg.CORBA_2_3.portable; \
+ org.omg.CORBA.DynAnyPackage; \
+ org.omg.CORBA.ORBPackage; \
+ org.omg.CORBA.portable; \
+ org.omg.CORBA.TypeCodePackage; \
+ org.omg.CosNaming; \
+ org.omg.CosNaming.NamingContextExtPackage; \
+ org.omg.CosNaming.NamingContextPackage; \
+ org.omg.Dynamic; \
+ org.omg.DynamicAny; \
+ org.omg.DynamicAny.DynAnyFactoryPackage; \
+ org.omg.DynamicAny.DynAnyPackage; \
+ org.omg.IOP; \
+ org.omg.IOP.CodecFactoryPackage; \
+ org.omg.IOP.CodecPackage; \
+ org.omg.Messaging; \
+ org.omg.PortableInterceptor; \
+ org.omg.PortableInterceptor.ORBInitInfoPackage; \
+ org.omg.PortableServer; \
+ org.omg.PortableServer.CurrentPackage; \
+ org.omg.PortableServer.POAManagerPackage; \
+ org.omg.PortableServer.POAPackage; \
+ org.omg.PortableServer.portable; \
+ org.omg.PortableServer.ServantLocatorPackage; \
+ org.omg.SendingContext; \
+ org.omg.stub.java.rmi; \
+ org.omg.stub.javax.management.remote.rmi; \
+ sun.misc; \
+ sun.reflect; \
+ version="1.5.0"
+
+jre-1.6= \
+ javax.accessibility; \
+ javax.activation; \
+ javax.activity; \
+ javax.annotation; \
+ javax.annotation.processing; \
+ javax.crypto; \
+ javax.crypto.interfaces; \
+ javax.crypto.spec; \
+ javax.imageio; \
+ javax.imageio.event; \
+ javax.imageio.metadata; \
+ javax.imageio.plugins.bmp; \
+ javax.imageio.plugins.jpeg; \
+ javax.imageio.spi; \
+ javax.imageio.stream; \
+ javax.jws; \
+ javax.jws.soap; \
+ javax.lang; \
+ javax.lang.model; \
+ javax.lang.model.element; \
+ javax.lang.model.type; \
+ javax.lang.model.util; \
+ javax.management; \
+ javax.management.loading; \
+ javax.management.modelmbean; \
+ javax.management.monitor; \
+ javax.management.openmbean; \
+ javax.management.relation; \
+ javax.management.remote; \
+ javax.management.remote.rmi; \
+ javax.management.timer; \
+ javax.naming; \
+ javax.naming.directory; \
+ javax.naming.event; \
+ javax.naming.ldap; \
+ javax.naming.spi; \
+ javax.net; \
+ javax.net.ssl; \
+ javax.print; \
+ javax.print.attribute; \
+ javax.print.attribute.standard; \
+ javax.print.event; \
+ javax.rmi; \
+ javax.rmi.CORBA; \
+ javax.rmi.ssl; \
+ javax.script; \
+ javax.security.auth; \
+ javax.security.auth.callback; \
+ javax.security.auth.kerberos; \
+ javax.security.auth.login; \
+ javax.security.auth.spi; \
+ javax.security.auth.x500; \
+ javax.security.cert; \
+ javax.security.sasl; \
+ javax.sound.midi; \
+ javax.sound.midi.spi; \
+ javax.sound.sampled; \
+ javax.sound.sampled.spi; \
+ javax.sql; \
+ javax.sql.rowset; \
+ javax.sql.rowset.serial; \
+ javax.sql.rowset.spi; \
+ javax.swing; \
+ javax.swing.border; \
+ javax.swing.colorchooser; \
+ javax.swing.event; \
+ javax.swing.filechooser; \
+ javax.swing.plaf; \
+ javax.swing.plaf.basic; \
+ javax.swing.plaf.metal; \
+ javax.swing.plaf.multi; \
+ javax.swing.plaf.synth; \
+ javax.swing.table; \
+ javax.swing.text; \
+ javax.swing.text.html; \
+ javax.swing.text.html.parser; \
+ javax.swing.text.rtf; \
+ javax.swing.tree; \
+ javax.swing.undo; \
+ javax.tools; \
+ org.ietf.jgss; \
+ org.omg.CORBA; \
+ org.omg.CORBA_2_3; \
+ org.omg.CORBA_2_3.portable; \
+ org.omg.CORBA.DynAnyPackage; \
+ org.omg.CORBA.ORBPackage; \
+ org.omg.CORBA.portable; \
+ org.omg.CORBA.TypeCodePackage; \
+ org.omg.CosNaming; \
+ org.omg.CosNaming.NamingContextExtPackage; \
+ org.omg.CosNaming.NamingContextPackage; \
+ org.omg.Dynamic; \
+ org.omg.DynamicAny; \
+ org.omg.DynamicAny.DynAnyFactoryPackage; \
+ org.omg.DynamicAny.DynAnyPackage; \
+ org.omg.IOP; \
+ org.omg.IOP.CodecFactoryPackage; \
+ org.omg.IOP.CodecPackage; \
+ org.omg.Messaging; \
+ org.omg.PortableInterceptor; \
+ org.omg.PortableInterceptor.ORBInitInfoPackage; \
+ org.omg.PortableServer; \
+ org.omg.PortableServer.CurrentPackage; \
+ org.omg.PortableServer.POAManagerPackage; \
+ org.omg.PortableServer.POAPackage; \
+ org.omg.PortableServer.portable; \
+ org.omg.PortableServer.ServantLocatorPackage; \
+ org.omg.SendingContext; \
+ org.omg.stub.java.rmi; \
+ org.omg.stub.javax.management.remote.rmi; \
+ sun.misc; \
+ sun.reflect; \
+ version="1.6.0"
+
diff --git a/karaf/filemonitor/pom.xml b/karaf/filemonitor/pom.xml
new file mode 100644
index 0000000..58468bf
--- /dev/null
+++ b/karaf/filemonitor/pom.xml
@@ -0,0 +1,86 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <!--
+
+        Licensed to the Apache Software Foundation (ASF) under one or more
+        contributor license agreements.  See the NOTICE file distributed with
+        this work for additional information regarding copyright ownership.
+        The ASF licenses this file to You under the Apache License, Version 2.0
+        (the "License"); you may not use this file except in compliance with
+        the License.  You may obtain a copy of the License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software
+        distributed under the License is distributed on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        See the License for the specific language governing permissions and
+        limitations under the License.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.servicemix.kernel</groupId>
+        <artifactId>kernel</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.servicemix.kernel</groupId>
+    <artifactId>org.apache.servicemix.kernel.filemonitor</artifactId>
+    <packaging>bundle</packaging>
+    <version>1.2.0-SNAPSHOT</version>
+    <name>Apache ServiceMix Kernel :: File Monitor</name>
+
+    <description>This bundle monitors the deploy directory for new OSGi bundles in jar form, expanded form or for
+        configuration file changes and undeploys/redeploys them
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>commons-logging</groupId>
+            <artifactId>commons-logging</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+
+        <!-- testing -->
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.commons-io</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName>
+                        <Export-Package>${pom.artifactId}</Export-Package>
+                        <Bundle-Activator>org.apache.servicemix.kernel.filemonitor.FileMonitorActivator
+                        </Bundle-Activator>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
\ No newline at end of file
diff --git a/karaf/filemonitor/src/main/java/org/apache/servicemix/kernel/filemonitor/DeploymentListener.java b/karaf/filemonitor/src/main/java/org/apache/servicemix/kernel/filemonitor/DeploymentListener.java
new file mode 100644
index 0000000..6423561
--- /dev/null
+++ b/karaf/filemonitor/src/main/java/org/apache/servicemix/kernel/filemonitor/DeploymentListener.java
@@ -0,0 +1,36 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.filemonitor;
+
+import java.io.File;
+
+
+public interface DeploymentListener {
+	
+    /**
+     * Returns true if the listener can process the given file
+     */
+    boolean canHandle(File artifact);
+
+   /**
+    * Process the given file (canHandle returned true previously)
+    * Can return <null> or a pointer to a transformed file.
+    */
+    File handle(File artifact, File tmpDir);
+   
+}
diff --git a/karaf/filemonitor/src/main/java/org/apache/servicemix/kernel/filemonitor/FileMonitor.java b/karaf/filemonitor/src/main/java/org/apache/servicemix/kernel/filemonitor/FileMonitor.java
new file mode 100644
index 0000000..c0bf235
--- /dev/null
+++ b/karaf/filemonitor/src/main/java/org/apache/servicemix/kernel/filemonitor/FileMonitor.java
@@ -0,0 +1,767 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.filemonitor;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.jar.Attributes;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.packageadmin.PackageAdmin;
+import org.osgi.service.prefs.Preferences;
+import org.osgi.service.prefs.PreferencesService;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * Watches a deploy directory for files that are added, updated or removed then
+ * processing them. Currently we support OSGi bundles, OSGi configuration files
+ * and expanded directories of OSGi bundles.
+ * 
+ * @version $Revision: 1.1 $
+ */
+public class FileMonitor {
+
+    public final static String CONFIG_DIR = "org.apache.servicemix.filemonitor.configDir";
+    public final static String DEPLOY_DIR = "org.apache.servicemix.filemonitor.monitorDir";
+    public final static String GENERATED_JAR_DIR = "org.apache.servicemix.filemonitor.generatedJarDir";
+    public final static String SCAN_INTERVAL = "org.apache.servicemix.filemonitor.scanInterval";
+    public final static String PREFERENCE_KEY = "FileMonitor";
+
+    protected static final String ALIAS_KEY = "_alias_factory_pid";
+
+    private static final Log LOGGER = LogFactory.getLog(FileMonitor.class);
+
+    private FileMonitorActivator activator;
+    private File configDir;
+    private File deployDir;
+    private File generateDir;
+    private Scanner scanner = new Scanner();
+    private long scanInterval = 500L;
+    private boolean loggedConfigAdminWarning;
+    private List<Bundle> bundlesToStart = new ArrayList<Bundle>();
+    private List<Bundle> bundlesToUpdate = new ArrayList<Bundle>();
+    private Map<String, String> artifactToBundle = new HashMap<String, String>();
+    private final Set<String> pendingTransformationArtifacts = new HashSet<String>();
+    private final Set<Bundle> pendingStartBundles = new HashSet<Bundle>();
+    private ServiceListener deployerListener;
+    private BundleListener bundleListener;
+    private Executor executor;
+    private String pid;
+
+    public FileMonitor() {
+        String base = System.getProperty("servicemix.base", ".");
+        configDir = new File(base, "etc");
+        deployDir = new File(base, "deploy");
+        generateDir = new File(base, "data/generated-bundles");
+    }
+
+    @SuppressWarnings("unchecked")
+    public FileMonitor(FileMonitorActivator activator, Dictionary properties, String pid) {
+        this();
+
+        this.activator = activator;
+        this.pid = pid;
+
+        File value = getFileValue(properties, CONFIG_DIR);
+        if (value != null) {
+            configDir = value;
+        }
+        value = getFileValue(properties, DEPLOY_DIR);
+        if (value != null) {
+            deployDir = value;
+        }
+        value = getFileValue(properties, GENERATED_JAR_DIR);
+        if (value != null) {
+            generateDir = value;
+        }
+        Long i = getLongValue(properties, SCAN_INTERVAL);
+        if (i != null) {
+            scanInterval = i;
+        }
+    }
+
+    public void start() {
+        executor = Executors.newSingleThreadExecutor();
+        if (configDir != null) {
+            configDir.mkdirs();
+        }
+        deployDir.mkdirs();
+        generateDir.mkdirs();
+
+        List<File> dirs = new ArrayList<File>();
+        if (configDir != null) {
+            dirs.add(configDir);
+        }
+        dirs.add(deployDir);
+        scanner.setScanDirs(dirs);
+        scanner.setScanInterval(scanInterval);
+        // load the scan results for this monitor
+        loadScannerState();
+        scanner.addListener(new Scanner.BulkListener() {
+            public void filesChanged(List<String> filenames) throws Exception {
+                onFilesChanged(filenames);
+            }
+        });
+
+        LOGGER.info("Starting to monitor the deploy directory: " + deployDir + " every " + scanInterval
+                    + " millis");
+        if (configDir != null) {
+            LOGGER.info("Config directory is at: " + configDir);
+        }
+        LOGGER.info("Will generate bundles from expanded source directories to: " + generateDir);
+
+        executor.execute(new Runnable() {
+            public void run() {
+                scanner.start();
+            }
+        });
+    }
+
+    public void stop() {
+        // first stop the scanner
+        scanner.stop();
+        // load the scan results for this monitor
+        saveScannerState();
+    }
+
+    // Properties
+    // -------------------------------------------------------------------------
+
+    public BundleContext getContext() {
+        return activator.getContext();
+    }
+
+    public FileMonitorActivator getActivator() {
+        return activator;
+    }
+
+    public void setActivator(FileMonitorActivator activator) {
+        this.activator = activator;
+    }
+
+    public File getConfigDir() {
+        return configDir;
+    }
+
+    public void setConfigDir(File configDir) {
+        this.configDir = configDir;
+    }
+
+    public File getDeployDir() {
+        return deployDir;
+    }
+
+    public void setDeployDir(File deployDir) {
+        this.deployDir = deployDir;
+    }
+
+    public File getGenerateDir() {
+        return generateDir;
+    }
+
+    public void setGenerateDir(File generateDir) {
+        this.generateDir = generateDir;
+    }
+
+    public long getScanInterval() {
+        return scanInterval;
+    }
+
+    public void setScanInterval(long scanInterval) {
+        this.scanInterval = scanInterval;
+    }
+
+    // Implementation methods
+    // -------------------------------------------------------------------------
+
+    protected synchronized void onFilesChanged(Collection<String> filenames) {
+        bundlesToStart.clear();
+        bundlesToUpdate.clear();
+        Set<File> bundleJarsCreated = new HashSet<File>();
+
+        for (String filename : filenames) {
+            File file = new File(filename);
+            try {
+                LOGGER.debug("File changed: " + filename);
+
+                // Handle config files
+                if (isValidConfigFile(file)) {
+                    if (file.exists()) {
+                        updateConfiguration(file);
+                    } else {
+                        deleteConfiguration(file);
+                    }
+                    continue;
+                }
+
+                // Handle exploded artifacts removal
+                if (!file.exists() && file.getName().equals("MANIFEST.MF")) {
+                    File parentFile = file.getParentFile();
+                    if (parentFile.getName().equals("META-INF")) {
+                        File bundleDir = parentFile.getParentFile();
+                        if (isValidBundleSourceDirectory(bundleDir)) {
+                            undeployBundle(bundleDir);
+                            continue;
+                        }
+                    }
+                }
+
+                // Handle exploded artifacts add
+                File jardir = getExpandedBundleRootDirectory(file);
+                if (jardir != null) {
+                    if (bundleJarsCreated.contains(jardir)) {
+                        continue;
+                    }
+                    bundleJarsCreated.add(jardir);
+                    file = createBundleJar(jardir);
+                }
+
+                // Transformation step
+                if (file.exists()) {
+                    File f = transformArtifact(file);
+                    if (f == null) {
+                        LOGGER.warn("Unsupported deployment: " + filename);
+                        rescheduleTransformation(file);
+                        continue;
+                    }
+                    file = f;
+                } else {
+                    String transformedFile = artifactToBundle.get(filename);
+                    if (transformedFile != null) {
+                        file = new File(transformedFile);
+                        if (file.exists()) {
+                            file.delete();
+                        }
+                    }
+                }
+
+                // Handle final bundles
+                if (isValidArtifactFile(file)) {
+                    if (file.exists()) {
+                        deployBundle(file);
+                    } else {
+                        undeployBundle(file);
+                    }
+                }
+            } catch (Exception e) {
+                LOGGER.warn("Failed to process: " + file + ". Reason: " + e, e);
+            }
+        }
+        refreshPackagesAndStartOrUpdateBundles();
+    }
+
+    private void rescheduleTransformation(File file) {
+        synchronized (pendingTransformationArtifacts) {
+            pendingTransformationArtifacts.add(file.getAbsolutePath());
+        }
+        if (deployerListener == null) {
+            try {
+                String filter = "(" + Constants.OBJECTCLASS + "=" + DeploymentListener.class.getName() + ")";
+                deployerListener = new ServiceListener() {
+                    public void serviceChanged(ServiceEvent event) {
+                        executor.execute(new Runnable() {
+                            public void run() {
+                                Set<String> files;
+                                synchronized (pendingTransformationArtifacts) {
+                                    files = new HashSet<String>(pendingTransformationArtifacts);
+                                    pendingTransformationArtifacts.clear();
+                                }
+                                onFilesChanged(files);
+                            }
+                        });
+                    }
+                };
+                getContext().addServiceListener(deployerListener, filter);
+            } catch (InvalidSyntaxException e) {
+                // Ignore
+            }
+        }
+    }
+
+    private File transformArtifact(File file) throws Exception {
+        // Check registered deployers
+        ServiceReference[] srvRefs = getContext().getAllServiceReferences(DeploymentListener.class.getName(),
+                                                                          null);
+        if (srvRefs != null) {
+            for (ServiceReference sr : srvRefs) {
+                try {
+                    DeploymentListener deploymentListener = (DeploymentListener)getContext().getService(sr);
+                    if (deploymentListener.canHandle(file)) {
+                        File transformedFile = deploymentListener.handle(file, getGenerateDir());
+                        artifactToBundle.put(file.getAbsolutePath(), transformedFile.getAbsolutePath());
+                        return transformedFile;
+                    }
+                } finally {
+                    getContext().ungetService(sr);
+                }
+            }
+        }
+        JarFile jar = null;
+        try {
+            // Handle OSGi bundles with the default deployer
+            if (file.getName().endsWith("txt") || file.getName().endsWith("xml")
+                || file.getName().endsWith("properties")) {
+                // that's file type which is not supported as bundle and avoid
+                // exception in the log
+                return null;
+            }
+            jar = new JarFile(file);
+            Manifest m = jar.getManifest();
+            if (m.getMainAttributes().getValue(new Attributes.Name("Bundle-SymbolicName")) != null
+                && m.getMainAttributes().getValue(new Attributes.Name("Bundle-Version")) != null) {
+                return file;
+            }
+        } catch (Exception e) {
+            LOGGER.debug("Error transforming artifact " + file.getName(), e);
+        } finally {
+            if (jar != null) {
+                jar.close();
+            }
+        }
+        return null;
+    }
+
+    protected void deployBundle(File file) throws IOException, BundleException {
+        LOGGER.info("Deploying: " + file.getCanonicalPath());
+
+        InputStream in = new FileInputStream(file);
+
+        try {
+            Bundle bundle = getBundleForJarFile(file);
+            if (bundle != null) {
+                bundlesToUpdate.add(bundle);
+            } else {
+                bundle = getContext().installBundle(file.getCanonicalFile().toURI().toString(), in);
+                if (!isBundleFragment(bundle)) {
+                    bundlesToStart.add(bundle);
+                }
+            }
+        } finally {
+            closeQuietly(in);
+        }
+    }
+
+    protected void undeployBundle(File file) throws BundleException, IOException {
+        LOGGER.info("Undeploying: " + file.getCanonicalPath());
+        Bundle bundle = getBundleForJarFile(file);
+
+        if (bundle == null) {
+            LOGGER.warn("Could not find Bundle for file: " + file.getCanonicalPath());
+        } else {
+            if (!isBundleFragment(bundle)) {
+                bundle.stop();
+            }
+            bundle.uninstall();
+        }
+    }
+
+    protected Bundle getBundleForJarFile(File file) throws IOException {
+        String absoluteFilePath = file.getAbsoluteFile().toURI().toString();
+        Bundle bundles[] = getContext().getBundles();
+        for (Bundle bundle : bundles) {
+            String location = bundle.getLocation();
+            if (filePathsMatch(absoluteFilePath, location)) {
+                return bundle;
+            }
+        }
+        return null;
+    }
+
+    protected static boolean filePathsMatch(String p1, String p2) {
+        p1 = normalizeFilePath(p1);
+        p2 = normalizeFilePath(p2);
+        return (p1 != null && p1.equalsIgnoreCase(p2));
+    }
+
+    protected static String normalizeFilePath(String path) {
+        if (path != null) {
+            path = path.replaceFirst("file:/*", "");
+            path = path.replaceAll("[\\\\/]+", "/");
+        }
+        return path;
+    }
+
+    protected void updateConfiguration(File file) throws IOException, InvalidSyntaxException {
+        ConfigurationAdmin configurationAdmin = activator.getConfigurationAdmin();
+        if (configurationAdmin == null) {
+            if (!loggedConfigAdminWarning) {
+                LOGGER.warn("No ConfigurationAdmin so cannot deploy configurations");
+                loggedConfigAdminWarning = true;
+            }
+        } else {
+            Properties properties = new Properties();
+            InputStream in = new FileInputStream(file);
+            try {
+                properties.load(in);
+                interpolation(properties);
+                closeQuietly(in);
+                String[] pid = parsePid(file);
+                Hashtable<Object, Object> hashtable = new Hashtable<Object, Object>();
+                hashtable.putAll(properties);
+                if (pid[1] != null) {
+                    hashtable.put(ALIAS_KEY, pid[1]);
+                }
+
+                Configuration config = getConfiguration(pid[0], pid[1]);
+                if (config.getBundleLocation() != null) {
+                    config.setBundleLocation(null);
+                }
+                config.update(hashtable);
+            } finally {
+                closeQuietly(in);
+            }
+        }
+    }
+
+    protected void interpolation(Properties properties) {
+        for (Enumeration e = properties.propertyNames(); e.hasMoreElements();) {
+            String key = (String)e.nextElement();
+            String val = properties.getProperty(key);
+            Matcher matcher = Pattern.compile("\\$\\{([^}]+)\\}").matcher(val);
+            while (matcher.find()) {
+                String rep = System.getProperty(matcher.group(1));
+                if (rep != null) {
+                    val = val.replace(matcher.group(0), rep);
+                    matcher.reset(val);
+                }
+            }
+            properties.put(key, val);
+        }
+    }
+
+    protected void deleteConfiguration(File file) throws IOException, InvalidSyntaxException {
+        String[] pid = parsePid(file);
+        Configuration config = getConfiguration(pid[0], pid[1]);
+        config.delete();
+    }
+
+    protected Configuration getConfiguration(String pid, String factoryPid) throws IOException,
+        InvalidSyntaxException {
+        ConfigurationAdmin configurationAdmin = activator.getConfigurationAdmin();
+        if (factoryPid != null) {
+            Configuration[] configs = configurationAdmin.listConfigurations("(|(" + ALIAS_KEY + "=" + pid
+                                                                            + ")(.alias_factory_pid="
+                                                                            + factoryPid + "))");
+            if (configs == null || configs.length == 0) {
+                return configurationAdmin.createFactoryConfiguration(pid, null);
+            } else {
+                return configs[0];
+            }
+        } else {
+            return configurationAdmin.getConfiguration(pid, null);
+        }
+    }
+
+    protected String[] parsePid(File file) {
+        String path = file.getName();
+        String pid = path.substring(0, path.length() - 4);
+        int n = pid.indexOf('-');
+        if (n > 0) {
+            String factoryPid = pid.substring(n + 1);
+            pid = pid.substring(0, n);
+            return new String[] {pid, factoryPid};
+        } else {
+            return new String[] {pid, null};
+        }
+    }
+
+    protected PackageAdmin getPackageAdmin() {
+        ServiceTracker packageAdminTracker = activator.getPackageAdminTracker();
+        if (packageAdminTracker != null) {
+            try {
+                return (PackageAdmin)packageAdminTracker.waitForService(5000L);
+            } catch (InterruptedException e) {
+                // ignore
+            }
+        }
+        return null;
+    }
+
+    protected boolean isBundleFragment(Bundle bundle) {
+        PackageAdmin packageAdmin = getPackageAdmin();
+        if (packageAdmin != null) {
+            return packageAdmin.getBundleType(bundle) == PackageAdmin.BUNDLE_TYPE_FRAGMENT;
+        }
+        return false;
+    }
+
+    protected void refreshPackagesAndStartOrUpdateBundles() {
+        for (Bundle bundle : bundlesToUpdate) {
+            try {
+                bundle.update();
+                LOGGER.info("Updated: " + bundle);
+            } catch (BundleException e) {
+                LOGGER.warn("Failed to update bundle: " + bundle + ". Reason: " + e, e);
+            }
+        }
+
+        for (Bundle bundle : bundlesToStart) {
+            try {
+                bundle.start();
+                LOGGER.info("Started: " + bundle);
+            } catch (BundleException e) {
+                LOGGER.warn("Failed to start bundle: " + bundle + ". Reason: " + e, e);
+                rescheduleStart(bundle);
+            }
+        }
+
+        PackageAdmin packageAdmin = getPackageAdmin();
+        if (packageAdmin != null) {
+            packageAdmin.refreshPackages(null);
+        }
+    }
+
+    private void rescheduleStart(Bundle bundle) {
+        synchronized (pendingStartBundles) {
+            pendingStartBundles.add(bundle);
+            if (bundleListener == null) {
+                bundleListener = new BundleListener() {
+                    public void bundleChanged(BundleEvent event) {
+                        if (event.getType() == BundleEvent.RESOLVED) {
+                            executor.execute(new Runnable() {
+                                public void run() {
+                                    retryPendingStartBundles();
+                                }
+                            });
+                        } else if (event.getType() == BundleEvent.UNINSTALLED) {
+                        	// bundle was uninstalled meanwhile, so remove
+                        	// it from the list of pending bundles
+                        	pendingStartBundles.remove(event.getBundle());
+                        }
+                    }
+                };
+                getContext().addBundleListener(bundleListener);
+            }
+        }
+    }
+
+    protected void retryPendingStartBundles() {
+        synchronized (pendingStartBundles) {
+            Set<Bundle> bundles = new HashSet<Bundle>();
+            bundles.addAll(pendingStartBundles);
+            pendingStartBundles.clear();
+            boolean success = false;
+            for (Bundle bundle : bundles) {
+                try {
+                    bundle.start();
+                    LOGGER.info("Pending bundle started: " + bundle);
+                    success = true;
+                } catch (BundleException e) {
+                    LOGGER.info("Pending bundle not started: " + bundle);
+                    pendingStartBundles.add(bundle);
+                }
+            }
+            if (success) {
+                PackageAdmin packageAdmin = getPackageAdmin();
+                if (packageAdmin != null) {
+                    packageAdmin.refreshPackages(null);
+                }
+            }
+        }
+    }
+
+    protected File createBundleJar(File dir) throws BundleException, IOException {
+        File destFile = new File(generateDir, dir.getName() + ".jar");
+        if (destFile.exists()) {
+            undeployBundle(destFile);
+            destFile.delete();
+        }
+        JarUtil.jarDir(dir.getPath(), destFile.getPath());
+        return destFile;
+    }
+
+    /**
+     * Returns the root directory of the expanded OSGi bundle if the file is
+     * part of an expanded OSGi bundle or null if it is not
+     */
+    protected File getExpandedBundleRootDirectory(File file) throws IOException {
+        File parent = file.getParentFile();
+        if (file.isDirectory()) {
+            String rootPath = deployDir.getCanonicalPath();
+            if (file.getCanonicalPath().equals(rootPath)) {
+                return null;
+            }
+            if (containsManifest(file)) {
+                return file;
+            }
+        }
+        if (isValidBundleSourceDirectory(parent)) {
+            return getExpandedBundleRootDirectory(parent);
+        }
+        return null;
+    }
+
+    /**
+     * Returns true if the given directory is a valid child directory within the
+     * {@link #deployDir}
+     */
+    protected boolean isValidBundleSourceDirectory(File dir) throws IOException {
+        if (dir != null) {
+            String parentPath = dir.getCanonicalPath();
+            String rootPath = deployDir.getCanonicalPath();
+            return !parentPath.equals(rootPath) && parentPath.startsWith(rootPath);
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Returns true if the given directory is a valid child file within the
+     * {@link #deployDir} or a child of {@link #generateDir}
+     */
+    protected boolean isValidArtifactFile(File file) throws IOException {
+        if (file != null) {
+            String filePath = file.getParentFile().getCanonicalPath();
+            String deployPath = deployDir.getCanonicalPath();
+            String generatePath = generateDir.getCanonicalPath();
+            return filePath.equals(deployPath) || filePath.startsWith(generatePath);
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Returns true if the given directory is a valid child file within the
+     * {@link #configDir}
+     */
+    protected boolean isValidConfigFile(File file) throws IOException {
+        if (file != null && file.getName().endsWith(".cfg")) {
+            String filePath = file.getParentFile().getCanonicalPath();
+            String configPath = configDir.getCanonicalPath();
+            return filePath.equals(configPath);
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Returns true if the given directory contains a valid manifest file
+     */
+    protected boolean containsManifest(File dir) {
+        File metaInfDir = new File(dir, "META-INF");
+        if (metaInfDir.exists() && metaInfDir.isDirectory()) {
+            File manifest = new File(metaInfDir, "MANIFEST.MF");
+            return manifest.exists() && !manifest.isDirectory();
+        }
+        return false;
+    }
+
+    @SuppressWarnings("unchecked")
+    protected File getFileValue(Dictionary properties, String key) {
+        Object value = properties.get(key);
+        if (value instanceof File) {
+            return (File)value;
+        } else if (value != null) {
+            return new File(value.toString());
+        }
+        return null;
+    }
+
+    @SuppressWarnings("unchecked")
+    protected Long getLongValue(Dictionary properties, String key) {
+        Object value = properties.get(key);
+        if (value instanceof Long) {
+            return (Long)value;
+        } else if (value != null) {
+            return Long.parseLong(value.toString());
+        }
+        return null;
+    }
+
+    protected void closeQuietly(Closeable in) {
+        try {
+            in.close();
+        } catch (IOException e) {
+            LOGGER.warn("Failed to close stream. " + e, e);
+        }
+    }
+
+    protected PreferencesService getPreferenceService() {
+        if (activator.getPreferenceServiceTracker() != null) {
+            try {
+                return (PreferencesService)activator.getPreferenceServiceTracker().waitForService(5000L);
+            } catch (InterruptedException e) {
+                // ignore
+            }
+        }
+        return null;
+    }
+
+    protected void saveScannerState() {
+        try {
+            Map<String, Long> results = scanner.getLastScanResults();
+            Preferences prefs = getPreferenceService().getUserPreferences(PREFERENCE_KEY).node(pid);
+            Iterator<String> it = results.keySet().iterator();
+            while (it.hasNext()) {
+                String key = it.next();
+                Long value = results.get(key);
+                prefs.putLong(key, value);
+            }
+            prefs.flush();
+        } catch (Exception e) {
+            LOGGER.error("Error persisting FileMonitor state", e);
+        }
+    }
+
+    protected void loadScannerState() {
+        try {
+            Preferences prefs = getPreferenceService().getUserPreferences(PREFERENCE_KEY).node(pid);
+            Map<String, Long> lastResult = new HashMap<String, Long>();
+            for (String key : prefs.keys()) {
+                lastResult.put(key, prefs.getLong(key, -1));
+            }
+            scanner.setLastScanResults(lastResult);
+        } catch (Exception e) {
+            LOGGER.error("Error loading FileMonitor state", e);
+        }
+    }
+}
diff --git a/karaf/filemonitor/src/main/java/org/apache/servicemix/kernel/filemonitor/FileMonitorActivator.java b/karaf/filemonitor/src/main/java/org/apache/servicemix/kernel/filemonitor/FileMonitorActivator.java
new file mode 100644
index 0000000..82dea71
--- /dev/null
+++ b/karaf/filemonitor/src/main/java/org/apache/servicemix/kernel/filemonitor/FileMonitorActivator.java
@@ -0,0 +1,146 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.filemonitor;
+
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedServiceFactory;
+import org.osgi.service.packageadmin.PackageAdmin;
+import org.osgi.service.prefs.PreferencesService;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * Inspired by <a href="http://www.aqute.biz/Code/FileInstall">FileInstall</a>
+ * by Peter Kriens.
+ * 
+ * @version $Revision: 1.1 $
+ */
+public class FileMonitorActivator implements BundleActivator, ManagedServiceFactory {
+    private static final Log LOGGER = LogFactory.getLog(FileMonitorActivator.class);
+
+    private BundleContext context;
+    private ServiceTracker packageAdminTracker;
+    private ServiceTracker configurationAdminTracker;
+    private ServiceTracker preferenceServiceTracker;
+    private Map<String, FileMonitor> fileMonitors = new HashMap<String, FileMonitor>();
+
+    // BundleActivator interface
+    // -------------------------------------------------------------------------
+    public void start(BundleContext context) throws Exception {
+        this.context = context;
+
+        Hashtable properties = new Hashtable();
+        properties.put(Constants.SERVICE_PID, getName());
+        context.registerService(ManagedServiceFactory.class.getName(), this, properties);
+
+        packageAdminTracker = new ServiceTracker(context, PackageAdmin.class.getName(), null);
+        packageAdminTracker.open();
+
+        configurationAdminTracker = new ServiceTracker(context, ConfigurationAdmin.class.getName(), null);
+        configurationAdminTracker.open();
+
+        preferenceServiceTracker = new ServiceTracker(context, PreferencesService.class.getName(), null);
+        preferenceServiceTracker.open();
+
+        Hashtable initialProperties = new Hashtable();
+        setPropertiesFromContext(initialProperties, FileMonitor.CONFIG_DIR, FileMonitor.DEPLOY_DIR,
+                                 FileMonitor.GENERATED_JAR_DIR, FileMonitor.SCAN_INTERVAL);
+        updated("initialPid", initialProperties);
+    }
+
+    public void stop(BundleContext context) throws Exception {
+        Collection<FileMonitor> fileMonitors = this.fileMonitors.values();
+        for (FileMonitor monitor : fileMonitors) {
+            try {
+                // stop the monitor
+                monitor.stop();
+            } catch (Exception e) {
+                // Ignore
+            }
+        }
+        this.fileMonitors.clear();
+
+        preferenceServiceTracker.close();
+        configurationAdminTracker.close();
+        packageAdminTracker.close();
+    }
+
+    // ManagedServiceFactory interface
+    // -------------------------------------------------------------------------
+    public String getName() {
+        return "org.apache.servicemix.kernel.filemonitor.FileMonitor";
+    }
+
+    public void updated(String pid, Dictionary properties) throws ConfigurationException {
+        deleted(pid);
+        FileMonitor monitor = new FileMonitor(this, properties, pid);
+        fileMonitors.put(pid, monitor);
+        monitor.start();
+    }
+
+    public void deleted(String pid) {
+        FileMonitor monitor = fileMonitors.remove(pid);
+        if (monitor != null) {
+            monitor.stop();
+        }
+    }
+
+    // Properties
+    // -------------------------------------------------------------------------
+    public BundleContext getContext() {
+        return context;
+    }
+
+    public ServiceTracker getConfigurationAdminTracker() {
+        return configurationAdminTracker;
+    }
+
+    public ServiceTracker getPackageAdminTracker() {
+        return packageAdminTracker;
+    }
+
+    public ConfigurationAdmin getConfigurationAdmin() {
+        return (ConfigurationAdmin)getConfigurationAdminTracker().getService();
+    }
+
+    public ServiceTracker getPreferenceServiceTracker() {
+        return preferenceServiceTracker;
+    }
+
+    // Implementation methods
+    // -------------------------------------------------------------------------
+    protected void setPropertiesFromContext(Hashtable properties, String... keys) {
+        for (String key : keys) {
+            Object value = context.getProperty(key);
+            if (value != null) {
+                properties.put(key, value);
+            }
+        }
+    }
+}
diff --git a/karaf/filemonitor/src/main/java/org/apache/servicemix/kernel/filemonitor/JarUtil.java b/karaf/filemonitor/src/main/java/org/apache/servicemix/kernel/filemonitor/JarUtil.java
new file mode 100644
index 0000000..98b6036
--- /dev/null
+++ b/karaf/filemonitor/src/main/java/org/apache/servicemix/kernel/filemonitor/JarUtil.java
@@ -0,0 +1,122 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.filemonitor;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Set;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+public class JarUtil {
+
+    /**
+     * Zip up a directory
+     *
+     * @param directory
+     * @param zipName
+     * @throws IOException
+     */
+    public static void zipDir(String directory, String zipName) throws IOException {
+        // create a ZipOutputStream to zip the data to
+        ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipName)));
+        String path = "";
+        zipDir(directory, zos, path, Collections.<String>emptySet());
+        // close the stream
+        zos.close();
+    }
+
+    /**
+     * Jar up a directory
+     *
+     * @param directory
+     * @param zipName
+     * @throws IOException
+     */
+    public static void jarDir(String directory, String zipName) throws IOException {
+        // create a ZipOutputStream to zip the data to
+        JarOutputStream zos = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(zipName)));
+        String path = "";
+        File manFile = new File(directory, JarFile.MANIFEST_NAME);
+        if (manFile.exists()) {
+            byte[] readBuffer = new byte[8192];
+            FileInputStream fis = new FileInputStream(manFile);
+            try {
+                ZipEntry anEntry = new ZipEntry(JarFile.MANIFEST_NAME);
+                zos.putNextEntry(anEntry);
+                int bytesIn = fis.read(readBuffer);
+                while (bytesIn != -1) {
+                    zos.write(readBuffer, 0, bytesIn);
+                    bytesIn = fis.read(readBuffer);
+                }
+            } finally {
+                fis.close();
+            }
+            zos.closeEntry();
+        }
+        zipDir(directory, zos, path, Collections.singleton(JarFile.MANIFEST_NAME));
+        // close the stream
+        zos.close();
+    }
+
+    /**
+     * Zip up a directory path
+     * @param directory
+     * @param zos
+     * @param path
+     * @throws IOException
+     */
+    public static void zipDir(String directory, ZipOutputStream zos, String path, Set<String> exclusions) throws IOException {
+        File zipDir = new File(directory);
+        // get a listing of the directory content
+        String[] dirList = zipDir.list();
+        byte[] readBuffer = new byte[8192];
+        int bytesIn = 0;
+        // loop through dirList, and zip the files
+        for (int i = 0; i < dirList.length; i++) {
+            File f = new File(zipDir, dirList[i]);
+            if (f.isDirectory()) {
+                String filePath = f.getPath();
+                zipDir(filePath, zos, path + f.getName() + "/", exclusions);
+                continue;
+            }
+            String entry = path + f.getName();
+            if (!exclusions.contains(entry)) {
+                FileInputStream fis = new FileInputStream(f);
+                try {
+                    ZipEntry anEntry = new ZipEntry(entry);
+                    zos.putNextEntry(anEntry);
+                    bytesIn = fis.read(readBuffer);
+                    while (bytesIn != -1) {
+                        zos.write(readBuffer, 0, bytesIn);
+                        bytesIn = fis.read(readBuffer);
+                    }
+                } finally {
+                    fis.close();
+                }
+            }
+        }
+    }
+
+}
diff --git a/karaf/filemonitor/src/main/java/org/apache/servicemix/kernel/filemonitor/Scanner.java b/karaf/filemonitor/src/main/java/org/apache/servicemix/kernel/filemonitor/Scanner.java
new file mode 100644
index 0000000..8b25226
--- /dev/null
+++ b/karaf/filemonitor/src/main/java/org/apache/servicemix/kernel/filemonitor/Scanner.java
@@ -0,0 +1,455 @@
+//========================================================================
+//$Id: Scanner.java 2180 2007-10-31 04:01:26Z janb $
+//Copyright 2006 Mort Bay Consulting Pty. Ltd.
+//------------------------------------------------------------------------
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//http://www.apache.org/licenses/LICENSE-2.0
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+//========================================================================
+package org.apache.servicemix.kernel.filemonitor;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Scanner
+ * <p/>
+ * Utility for scanning a directory for added, removed and changed files and
+ * reporting these events via registered Listeners.
+ * <p/>
+ * From the <a href="http://jetty.codehaus.org/">Jetty Util project</a>
+ * 
+ * @version $Revision: 1.1 $
+ */
+public class Scanner {
+
+    private static Log logger = LogFactory.getLog(Scanner.class);
+    private long _scanInterval;
+    private List<Listener> _listeners = Collections.synchronizedList(new ArrayList<Listener>());
+    private Map<String, Long> _prevScan = new HashMap<String, Long>();
+    private FilenameFilter _filter;
+    private List<File> _scanDirs;
+    private volatile boolean _running = false;
+    private boolean _reportExisting = true;
+    private Timer _timer;
+    private TimerTask _task;
+
+    /**
+     * Listener
+     * <p/>
+     * Marker for notifications re file changes.
+     */
+    public interface Listener {
+    }
+
+    public interface DiscreteListener extends Listener {
+        public void fileChanged(String filename) throws Exception;
+
+        public void fileAdded(String filename) throws Exception;
+
+        public void fileRemoved(String filename) throws Exception;
+    }
+
+    public interface BulkListener extends Listener {
+        public void filesChanged(List<String> filenames) throws Exception;
+    }
+
+    /**
+     *
+     */
+    public Scanner() {
+    }
+
+    /**
+     * Get the scan interval
+     * 
+     * @return interval between scans in millis
+     */
+    public long getScanInterval() {
+        return _scanInterval;
+    }
+
+    /**
+     * Set the scan interval
+     * 
+     * @param scanInterval pause between scans in millis
+     */
+    public synchronized void setScanInterval(long scanInterval) {
+        this._scanInterval = scanInterval;
+
+        if (_running) {
+            stop();
+
+            _timer = newTimer();
+            _task = newTimerTask();
+
+            schedule(_timer, _task);
+            _running = true;
+        }
+    }
+
+    /**
+     * Set the location of the directory to scan.
+     * 
+     * @param dir
+     * @deprecated use setScanDirs(List dirs) instead
+     */
+    public void setScanDir(File dir) {
+        _scanDirs = new ArrayList<File>();
+        _scanDirs.add(dir);
+    }
+
+    /**
+     * Get the location of the directory to scan
+     * 
+     * @return
+     * @deprecated use getScanDirs() instead
+     */
+    public File getScanDir() {
+        return (_scanDirs == null ? null : (File)_scanDirs.get(0));
+    }
+
+    public void setScanDirs(List<File> dirs) {
+        _scanDirs = dirs;
+    }
+
+    public List<File> getScanDirs() {
+        return _scanDirs;
+    }
+
+    /**
+     * Apply a filter to files found in the scan directory. Only files matching
+     * the filter will be reported as added/changed/removed.
+     * 
+     * @param filter
+     */
+    public void setFilenameFilter(FilenameFilter filter) {
+        this._filter = filter;
+    }
+
+    /**
+     * Get any filter applied to files in the scan dir.
+     * 
+     * @return
+     */
+    public FilenameFilter getFilenameFilter() {
+        return _filter;
+    }
+
+    /**
+     * Whether or not an initial scan will report all files as being added.
+     * 
+     * @param reportExisting if true, all files found on initial scan will be
+     *            reported as being added, otherwise not
+     */
+    public void setReportExistingFilesOnStartup(boolean reportExisting) {
+        this._reportExisting = reportExisting;
+    }
+
+    /**
+     * Add an added/removed/changed listener
+     * 
+     * @param listener
+     */
+    public synchronized void addListener(Listener listener) {
+        if (listener == null) {
+            return;
+        }
+
+        _listeners.add(listener);
+    }
+
+    /**
+     * Remove a registered listener
+     * 
+     * @param listener the Listener to be removed
+     */
+    public synchronized void removeListener(Listener listener) {
+        if (listener == null) {
+            return;
+        }
+        _listeners.remove(listener);
+    }
+
+    /**
+     * Start the scanning action.
+     */
+    public synchronized void start() {
+        if (_running) {
+            return;
+        }
+
+        _running = true;
+
+        if (_reportExisting) {
+            // if files exist at startup, report them
+            scan();
+        } else {
+            // just register the list of existing files and only report changes
+            _prevScan = scanFiles();
+        }
+
+        _timer = newTimer();
+        _task = newTimerTask();
+
+        schedule(_timer, _task);
+    }
+
+    public TimerTask newTimerTask() {
+        return new TimerTask() {
+            public void run() {
+                scan();
+            }
+        };
+    }
+
+    public Timer newTimer() {
+        return new Timer(true);
+    }
+
+    public void schedule(Timer timer, TimerTask task) {
+        if (timer == null) {
+            throw new IllegalArgumentException("Timer is null");
+        }
+        if (task == null) {
+            throw new IllegalArgumentException("TimerTask is null");
+        }
+
+        if (getScanInterval() > 0) {
+            timer.scheduleAtFixedRate(task, getScanInterval(), getScanInterval());
+        }
+    }
+
+    /**
+     * Stop the scanning.
+     */
+    public synchronized void stop() {
+        if (_running) {
+            _running = false;
+            _timer.cancel();
+            _task.cancel();
+            _task = null;
+            _timer = null;
+        }
+    }
+
+    /**
+     * Perform a pass of the scanner and report changes
+     */
+    public void scan() {
+        Map<String, Long> currentScan = scanFiles();
+        reportDifferences(currentScan, _prevScan);
+        _prevScan = currentScan;
+    }
+
+    /**
+     * Recursively scan all files in the designated directories.
+     * 
+     * @return Map of name of file to last modified time
+     */
+    public Map<String, Long> scanFiles() {
+        if (_scanDirs == null) {
+            return Collections.emptyMap();
+        }
+
+        HashMap<String, Long> scanInfo = new HashMap<String, Long>();
+        Iterator<File> itor = _scanDirs.iterator();
+        while (itor.hasNext()) {
+            File dir = (File)itor.next();
+
+            if ((dir != null) && (dir.exists())) {
+                scanFile(dir, scanInfo);
+            }
+        }
+
+        return scanInfo;
+    }
+
+    /**
+     * Report the adds/changes/removes to the registered listeners
+     * 
+     * @param currentScan the info from the most recent pass
+     * @param oldScan info from the previous pass
+     */
+    public void reportDifferences(Map<String, Long> currentScan, Map<String, Long> oldScan) {
+        List<String> bulkChanges = new ArrayList<String>();
+
+        Set<String> oldScanKeys = new HashSet<String>(oldScan.keySet());
+        Iterator<Map.Entry<String, Long>> itor = currentScan.entrySet().iterator();
+        while (itor.hasNext()) {
+            Map.Entry<String, Long> entry = itor.next();
+            if (!oldScanKeys.contains(entry.getKey())) {
+                logger.debug("File added: " + entry.getKey());
+                reportAddition(entry.getKey());
+                bulkChanges.add(entry.getKey());
+            } else if (!oldScan.get(entry.getKey()).equals(entry.getValue())) {
+                logger.debug("File changed: " + entry.getKey());
+                reportChange(entry.getKey());
+                oldScanKeys.remove(entry.getKey());
+                bulkChanges.add(entry.getKey());
+            } else {
+                oldScanKeys.remove(entry.getKey());
+            }
+        }
+
+        if (!oldScanKeys.isEmpty()) {
+
+            Iterator<String> keyItor = oldScanKeys.iterator();
+            while (keyItor.hasNext()) {
+                String filename = keyItor.next();
+                logger.debug("File removed: " + filename);
+                reportRemoval(filename);
+                bulkChanges.add(filename);
+            }
+        }
+
+        if (!bulkChanges.isEmpty()) {
+            reportBulkChanges(bulkChanges);
+        }
+    }
+
+    /**
+     * Get last modified time on a single file or recurse if the file is a
+     * directory.
+     * 
+     * @param f file or directory
+     * @param scanInfoMap map of filenames to last modified times
+     */
+    private void scanFile(File f, Map<String, Long> scanInfoMap) {
+        try {
+            if (!f.exists()) {
+                return;
+            }
+
+            if (f.isFile()) {
+                if ((_filter == null)
+                    || ((_filter != null) && _filter.accept(f.getParentFile(), f.getName()))) {
+                    String name = f.getCanonicalPath();
+                    long lastModified = f.lastModified();
+                    scanInfoMap.put(name, new Long(lastModified));
+                }
+            } else if (f.isDirectory()) {
+                File[] files = f.listFiles();
+                for (int i = 0; i < files.length; i++) {
+                    scanFile(files[i], scanInfoMap);
+                }
+            }
+        } catch (IOException e) {
+            logger.warn("Error scanning watched files", e);
+        }
+    }
+
+    /**
+     * Report a file addition to the registered FileAddedListeners
+     * 
+     * @param filename
+     */
+    private void reportAddition(String filename) {
+        Iterator<Listener> itor = _listeners.iterator();
+        while (itor.hasNext()) {
+            try {
+                Listener l = itor.next();
+                if (l instanceof DiscreteListener) {
+                    ((DiscreteListener)l).fileAdded(filename);
+                }
+            } catch (Exception e) {
+                logger.warn(e);
+            } catch (Error e) {
+                logger.warn(e);
+            }
+        }
+    }
+
+    /**
+     * Report a file removal to the FileRemovedListeners
+     * 
+     * @param filename
+     */
+    private void reportRemoval(String filename) {
+        Iterator<Listener> itor = _listeners.iterator();
+        while (itor.hasNext()) {
+            try {
+                Listener l = itor.next();
+                if (l instanceof DiscreteListener) {
+                    ((DiscreteListener)l).fileRemoved(filename);
+                }
+            } catch (Exception e) {
+                logger.warn(e);
+            } catch (Error e) {
+                logger.warn(e);
+            }
+        }
+    }
+
+    /**
+     * Report a file change to the FileChangedListeners
+     * 
+     * @param filename
+     */
+    private void reportChange(String filename) {
+        Iterator<Listener> itor = _listeners.iterator();
+        while (itor.hasNext()) {
+            try {
+                Listener l = itor.next();
+                if (l instanceof DiscreteListener) {
+                    ((DiscreteListener)l).fileChanged(filename);
+                }
+            } catch (Exception e) {
+                logger.warn(e);
+            } catch (Error e) {
+                logger.warn(e);
+            }
+        }
+    }
+
+    private void reportBulkChanges(List<String> filenames) {
+        Iterator<Listener> itor = _listeners.iterator();
+        while (itor.hasNext()) {
+            try {
+                Listener l = itor.next();
+                if (l instanceof BulkListener) {
+                    ((BulkListener)l).filesChanged(filenames);
+                }
+            } catch (Exception e) {
+                logger.warn(e);
+            } catch (Error e) {
+                logger.warn(e);
+            }
+        }
+    }
+
+    protected Map<String, Long> getLastScanResults() {
+        Map<String, Long> result = new HashMap<String, Long>();
+        synchronized (_prevScan) {
+            result.putAll(_prevScan);
+        }
+        return result;
+    }
+
+    protected void setLastScanResults(Map<String, Long> results) {
+        synchronized (_prevScan) {
+            _prevScan.clear();
+            _prevScan.putAll(results);
+        }
+    }
+}
diff --git a/karaf/filemonitor/src/test/data/camel-example-spring/META-INF/LICENSE.txt b/karaf/filemonitor/src/test/data/camel-example-spring/META-INF/LICENSE.txt
new file mode 100644
index 0000000..6b0b127
--- /dev/null
+++ b/karaf/filemonitor/src/test/data/camel-example-spring/META-INF/LICENSE.txt
@@ -0,0 +1,203 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.
+
diff --git a/karaf/filemonitor/src/test/data/camel-example-spring/META-INF/MANIFEST.MF b/karaf/filemonitor/src/test/data/camel-example-spring/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..15e6aae
--- /dev/null
+++ b/karaf/filemonitor/src/test/data/camel-example-spring/META-INF/MANIFEST.MF
@@ -0,0 +1,24 @@
+Manifest-Version: 1.0
+Created-By: 1.5.0_07 (Apple Computer, Inc.)
+Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt
+Import-Package: org.apache.camel.builder,org.apache.camel.example.spri
+ ng;version=1.3.0.SNAPSHOT,org.apache.camel.model,org.apache.camel.spr
+ ing
+Include-Resource: src/main/resources
+Bnd-LastModified: 1195835480265
+Export-Package: org.apache.camel.example.spring;uses:="org.apache.came
+ l.model,org.apache.camel.builder,org.apache.camel.spring";version=1.3
+ .0.SNAPSHOT
+Bundle-Version: 1.3.0.SNAPSHOT
+Bundle-Name: camel-example-spring
+Bundle-Description: An example showing how to work with Camel and Spri
+ ng
+Private-Package: META-INF.spring
+Bundle-DocURL: http://www.apache.org/
+Bundle-Vendor: Apache Software Foundation
+Bundle-ManifestVersion: 2
+Implementation-Title: Apache Camel
+Bundle-SymbolicName: org.apache.camel.camel-example-spring
+Tool: Bnd-0.0.160
+Implementation-Version: 1.3-SNAPSHOT
+
diff --git a/karaf/filemonitor/src/test/data/camel-example-spring/META-INF/NOTICE.txt b/karaf/filemonitor/src/test/data/camel-example-spring/META-INF/NOTICE.txt
new file mode 100644
index 0000000..2e215bf
--- /dev/null
+++ b/karaf/filemonitor/src/test/data/camel-example-spring/META-INF/NOTICE.txt
@@ -0,0 +1,11 @@
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Apache Camel distribution.                    ==
+   =========================================================================
+
+   This product includes software developed by
+   The Apache Software Foundation (http://www.apache.org/).
+
+   Please read the different LICENSE files present in the licenses directory of
+   this distribution.
diff --git a/karaf/filemonitor/src/test/data/camel-example-spring/META-INF/spring/camel-context.xml b/karaf/filemonitor/src/test/data/camel-example-spring/META-INF/spring/camel-context.xml
new file mode 100644
index 0000000..eb2c42a
--- /dev/null
+++ b/karaf/filemonitor/src/test/data/camel-example-spring/META-INF/spring/camel-context.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<!--
+
+  The default Application Context used by the org.apache.camel.spring.Main if there
+  is no /META-INF/sprint.xml
+
+ -->
+
+<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
+       http://activemq.apache.org/camel/schema/spring http://activemq.apache.org/camel/schema/spring/camel-spring.xsd">
+
+  <camelContext id="camel" useJmx="true" mbeanServer="mbeanServer"
+                xmlns="http://activemq.apache.org/camel/schema/spring">
+    <package>org.apache.camel.example.spring</package>
+  </camelContext>
+
+  <!-- lets configure the default ActiveMQ broker URL -->
+  <bean id="jms" class="org.apache.camel.component.jms.JmsComponent">
+    <property name="connectionFactory">
+      <bean class="org.apache.activemq.ActiveMQConnectionFactory">
+        <property name="brokerURL" value="vm://localhost?broker.persistent=false&amp;broker.useJmx=false"/>
+      </bean>
+    </property>
+  </bean>
+
+  <!-- Use JMX -->
+  <bean id="agent" class="org.apache.camel.spring.SpringInstrumentationAgent">
+    <property name="MBeanServer" ref="mbeanServer"/>
+  </bean>
+
+  <!--
+    this bean needs to be eagerly pre-instantiated in order for the exporting to occur;
+    this means that it must not be marked as lazily initialized
+  -->
+  <bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean">
+    <property name="defaultDomain" value="org.apache.camel.test"/>
+  </bean>
+  <bean id="registry" class="org.springframework.remoting.rmi.RmiRegistryFactoryBean">
+    <property name="port" value="1099"/>
+  </bean>
+  <bean id="serverConnector"
+        class="org.springframework.jmx.support.ConnectorServerFactoryBean" depends-on="registry">
+    <property name="objectName" value="connector:name=rmi"/>
+    <property name="serviceUrl"
+              value="service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi"/>
+    <property name="threaded" value="true"/>
+    <property name="daemon" value="true"/>
+  </bean>
+
+</beans>
diff --git a/karaf/filemonitor/src/test/data/camel-example-spring/org/apache/camel/example/spring/MyRouteBuilder$SomeBean.class b/karaf/filemonitor/src/test/data/camel-example-spring/org/apache/camel/example/spring/MyRouteBuilder$SomeBean.class
new file mode 100644
index 0000000..158c9da
--- /dev/null
+++ b/karaf/filemonitor/src/test/data/camel-example-spring/org/apache/camel/example/spring/MyRouteBuilder$SomeBean.class
Binary files differ
diff --git a/karaf/filemonitor/src/test/data/camel-example-spring/org/apache/camel/example/spring/MyRouteBuilder.class b/karaf/filemonitor/src/test/data/camel-example-spring/org/apache/camel/example/spring/MyRouteBuilder.class
new file mode 100644
index 0000000..79a433e
--- /dev/null
+++ b/karaf/filemonitor/src/test/data/camel-example-spring/org/apache/camel/example/spring/MyRouteBuilder.class
Binary files differ
diff --git a/karaf/filemonitor/src/test/data/foo/META-INF/MANIFEST.MF b/karaf/filemonitor/src/test/data/foo/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..001dd22
--- /dev/null
+++ b/karaf/filemonitor/src/test/data/foo/META-INF/MANIFEST.MF
@@ -0,0 +1,17 @@
+Manifest-Version: 1.0
+License-00: 
+License-01: Licensed to the Apache Software Foundation (ASF) under one or more
+License-02: contributor license agreements.  See the NOTICE file distributed with
+License-03: this work for additional information regarding copyright ownership.
+License-04: The ASF licenses this file to You under the Apache License, Version 2.0
+License-05: (the "License"); you may not use this file except in compliance with
+License-06: the License.  You may obtain a copy of the License at
+License-07: 
+License-08:      http://www.apache.org/licenses/LICENSE-2.0
+License-09: 
+License-10: Unless required by applicable law or agreed to in writing, software
+License-11: distributed under the License is distributed on an "AS IS" BASIS,
+License-12: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+License-13: See the License for the specific language governing permissions and
+License-14: limitations under the License.
+License-15:
diff --git a/karaf/filemonitor/src/test/data/foo/foo.txt b/karaf/filemonitor/src/test/data/foo/foo.txt
new file mode 100644
index 0000000..c094a79
--- /dev/null
+++ b/karaf/filemonitor/src/test/data/foo/foo.txt
@@ -0,0 +1,18 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+Hey!
\ No newline at end of file
diff --git a/karaf/filemonitor/src/test/java/org/apache/servicemix/kernel/filemonitor/BundlePackerTest.java b/karaf/filemonitor/src/test/java/org/apache/servicemix/kernel/filemonitor/BundlePackerTest.java
new file mode 100644
index 0000000..78a9159
--- /dev/null
+++ b/karaf/filemonitor/src/test/java/org/apache/servicemix/kernel/filemonitor/BundlePackerTest.java
@@ -0,0 +1,45 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.filemonitor;
+
+import java.io.File;
+
+import junit.framework.TestCase;
+import org.apache.commons.io.FileUtils;
+
+/**
+ * @version $Revision: 1.1 $
+ */
+public class BundlePackerTest extends TestCase {
+    public void testFiles() throws Exception {
+        File bundleDir = new File("target/deploy");
+        File unpackDir = new File("target/data");
+        FileUtils.deleteDirectory(unpackDir);
+
+        bundleDir.mkdirs();
+        unpackDir.mkdirs();
+
+        FileUtils.copyDirectory(new File("src/test/data"), unpackDir);
+
+/*
+        FileMonitor packer = new FileMonitor(bundleDir, unpackDir);
+        packer.scan();
+*/
+    }
+
+}
diff --git a/karaf/filemonitor/src/test/java/org/apache/servicemix/kernel/filemonitor/FileMonitorTest.java b/karaf/filemonitor/src/test/java/org/apache/servicemix/kernel/filemonitor/FileMonitorTest.java
new file mode 100644
index 0000000..5a99c96
--- /dev/null
+++ b/karaf/filemonitor/src/test/java/org/apache/servicemix/kernel/filemonitor/FileMonitorTest.java
@@ -0,0 +1,99 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.filemonitor;
+
+import junit.framework.TestCase;
+
+/**
+ * FileMonitor Tester.
+ *
+ * @author <Authors name>
+ * @version 1.0
+ * @since <pre>07/02/2008</pre>
+ */
+public class FileMonitorTest extends TestCase {
+
+    public FileMonitorTest(String name) {
+        super(name);
+    }
+
+    public void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    public void testFilePathsMatch() throws Exception {
+        assertTrue(FileMonitor.filePathsMatch(
+                "C:/Apps/apache-servicemix-kernel-1.0.0-rc1/src/README.txt",
+                "C:/Apps/apache-servicemix-kernel-1.0.0-rc1/src/README.txt"));
+
+        assertTrue(FileMonitor.filePathsMatch(
+                "C:\\Apps\\apache-servicemix-kernel-1.0.0-rc1\\src\\README.txt",
+                "C:\\Apps\\apache-servicemix-kernel-1.0.0-rc1\\src\\README.txt"));
+
+        assertTrue(FileMonitor.filePathsMatch(
+                "C:/Apps/apache-servicemix-kernel-1.0.0-rc1/src/README.txt",
+                "C:\\Apps\\apache-servicemix-kernel-1.0.0-rc1\\src\\README.txt"));
+
+        assertTrue(FileMonitor.filePathsMatch(
+                "file:/C:/Apps/apache-servicemix-kernel-1.0.0-rc1/src/README.txt",
+                "C:\\Apps\\apache-servicemix-kernel-1.0.0-rc1\\src\\README.txt"));
+
+        assertTrue(FileMonitor.filePathsMatch(
+                "file://C:/Apps/apache-servicemix-kernel-1.0.0-rc1/src/README.txt",
+                "C:\\Apps\\apache-servicemix-kernel-1.0.0-rc1\\src\\README.txt"));
+    }
+
+    public void testNormalizeFilePath() throws Exception {
+        assertEquals(
+                "C:/Apps/apache-servicemix-kernel-1.0.0-rc1/src/README.txt",
+                FileMonitor.normalizeFilePath("C:/Apps/apache-servicemix-kernel-1.0.0-rc1/src/README.txt"));
+
+        assertEquals(
+                "C:/Apps/apache-servicemix-kernel-1.0.0-rc1/src/README.txt",
+                FileMonitor.normalizeFilePath("C:/Apps//apache-servicemix-kernel-1.0.0-rc1////src/////README.txt"));
+
+        assertEquals(
+                "C:/Apps/apache-servicemix-kernel-1.0.0-rc1/src/README.txt",
+                FileMonitor.normalizeFilePath("C:\\Apps\\apache-servicemix-kernel-1.0.0-rc1\\src\\README.txt"));
+
+        assertEquals(
+                "C:/Apps/apache-servicemix-kernel-1.0.0-rc1/src/README.txt",
+                FileMonitor.normalizeFilePath("C:\\\\Apps\\\\apache-servicemix-kernel-1.0.0-rc1\\\\src\\\\README.txt"));
+
+        assertEquals(
+                "C:/Apps/apache-servicemix-kernel-1.0.0-rc1/src/README.txt",
+                FileMonitor.normalizeFilePath("C:\\Apps\\//apache-servicemix-kernel-1.0.0-rc1\\/\\src///\\\\README.txt"));
+
+        assertEquals(
+                "C:/Apps/apache-servicemix-kernel-1.0.0-rc1/src/README.txt",
+                FileMonitor.normalizeFilePath("file:C:/Apps/apache-servicemix-kernel-1.0.0-rc1/src/README.txt"));
+
+        assertEquals(
+                "C:/Apps/apache-servicemix-kernel-1.0.0-rc1/src/README.txt",
+                FileMonitor.normalizeFilePath("file:/C:/Apps/apache-servicemix-kernel-1.0.0-rc1/src/README.txt"));
+
+        assertEquals(
+                "C:/Apps/apache-servicemix-kernel-1.0.0-rc1/src/README.txt",
+                FileMonitor.normalizeFilePath("file://C:/Apps/apache-servicemix-kernel-1.0.0-rc1/src/README.txt"));
+    }
+
+}
diff --git a/karaf/gshell/gshell-admin/pom.xml b/karaf/gshell/gshell-admin/pom.xml
new file mode 100644
index 0000000..0a6a2a4
--- /dev/null
+++ b/karaf/gshell/gshell-admin/pom.xml
@@ -0,0 +1,154 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <!--
+
+        Licensed to the Apache Software Foundation (ASF) under one or more
+        contributor license agreements.  See the NOTICE file distributed with
+        this work for additional information regarding copyright ownership.
+        The ASF licenses this file to You under the Apache License, Version 2.0
+        (the "License"); you may not use this file except in compliance with
+        the License.  You may obtain a copy of the License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software
+        distributed under the License is distributed on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        See the License for the specific language governing permissions and
+        limitations under the License.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.servicemix.kernel.gshell</groupId>
+        <artifactId>gshell</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.servicemix.kernel.gshell</groupId>
+    <artifactId>org.apache.servicemix.kernel.gshell.admin</artifactId>
+    <packaging>bundle</packaging>
+    <version>1.2.0-SNAPSHOT</version>
+    <name>Apache ServiceMix Kernel :: GShell Admin</name>
+
+    <description>
+        Provides administration commands
+    </description>
+
+    <properties>
+        <gshell.osgi.import>
+            org.apache.servicemix.kernel.main.spi.*;resolution:=optional,
+            org.apache.geronimo.gshell*,
+        </gshell.osgi.import>
+        <gshell.osgi.export>
+            org.apache.servicemix.jpm
+        </gshell.osgi.export>
+        <gshell.osgi.private>
+            org.apache.servicemix.kernel.gshell.admin.*,
+            org.apache.servicemix.jpm.impl
+        </gshell.osgi.private>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel.gshell</groupId>
+            <artifactId>org.apache.servicemix.kernel.gshell.core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.osgi</groupId>
+            <artifactId>spring-osgi-core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <resources>
+            <resource>
+                <directory>${pom.basedir}/src/main/resources</directory>
+                <includes>
+                    <include>**/*</include>
+                </includes>
+            </resource>
+            <resource>
+                <directory>${pom.basedir}/src/main/filtered-resources</directory>
+                <filtering>true</filtering>
+                <includes>
+                    <include>**/*</include>
+                </includes>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-resources-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>copy-resources</id>
+                        <!-- here the phase you need -->
+                        <phase>compile</phase>
+                        <goals>
+                            <goal>copy-resources</goal>
+                        </goals>
+                        <configuration>
+                            <outputDirectory>${basedir}/target/classes/org/apache/servicemix/kernel/gshell/admin/etc</outputDirectory>
+                            <resources>          
+                                <resource>
+                                    <directory>../../${config.location}</directory>
+                                    <includes>
+                                        <include>config.properties</include>
+                                    </includes>
+                                </resource>
+                            </resources>              
+                        </configuration>            
+                    </execution>
+                </executions>
+            </plugin>            
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>exec-maven-plugin</artifactId>
+                <configuration>
+                    <mainClass>Main</mainClass>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>${artifactId}</Bundle-SymbolicName>
+                        <Export-Package>org.apache.servicemix.kernel.gshell.admin.*;version=${project.version}
+                        </Export-Package>
+                        <Import-Package>
+                            org.apache.geronimo.gshell.wisdom.command,
+                            org.apache.geronimo.gshell.wisdom.registry,
+                            org.apache.servicemix.kernel.gshell.core,
+                            *
+                        </Import-Package>
+                        <Private-Package>org.apache.servicemix.jpm.*</Private-Package>
+                        <Spring-Context>*;publish-context:=false;create-asynchronously:=false</Spring-Context>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/karaf/gshell/gshell-admin/src/main/filtered-resources/org/apache/servicemix/kernel/gshell/admin/etc/org.apache.servicemix.features.cfg b/karaf/gshell/gshell-admin/src/main/filtered-resources/org/apache/servicemix/kernel/gshell/admin/etc/org.apache.servicemix.features.cfg
new file mode 100644
index 0000000..2e22aec
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/filtered-resources/org/apache/servicemix/kernel/gshell/admin/etc/org.apache.servicemix.features.cfg
@@ -0,0 +1,28 @@
+################################################################################

+#

+#    Licensed to the Apache Software Foundation (ASF) under one or more

+#    contributor license agreements.  See the NOTICE file distributed with

+#    this work for additional information regarding copyright ownership.

+#    The ASF licenses this file to You under the Apache License, Version 2.0

+#    (the "License"); you may not use this file except in compliance with

+#    the License.  You may obtain a copy of the License at

+#

+#       http://www.apache.org/licenses/LICENSE-2.0

+#

+#    Unless required by applicable law or agreed to in writing, software

+#    distributed under the License is distributed on an "AS IS" BASIS,

+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+#    See the License for the specific language governing permissions and

+#    limitations under the License.

+#

+################################################################################

+

+#

+# Comma separated list of features repositories to register by default

+#

+featuresRepositories=mvn:org.apache.servicemix.kernel/apache-servicemix-kernel/${version}/xml/features

+

+#

+# Comma separated list of features to install at startup

+#

+featuresBoot=

diff --git a/karaf/gshell/gshell-admin/src/main/filtered-resources/org/apache/servicemix/kernel/gshell/admin/etc/startup.properties b/karaf/gshell/gshell-admin/src/main/filtered-resources/org/apache/servicemix/kernel/gshell/admin/etc/startup.properties
new file mode 100644
index 0000000..f9689b1
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/filtered-resources/org/apache/servicemix/kernel/gshell/admin/etc/startup.properties
@@ -0,0 +1,76 @@
+################################################################################
+#
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+################################################################################
+
+# This file allows you to control the start level of each bundle.
+#
+
+#
+# Startup core services like logging
+#
+org/ops4j/pax/url/pax-url-mvn/${pax.url.version}/pax-url-mvn-${pax.url.version}.jar=5
+org/ops4j/pax/url/pax-url-wrap/${pax.url.version}/pax-url-wrap-${pax.url.version}.jar=5
+org/apache/geronimo/specs/geronimo-servlet_2.5_spec/${geronimo.servlet.version}/geronimo-servlet_2.5_spec-${geronimo.servlet.version}.jar=10
+org/apache/servicemix/specs/org.apache.servicemix.specs.jaxp-api-1.4/${servicemix.specs.version}/org.apache.servicemix.specs.jaxp-api-1.4-${servicemix.specs.version}.jar=10
+org/apache/servicemix/bundles/org.apache.servicemix.bundles.jaxp-ri/${jaxp.ri.version}/org.apache.servicemix.bundles.jaxp-ri-${jaxp.ri.version}.jar=10
+org/apache/felix/org.osgi.compendium/${felix.compendium.version}/org.osgi.compendium-${felix.compendium.version}.jar=10
+org/apache/felix/org.apache.felix.configadmin/${felix.configadmin.version}/org.apache.felix.configadmin-${felix.configadmin.version}.jar=10
+org/apache/geronimo/specs/geronimo-annotation_1.0_spec/${geronimo.annotation.version}/geronimo-annotation_1.0_spec-${geronimo.annotation.version}.jar=10
+org/apache/felix/org.apache.felix.prefs/${felix.prefs.version}/org.apache.felix.prefs-${felix.prefs.version}.jar=10
+org/apache/servicemix/kernel/org.apache.servicemix.kernel.filemonitor/${pom.version}/org.apache.servicemix.kernel.filemonitor-${pom.version}.jar=15
+org/ops4j/pax/logging/pax-logging-api/${pax.logging.version}/pax-logging-api-${pax.logging.version}.jar=20
+org/ops4j/pax/logging/pax-logging-service/${pax.logging.version}/pax-logging-service-${pax.logging.version}.jar=20
+
+#
+# The rest of the services..
+#
+org/apache/servicemix/bundles/org.apache.servicemix.bundles.jline/${jline.version}/org.apache.servicemix.bundles.jline-${jline.version}.jar=30
+org/apache/servicemix/bundles/org.apache.servicemix.bundles.aopalliance/${aopalliance.version}/org.apache.servicemix.bundles.aopalliance-${aopalliance.version}.jar=30
+org/apache/servicemix/bundles/org.apache.servicemix.bundles.cglib/${cglib.version}/org.apache.servicemix.bundles.cglib-${cglib.version}.jar=30
+org/apache/servicemix/bundles/org.apache.servicemix.bundles.mina/${mina.version}/org.apache.servicemix.bundles.mina-${mina.version}.jar=30
+org/apache/servicemix/bundles/org.apache.servicemix.bundles.oro/${oro.version}/org.apache.servicemix.bundles.oro-${oro.version}.jar=30
+org/apache/servicemix/bundles/org.apache.servicemix.bundles.commons-codec/${commons.codec.version}/org.apache.servicemix.bundles.commons-codec-${commons.codec.version}.jar=30
+org/apache/servicemix/bundles/org.apache.servicemix.bundles.commons-httpclient/${commons.httpclient.version}/org.apache.servicemix.bundles.commons-httpclient-${commons.httpclient.version}.jar=30
+org/apache/servicemix/bundles/org.apache.servicemix.bundles.commons-jexl/${commons.jexl.version}/org.apache.servicemix.bundles.commons-jexl-${commons.jexl.version}.jar=30
+org/apache/servicemix/bundles/org.apache.servicemix.bundles.commons-vfs/${commons.vfs.version}/org.apache.servicemix.bundles.commons-vfs-${commons.vfs.version}.jar=30
+org/springframework/spring-aop/${spring.version}/spring-aop-${spring.version}.jar=30
+org/springframework/spring-beans/${spring.version}/spring-beans-${spring.version}.jar=30
+org/springframework/spring-context/${spring.version}/spring-context-${spring.version}.jar=30
+org/springframework/spring-core/${spring.version}/spring-core-${spring.version}.jar=30
+org/springframework/osgi/spring-osgi-core/${spring.osgi.version}/spring-osgi-core-${spring.osgi.version}.jar=30
+org/springframework/osgi/spring-osgi-extender/${spring.osgi.version}/spring-osgi-extender-${spring.osgi.version}.jar=30
+org/springframework/osgi/spring-osgi-io/${spring.osgi.version}/spring-osgi-io-${spring.osgi.version}.jar=30
+org/apache/servicemix/kernel/org.apache.servicemix.kernel.spring/${pom.version}/org.apache.servicemix.kernel.spring-${pom.version}.jar=30
+org/apache/servicemix/kernel/org.apache.servicemix.kernel.management/${pom.version}/org.apache.servicemix.kernel.management-${pom.version}.jar=30
+org/apache/servicemix/kernel/gshell/org.apache.servicemix.kernel.gshell.admin/${pom.version}/org.apache.servicemix.kernel.gshell.admin-${pom.version}.jar=30
+org/apache/servicemix/kernel/gshell/org.apache.servicemix.kernel.gshell.osgi/${pom.version}/org.apache.servicemix.kernel.gshell.osgi-${pom.version}.jar=30
+org/apache/servicemix/kernel/gshell/org.apache.servicemix.kernel.gshell.features/${pom.version}/org.apache.servicemix.kernel.gshell.features-${pom.version}.jar=30
+org/apache/servicemix/kernel/gshell/org.apache.servicemix.kernel.gshell.log/${pom.version}/org.apache.servicemix.kernel.gshell.log-${pom.version}.jar=30
+org/apache/servicemix/kernel/gshell/org.apache.servicemix.kernel.gshell.config/${pom.version}/org.apache.servicemix.kernel.gshell.config-${pom.version}.jar=30
+org/apache/servicemix/kernel/gshell/org.apache.servicemix.kernel.gshell.packages/${pom.version}/org.apache.servicemix.kernel.gshell.packages-${pom.version}.jar=30
+org/apache/servicemix/kernel/jaas/org.apache.servicemix.kernel.jaas.config/${pom.version}/org.apache.servicemix.kernel.jaas.config-${pom.version}.jar=30
+org/apache/servicemix/kernel/jaas/org.apache.servicemix.kernel.jaas.modules/${pom.version}/org.apache.servicemix.kernel.jaas.modules-${pom.version}.jar=30
+com/google/code/sshd/sshd/${sshd.version}/sshd-${sshd.version}.jar=30
+org/osgi/jmx/${osgi.jmx.version}/jmx-${osgi.jmx.version}.jar=30
+com/oracle/osgi/jmx-impl/${osgi.jmx.version}/jmx-impl-${osgi.jmx.version}.jar=30
+
+#
+# Start console last
+#
+org/apache/servicemix/kernel/gshell/org.apache.servicemix.kernel.gshell.core/${pom.version}/org.apache.servicemix.kernel.gshell.core-${pom.version}.jar=40
+
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/Process.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/Process.java
new file mode 100644
index 0000000..eedb31d
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/Process.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.jpm;
+
+import java.io.IOException;
+import java.io.Serializable;
+
+/**
+ * Interface representing a process
+ */
+public interface Process extends Serializable {
+
+    /**
+     * Retrieves the PID of the process
+     * @return the pid
+     */
+    int getPid();
+
+    /**
+     * Check if this process is still running
+     * @return <code>true</code> if the process is running
+     * @throws IOException if an error occurs
+     */
+    boolean isRunning() throws IOException;
+
+    /**
+     * Destroy the process.
+     *
+     * @throws IOException
+     */
+    void destroy() throws IOException;
+
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/ProcessBuilder.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/ProcessBuilder.java
new file mode 100644
index 0000000..6862222
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/ProcessBuilder.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.jpm;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Interface used to create new processes.
+ */
+public interface ProcessBuilder {
+
+    /**
+     * Specified the current directory to run the command from
+     *
+     * @param dir the directory to run the command from
+     * @return the ProcessBuilder instance
+     */
+    ProcessBuilder directory(File dir);
+
+    /**
+     * Set the command to execute
+     *
+     * @param command the command to execute
+     * @return the ProcessBuilder instance
+     */
+    ProcessBuilder command(String command);
+
+    /**
+     * Create and start the process
+     *
+     * @return the process that has been started
+     * @throws IOException if the process can not be created
+     */
+    Process start() throws IOException;
+
+    /**
+     * Attach to an existing process
+     *
+     * @return the process that has been attached
+     * @throws IOException if the process can not be attached to
+     */
+    Process attach(int pid) throws IOException;
+
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/ProcessBuilderFactory.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/ProcessBuilderFactory.java
new file mode 100644
index 0000000..433b615
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/ProcessBuilderFactory.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.jpm;
+
+/**
+ * Factory for process builders.
+ */
+public abstract class ProcessBuilderFactory {
+
+    public static ProcessBuilderFactory newInstance() {
+        return new org.apache.servicemix.jpm.impl.ProcessBuilderFactoryImpl();
+    }
+
+    public abstract ProcessBuilder newBuilder();
+
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/impl/ProcessBuilderFactoryImpl.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/impl/ProcessBuilderFactoryImpl.java
new file mode 100644
index 0000000..4db4657
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/impl/ProcessBuilderFactoryImpl.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.jpm.impl;
+
+import org.apache.servicemix.jpm.ProcessBuilder;
+import org.apache.servicemix.jpm.ProcessBuilderFactory;
+
+public class ProcessBuilderFactoryImpl extends ProcessBuilderFactory {
+
+    public ProcessBuilder newBuilder() {
+        return new ProcessBuilderImpl();
+    }
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/impl/ProcessBuilderImpl.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/impl/ProcessBuilderImpl.java
new file mode 100644
index 0000000..649da6b
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/impl/ProcessBuilderImpl.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.jpm.impl;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.servicemix.jpm.Process;
+import org.apache.servicemix.jpm.ProcessBuilder;
+
+
+public class ProcessBuilderImpl implements ProcessBuilder {
+
+    private File dir;
+    private String command;
+
+    public ProcessBuilder directory(File dir) {
+        this.dir = dir;
+        return this;
+    }
+
+    public ProcessBuilder command(String command) {
+        this.command = command;
+        return this;
+    }
+
+    public Process start() throws IOException {
+        return ProcessImpl.create(dir, command);
+    }
+
+    public Process attach(int pid) throws IOException {
+        return ProcessImpl.attach(pid);
+    }
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/impl/ProcessImpl.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/impl/ProcessImpl.java
new file mode 100644
index 0000000..71146fa
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/impl/ProcessImpl.java
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.jpm.impl;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.InterruptedIOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.servicemix.jpm.Process;
+
+public class ProcessImpl implements Process {
+
+    private int pid;
+    //private File input;
+    //private File output;
+    //private File error;
+
+    public ProcessImpl(int pid/*, File input, File output, File error*/) {
+        this.pid = pid;
+        //this.input = input;
+        //this.output = output;
+        //this.error = error;
+    }
+
+    public int getPid() {
+        return pid;
+    }
+
+    public boolean isRunning() throws IOException {
+        if (ScriptUtils.isWindows()) {
+            Map<String, String> props = new HashMap<String, String>();
+            props.put("${pid}", Integer.toString(pid));
+            int ret = ScriptUtils.execute("running", props);
+            return ret == 0;
+        } else {
+            try {
+                java.lang.Process process = new java.lang.ProcessBuilder("ps", "-p", Integer.toString(pid)).start();
+                BufferedReader r = new BufferedReader(new InputStreamReader(process.getInputStream()));
+                r.readLine(); // skip headers
+                String s = r.readLine();
+                boolean running = s != null && s.length() > 0;
+                int ret = process.waitFor();
+                return running;
+            } catch (InterruptedException e) {
+                throw new InterruptedIOException();
+            }
+        }
+    }
+
+    public void destroy() throws IOException {
+        int ret;
+        if (ScriptUtils.isWindows()) {
+            Map<String, String> props = new HashMap<String, String>();
+            props.put("${pid}", Integer.toString(pid));
+            ret = ScriptUtils.execute("destroy", props);
+        } else {
+            ret = ScriptUtils.executeProcess(new java.lang.ProcessBuilder("kill", "-9", Integer.toString(pid)));
+        }
+        if (ret != 0) {
+            throw new IOException("Unable to destroy proces, it may be already terminated");
+        }
+    }
+
+    /*
+    public OutputStream getInputStream() throws FileNotFoundException {
+        return new FileOutputStream(input);
+    }
+
+    public InputStream getOutputStream() throws FileNotFoundException {
+        return new FileInputStream(output);
+    }
+
+    public InputStream getErrorStream() throws FileNotFoundException {
+        return new FileInputStream(error);
+    }
+    */
+
+    public int waitFor() throws InterruptedException {
+        return 0;
+    }
+
+    public int exitValue() {
+        return 0;
+    }
+
+    public static Process create(File dir, String command) throws IOException {
+        //File input = File.createTempFile("jpm.", ".input");
+        //File output = File.createTempFile("jpm.", ".output");
+        //File error = File.createTempFile("jpm.", ".error");
+        File pidFile = File.createTempFile("jpm.", ".pid");
+        try {
+            Map<String, String> props = new HashMap<String, String>();
+            //props.put("${in.file}", input.getCanonicalPath());
+            //props.put("${out.file}", output.getCanonicalPath());
+            //props.put("${err.file}", error.getCanonicalPath());
+            props.put("${pid.file}", pidFile.getCanonicalPath());
+            props.put("${dir}", dir != null ? dir.getCanonicalPath() : "");
+            if (ScriptUtils.isWindows()) {
+                command = command.replaceAll("\"", "\"\"");
+            }
+            props.put("${command}", command);
+            int ret = ScriptUtils.execute("start", props);
+            if (ret != 0) {
+                throw new IOException("Unable to create process (error code: " + ret + ")");
+            }
+            int pid = readPid(pidFile);
+            return new ProcessImpl(pid/*, input, output, error*/);
+        } finally {
+            pidFile.delete();
+        }
+    }
+
+    public static Process attach(int pid) throws IOException {
+        return new ProcessImpl(pid);
+    }
+
+    private static int readPid(File pidFile) throws IOException {
+        InputStream is = new FileInputStream(pidFile);
+        try {
+            BufferedReader r = new BufferedReader(new InputStreamReader(is));
+            String pidString = r.readLine();
+            return Integer.valueOf(pidString);
+        } finally {
+            try {
+                is.close();
+            } catch (IOException e) {}
+        }
+    }
+
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/impl/ScriptUtils.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/impl/ScriptUtils.java
new file mode 100644
index 0000000..869c958
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/impl/ScriptUtils.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.jpm.impl;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InterruptedIOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.Map;
+import java.util.Scanner;
+
+public class ScriptUtils {
+
+    public static int execute(String name, Map<String, String> props) throws IOException {
+        File script = File.createTempFile("jpm.", ".script");
+        try {
+            if (isWindows()) {
+                String res = "windows/" + name + ".vbs";
+                ScriptUtils.copyFilteredResource(res, script, props);
+                return executeProcess(new java.lang.ProcessBuilder("cscript",
+                                                                   "/NOLOGO",
+                                                                   "//E:vbs",
+                                                                   script.getCanonicalPath()));
+            } else {
+                String res = "unix/" + name + ".sh";
+                ScriptUtils.copyFilteredResource(res, script, props);
+                return executeProcess(new java.lang.ProcessBuilder("/bin/sh",
+                                                                   script.getCanonicalPath()));
+            }
+        } finally {
+            script.delete();
+        }
+    }
+
+    public static int executeProcess(java.lang.ProcessBuilder builder) throws IOException {
+        try {
+            java.lang.Process process = builder.start();
+            return process.waitFor();
+        } catch (InterruptedException e) {
+            throw new InterruptedIOException();
+        }
+    }
+
+    public static void copyFilteredResource(String resource, File outFile, Map<String, String> props) throws IOException {
+        InputStream is = null;
+        try {
+            is = ScriptUtils.class.getResourceAsStream(resource);
+            // Read it line at a time so that we can use the platform line ending when we write it out.
+            PrintStream out = new PrintStream(new FileOutputStream(outFile));
+            try {
+                Scanner scanner = new Scanner(is);
+                while (scanner.hasNextLine() ) {
+                    String line = scanner.nextLine();
+                    line = filter(line, props);
+                    out.println(line);
+                }
+            } finally {
+                safeClose(out);
+            }
+        } finally {
+            safeClose(is);
+        }
+    }
+
+    private static void safeClose(InputStream is) throws IOException {
+        if (is == null) {
+            return;
+        }
+        try {
+            is.close();
+        } catch (Throwable ignore) {
+        }
+    }
+
+    private static void safeClose(OutputStream is) throws IOException {
+        if (is == null) {
+            return;
+        }
+        try {
+            is.close();
+        } catch (Throwable ignore) {
+        }
+    }
+
+    private static String filter(String line, Map<String, String> props) {
+        for (Map.Entry<String, String> i : props.entrySet()) {
+            int p1 = line.indexOf(i.getKey());
+            if( p1 >= 0 ) {
+                String l1 = line.substring(0, p1);
+                String l2 = line.substring(p1+i.getKey().length());
+                line = l1+i.getValue()+l2;
+            }
+        }
+        return line;
+    }
+
+    private static final boolean windows;
+
+    static {
+        windows = System.getProperty("os.name").toLowerCase().indexOf("windows") != -1;
+    }
+
+    public static boolean isWindows() {
+        return windows;
+    }
+
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/AdminService.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/AdminService.java
new file mode 100644
index 0000000..cbf7181
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/AdminService.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.admin;
+
+public interface AdminService {
+
+    Instance createInstance(String name, int port, String location) throws Exception;
+
+    Instance[] getInstances();
+
+    Instance getInstance(String name);
+
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/AdminServiceMBean.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/AdminServiceMBean.java
new file mode 100644
index 0000000..8a68d2d
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/AdminServiceMBean.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.admin;
+
+public interface AdminServiceMBean {
+
+    void createInstance(String name, int port, String location) throws Exception;
+
+    String[] getInstances();
+
+    int getPort(String name) throws Exception;
+
+    void changePort(String name, int port) throws Exception;
+
+    String getState(String name) throws Exception;
+
+    void start(String name, String javaOpts) throws Exception;
+
+    void stop(String name) throws Exception;
+
+    void destroy(String name) throws Exception;
+
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/Instance.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/Instance.java
new file mode 100644
index 0000000..07612aa
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/Instance.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.admin;
+
+public interface Instance {
+
+    String STOPPED = "Stopped";
+    String STARTING = "Starting";
+    String STARTED = "Started";
+
+    String getName();
+
+    String getLocation();
+
+    int getPid();
+
+    int getPort() throws Exception;
+
+    void changePort(int port) throws Exception;
+
+    void start(String javaOpts) throws Exception;
+
+    void stop() throws Exception;
+
+    void destroy() throws Exception;
+
+    String getState() throws Exception;
+
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/AdminServiceImpl.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/AdminServiceImpl.java
new file mode 100644
index 0000000..54283a8
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/AdminServiceImpl.java
@@ -0,0 +1,299 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.admin.internal;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.net.ServerSocket;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Scanner;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.geronimo.gshell.shell.ShellContext;
+import org.apache.geronimo.gshell.shell.ShellContextHolder;
+import org.apache.servicemix.kernel.gshell.admin.AdminService;
+import org.apache.servicemix.kernel.gshell.admin.Instance;
+import org.osgi.service.prefs.BackingStoreException;
+import org.osgi.service.prefs.Preferences;
+import org.osgi.service.prefs.PreferencesService;
+import org.springframework.beans.factory.InitializingBean;
+
+public class AdminServiceImpl implements AdminService, InitializingBean {
+
+    private static final Log LOGGER = LogFactory.getLog(AdminServiceImpl.class);
+
+    private PreferencesService preferences;
+
+    private Map<String, Instance> instances = new HashMap<String, Instance>();
+
+    private int defaultPortStart = 8101;
+
+    public PreferencesService getPreferences() {
+        return preferences;
+    }
+
+    public void setPreferences(PreferencesService preferences) {
+        this.preferences = preferences;
+    }
+
+    public synchronized void afterPropertiesSet() throws Exception {
+        try {
+            Preferences prefs = preferences.getUserPreferences("AdminServiceState");
+            Preferences child = prefs.node("Instances");
+            int count = child.getInt("count", 0);
+            Map<String, Instance> newInstances = new HashMap<String, Instance>();
+            for (int i = 0; i < count; i++) {
+                String name = child.get("item." + i + ".name", null);
+                String loc = child.get("item." + i + ".loc", null);
+                int pid = child.getInt("item." + i + ".pid", 0);
+                if (name != null) {
+                    InstanceImpl instance = new InstanceImpl(this, name, loc);
+                    if (pid > 0) {
+                        try {
+                            instance.attach(pid);
+                        } catch (IOException e) {
+                            // Ignore
+                        }
+                    }
+                    newInstances.put(name, instance);
+                }
+            }
+            instances = newInstances;
+        } catch (Exception e) {
+            LOGGER.warn("Unable to reload ServiceMix instance list", e);
+        }
+    }
+
+    public synchronized Instance createInstance(String name, int port, String location) throws Exception {
+        if (instances.get(name) != null) {
+            throw new IllegalArgumentException("Instance '" + name + "' already exists");
+        }
+        File serviceMixBase = new File(location != null ? location : ("instances/" + name)).getCanonicalFile();
+        int sshPort = port;
+        if (sshPort <= 0) {
+            try {
+                Preferences prefs = preferences.getUserPreferences("AdminServiceState");
+                sshPort = prefs.getInt("port", defaultPortStart + 1);
+                prefs.putInt("port", sshPort + 1);
+                prefs.flush();
+                prefs.sync();
+            } catch (Exception e) {
+                try {
+                    ServerSocket ss = new ServerSocket(0);
+                    sshPort = ss.getLocalPort();
+                    ss.close();
+                } catch (Exception t) {
+                }
+            }
+            if (sshPort <= 0) {
+                sshPort = defaultPortStart;
+            }
+        }
+        println("Creating new instance on port " + sshPort + " at: @|bold " + serviceMixBase + "|");
+
+        mkdir(serviceMixBase, "bin");
+        mkdir(serviceMixBase, "etc");
+        mkdir(serviceMixBase, "system");
+        mkdir(serviceMixBase, "deploy");
+        mkdir(serviceMixBase, "data");
+
+        copyResourceToDir(serviceMixBase, "etc/config.properties", true);
+        copyResourceToDir(serviceMixBase, "etc/org.apache.servicemix.features.cfg", true);
+        copyResourceToDir(serviceMixBase, "etc/users.properties", true);
+        copyResourceToDir(serviceMixBase, "etc/org.ops4j.pax.logging.cfg", true);
+        copyResourceToDir(serviceMixBase, "etc/org.ops4j.pax.url.mvn.cfg", true);
+        copyResourceToDir(serviceMixBase, "etc/startup.properties", true);
+
+        HashMap<String, String> props = new HashMap<String, String>();
+        props.put("${servicemix.name}", name);
+        props.put("${servicemix.home}", System.getProperty("servicemix.home"));
+        props.put("${servicemix.base}", serviceMixBase.getPath());
+        props.put("${servicemix.sshPort}", Integer.toString(sshPort));
+        copyFilteredResourceToDir(serviceMixBase, "etc/system.properties", props);
+        copyFilteredResourceToDir(serviceMixBase, "etc/org.apache.servicemix.shell.cfg", props);
+        if( System.getProperty("os.name").startsWith("Win") ) {
+            copyFilteredResourceToDir(serviceMixBase, "bin/servicemix.bat", props);
+        } else {
+            copyFilteredResourceToDir(serviceMixBase, "bin/servicemix", props);
+            chmod(new File(serviceMixBase, "bin/servicemix"), "a+x");
+        }
+        Instance instance = new InstanceImpl(this, name, serviceMixBase.toString());
+        instances.put(name, instance);
+        saveState();
+        return instance;
+    }
+
+    public synchronized Instance[] getInstances() {
+        return instances.values().toArray(new Instance[0]);
+    }
+
+    public synchronized Instance getInstance(String name) {
+        return instances.get(name);
+    }
+
+    synchronized void forget(String name) {
+        instances.remove(name);
+    }
+
+    synchronized void saveState() throws IOException, BackingStoreException {
+        Preferences prefs = preferences.getUserPreferences("AdminServiceState");
+        Preferences child = prefs.node("Instances");
+        child.clear();
+        Instance[] data = getInstances();
+        child.putInt("count", data.length);
+        for (int i = 0; i < data.length; i++) {
+            child.put("item." + i + ".name", data[i].getName());
+            child.put("item." + i + ".loc", data[i].getLocation());
+            child.putInt("item." + i + ".pid", data[i].getPid());
+        }
+        prefs.flush();
+        prefs.sync();
+    }
+
+    private void copyResourceToDir(File target, String resource, boolean text) throws Exception {
+        File outFile = new File(target, resource);
+        if( !outFile.exists() ) {
+            println("Creating file: @|bold " + outFile.getPath() + "|");
+            InputStream is = getClass().getClassLoader().getResourceAsStream("/org/apache/servicemix/kernel/gshell/admin/" + resource);
+            try {
+                if( text ) {
+                    // Read it line at a time so that we can use the platform line ending when we write it out.
+                    PrintStream out = new PrintStream(new FileOutputStream(outFile));
+                    try {
+                        Scanner scanner = new Scanner(is);
+                        while (scanner.hasNextLine() ) {
+                            String line = scanner.nextLine();
+                            out.println(line);
+                        }
+                    } finally {
+                        safeClose(out);
+                    }
+                } else {
+                    // Binary so just write it out the way it came in.
+                    FileOutputStream out = new FileOutputStream(new File(target, resource));
+                    try {
+                        int c=0;
+                        while((c=is.read())>=0) {
+                            out.write(c);
+                        }
+                    } finally {
+                        safeClose(out);
+                    }
+                }
+            } finally {
+                safeClose(is);
+            }
+        }
+    }
+
+    private void println(String st) {
+        ShellContext ctx = ShellContextHolder.get(true);
+        if (ctx != null) {
+            ctx.getIo().out.println(st);
+        } else {
+            System.out.println(st);
+        }
+    }
+
+    private void copyFilteredResourceToDir(File target, String resource, HashMap<String, String> props) throws Exception {
+        File outFile = new File(target, resource);
+        if( !outFile.exists() ) {
+            println("Creating file: @|bold "+outFile.getPath()+"|");
+            InputStream is = getClass().getClassLoader().getResourceAsStream("/org/apache/servicemix/kernel/gshell/admin/" + resource);
+            try {
+                // Read it line at a time so that we can use the platform line ending when we write it out.
+                PrintStream out = new PrintStream(new FileOutputStream(outFile));
+                try {
+                    Scanner scanner = new Scanner(is);
+                    while (scanner.hasNextLine() ) {
+                        String line = scanner.nextLine();
+                        line = filter(line, props);
+                        out.println(line);
+                    }
+                } finally {
+                    safeClose(out);
+                }
+            } finally {
+                safeClose(is);
+            }
+        }
+    }
+
+    private void safeClose(InputStream is) throws IOException {
+        if (is == null) {
+            return;
+        }
+        try {
+            is.close();
+        } catch (Throwable ignore) {
+        }
+    }
+
+    private void safeClose(OutputStream is) throws IOException {
+        if (is == null) {
+            return;
+        }
+        try {
+            is.close();
+        } catch (Throwable ignore) {
+        }
+    }
+
+    private String filter(String line, HashMap<String, String> props) {
+        for (Map.Entry<String, String> i : props.entrySet()) {
+            int p1 = line.indexOf(i.getKey());
+            if( p1 >= 0 ) {
+                String l1 = line.substring(0, p1);
+                String l2 = line.substring(p1+i.getKey().length());
+                line = l1+i.getValue()+l2;
+            }
+        }
+        return line;
+    }
+
+    private void mkdir(File serviceMixBase, String path) {
+        File file = new File(serviceMixBase, path);
+        if( !file.exists() ) {
+            println("Creating dir:  @|bold "+file.getPath()+"|");
+            file.mkdirs();
+        }
+    }
+
+    private int chmod(File serviceFile, String mode) throws Exception {
+        ProcessBuilder builder = new ProcessBuilder();
+        builder.command("chmod", mode, serviceFile.getCanonicalPath());
+        Process p = builder.start();
+
+        // gnodet: Fix SMX4KNL-46: cpu goes to 100% after running the 'admin create' command
+        // Not sure exactly what happens, but commenting the process io redirection seems
+        // to work around the problem.
+        //
+        //PumpStreamHandler handler = new PumpStreamHandler(io.inputStream, io.outputStream, io.errorStream);
+        //handler.attach(p);
+        //handler.start();
+        int status = p.waitFor();
+        //handler.stop();
+        return status;
+    }
+
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/AdminServiceMBeanImpl.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/AdminServiceMBeanImpl.java
new file mode 100644
index 0000000..a53b663
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/AdminServiceMBeanImpl.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.admin.internal;
+
+import org.apache.servicemix.kernel.gshell.admin.AdminService;
+import org.apache.servicemix.kernel.gshell.admin.AdminServiceMBean;
+import org.apache.servicemix.kernel.gshell.admin.Instance;
+
+public class AdminServiceMBeanImpl implements AdminServiceMBean {
+
+    private AdminService adminService;
+
+    public AdminService getAdminService() {
+        return adminService;
+    }
+
+    public void setAdminService(AdminService adminService) {
+        this.adminService = adminService;
+    }
+
+    public void createInstance(String name, int port, String location) throws Exception {
+        adminService.createInstance(name, port, location);
+    }
+
+    public String[] getInstances() {
+        Instance[] instances = adminService.getInstances();
+        String[] names = new String[instances.length];
+        for (int i = 0; i < instances.length; i++) {
+            names[i] = instances[i].getName();
+        }
+        return names;
+    }
+
+    public int getPort(String name) throws Exception {
+        return getExistingInstance(name).getPort();
+    }
+
+    public void changePort(String name, int port) throws Exception {
+        getExistingInstance(name).changePort(port);
+    }
+
+    public String getState(String name) throws Exception {
+        return getExistingInstance(name).getState();
+    }
+
+    public void start(String name, String javaOpts) throws Exception {
+        getExistingInstance(name).start(javaOpts);
+    }
+
+    public void stop(String name) throws Exception {
+        getExistingInstance(name).stop();
+    }
+
+    public void destroy(String name) throws Exception {
+        getExistingInstance(name).destroy();
+    }
+
+
+    private Instance getExistingInstance(String name) {
+        Instance i = adminService.getInstance(name);
+        if (i == null) {
+            throw new IllegalArgumentException("Instance '" + name + "' does not exist");
+        }
+        return i;
+    }
+
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/InstanceImpl.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/InstanceImpl.java
new file mode 100644
index 0000000..3815ca5
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/InstanceImpl.java
@@ -0,0 +1,220 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.admin.internal;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.util.Properties;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.servicemix.jpm.Process;
+import org.apache.servicemix.jpm.ProcessBuilderFactory;
+import org.apache.servicemix.jpm.impl.ScriptUtils;
+import org.apache.servicemix.kernel.gshell.admin.Instance;
+
+public class InstanceImpl implements Instance {
+
+    private static final Log LOG = LogFactory.getLog(InstanceImpl.class);
+
+    private AdminServiceImpl service;
+    private String name;
+    private String location;
+    private Process process;
+
+    public InstanceImpl(AdminServiceImpl service, String name, String location) {
+        this.service = service;
+        this.name = name;
+        this.location = location;
+    }
+
+    public void attach(int pid) throws IOException {
+        checkProcess();
+        if (this.process != null) {
+            throw new IllegalStateException("Instance already started");
+        }
+        this.process = ProcessBuilderFactory.newInstance().newBuilder().attach(pid);
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    public String getLocation() {
+        return location;
+    }
+
+    public int getPid() {
+        checkProcess();
+        return this.process != null ? this.process.getPid() : 0;
+    }
+
+    public int getPort() throws Exception {
+        InputStream is = null;
+        try {
+            File f = new File(location, "etc/org.apache.servicemix.shell.cfg");
+            is = new FileInputStream(f);
+            Properties props = new Properties();
+            props.load(is);
+            String loc = props.getProperty("sshPort");
+            return Integer.parseInt(loc);
+        } finally {
+            if (is != null) {
+                is.close();
+            }
+        }
+    }
+
+    public void changePort(int port) throws Exception {
+        checkProcess();
+        if (this.process != null) {
+            throw new IllegalStateException("Instance not stopped");
+        }
+        Properties props = new Properties();
+        File f = new File(location, "etc/org.apache.servicemix.shell.cfg");
+        InputStream is = new FileInputStream(f);
+        try {
+            props.load(is);
+        } finally {
+            is.close();
+        }
+        props.setProperty("sshPort", Integer.toString(port));
+        OutputStream os = new FileOutputStream(f);
+        try {
+            props.store(os, null);
+        } finally {
+            os.close();
+        }
+    }
+
+    public synchronized void start(String javaOpts) throws Exception {
+        checkProcess();
+        if (this.process != null) {
+            throw new IllegalStateException("Instance already started");
+        }
+        if (javaOpts == null) {
+            javaOpts = "-server -Xmx512M -Dcom.sun.management.jmxremote";
+        }
+        File libDir = new File(System.getProperty("servicemix.home"), "lib");
+        File[] jars = libDir.listFiles(new FilenameFilter() {
+            public boolean accept(File dir, String name) {
+                return name.endsWith(".jar");
+            }
+        });
+        StringBuilder classpath = new StringBuilder();
+        for (File jar : jars) {
+            if (classpath.length() > 0) {
+                classpath.append(System.getProperty("path.separator"));
+            }
+            classpath.append(jar.getCanonicalPath());
+        }
+        String command = new File(System.getProperty("java.home"), ScriptUtils.isWindows() ? "bin\\java.exe" : "bin/java").getCanonicalPath()
+                + " " + javaOpts
+                + " -Dservicemix.home=\"" + System.getProperty("servicemix.home") + "\""
+                + " -Dservicemix.base=\"" + new File(location).getCanonicalPath() + "\""
+                + " -Dservicemix.startLocalConsole=false"
+                + " -Dservicemix.startRemoteShell=true"
+                + " -classpath " + classpath.toString()
+                + " org.apache.servicemix.kernel.main.Main";
+        LOG.debug("Starting instance with command: " + command);
+        this.process = ProcessBuilderFactory.newInstance().newBuilder()
+                        .directory(new File(location))
+                        .command(command)
+                        .start();
+        this.service.saveState();
+    }
+
+    public synchronized void stop() throws Exception {
+        checkProcess();
+        if (this.process == null) {
+            throw new IllegalStateException("Instance not started");
+        }
+        this.process.destroy();
+    }
+
+    public synchronized void destroy() throws Exception {
+        checkProcess();
+        if (this.process != null) {
+            throw new IllegalStateException("Instance not stopped");
+        }
+        deleteFile(new File(location));
+        this.service.forget(name);
+        this.service.saveState();
+    }
+
+
+    public synchronized String getState() {
+        checkProcess();
+        if (this.process == null) {
+            return STOPPED;
+        } else {
+            try {
+                int port = getPort();
+                Socket s = new Socket("localhost", port);
+                s.close();
+                return STARTED;
+            } catch (Exception e) {
+                // ignore
+            }
+            return STARTING;
+        }
+    }
+
+    protected void checkProcess() {
+        if (this.process != null) {
+            try {
+                if (!this.process.isRunning()) {
+                    this.process = null;
+                }
+            } catch (IOException e) {
+            }
+        }
+    }
+
+    protected static boolean deleteFile(File fileToDelete) {
+        if (fileToDelete == null || !fileToDelete.exists()) {
+            return true;
+        }
+        boolean result = true;
+        if (fileToDelete.isDirectory()) {
+            File[] files = fileToDelete.listFiles();
+            if (files == null) {
+                result = false;
+            } else {
+                for (int i = 0; i < files.length; i++) {
+                    File file = files[i];
+                    if (file.getName().equals(".") || file.getName().equals("..")) {
+                        continue;
+                    }
+                    if (file.isDirectory()) {
+                        result &= deleteFile(file);
+                    } else {
+                        result &= file.delete();
+                    }
+                }
+            }
+        }
+        result &= fileToDelete.delete();
+        return result;
+    }
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/AdminCommandSupport.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/AdminCommandSupport.java
new file mode 100644
index 0000000..9da97b4
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/AdminCommandSupport.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.admin.internal.commands;
+
+import org.apache.servicemix.kernel.gshell.admin.AdminService;
+import org.apache.servicemix.kernel.gshell.admin.Instance;
+import org.apache.servicemix.kernel.gshell.core.OsgiCommandSupport;
+
+public abstract class AdminCommandSupport extends OsgiCommandSupport {
+
+    private AdminService adminService;
+
+    public AdminService getAdminService() {
+        return adminService;
+    }
+
+    public void setAdminService(AdminService adminService) {
+        this.adminService = adminService;
+    }
+
+    protected Instance getExistingInstance(String name) {
+        Instance i = adminService.getInstance(name);
+        if (i == null) {
+            throw new IllegalArgumentException("Instance '" + name + "' does not exist");
+        }
+        return i;
+    }
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/ChangePortCommand.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/ChangePortCommand.java
new file mode 100644
index 0000000..adbf2f6
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/ChangePortCommand.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.admin.internal.commands;
+
+import org.apache.geronimo.gshell.clp.Argument;
+
+public class ChangePortCommand extends AdminCommandSupport {
+
+    @Argument(index=0, required=true, description="The instance name")
+    private String instance = null;
+
+    @Argument(index=1, required=true, description="The new port")
+    private int port = 0;
+
+    protected Object doExecute() throws Exception {
+        getExistingInstance(instance).changePort(port);
+        return Result.SUCCESS;
+    }
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/ConnectCommand.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/ConnectCommand.java
new file mode 100644
index 0000000..244b9f8
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/ConnectCommand.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.servicemix.kernel.gshell.admin.internal.commands;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.apache.geronimo.gshell.clp.Option;
+import org.apache.geronimo.gshell.shell.ShellContextHolder;
+
+public class ConnectCommand extends AdminCommandSupport {
+
+    @Argument(index=0, required=true, description="The instance name")
+    private String instance = null;
+
+    @Option(name="-u", aliases={"--username"}, token="USERNAME", description="Remote user name")
+    private String username = "smx";
+
+    @Option(name="-p", aliases={"--password"}, token="PASSWORD", description="Remote user password")
+    private String password = "smx";
+
+    protected Object doExecute() throws Exception {
+        int port = getExistingInstance(instance).getPort();
+        ShellContextHolder.get().getShell().execute("ssh -l " + username + " -P " + password + " -p " + port + " localhost");
+        return Result.SUCCESS;
+    }
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/CreateCommand.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/CreateCommand.java
new file mode 100644
index 0000000..d13c381
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/CreateCommand.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.admin.internal.commands;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.apache.geronimo.gshell.clp.Option;
+
+/**
+ * Creates a new servicemix instance 
+ *
+ * @version $Rev: 679826 $ $Date: 2008-07-25 17:00:12 +0200 (Fri, 25 Jul 2008) $
+ */
+public class CreateCommand extends AdminCommandSupport
+{
+    @Option(name = "-p", aliases = { "--port"}, description = "Port number for remote shell connection")
+    private int port = 0;
+
+    @Option(name = "-l", aliases = { "--location"}, description = "Location of the new instance on the file system")
+    private String location;
+
+    @Argument(index=0, required=true, description="Name of the new ServiceMix instance")
+    private String instance = null;
+
+    protected Object doExecute() throws Exception {
+        getAdminService().createInstance(instance, port, location);
+        return Result.SUCCESS;
+    }
+
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/DestroyCommand.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/DestroyCommand.java
new file mode 100644
index 0000000..6084caa
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/DestroyCommand.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.admin.internal.commands;
+
+import org.apache.geronimo.gshell.clp.Argument;
+
+/**
+ * Creates a new servicemix instance
+ *
+ * @version $Rev: 679826 $ $Date: 2008-07-25 17:00:12 +0200 (Fri, 25 Jul 2008) $
+ */
+public class DestroyCommand extends AdminCommandSupport
+{
+    @Argument(index=0, required=true, description="The name of the ServiceMix instance to destroy")
+    private String instance = null;
+
+    protected Object doExecute() throws Exception {
+        getExistingInstance(instance).destroy();
+        return Result.SUCCESS;
+    }
+
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/ListCommand.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/ListCommand.java
new file mode 100644
index 0000000..61f3afb
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/ListCommand.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.admin.internal.commands;
+
+import org.apache.geronimo.gshell.clp.Option;
+import org.apache.servicemix.kernel.gshell.admin.Instance;
+
+/**
+ * List available instances
+ */
+public class ListCommand extends AdminCommandSupport {
+
+    @Option(name = "-l", aliases = { "--location" }, description = "Display instances location")
+    boolean location;
+
+    protected Object doExecute() throws Exception {
+        Instance[] instances = getAdminService().getInstances();
+        if (location) {
+            io.out.println("  Port   State       Pid  Location");
+        } else {
+            io.out.println("  Port   State       Pid  Name");
+        }
+        for (Instance instance : instances) {
+            StringBuilder sb = new StringBuilder();
+            sb.append('[');
+            String s = Integer.toString(instance.getPort());
+            for (int i = s.length(); i < 5; i++) {
+                sb.append(' ');
+            }
+            sb.append(s);
+            sb.append("] [");
+            String state = instance.getState();
+            while (state.length() < "starting".length()) {
+                state += " ";
+            }
+            sb.append(state);
+            sb.append("] [");
+            s = Integer.toString(instance.getPid());
+            for (int i = s.length(); i < 5; i++) {
+                sb.append(' ');
+            }
+            sb.append(s);
+            sb.append("] ");
+            if (location) {
+                sb.append(instance.getLocation());
+            } else {
+                sb.append(instance.getName());
+            }
+            io.out.println(sb.toString());
+        }
+        return Result.SUCCESS;
+    }
+
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/StartCommand.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/StartCommand.java
new file mode 100644
index 0000000..77afa91
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/StartCommand.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.admin.internal.commands;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.apache.geronimo.gshell.clp.Option;
+
+public class StartCommand extends AdminCommandSupport {
+
+    @Option(name = "-o", aliases = { "--java-opts"}, description = "Java options when launching the instance")
+    private String javaOpts;
+
+    @Argument(index=0, required=true, description="The instance name")
+    private String instance = null;
+
+    protected Object doExecute() throws Exception {
+        getExistingInstance(instance).start(javaOpts);
+        return Result.SUCCESS;
+    }
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/StopCommand.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/StopCommand.java
new file mode 100644
index 0000000..c449387
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/StopCommand.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.admin.internal.commands;
+
+import org.apache.geronimo.gshell.clp.Argument;
+
+public class StopCommand extends AdminCommandSupport {
+
+    @Argument(index=0, required=true, description="The instance name")
+    private String instance = null;
+
+    protected Object doExecute() throws Exception {
+        getExistingInstance(instance).stop();
+        return Result.SUCCESS;
+    }
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/completers/InstanceCompleter.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/completers/InstanceCompleter.java
new file mode 100644
index 0000000..cfcb95a
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/completers/InstanceCompleter.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.admin.internal.completers;
+
+import java.util.List;
+
+import org.apache.servicemix.kernel.gshell.admin.AdminService;
+import org.apache.servicemix.kernel.gshell.admin.Instance;
+import org.apache.geronimo.gshell.console.completer.StringsCompleter;
+import jline.Completor;
+
+/**
+ * {@link jline.Completor} for server instance names.
+ *
+ * Displays a list of configured server instances for the Admin commands.
+ *
+ */
+public class InstanceCompleter implements Completor {
+    private AdminService adminService;
+
+    public void setAdminService(AdminService adminService) {
+        this.adminService = adminService;
+    }
+
+    public int complete(String buffer, int cursor, List candidates) {
+        StringsCompleter delegate = new StringsCompleter();
+        for (Instance instance : adminService.getInstances()) {
+            delegate.getStrings().add(instance.getName());
+        }
+        return delegate.complete(buffer, cursor, candidates);
+    }
+}
diff --git a/karaf/gshell/gshell-admin/src/main/resources/META-INF/spring/gshell-admin.xml b/karaf/gshell/gshell-admin/src/main/resources/META-INF/spring/gshell-admin.xml
new file mode 100644
index 0000000..5f05513
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/META-INF/spring/gshell-admin.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<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:osgix="http://www.springframework.org/schema/osgi-compendium"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xmlns:gshell="http://servicemix.apache.org/schema/servicemix-gshell"
+       xsi:schemaLocation="
+  http://www.springframework.org/schema/beans
+  http://www.springframework.org/schema/beans/spring-beans.xsd
+  http://www.springframework.org/schema/osgi
+  http://www.springframework.org/schema/osgi/spring-osgi.xsd
+  http://www.springframework.org/schema/osgi-compendium
+  http://www.springframework.org/schema/osgi-compendium/spring-osgi-compendium.xsd
+  http://www.springframework.org/schema/util
+  http://www.springframework.org/schema/util/spring-util.xsd
+  http://servicemix.apache.org/schema/servicemix-gshell
+  http://servicemix.apache.org/schema/servicemix-gshell/servicemix-gshell.xsd">
+
+    <import resource="classpath:org/apache/servicemix/kernel/gshell/core/commands.xml" />
+
+    <bean id="adminCommandBundleSupport" scope="prototype">
+        <property name="adminService" ref="adminService" />
+    </bean>
+
+    <gshell:command-bundle>
+        <gshell:command name="admin/create">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.admin.internal.commands.CreateCommand"
+                           parent="adminCommandBundleSupport" />
+        </gshell:command>
+        <gshell:command name="admin/connect">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.admin.internal.commands.ConnectCommand"
+                           parent="adminCommandBundleSupport" />
+            <gshell:completers>
+                <ref bean="instanceCompleter" />
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+        <gshell:command name="admin/list">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.admin.internal.commands.ListCommand"
+                           parent="adminCommandBundleSupport" />
+        </gshell:command>
+        <gshell:command name="admin/start">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.admin.internal.commands.StartCommand"
+                           parent="adminCommandBundleSupport" />
+            <gshell:completers>
+                <ref bean="instanceCompleter" />
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+        <gshell:command name="admin/stop">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.admin.internal.commands.StopCommand"
+                           parent="adminCommandBundleSupport" />
+            <gshell:completers>
+                <ref bean="instanceCompleter" />
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+        <gshell:command name="admin/destroy">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.admin.internal.commands.DestroyCommand"
+                           parent="adminCommandBundleSupport" />
+            <gshell:completers>
+                <ref bean="instanceCompleter" />
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+        <gshell:command name="admin/change-port">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.admin.internal.commands.ChangePortCommand"
+                           parent="adminCommandBundleSupport" />
+            <gshell:completers>
+                <ref bean="instanceCompleter" />
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+    </gshell:command-bundle>
+
+    <osgi:reference id="preferences" interface="org.osgi.service.prefs.PreferencesService" cardinality="0..1" />
+
+    <bean id="adminService" class="org.apache.servicemix.kernel.gshell.admin.internal.AdminServiceImpl">
+        <property name="preferences" ref="preferences" />
+    </bean>
+
+    <bean id="instanceCompleter" class="org.apache.servicemix.kernel.gshell.admin.internal.completers.InstanceCompleter">
+        <property name="adminService" ref="adminService" />
+    </bean>
+
+
+</beans>
\ No newline at end of file
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/jpm/impl/unix/start.sh b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/jpm/impl/unix/start.sh
new file mode 100644
index 0000000..1d1d720
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/jpm/impl/unix/start.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+################################################################################
+#
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+################################################################################
+
+#exec 1>${out.file}
+#exec 2>${err.file}
+exec 1>/dev/null
+exec 2>/dev/null
+if [ "x${dir}" != "x" ]; then
+    cd ${dir}
+fi
+nohup ${command} &
+echo $! > ${pid.file}
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/jpm/impl/windows/destroy.vbs b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/jpm/impl/windows/destroy.vbs
new file mode 100644
index 0000000..abd60eb
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/jpm/impl/windows/destroy.vbs
@@ -0,0 +1,27 @@
+'===============================================================================
+'
+'    Licensed to the Apache Software Foundation (ASF) under one or more
+'    contributor license agreements.  See the NOTICE file distributed with
+'    this work for additional information regarding copyright ownership.
+'    The ASF licenses this file to You under the Apache License, Version 2.0
+'    (the "License"); you may not use this file except in compliance with
+'    the License.  You may obtain a copy of the License at
+'
+'       http://www.apache.org/licenses/LICENSE-2.0
+'
+'    Unless required by applicable law or agreed to in writing, software
+'    distributed under the License is distributed on an "AS IS" BASIS,
+'    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+'    See the License for the specific language governing permissions and
+'    limitations under the License.
+'
+'===============================================================================
+
+Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")
+Set colProcessList = objWMIService.ExecQuery("Select * from Win32_Process Where ProcessId = ${pid}")
+intRetVal = 1
+For Each objProcess in colProcessList
+    objProcess.Terminate()
+    intRetVal = 0
+Next
+WScript.Quit(intRetVal)
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/jpm/impl/windows/running.vbs b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/jpm/impl/windows/running.vbs
new file mode 100644
index 0000000..32c65c5
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/jpm/impl/windows/running.vbs
@@ -0,0 +1,26 @@
+'===============================================================================
+'
+'    Licensed to the Apache Software Foundation (ASF) under one or more
+'    contributor license agreements.  See the NOTICE file distributed with
+'    this work for additional information regarding copyright ownership.
+'    The ASF licenses this file to You under the Apache License, Version 2.0
+'    (the "License"); you may not use this file except in compliance with
+'    the License.  You may obtain a copy of the License at
+'
+'       http://www.apache.org/licenses/LICENSE-2.0
+'
+'    Unless required by applicable law or agreed to in writing, software
+'    distributed under the License is distributed on an "AS IS" BASIS,
+'    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+'    See the License for the specific language governing permissions and
+'    limitations under the License.
+'
+'===============================================================================
+
+Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")
+Set colProcessList = objWMIService.ExecQuery("Select * from Win32_Process Where ProcessId = ${pid}")
+intRetVal = 1
+For Each objProcess in colProcessList
+    intRetVal = 0
+Next
+WScript.Quit(intRetVal)
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/jpm/impl/windows/start.vbs b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/jpm/impl/windows/start.vbs
new file mode 100644
index 0000000..6004c86
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/jpm/impl/windows/start.vbs
@@ -0,0 +1,34 @@
+'===============================================================================
+'
+'    Licensed to the Apache Software Foundation (ASF) under one or more
+'    contributor license agreements.  See the NOTICE file distributed with
+'    this work for additional information regarding copyright ownership.
+'    The ASF licenses this file to You under the Apache License, Version 2.0
+'    (the "License"); you may not use this file except in compliance with
+'    the License.  You may obtain a copy of the License at
+'
+'       http://www.apache.org/licenses/LICENSE-2.0
+'
+'    Unless required by applicable law or agreed to in writing, software
+'    distributed under the License is distributed on an "AS IS" BASIS,
+'    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+'    See the License for the specific language governing permissions and
+'    limitations under the License.
+'
+'===============================================================================
+
+Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")
+Set objConfig = objWMIService.Get("Win32_ProcessStartup").SpawnInstance_
+objConfig.ShowWindow = SW_HIDE
+objConfig.CreateFlags = 8
+If Len("${dir}") > 0 Then
+    intReturn = objWMIService.Get("Win32_Process").Create("${command}", "${dir}", objConfig, intProcessID)
+Else
+    intReturn = objWMIService.Get("Win32_Process").Create("${command}", Null, objConfig, intProcessID)
+End If
+If intReturn = 0 Then
+    Set objOutputFile = CreateObject("Scripting.fileSystemObject").CreateTextFile("${pid.file}", TRUE)
+    objOutputFile.WriteLine(intProcessID)
+    objOutputFile.Close
+End If
+WScript.Quit(intReturn)
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/bin/servicemix b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/bin/servicemix
new file mode 100644
index 0000000..20a33e6
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/bin/servicemix
@@ -0,0 +1,25 @@
+#!/bin/sh
+################################################################################
+#
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+################################################################################
+
+SERVICEMIX_HOME=${servicemix.home}
+SERVICEMIX_BASE=${servicemix.base}
+
+export SERVICEMIX_BASE
+${SERVICEMIX_HOME}/bin/servicemix "$*"
\ No newline at end of file
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/bin/servicemix.bat b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/bin/servicemix.bat
new file mode 100644
index 0000000..13c155a
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/bin/servicemix.bat
@@ -0,0 +1,25 @@
+@ECHO OFF
+REM =========================================================================
+REM 
+REM Licensed to the Apache Software Foundation (ASF) under one or more
+REM contributor license agreements.  See the NOTICE file distributed with
+REM this work for additional information regarding copyright ownership.
+REM The ASF licenses this file to You under the Apache License, Version 2.0
+REM (the "License"); you may not use this file except in compliance with
+REM the License.  You may obtain a copy of the License at
+REM 
+REM    http://www.apache.org/licenses/LICENSE-2.0
+REM 
+REM Unless required by applicable law or agreed to in writing, software
+REM distributed under the License is distributed on an "AS IS" BASIS,
+REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+REM See the License for the specific language governing permissions and
+REM limitations under the License.
+REM 
+REM =========================================================================
+
+SET SERVICEMIX_BASE=${servicemix.base}
+SETLOCAL
+SET SERVICEMIX_HOME=${servicemix.home}
+
+%SERVICEMIX_HOME%\bin\servicemix.bat %*
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/etc/org.apache.servicemix.shell.cfg b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/etc/org.apache.servicemix.shell.cfg
new file mode 100644
index 0000000..e6a8fd2
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/etc/org.apache.servicemix.shell.cfg
@@ -0,0 +1,23 @@
+################################################################################
+#
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+################################################################################
+
+#
+startLocalConsole=${servicemix.startLocalConsole}
+startRemoteShell=${servicemix.startRemoteShell}
+sshPort=${servicemix.sshPort}
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/etc/org.ops4j.pax.logging.cfg b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/etc/org.ops4j.pax.logging.cfg
new file mode 100644
index 0000000..24ddea5
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/etc/org.ops4j.pax.logging.cfg
@@ -0,0 +1,36 @@
+################################################################################
+#
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+################################################################################
+
+# Root logger
+log4j.rootLogger=INFO, out, osgi:VmLogAppender
+
+# Logger infos
+log4j.logger.org.apache.geronimo.gshell.remote=WARN
+
+# CONSOLE appender not used by default
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} | %-5.5p | %-16.16t | %-32.32c{1} | %-32.32C %4L | %m%n
+
+# File appender
+log4j.appender.out=org.apache.log4j.FileAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.out.layout.ConversionPattern=%d{ABSOLUTE} | %-5.5p | %-16.16t | %-32.32c{1} | %-32.32C %4L | %m%n
+log4j.appender.out.file=${servicemix.base}/data/log/servicemix.log
+log4j.appender.out.append=true
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/etc/org.ops4j.pax.url.mvn.cfg b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/etc/org.ops4j.pax.url.mvn.cfg
new file mode 100644
index 0000000..d0317cd
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/etc/org.ops4j.pax.url.mvn.cfg
@@ -0,0 +1,73 @@
+################################################################################
+#
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+################################################################################
+
+#
+# If set to true, the following property will not allow any certificate to be used
+# when accessing maven repositories through SSL
+#
+#org.ops4j.pax.url.mvn.certificateCheck=
+
+#
+# Path to the local maven settings file.
+# The repositories defined in this file will be automatically added to the list
+# of default repositories if the 'org.ops4j.pax.url.mvn.repositories' property
+# below is not set.
+# The following locations are checked for the existence of the settings.xml file
+#   * 1. looks for the specified url
+#   * 2. if not found looks for ${user.home}/.m2/settings.xml
+#   * 3. if not found looks for ${maven.home}/conf/settings.xml
+#   * 4. if not found looks for ${M2_HOME}/conf/settings.xml
+#
+#org.ops4j.pax.url.mvn.settings=
+
+#
+# Path to the local maven repository which is used to avoid downloading
+# artifacts when they already exist locally.
+# The value of this property will be extracted from the settings.xml file
+# above, or defaulted to:
+#     System.getProperty( "user.home" ) + "/.m2/repository"
+#
+#org.ops4j.pax.url.mvn.localRepository=
+
+#
+# Comma separated list of repositories scanned when resolving an artifact.
+# Those repositories will be checked before iterating through the
+     below list of repositories and even before the local repository
+# A repository url can be appended with zero or more of the following flags:
+#    @snapshots  : the repository contains snaphots
+#    @noreleases : the repository does not contain any released artifacts
+#
+# The following property value will add the system folder as a repo.
+#
+org.ops4j.pax.url.mvn.defaultRepositories=file:${servicemix.home}/system@snapshots,file:${servicemix.base}/system@snapshots
+
+#
+# Comma separated list of repositories scanned when resolving an artifact.
+# The default list includes the following repositories:
+#    http://repo1.maven.org/maven2
+#    http://repository.ops4j.org/maven2
+# To add repositories to the default ones, prepend '+' to the list of repositories
+# to add.
+# A repository url can be appended with zero or more of the following flags:
+#    @snapshots  : the repository contains snaphots
+#    @noreleases : the repository does not contain any released artifacts
+#
+# The following property value will add the system folders as a repo.
+#
+org.ops4j.pax.url.mvn.repositories=file:${servicemix.base}/system@snapshots,file:${user.home}/.m2/repository@snapshots,http://repo1.maven.org/maven2,http://people.apache.org/repo/m2-snapshot-repository@snapshots@noreleases,http://svn.apache.org/repos/asf/servicemix/m2-repo
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/etc/system.properties b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/etc/system.properties
new file mode 100644
index 0000000..255295e
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/etc/system.properties
@@ -0,0 +1,21 @@
+################################################################################
+#
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+################################################################################
+
+org.ops4j.pax.logging.DefaultServiceLog.level=ERROR
+servicemix.name=${servicemix.name}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/etc/users.properties b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/etc/users.properties
new file mode 100644
index 0000000..0348fae
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/etc/users.properties
@@ -0,0 +1,21 @@
+################################################################################
+#
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+################################################################################
+
+#
+smx=smx,admin
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/ChangePortCommand.properties b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/ChangePortCommand.properties
new file mode 100644
index 0000000..6a7edbf
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/ChangePortCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Change the port of an existing instance.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/ConnectCommand.properties b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/ConnectCommand.properties
new file mode 100644
index 0000000..1c78a34
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/ConnectCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Connect to an existing instance.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/CreateCommand.properties b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/CreateCommand.properties
new file mode 100644
index 0000000..532ada2
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/CreateCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Create a new instance.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/DestroyCommand.properties b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/DestroyCommand.properties
new file mode 100644
index 0000000..cb0581c
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/DestroyCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Destroy an existing instance.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/ListCommand.properties b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/ListCommand.properties
new file mode 100644
index 0000000..c473471
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/ListCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=List existing instances.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/StartCommand.properties b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/StartCommand.properties
new file mode 100644
index 0000000..dfb4046
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/StartCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Start an existing instance.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/StopCommand.properties b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/StopCommand.properties
new file mode 100644
index 0000000..0cd3acd
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/StopCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Stop an existing instance.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-admin/src/test/java/org/apache/servicemix/jpm/MainTest.java b/karaf/gshell/gshell-admin/src/test/java/org/apache/servicemix/jpm/MainTest.java
new file mode 100644
index 0000000..1833584
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/test/java/org/apache/servicemix/jpm/MainTest.java
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.jpm;
+
+public class MainTest {
+
+    public static void main(String[] args) throws Exception {
+        Thread.sleep(Long.parseLong(args[0]));
+    }
+}
diff --git a/karaf/gshell/gshell-admin/src/test/java/org/apache/servicemix/jpm/ProcessTest.java b/karaf/gshell/gshell-admin/src/test/java/org/apache/servicemix/jpm/ProcessTest.java
new file mode 100644
index 0000000..8328813
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/test/java/org/apache/servicemix/jpm/ProcessTest.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.jpm;
+
+import java.io.File;
+
+import junit.framework.TestCase;
+import org.apache.servicemix.jpm.impl.ScriptUtils;
+
+public class ProcessTest extends TestCase {
+
+    public void testCreate() throws Exception {
+        String javaPath = new File(System.getProperty("java.home"), ScriptUtils.isWindows() ? "bin\\java.exe" : "bin/java").getCanonicalPath();
+        System.err.println(javaPath);
+        StringBuilder command = new StringBuilder();
+        command.append(javaPath);
+        command.append(" -Dprop=\"key\"");
+        command.append(" -classpath ");
+        String clRes = getClass().getName().replace('.', '/') + ".class";
+        String str = getClass().getClassLoader().getResource(clRes).toString();
+        str = str.substring("file:".length(), str.indexOf(clRes));
+        command.append(str);
+        command.append(" ");
+        command.append(MainTest.class.getName());
+        command.append(" ");
+        command.append(60000);
+        System.err.println("Executing: " + command.toString());
+
+        ProcessBuilder builder = ProcessBuilderFactory.newInstance().newBuilder();
+        Process p = builder.command(command.toString()).start();
+        assertNotNull(p);
+        System.err.println("Process: " + p.getPid());
+        assertNotNull(p.getPid());
+        Thread.currentThread().sleep(1000);
+        System.err.println("Running: " + p.isRunning());
+        assertTrue(p.isRunning());
+        System.err.println("Destroying");
+        p.destroy();
+        Thread.currentThread().sleep(1000);
+        System.err.println("Running: " + p.isRunning());
+        assertFalse(p.isRunning());
+    }
+
+    /*
+     * When the process creation fails, no error is reported by the script
+     * 
+    public void testFailure() throws Exception {
+        ProcessBuilder builder = ProcessBuilderFactory.newInstance().newBuilder();
+        Process p = builder.command("ec").start();
+        fail("An exception should have been thrown");
+    }
+    */
+}
diff --git a/karaf/gshell/gshell-config/pom.xml b/karaf/gshell/gshell-config/pom.xml
new file mode 100644
index 0000000..8bab513
--- /dev/null
+++ b/karaf/gshell/gshell-config/pom.xml
@@ -0,0 +1,93 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <!--
+
+        Licensed to the Apache Software Foundation (ASF) under one or more
+        contributor license agreements.  See the NOTICE file distributed with
+        this work for additional information regarding copyright ownership.
+        The ASF licenses this file to You under the Apache License, Version 2.0
+        (the "License"); you may not use this file except in compliance with
+        the License.  You may obtain a copy of the License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software
+        distributed under the License is distributed on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        See the License for the specific language governing permissions and
+        limitations under the License.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.servicemix.kernel.gshell</groupId>
+        <artifactId>gshell</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.servicemix.kernel.gshell</groupId>
+    <artifactId>org.apache.servicemix.kernel.gshell.config</artifactId>
+    <packaging>bundle</packaging>
+    <version>1.2.0-SNAPSHOT</version>
+    <name>Apache ServiceMix Kernel :: GShell ConfigAdmin Commands</name>
+
+    <description>
+        Provides the ConfigAdmin GShell commands
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel.gshell</groupId>
+            <artifactId>org.apache.servicemix.kernel.gshell.core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.osgi</groupId>
+            <artifactId>spring-osgi-core</artifactId>
+        </dependency>
+
+        <dependency>
+             <groupId>org.apache.geronimo.specs</groupId>
+             <artifactId>geronimo-annotation_1.0_spec</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>${artifactId}</Bundle-SymbolicName>
+                        <Export-Package>
+                            org.apache.servicemix.kernel.gshell.config*;version=${project.version};-split-package:=merge-first
+                        </Export-Package>
+                        <Import-Package>
+                            org.apache.geronimo.gshell.wisdom.command,
+                            org.apache.geronimo.gshell.wisdom.registry,
+                            org.apache.servicemix.kernel.gshell.core,
+                            *
+                        </Import-Package>
+                        <Private-Package>!*</Private-Package>
+                        <Spring-Context>*;publish-context:=false;create-asynchronously:=false</Spring-Context>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/karaf/gshell/gshell-config/src/main/java/org/apache/servicemix/kernel/gshell/config/CancelCommand.java b/karaf/gshell/gshell-config/src/main/java/org/apache/servicemix/kernel/gshell/config/CancelCommand.java
new file mode 100644
index 0000000..e31ccfb
--- /dev/null
+++ b/karaf/gshell/gshell-config/src/main/java/org/apache/servicemix/kernel/gshell/config/CancelCommand.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.config;
+
+import org.osgi.service.cm.ConfigurationAdmin;
+
+public class CancelCommand extends ConfigCommandSupport {
+
+    protected void doExecute(ConfigurationAdmin admin) throws Exception {
+        this.variables.parent().unset(PROPERTY_CONFIG_PID);
+        this.variables.parent().unset(PROPERTY_CONFIG_PROPS);
+    }
+
+}
diff --git a/karaf/gshell/gshell-config/src/main/java/org/apache/servicemix/kernel/gshell/config/ConfigCommandSupport.java b/karaf/gshell/gshell-config/src/main/java/org/apache/servicemix/kernel/gshell/config/ConfigCommandSupport.java
new file mode 100644
index 0000000..5a28289
--- /dev/null
+++ b/karaf/gshell/gshell-config/src/main/java/org/apache/servicemix/kernel/gshell/config/ConfigCommandSupport.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.config;
+
+import java.util.Dictionary;
+
+import org.apache.servicemix.kernel.gshell.core.OsgiCommandSupport;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+/**
+ * Abstract class from which all commands related to the ConfigurationAdmin
+ * service should derive.
+ * This command retrieves a reference to the ConfigurationAdmin service before
+ * calling another method to actually process the command.
+ */
+public abstract class ConfigCommandSupport extends OsgiCommandSupport {
+
+    public static final String PROPERTY_CONFIG_PID = "ConfigCommand.PID";
+    public static final String PROPERTY_CONFIG_PROPS = "ConfigCommand.Props";
+
+    protected Object doExecute() throws Exception {
+        // Get config admin service.
+        ServiceReference ref = getBundleContext().getServiceReference(ConfigurationAdmin.class.getName());
+        if (ref == null) {
+            io.out.println("ConfigurationAdmin service is unavailable.");
+            return null;
+        }
+        try {
+            ConfigurationAdmin admin = (ConfigurationAdmin) getBundleContext().getService(ref);
+            if (admin == null) {
+                io.out.println("ConfigAdmin service is unavailable.");
+                return null;
+            }
+
+            doExecute(admin);
+        }
+        finally {
+            getBundleContext().ungetService(ref);
+        }
+        return null;
+    }
+
+    protected Dictionary getEditedProps() throws Exception {
+        return (Dictionary) this.variables.parent().get(PROPERTY_CONFIG_PROPS);
+    }
+
+    protected abstract void doExecute(ConfigurationAdmin admin) throws Exception;
+
+}
diff --git a/karaf/gshell/gshell-config/src/main/java/org/apache/servicemix/kernel/gshell/config/EditCommand.java b/karaf/gshell/gshell-config/src/main/java/org/apache/servicemix/kernel/gshell/config/EditCommand.java
new file mode 100644
index 0000000..f041da3
--- /dev/null
+++ b/karaf/gshell/gshell-config/src/main/java/org/apache/servicemix/kernel/gshell/config/EditCommand.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.config;
+
+import java.util.Dictionary;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.apache.geronimo.gshell.clp.Option;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+public class EditCommand extends ConfigCommandSupport {
+
+    @Argument(required = true, description = "PID of the configuration")
+    String pid;
+
+    @Option(name = "--force", description = "Force the edition of this config, even if another one was under edition")
+    boolean force;
+
+    protected void doExecute(ConfigurationAdmin admin) throws Exception {
+        String oldPid = (String) this.variables.get(PROPERTY_CONFIG_PID);
+        if (oldPid != null && !oldPid.equals(pid) && !force) {
+            io.err.println("Another config is being edited.  Cancel / update first, or use the --force option");
+            return;
+        }
+        Dictionary props = admin.getConfiguration(pid).getProperties();
+        this.variables.parent().set(PROPERTY_CONFIG_PID, pid);
+        this.variables.parent().set(PROPERTY_CONFIG_PROPS, props);
+    }
+}
diff --git a/karaf/gshell/gshell-config/src/main/java/org/apache/servicemix/kernel/gshell/config/ListCommand.java b/karaf/gshell/gshell-config/src/main/java/org/apache/servicemix/kernel/gshell/config/ListCommand.java
new file mode 100644
index 0000000..7657d6b
--- /dev/null
+++ b/karaf/gshell/gshell-config/src/main/java/org/apache/servicemix/kernel/gshell/config/ListCommand.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.config;
+
+import java.util.Dictionary;
+import java.util.Enumeration;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+public class ListCommand extends ConfigCommandSupport {
+
+    @Argument(required = false, description = "LDAP query")
+    String query;
+
+    protected void doExecute(ConfigurationAdmin admin) throws Exception {
+        Configuration[] configs = admin.listConfigurations(query);
+        for (Configuration config : configs) {
+            io.out.println("----------------------------------------------------------------");
+            io.out.println("Pid:            " + config.getPid());
+            if (config.getFactoryPid() != null) {
+                io.out.println("FactoryPid:     " + config.getFactoryPid());
+            }
+            io.out.println("BundleLocation: " + config.getBundleLocation());
+            if (config.getProperties() != null) {
+                io.out.println("Properties:");
+                Dictionary props = config.getProperties();
+                for (Enumeration e = props.keys(); e.hasMoreElements();) {
+                    Object key = e.nextElement();
+                    io.out.println("   " + key + " = " + props.get(key));
+                }
+            }
+        }
+    }
+}
diff --git a/karaf/gshell/gshell-config/src/main/java/org/apache/servicemix/kernel/gshell/config/PropDelCommand.java b/karaf/gshell/gshell-config/src/main/java/org/apache/servicemix/kernel/gshell/config/PropDelCommand.java
new file mode 100644
index 0000000..8e87dc7
--- /dev/null
+++ b/karaf/gshell/gshell-config/src/main/java/org/apache/servicemix/kernel/gshell/config/PropDelCommand.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.config;
+
+import java.util.Dictionary;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+public class PropDelCommand extends ConfigCommandSupport {
+
+    @Argument(index = 0, required = true, description = "the property to delete")
+    String prop;
+
+    protected void doExecute(ConfigurationAdmin admin) throws Exception {
+        Dictionary props = getEditedProps();
+        if (props == null) {
+            System.err.println("No configuration is being edited. Run the edit command first");
+        } else {
+            props.remove(prop);
+        }
+    }
+
+}
diff --git a/karaf/gshell/gshell-config/src/main/java/org/apache/servicemix/kernel/gshell/config/PropListCommand.java b/karaf/gshell/gshell-config/src/main/java/org/apache/servicemix/kernel/gshell/config/PropListCommand.java
new file mode 100644
index 0000000..2f7a446
--- /dev/null
+++ b/karaf/gshell/gshell-config/src/main/java/org/apache/servicemix/kernel/gshell/config/PropListCommand.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.config;
+
+import java.util.Dictionary;
+import java.util.Enumeration;
+
+import org.osgi.service.cm.ConfigurationAdmin;
+
+public class PropListCommand extends ConfigCommandSupport {
+
+    protected void doExecute(ConfigurationAdmin admin) throws Exception {
+        Dictionary props = getEditedProps();
+        if (props == null) {
+            System.err.println("No configuration is being edited. Run the edit command first");
+        } else {
+            for (Enumeration e = props.keys(); e.hasMoreElements();) {
+                Object key = e.nextElement();
+                io.out.println("   " + key + " = " + props.get(key));
+            }
+        }
+    }
+
+}
diff --git a/karaf/gshell/gshell-config/src/main/java/org/apache/servicemix/kernel/gshell/config/PropSetCommand.java b/karaf/gshell/gshell-config/src/main/java/org/apache/servicemix/kernel/gshell/config/PropSetCommand.java
new file mode 100644
index 0000000..a0c3112
--- /dev/null
+++ b/karaf/gshell/gshell-config/src/main/java/org/apache/servicemix/kernel/gshell/config/PropSetCommand.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.config;
+
+import java.util.Dictionary;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+public class PropSetCommand extends ConfigCommandSupport {
+
+    @Argument(index = 0, required = true, description = "the property to set")
+    String prop;
+
+    @Argument(index = 1, required = true, description = "the value of the property")
+    String value;
+
+    protected void doExecute(ConfigurationAdmin admin) throws Exception {
+        Dictionary props = getEditedProps();
+        if (props == null) {
+            System.err.println("No configuration is being edited. Run the edit command first");
+        } else {
+            props.put(prop, value);
+        }
+    }
+
+}
diff --git a/karaf/gshell/gshell-config/src/main/java/org/apache/servicemix/kernel/gshell/config/UpdateCommand.java b/karaf/gshell/gshell-config/src/main/java/org/apache/servicemix/kernel/gshell/config/UpdateCommand.java
new file mode 100644
index 0000000..1c6683f
--- /dev/null
+++ b/karaf/gshell/gshell-config/src/main/java/org/apache/servicemix/kernel/gshell/config/UpdateCommand.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.config;
+
+import java.util.Dictionary;
+
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+public class UpdateCommand extends ConfigCommandSupport {
+
+    protected void doExecute(ConfigurationAdmin admin) throws Exception {
+        Dictionary props = getEditedProps();
+        if (props == null) {
+            System.err.println("No configuration is being edited. Run the edit command first");
+        } else {
+            String pid = (String) this.variables.parent().get(PROPERTY_CONFIG_PID);
+            Configuration cfg = admin.getConfiguration(pid, null);
+            cfg.update(props);
+            this.variables.parent().unset(PROPERTY_CONFIG_PID);
+            this.variables.parent().unset(PROPERTY_CONFIG_PROPS);
+        }
+    }
+}
diff --git a/karaf/gshell/gshell-config/src/main/java/org/apache/servicemix/kernel/gshell/config/completers/ConfigurationCompleter.java b/karaf/gshell/gshell-config/src/main/java/org/apache/servicemix/kernel/gshell/config/completers/ConfigurationCompleter.java
new file mode 100644
index 0000000..7b63351
--- /dev/null
+++ b/karaf/gshell/gshell-config/src/main/java/org/apache/servicemix/kernel/gshell/config/completers/ConfigurationCompleter.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.servicemix.kernel.gshell.config.completers;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import javax.annotation.PostConstruct;
+
+import jline.Completor;
+import org.apache.geronimo.gshell.console.completer.StringsCompleter;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.cm.ConfigurationEvent;
+import org.osgi.service.cm.ConfigurationListener;
+
+/**
+ * {@link jline.Completor} for Configuration Admin configurations.
+ *
+ * Displays a list of existing config admin configurations for completion.
+ *
+ */
+public class ConfigurationCompleter implements Completor, ConfigurationListener {
+
+    private final StringsCompleter delegate = new StringsCompleter();
+
+    private ConfigurationAdmin admin;
+
+    public void setAdmin(ConfigurationAdmin admin) {
+        this.admin = admin;
+    }
+
+    @PostConstruct
+    public void init() {
+        Configuration[] configs;
+        try {
+            configs = admin.listConfigurations(null);
+        } catch (Exception e) {
+            return;
+        }
+
+        Collection<String> pids = new ArrayList<String>();
+
+        for (Configuration config : configs) {
+            if (config.getFactoryPid() != null) {
+                pids.add(config.getFactoryPid());
+            } else {
+                pids.add(config.getPid());
+            }
+        }
+
+        delegate.getStrings().addAll(pids);
+
+    }
+
+    public int complete(final String buffer, final int cursor, final List candidates) {
+        return delegate.complete(buffer, cursor, candidates);
+    }
+
+    public void configurationEvent(ConfigurationEvent configurationEvent) {
+        String pid = configurationEvent.getFactoryPid()!=null ? configurationEvent.getFactoryPid() : configurationEvent.getPid();
+        if (configurationEvent.getType() == ConfigurationEvent.CM_DELETED) {
+            delegate.getStrings().remove(pid);
+        } else if (configurationEvent.getType() == ConfigurationEvent.CM_UPDATED) {
+            delegate.getStrings().add(pid);
+        }
+    }
+}
diff --git a/karaf/gshell/gshell-config/src/main/java/org/apache/servicemix/kernel/gshell/config/completers/ConfigurationPropertyCompleter.java b/karaf/gshell/gshell-config/src/main/java/org/apache/servicemix/kernel/gshell/config/completers/ConfigurationPropertyCompleter.java
new file mode 100644
index 0000000..e21a8e3
--- /dev/null
+++ b/karaf/gshell/gshell-config/src/main/java/org/apache/servicemix/kernel/gshell/config/completers/ConfigurationPropertyCompleter.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.servicemix.kernel.gshell.config.completers;
+
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.List;
+
+import jline.Completor;
+import org.apache.geronimo.gshell.command.Variables;
+import org.apache.geronimo.gshell.console.completer.StringsCompleter;
+import org.apache.geronimo.gshell.shell.ShellContextHolder;
+import org.apache.servicemix.kernel.gshell.config.ConfigCommandSupport;
+
+/**
+ * {@link jline.Completor} for Configuration Admin properties.
+ *
+ * Displays a list of existing properties based on the current configuration being edited.
+ *
+ */
+public class ConfigurationPropertyCompleter implements Completor {
+
+    public int complete(final String buffer, final int cursor, final List candidates) {
+        Variables vars = ShellContextHolder.get().getVariables();
+        if (vars.get(ConfigCommandSupport.PROPERTY_CONFIG_PID) == null) {
+            return -1;
+        }
+
+        Dictionary props = (Dictionary) vars.get(ConfigCommandSupport.PROPERTY_CONFIG_PROPS);
+        StringsCompleter delegate = new StringsCompleter();
+
+        for (Enumeration e = props.keys(); e.hasMoreElements();) {
+            String key = (String) e.nextElement();
+            delegate.getStrings().add(key);
+        }
+
+        return delegate.complete(buffer, cursor, candidates);
+    }
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-config/src/main/resources/META-INF/spring/gshell-config.xml b/karaf/gshell/gshell-config/src/main/resources/META-INF/spring/gshell-config.xml
new file mode 100644
index 0000000..e5c9d6d
--- /dev/null
+++ b/karaf/gshell/gshell-config/src/main/resources/META-INF/spring/gshell-config.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<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:osgix="http://www.springframework.org/schema/osgi-compendium"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xmlns:gshell="http://servicemix.apache.org/schema/servicemix-gshell"
+       xsi:schemaLocation="
+  http://www.springframework.org/schema/beans
+  http://www.springframework.org/schema/beans/spring-beans.xsd
+  http://www.springframework.org/schema/osgi
+  http://www.springframework.org/schema/osgi/spring-osgi.xsd
+  http://www.springframework.org/schema/osgi-compendium
+  http://www.springframework.org/schema/osgi-compendium/spring-osgi-compendium.xsd
+  http://www.springframework.org/schema/util
+  http://www.springframework.org/schema/util/spring-util.xsd
+  http://servicemix.apache.org/schema/servicemix-gshell
+  http://servicemix.apache.org/schema/servicemix-gshell/servicemix-gshell.xsd">
+
+    <import resource="classpath:org/apache/servicemix/kernel/gshell/core/commands.xml" />
+
+    <gshell:command-bundle>
+        <gshell:command name="config/cancel">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.config.CancelCommand" />
+        </gshell:command>
+        <gshell:command name="config/edit">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.config.EditCommand"/>
+            <gshell:completers>
+                <ref bean="configCompleter" />
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+        <gshell:command name="config/list">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.config.ListCommand" />
+        </gshell:command>
+        <gshell:command name="config/propdel">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.config.PropDelCommand" />
+            <gshell:completers>
+                <ref bean="configPropertyCompleter" />
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+        <gshell:command name="config/proplist">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.config.PropListCommand" />
+        </gshell:command>
+        <gshell:command name="config/propset">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.config.PropSetCommand" />
+            <gshell:completers>
+                <ref bean="configPropertyCompleter" />
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+        <gshell:command name="config/update">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.config.UpdateCommand" />
+        </gshell:command>
+    </gshell:command-bundle>
+
+    <bean id="configCompleter" class="org.apache.servicemix.kernel.gshell.config.completers.ConfigurationCompleter" init-method="init">
+        <property name="admin" ref="configAdmin"/>
+    </bean>
+
+    <bean id="configPropertyCompleter" class="org.apache.servicemix.kernel.gshell.config.completers.ConfigurationPropertyCompleter" />
+
+    <osgi:reference id="configAdmin" interface="org.osgi.service.cm.ConfigurationAdmin"  />
+
+    <osgi:service ref="configCompleter" interface="org.osgi.service.cm.ConfigurationListener" /> 
+
+</beans>
\ No newline at end of file
diff --git a/karaf/gshell/gshell-config/src/main/resources/org/apache/servicemix/kernel/gshell/config/CancelCommand.properties b/karaf/gshell/gshell-config/src/main/resources/org/apache/servicemix/kernel/gshell/config/CancelCommand.properties
new file mode 100644
index 0000000..1bc5226
--- /dev/null
+++ b/karaf/gshell/gshell-config/src/main/resources/org/apache/servicemix/kernel/gshell/config/CancelCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Change the changes to the configuration being edited.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-config/src/main/resources/org/apache/servicemix/kernel/gshell/config/EditCommand.properties b/karaf/gshell/gshell-config/src/main/resources/org/apache/servicemix/kernel/gshell/config/EditCommand.properties
new file mode 100644
index 0000000..ca2f8e6
--- /dev/null
+++ b/karaf/gshell/gshell-config/src/main/resources/org/apache/servicemix/kernel/gshell/config/EditCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Create or edit a configuration.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-config/src/main/resources/org/apache/servicemix/kernel/gshell/config/ListCommand.properties b/karaf/gshell/gshell-config/src/main/resources/org/apache/servicemix/kernel/gshell/config/ListCommand.properties
new file mode 100644
index 0000000..a5d2c31
--- /dev/null
+++ b/karaf/gshell/gshell-config/src/main/resources/org/apache/servicemix/kernel/gshell/config/ListCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=List existing configurations.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-config/src/main/resources/org/apache/servicemix/kernel/gshell/config/PropDelCommand.properties b/karaf/gshell/gshell-config/src/main/resources/org/apache/servicemix/kernel/gshell/config/PropDelCommand.properties
new file mode 100644
index 0000000..9e76af6
--- /dev/null
+++ b/karaf/gshell/gshell-config/src/main/resources/org/apache/servicemix/kernel/gshell/config/PropDelCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Delete a property from the edited configuration.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-config/src/main/resources/org/apache/servicemix/kernel/gshell/config/PropListCommand.properties b/karaf/gshell/gshell-config/src/main/resources/org/apache/servicemix/kernel/gshell/config/PropListCommand.properties
new file mode 100644
index 0000000..9dab240
--- /dev/null
+++ b/karaf/gshell/gshell-config/src/main/resources/org/apache/servicemix/kernel/gshell/config/PropListCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=List properties from the edited configuration.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-config/src/main/resources/org/apache/servicemix/kernel/gshell/config/PropSetCommand.properties b/karaf/gshell/gshell-config/src/main/resources/org/apache/servicemix/kernel/gshell/config/PropSetCommand.properties
new file mode 100644
index 0000000..df4a2dc
--- /dev/null
+++ b/karaf/gshell/gshell-config/src/main/resources/org/apache/servicemix/kernel/gshell/config/PropSetCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Set a property on the edited configuration.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-config/src/main/resources/org/apache/servicemix/kernel/gshell/config/UpdateCommand.properties b/karaf/gshell/gshell-config/src/main/resources/org/apache/servicemix/kernel/gshell/config/UpdateCommand.properties
new file mode 100644
index 0000000..810f08f
--- /dev/null
+++ b/karaf/gshell/gshell-config/src/main/resources/org/apache/servicemix/kernel/gshell/config/UpdateCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Save and propagate changes from the configuration being edited.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-core/pom.xml b/karaf/gshell/gshell-core/pom.xml
new file mode 100644
index 0000000..19e9a27
--- /dev/null
+++ b/karaf/gshell/gshell-core/pom.xml
@@ -0,0 +1,480 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <!--
+
+        Licensed to the Apache Software Foundation (ASF) under one or more
+        contributor license agreements.  See the NOTICE file distributed with
+        this work for additional information regarding copyright ownership.
+        The ASF licenses this file to You under the Apache License, Version 2.0
+        (the "License"); you may not use this file except in compliance with
+        the License.  You may obtain a copy of the License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software
+        distributed under the License is distributed on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        See the License for the specific language governing permissions and
+        limitations under the License.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.servicemix.kernel.gshell</groupId>
+        <artifactId>gshell</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.servicemix.kernel.gshell</groupId>
+    <artifactId>org.apache.servicemix.kernel.gshell.core</artifactId>
+    <packaging>bundle</packaging>
+    <version>1.2.0-SNAPSHOT</version>
+    <name>Apache ServiceMix Kernel :: GShell Core</name>
+
+    <description>
+        Provides the OSGi GShell integration
+    </description>
+
+    <properties>
+        <gshell.osgi.import>
+            org.springframework.aop,
+            org.springframework.aop.framework,
+            org.springframework.beans.factory.annotation,
+            org.springframework.context.annotation,
+            org.springframework.osgi.service.importer,
+            org.aopalliance.aop,
+            org.apache.commons.vfs.provider.temp,
+            org.apache.commons.vfs.provider.ram,
+            jline*,
+            org.apache.servicemix.kernel.jaas.config;resolution:=optional,
+            org.apache.servicemix.kernel.version;resolution:=optional, 
+            org.apache.servicemix.kernel.main.spi;resolution:=optional;version="1.0.0",
+            org.codehaus.plexus*;resolution:=optional,
+            org.apache.sshd.server.keyprovider,
+            org.apache.sshd.server.jaas,
+            org.jsecurity*;resolution:=optional,
+            *
+        </gshell.osgi.import>
+        <!-- TODO: remove plexus util package -->
+        <gshell.osgi.export>
+            org.apache.geronimo.gshell*;version="1.0.0.alpha-2-SNAPSHOT";-split-package:=merge-first,
+            org.apache.servicemix.kernel.gshell.core*,
+            org.codehaus.plexus.interpolation*;-split-package:=merge-first,
+            org.codehaus.plexus.util;-split-package:=merge-first
+        </gshell.osgi.export>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel</groupId>
+            <artifactId>org.apache.servicemix.kernel.main</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel.jaas</groupId>
+            <artifactId>org.apache.servicemix.kernel.jaas.config</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.cglib</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.osgi</groupId>
+            <artifactId>spring-osgi-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.geronimo.gshell.commands</groupId>
+            <artifactId>gshell-builtin</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>oro</groupId>
+                    <artifactId>oro</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>commons-vfs</groupId>
+                    <artifactId>commons-vfs</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.geronimo.gshell.commands</groupId>
+            <artifactId>gshell-file</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.geronimo.gshell.commands</groupId>
+            <artifactId>gshell-network</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.geronimo.gshell.commands</groupId>
+            <artifactId>gshell-shell</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.geronimo.gshell.commands</groupId>
+            <artifactId>gshell-ssh</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.geronimo.gshell.commands</groupId>
+            <artifactId>gshell-text</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.geronimo.gshell.wisdom</groupId>
+            <artifactId>gshell-wisdom-core</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.geronimo.gshell.support</groupId>
+                    <artifactId>gshell-ivy</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.geronimo.gshell.support</groupId>
+                    <artifactId>gshell-xstore</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>commons-jexl</groupId>
+                    <artifactId>commons-jexl</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.plexus</groupId>
+            <artifactId>plexus-utils</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-aop</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-jdk14</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.commons-httpclient</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>commons-codec</groupId>
+                    <artifactId>commons-codec</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.commons-codec</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.commons-jexl</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>junit</groupId>
+                    <artifactId>junit</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.commons-vfs</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.oro</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.mina</groupId>
+            <artifactId>mina-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sshd</groupId>
+            <artifactId>sshd-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.jline</artifactId>
+        </dependency>
+        
+        <!-- jsecurity is a dependency for the ssh commands -->
+        <dependency>
+            <groupId>org.jsecurity</groupId>
+            <artifactId>jsecurity</artifactId>
+            <version>0.9.0-RC2</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>commons-logging</groupId>
+                    <artifactId>commons-logging</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <resources>
+            <resource>
+                <directory>${pom.basedir}/src/main/resources</directory>
+                <includes>
+                    <include>**/*</include>
+                </includes>
+            </resource>
+            <resource>
+                <directory>${pom.basedir}/src/main/filtered-resources</directory>
+                <filtering>true</filtering>
+                <includes>
+                    <include>**/*</include>
+                </includes>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>exec-maven-plugin</artifactId>
+                <configuration>
+                    <mainClass>Main</mainClass>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>${artifactId}</Bundle-SymbolicName>
+                        <Import-Package>${gshell.osgi.import}</Import-Package>
+                        <Export-Package>${gshell.osgi.export}</Export-Package>
+                        <Spring-Context>*;publish-context:=false;create-asynchronously:=false</Spring-Context>
+                    </instructions>
+                    <unpackBundle>true</unpackBundle>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                        <configuration>
+                            <artifactSet>
+                                <includes>
+                                    <include>org.apache.geronimo.gshell:gshell-api</include>
+                                    <include>org.apache.geronimo.gshell:gshell-application</include>
+                                    <include>org.apache.geronimo.gshell:gshell-parser</include>
+                                    <include>org.apache.geronimo.gshell.commands:gshell-builtin</include>
+                                    <include>org.apache.geronimo.gshell.commands:gshell-file</include>
+                                    <include>org.apache.geronimo.gshell.commands:gshell-network</include>
+                                    <include>org.apache.geronimo.gshell.commands:gshell-shell</include>
+                                    <include>org.apache.geronimo.gshell.commands:gshell-text</include>
+                                    <include>org.apache.geronimo.gshell.support:gshell-ansi</include>
+                                    <include>org.apache.geronimo.gshell.support:gshell-artifact</include>
+                                    <include>org.apache.geronimo.gshell.support:gshell-chronos</include>
+                                    <include>org.apache.geronimo.gshell.support:gshell-clp</include>
+                                    <include>org.apache.geronimo.gshell.support:gshell-console</include>
+                                    <include>org.apache.geronimo.gshell.support:gshell-event</include>
+                                    <include>org.apache.geronimo.gshell.support:gshell-i18n</include>
+                                    <include>org.apache.geronimo.gshell.support:gshell-interpolation</include>
+                                    <include>org.apache.geronimo.gshell.support:gshell-io</include>
+                                    <include>org.apache.geronimo.gshell.support:gshell-security</include>
+                                    <include>org.apache.geronimo.gshell.support:gshell-spring</include>
+                                    <include>org.apache.geronimo.gshell.support:gshell-terminal</include>
+                                    <include>org.apache.geronimo.gshell.support:gshell-vfs</include>
+                                    <include>org.apache.geronimo.gshell.support:gshell-vfs-meta</include>
+                                    <include>org.apache.geronimo.gshell.support:gshell-yarn</include>
+                                    <include>org.apache.geronimo.gshell.wisdom:gshell-wisdom-core</include>
+                                    <include>org.apache.geronimo.gshell.wisdom:gshell-wisdom-bootstrap</include>
+                                    <include>org.codehaus.plexus:plexus-utils</include>
+                                    <include>org.codehaus.plexus:plexus-interpolation</include>
+                                    <include>${project.groupId}:${project.artifactId}</include>
+                                </includes>
+                            </artifactSet>
+                            <filters>
+                                <filter>
+                                    <artifact>org.apache.geronimo.gshell:gshell-api</artifact>
+                                    <excludes>
+                                        <exclude>org/apache/geronimo/gshell/**</exclude>
+                                    </excludes>
+                                </filter>
+                                <filter>
+                                    <artifact>org.apache.geronimo.gshell:gshell-application</artifact>
+                                    <excludes>
+                                        <exclude>org/apache/geronimo/gshell/**</exclude>
+                                    </excludes>
+                                </filter>
+                                <filter>
+                                    <artifact>org.apache.geronimo.gshell:gshell-parser</artifact>
+                                    <excludes>
+                                        <exclude>org/apache/geronimo/gshell/**</exclude>
+                                    </excludes>
+                                </filter>
+                                <filter>
+                                    <artifact>org.apache.geronimo.gshell.commands:gshell-builtin</artifact>
+                                    <excludes>
+                                        <exclude>org/apache/geronimo/gshell/**</exclude>
+                                    </excludes>
+                                </filter>
+                                <filter>
+                                    <artifact>org.apache.geronimo.gshell.commands:gshell-file</artifact>
+                                    <excludes>
+                                        <exclude>org/apache/geronimo/gshell/**</exclude>
+                                    </excludes>
+                                </filter>
+                                <filter>
+                                    <artifact>org.apache.geronimo.gshell.commands:gshell-network</artifact>
+                                    <excludes>
+                                        <exclude>org/apache/geronimo/gshell/**</exclude>
+                                    </excludes>
+                                </filter>
+                                <filter>
+                                    <artifact>org.apache.geronimo.gshell.commands:gshell-shell</artifact>
+                                    <excludes>
+                                        <exclude>org/apache/geronimo/gshell/**</exclude>
+                                    </excludes>
+                                </filter>
+                                <filter>
+                                    <artifact>org.apache.geronimo.gshell.commands:gshell-ssh</artifact>
+                                    <excludes>
+                                        <exclude>org/apache/geronimo/gshell/**</exclude>
+                                    </excludes>
+                                </filter>
+                                <filter>
+                                    <artifact>org.apache.geronimo.gshell.commands:gshell-text</artifact>
+                                    <excludes>
+                                        <exclude>org/apache/geronimo/gshell/**</exclude>
+                                    </excludes>
+                                </filter>
+                                <filter>
+                                    <artifact>org.apache.geronimo.gshell.support:gshell-ansi</artifact>
+                                    <excludes>
+                                        <exclude>org/apache/geronimo/gshell/**</exclude>
+                                    </excludes>
+                                </filter>
+                                <filter>
+                                    <artifact>org.apache.geronimo.gshell.support:gshell-artifact</artifact>
+                                    <excludes>
+                                        <exclude>org/apache/geronimo/gshell/**</exclude>
+                                    </excludes>
+                                </filter>
+                                <filter>
+                                    <artifact>org.apache.geronimo.gshell.support:gshell-chronos</artifact>
+                                    <excludes>
+                                        <exclude>org/apache/geronimo/gshell/**</exclude>
+                                    </excludes>
+                                </filter>
+                                <filter>
+                                    <artifact>org.apache.geronimo.gshell.support:gshell-clp</artifact>
+                                    <excludes>
+                                        <exclude>org/apache/geronimo/gshell/**</exclude>
+                                    </excludes>
+                                </filter>
+                                <filter>
+                                    <artifact>org.apache.geronimo.gshell.support:gshell-console</artifact>
+                                    <excludes>
+                                        <exclude>org/apache/geronimo/gshell/**</exclude>
+                                    </excludes>
+                                </filter>
+                                <filter>
+                                    <artifact>org.apache.geronimo.gshell.support:gshell-event</artifact>
+                                    <excludes>
+                                        <exclude>org/apache/geronimo/gshell/**</exclude>
+                                    </excludes>
+                                </filter>
+                                <filter>
+                                    <artifact>org.apache.geronimo.gshell.support:gshell-i18n</artifact>
+                                    <excludes>
+                                        <exclude>org/apache/geronimo/gshell/**</exclude>
+                                    </excludes>
+                                </filter>
+                                <filter>
+                                    <artifact>org.apache.geronimo.gshell.support:gshell-interpolation</artifact>
+                                    <excludes>
+                                        <exclude>org/apache/geronimo/gshell/**</exclude>
+                                    </excludes>
+                                </filter>
+                                <filter>
+                                    <artifact>org.apache.geronimo.gshell.support:gshell-io</artifact>
+                                    <excludes>
+                                        <exclude>org/apache/geronimo/gshell/**</exclude>
+                                    </excludes>
+                                </filter>
+                                <filter>
+                                    <artifact>org.apache.geronimo.gshell.support:gshell-security</artifact>
+                                    <excludes>
+                                        <exclude>org/apache/geronimo/gshell/**</exclude>
+                                    </excludes>
+                                </filter>
+                                <filter>
+                                    <artifact>org.apache.geronimo.gshell.support:gshell-spring</artifact>
+                                    <excludes>
+                                        <exclude>org/apache/geronimo/gshell/**</exclude>
+                                    </excludes>
+                                </filter>
+                                <filter>
+                                    <artifact>org.apache.geronimo.gshell.support:gshell-terminal</artifact>
+                                    <excludes>
+                                        <exclude>org/apache/geronimo/gshell/**</exclude>
+                                    </excludes>
+                                </filter>
+                                <filter>
+                                    <artifact>org.apache.geronimo.gshell.support:gshell-vfs</artifact>
+                                    <excludes>
+                                        <exclude>org/apache/geronimo/gshell/**</exclude>
+                                    </excludes>
+                                </filter>
+                                <filter>
+                                    <artifact>org.apache.geronimo.gshell.support:gshell-vfs-meta</artifact>
+                                    <excludes>
+                                        <exclude>org/apache/geronimo/gshell/**</exclude>
+                                    </excludes>
+                                </filter>
+                                <filter>
+                                    <artifact>org.apache.geronimo.gshell.support:gshell-yarn</artifact>
+                                    <excludes>
+                                        <exclude>org/apache/geronimo/gshell/**</exclude>
+                                    </excludes>
+                                </filter>
+                                <filter>
+                                    <artifact>org.apache.geronimo.gshell.wisdom:gshell-wisdom-core</artifact>
+                                    <excludes>
+                                        <exclude>org/apache/geronimo/gshell/**</exclude>
+                                    </excludes>
+                                </filter>
+                                <filter>
+                                    <artifact>org.apache.geronimo.gshell.wisdom:gshell-wisdom-bootstrap</artifact>
+                                    <excludes>
+                                        <exclude>org/apache/geronimo/gshell/**</exclude>
+                                    </excludes>
+                                </filter>
+                                <filter>
+                                    <artifact>org.codehaus.plexus:plexus-utils</artifact>
+                                    <excludes>
+                                        <exclude>org/codehaus/plexus/**</exclude>
+                                    </excludes>
+                                </filter>
+                                <filter>
+                                    <artifact>org.codehaus.plexus:plexus-interpolation</artifact>
+                                    <excludes>
+                                        <exclude>org/codehaus/plexus/**</exclude>
+                                    </excludes>
+                                </filter>
+                            </filters>
+                            <createSourcesJar>${createSourcesJar}</createSourcesJar>
+                            <promoteTransitiveDependencies>true</promoteTransitiveDependencies>
+                            <createDependencyReducedPom>true</createDependencyReducedPom>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/karaf/gshell/gshell-core/src/main/filtered-resources/org/apache/servicemix/kernel/gshell/core/servicemix-version.properties b/karaf/gshell/gshell-core/src/main/filtered-resources/org/apache/servicemix/kernel/gshell/core/servicemix-version.properties
new file mode 100644
index 0000000..1fc0355
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/filtered-resources/org/apache/servicemix/kernel/gshell/core/servicemix-version.properties
@@ -0,0 +1,20 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+version=${pom.version}
diff --git a/karaf/gshell/gshell-core/src/main/java/org/apache/geronimo/gshell/commands/shell/FindAction.java b/karaf/gshell/gshell-core/src/main/java/org/apache/geronimo/gshell/commands/shell/FindAction.java
new file mode 100644
index 0000000..203e340
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/java/org/apache/geronimo/gshell/commands/shell/FindAction.java
@@ -0,0 +1,208 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.geronimo.gshell.commands.shell;
+
+import java.net.URI;
+
+import org.apache.commons.vfs.FileObject;
+import org.apache.commons.vfs.FileSelectInfo;
+import org.apache.commons.vfs.FileSelector;
+import org.apache.commons.vfs.FileSystemException;
+import org.apache.commons.vfs.FileType;
+import org.apache.geronimo.gshell.clp.Argument;
+import org.apache.geronimo.gshell.clp.Option;
+import org.apache.geronimo.gshell.command.CommandAction;
+import org.apache.geronimo.gshell.command.CommandContext;
+import org.apache.geronimo.gshell.io.IO;
+import org.apache.geronimo.gshell.vfs.FileObjects;
+import org.apache.geronimo.gshell.vfs.selector.AggregateFileSelector;
+import org.apache.geronimo.gshell.vfs.support.VfsActionSupport;
+import org.apache.oro.text.GlobCompiler;
+import org.apache.oro.text.regex.MalformedPatternException;
+import org.apache.oro.text.regex.Pattern;
+import org.apache.oro.text.regex.PatternCompiler;
+import org.apache.oro.text.regex.PatternMatcher;
+import org.apache.oro.text.regex.Perl5Matcher;
+
+/**
+ * Find files in a hierarchy.
+ *
+ * TODO: remove this file when gshell is upgraded
+ *
+ * @version $Rev: 722797 $ $Date: 2008-12-03 08:18:16 +0100 (Wed, 03 Dec 2008) $
+ */
+public class FindAction
+    extends VfsActionSupport
+{
+    private final AggregateFileSelector selector = new AggregateFileSelector();
+
+    @Option(name="-name")
+    private void addNameFilter(final String name) throws MalformedPatternException {
+        log.debug("Adding -name selector for: {}", name);
+        selector.getSelectors().add(new NameSelector(name));
+    }
+
+    @Option(name="-iname")
+    private void addiNameFilter(final String name) throws MalformedPatternException {
+        log.debug("Adding -iname selector for: {}", name);
+        selector.getSelectors().add(new NameSelector(name, true));
+    }
+
+    @Option(name="-type")
+    private void addTypeFilter(final Type type) {
+        log.debug("Adding -type selector for: {}", type);
+        selector.getSelectors().add(new TypeSelector(type));
+    }
+
+    @Argument(required=true)
+    private String path;
+
+    public Object execute(final CommandContext context) throws Exception {
+        assert context != null;
+        IO io = context.getIo();
+
+        FileObject root = resolveFile(context, path);
+
+        ensureFileExists(root);
+
+        find(context, root, selector);
+
+        FileObjects.close(root);
+
+        return CommandAction.Result.SUCCESS;
+    }
+
+    private void find(final CommandContext context, final FileObject file, final FileSelector selector) throws FileSystemException {
+        assert context != null;
+        assert file != null;
+        assert selector != null;
+
+        FileObject[] files = file.findFiles(selector);
+
+        if (files != null && files.length != 0) {
+            for (FileObject child : files) {
+                display(context, child, file);
+            }
+        }
+    }
+
+    private void display(final CommandContext context, final FileObject file, final FileObject root) throws FileSystemException {
+        assert context != null;
+        assert file != null;
+
+        String path;
+        try {
+            path = new URI(this.path).resolve(root.getURL().toURI().relativize(file.getURL().toURI())).toString();
+        } catch (Exception e) {
+            path = file.getName().getPath();
+        }
+        IO io = context.getIo();
+        io.info(path);
+    }
+
+    //
+    // Type & TypeSelector
+    //
+
+    private enum Type
+    {
+        F, // normal file
+        D, // directory
+    }
+
+    private class TypeSelector
+        implements FileSelector
+    {
+        private final Type type;
+
+        public TypeSelector(final Type type) {
+            assert type != null;
+
+            this.type = type;
+
+            log.trace("Type: {}", type);
+        }
+
+        public boolean includeFile(final FileSelectInfo selection) throws Exception {
+            assert selection != null;
+
+            FileType ftype = selection.getFile().getType();
+
+            switch (type) {
+                case D:
+                    return ftype == FileType.FOLDER;
+
+                case F:
+                    return ftype == FileType.FILE;
+
+                // TODO: Handle FileType.FILE_OR_FOLDER
+
+                default:
+                    return false;
+            }
+        }
+
+        public boolean traverseDescendents(final FileSelectInfo selection) throws Exception {
+            return true;
+        }
+    }
+
+    //
+    // NameSelector
+    //
+
+    private class NameSelector
+        implements FileSelector
+    {
+        private final Pattern pattern;
+
+        private final PatternMatcher matcher;
+
+        public NameSelector(final String name, final boolean ignoreCase) throws MalformedPatternException {
+            assert name != null;
+
+            PatternCompiler compiler = new GlobCompiler();
+            int options;
+            if (ignoreCase) {
+                options = GlobCompiler.CASE_INSENSITIVE_MASK;
+            }
+            else {
+                options = GlobCompiler.DEFAULT_MASK;
+            }
+            this.pattern = compiler.compile(name, options);
+            this.matcher = new Perl5Matcher();
+
+            log.trace("Pattern: {}", pattern.getPattern());
+        }
+
+        public NameSelector(final String name) throws MalformedPatternException {
+            this(name, false);
+        }
+
+        public boolean includeFile(final FileSelectInfo selection) throws Exception {
+            assert selection != null;
+            return matcher.matches(selection.getFile().getName().getBaseName(), pattern);
+        }
+
+        public boolean traverseDescendents(final FileSelectInfo selection) throws Exception {
+            return true;
+        }
+    }
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-core/src/main/java/org/apache/geronimo/gshell/commands/ssh/JSecurityPasswordAuthenticator.java b/karaf/gshell/gshell-core/src/main/java/org/apache/geronimo/gshell/commands/ssh/JSecurityPasswordAuthenticator.java
new file mode 100644
index 0000000..d3bb6de
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/java/org/apache/geronimo/gshell/commands/ssh/JSecurityPasswordAuthenticator.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.geronimo.gshell.commands.ssh;
+
+import org.apache.sshd.server.PasswordAuthenticator;
+import org.jsecurity.SecurityUtils;
+import org.jsecurity.authc.AuthenticationException;
+import org.jsecurity.authc.UsernamePasswordToken;
+import org.jsecurity.mgt.SecurityManager;
+import org.jsecurity.subject.Subject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * <a href="http://jsecurity.org">JSecurity</a> {@link PasswordAuthenticator}.
+ *
+ * @version $Rev: 722797 $ $Date: 2008-12-03 08:18:16 +0100 (Wed, 03 Dec 2008) $
+ */
+public class JSecurityPasswordAuthenticator
+    implements PasswordAuthenticator
+{
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    private final SecurityManager securityManager;
+
+    public JSecurityPasswordAuthenticator(final SecurityManager securityManager) {
+        // securityManager can be null
+        this.securityManager = securityManager;
+    }
+
+    public JSecurityPasswordAuthenticator() {
+        this(null);
+    }
+
+    public Object authenticate(final String username, final String password) {
+        assert username != null;
+        assert password != null;
+
+        log.debug("Authenticating: {}/{}", username, password);
+
+        Subject currentUser;
+
+        if (securityManager != null) {
+            currentUser = securityManager.getSubject();
+        }
+        else {
+            currentUser = SecurityUtils.getSubject();
+        }
+
+        if (currentUser.isAuthenticated()) {
+            log.debug("Logging out current user: {}", currentUser.getPrincipal());
+            currentUser.logout();
+        }
+
+        try {
+            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
+            currentUser.login(token);
+            Object principal = currentUser.getPrincipal();
+            log.info("User [{}] logged in successfully", principal);
+            return principal;
+        }
+        catch (AuthenticationException e) {
+            log.error("Authentication failed: " + e, e);
+            return null;
+        }
+    }
+}
diff --git a/karaf/gshell/gshell-core/src/main/java/org/apache/geronimo/gshell/commands/ssh/ShellFactoryImpl.java b/karaf/gshell/gshell-core/src/main/java/org/apache/geronimo/gshell/commands/ssh/ShellFactoryImpl.java
new file mode 100644
index 0000000..9795f01
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/java/org/apache/geronimo/gshell/commands/ssh/ShellFactoryImpl.java
@@ -0,0 +1,267 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.geronimo.gshell.commands.ssh;
+
+import org.apache.sshd.server.ShellFactory;
+import jline.Completor;
+import jline.History;
+import org.apache.geronimo.gshell.command.Variables;
+import org.apache.geronimo.gshell.commandline.CommandLineExecutor;
+import org.apache.geronimo.gshell.console.Console;
+import org.apache.geronimo.gshell.console.JLineConsole;
+import org.apache.geronimo.gshell.console.completer.AggregateCompleter;
+import org.apache.geronimo.gshell.io.Closer;
+import org.apache.geronimo.gshell.io.IO;
+import org.apache.geronimo.gshell.notification.ExitNotification;
+import org.apache.geronimo.gshell.shell.ShellContext;
+import org.apache.geronimo.gshell.shell.ShellContextHolder;
+import org.apache.geronimo.gshell.registry.CommandResolver;
+import org.apache.geronimo.gshell.application.Application;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * SSHD {@link ShellFactory} which provides access to GShell.
+ *
+ * @version $Rev: 731517 $ $Date: 2009-01-05 11:25:19 +0100 (Mon, 05 Jan 2009) $
+ */
+public class ShellFactoryImpl
+    implements ShellFactory
+{
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    private Application application;
+
+    private Console.Prompter prompter;
+
+    private CommandLineExecutor executor;
+
+    private History history;
+
+    private List<Completor> completers;
+
+    private Console.ErrorHandler errorHandler;
+
+    public Console.Prompter getPrompter() {
+        return prompter;
+    }
+
+    public void setPrompter(final Console.Prompter prompter) {
+        this.prompter = prompter;
+    }
+
+    public CommandLineExecutor getExecutor() {
+        return executor;
+    }
+
+    public void setExecutor(final CommandLineExecutor executor) {
+        this.executor = executor;
+    }
+
+    public History getHistory() {
+        return history;
+    }
+
+    public void setHistory(final History history) {
+        this.history = history;
+    }
+
+    public List<Completor> getCompleters() {
+        return completers;
+    }
+
+    public void setCompleters(final List<Completor> completers) {
+        this.completers = completers;
+    }
+
+    public Console.ErrorHandler getErrorHandler() {
+        return errorHandler;
+    }
+
+    public void setErrorHandler(final Console.ErrorHandler errorHandler) {
+        this.errorHandler = errorHandler;
+    }
+
+    public Application getApplication() {
+        return application;
+    }
+
+    public void setApplication(Application application) {
+        this.application = application;
+    }
+
+    public Shell createShell() {
+        return new ShellImpl();
+    }
+
+    public class ShellImpl
+        implements ShellFactory.Shell, org.apache.geronimo.gshell.shell.Shell, ShellContext, Runnable
+    {
+        private InputStream in;
+
+        private OutputStream out;
+
+        private OutputStream err;
+
+        private ExitCallback callback;
+
+        private IO io;
+
+        private Variables variables;
+
+        private boolean closed;
+
+        public void setInputStream(final InputStream in) {
+            this.in = in;
+        }
+
+        public void setOutputStream(final OutputStream out) {
+            this.out = out;
+        }
+
+        public void setErrorStream(final OutputStream err) {
+            this.err = err;
+        }
+
+        public void setExitCallback(ExitCallback callback) {
+            this.callback = callback;
+        }
+
+        public void start(final Map<String,String> env) throws IOException {
+            this.io = new IO(in, out, err, false);
+
+            // Create variables, inheriting the application ones
+            this.variables = new Variables(application.getVariables());
+            // Set up additional env
+            if (env != null) {
+                for (Map.Entry<String,String> entry : env.entrySet()) {
+                    this.variables.set(entry.getKey(), entry.getValue());
+                }
+            }
+            this.variables.set("gshell.prompt", application.getModel().getBranding().getPrompt());
+            this.variables.set(CommandResolver.GROUP, "/");
+            this.variables.set("gshell.username", env.get("USER"));
+            this.variables.set("gshell.hostname", application.getLocalHost());
+            // HACK: Add history for the 'history' command, since its not part of the Shell intf it can't really access it
+            this.variables.set("gshell.internal.history", getHistory(), true);
+            new Thread(this).start();
+        }
+
+        public void destroy() {
+            close();
+        }
+
+        public ShellContext getContext() {
+            return this;
+        }
+
+        public Object execute(final String line) throws Exception {
+
+            return executor.execute(getContext(), line);
+        }
+
+        public Object execute(final String command, final Object[] args) throws Exception {
+            return executor.execute(getContext(), args);
+        }
+
+        public Object execute(final Object... args) throws Exception {
+            return executor.execute(getContext(), args);
+        }
+
+        public boolean isOpened() {
+            return !closed;
+        }
+
+        public void close() {
+            closed = true;
+            Closer.close(in, out, err);
+            callback.onExit(0);
+        }
+
+        public boolean isInteractive() {
+            return false;
+        }
+
+        public void run(final Object... args) throws Exception {
+            Console.Executor executor = new Console.Executor()
+            {
+                public Result execute(final String line) throws Exception {
+                    assert line != null;
+                    try {
+                        ShellImpl.this.execute(line);
+                    }
+                    catch (ExitNotification n) {
+                        return Result.STOP;
+                    }
+                    return Result.CONTINUE;
+                }
+            };
+
+            IO io = getContext().getIo();
+
+            // Setup the console runner
+            JLineConsole console = new JLineConsole(executor, io);
+            console.setPrompter(getPrompter());
+            console.setErrorHandler(getErrorHandler());
+            console.setHistory(getHistory());
+
+            if (completers != null) {
+                // Have to use aggregate here to get the completion list to update properly
+                console.addCompleter(new AggregateCompleter(completers));
+            }
+            
+            console.run();
+        }
+
+        public org.apache.geronimo.gshell.shell.Shell getShell() {
+            return this;
+        }
+
+        public IO getIo() {
+            return io;
+        }
+
+        public Variables getVariables() {
+            return variables;
+        }
+
+        public void run() {
+            ShellContext ctx = ShellContextHolder.get(true);
+
+            try {
+                ShellContextHolder.set(getContext());
+                run(new Object[0]);
+            }
+            catch (Exception e) {
+                log.error("Unhandled failure: " + e, e);
+            }
+            finally {
+                ShellContextHolder.set(ctx);
+                close();
+            }
+        }
+    }
+}
diff --git a/karaf/gshell/gshell-core/src/main/java/org/apache/geronimo/gshell/commands/ssh/SshAction.java b/karaf/gshell/gshell-core/src/main/java/org/apache/geronimo/gshell/commands/ssh/SshAction.java
new file mode 100644
index 0000000..cafc437
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/java/org/apache/geronimo/gshell/commands/ssh/SshAction.java
@@ -0,0 +1,169 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.geronimo.gshell.commands.ssh;
+
+import org.apache.sshd.ClientChannel;
+import org.apache.sshd.ClientSession;
+import org.apache.sshd.SshClient;
+import org.apache.sshd.client.future.ConnectFuture;
+import org.apache.sshd.common.util.NoCloseInputStream;
+import org.apache.sshd.common.util.NoCloseOutputStream;
+import org.apache.geronimo.gshell.clp.Argument;
+import org.apache.geronimo.gshell.clp.Option;
+import org.apache.geronimo.gshell.command.CommandAction;
+import org.apache.geronimo.gshell.command.CommandContext;
+import org.apache.geronimo.gshell.i18n.MessageSource;
+import org.apache.geronimo.gshell.io.IO;
+import org.apache.geronimo.gshell.io.PromptReader;
+import org.apache.geronimo.gshell.spring.BeanContainer;
+import org.apache.geronimo.gshell.spring.BeanContainerAware;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Connect to a SSH server.
+ *
+ * @version $Rev: 721244 $ $Date: 2008-11-27 18:19:56 +0100 (Thu, 27 Nov 2008) $
+ */
+public class SshAction
+    implements CommandAction, BeanContainerAware
+{
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    @Option(name="-l", aliases={"--username"})
+    private String username;
+
+    @Option(name="-P", aliases={"--password"})
+    private String password;
+
+    @Argument(required=true)
+    private String hostname;
+
+    @Option(name="-p", aliases={"--port"})
+    private int port = 22;
+
+    private BeanContainer container;
+
+	private ClientSession session;
+
+    public void setBeanContainer(final BeanContainer container) {
+        assert container != null;
+        this.container = container;
+    }
+
+    /**
+     * Helper to validate that prompted username or password is not null or empty.
+     */
+    private class UsernamePasswordValidator
+        implements PromptReader.Validator
+    {
+        private String type;
+
+        private int count = 0;
+
+        private int max = 3;
+
+        public UsernamePasswordValidator(final String type) {
+            assert type != null;
+
+            this.type = type;
+        }
+
+        public boolean isValid(final String value) {
+            count++;
+
+            if (value != null && value.trim().length() > 0) {
+                return true;
+            }
+
+            if (count >= max) {
+                throw new RuntimeException("Too many attempts; failed to prompt user for " + type + " after " + max + " tries");
+            }
+
+            return false;
+        }
+    }
+
+    public Object execute(final CommandContext context) throws Exception {
+        assert context != null;
+        IO io = context.getIo();
+        MessageSource messages = context.getCommand().getMessages();
+
+        //
+        // TODO: Parse hostname for <username>@<hostname>
+        //
+        
+        io.info(messages.format("info.connecting", hostname, port));
+
+        // If the username/password was not configured via cli, then prompt the user for the values
+        if (username == null || password == null) {
+            PromptReader prompter = new PromptReader(io);
+            String text;
+
+            log.debug("Prompting user for credentials");
+
+            if (username == null) {
+                text = messages.getMessage("prompt.username");
+                username = prompter.readLine(text + ": ", new UsernamePasswordValidator(text));
+            }
+
+            if (password == null) {
+                text = messages.getMessage("prompt.password");
+                password = prompter.readPassword(text + ": ", new UsernamePasswordValidator(text));
+            }
+        }
+
+        // Create the client from prototype
+        SshClient client = container.getBean(SshClient.class);
+        log.debug("Created client: {}", client);
+        client.start();;
+
+        try {
+            ConnectFuture future = client.connect(hostname, port);
+            future.await();
+            session = future.getSession();
+            try {
+                io.info(messages.getMessage("info.connected"));
+
+                session.authPassword(username, password);
+                int ret = session.waitFor(ClientSession.WAIT_AUTH | ClientSession.CLOSED | ClientSession.AUTHED, 0);
+                if ((ret & ClientSession.AUTHED) == 0) {
+                    io.err.println("Authentication failed");
+                    return Result.FAILURE;
+                }
+
+                ClientChannel channel = session.createChannel("shell");
+                channel.setIn(new NoCloseInputStream(io.inputStream));
+                channel.setOut(new NoCloseOutputStream(io.outputStream));
+                channel.setErr(new NoCloseOutputStream(io.errorStream));
+                channel.open();
+                channel.waitFor(ClientChannel.CLOSED, 0);
+            } finally {
+                session.close(false);
+            }
+        } finally {
+            client.stop();
+        }
+
+        io.verbose(messages.getMessage("verbose.disconnected"));
+
+        return Result.SUCCESS;
+    }
+}
diff --git a/karaf/gshell/gshell-core/src/main/java/org/apache/geronimo/gshell/commands/ssh/SshServerAction.java b/karaf/gshell/gshell-core/src/main/java/org/apache/geronimo/gshell/commands/ssh/SshServerAction.java
new file mode 100644
index 0000000..db1cfb0
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/java/org/apache/geronimo/gshell/commands/ssh/SshServerAction.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.geronimo.gshell.commands.ssh;
+
+import org.apache.sshd.SshServer;
+import org.apache.geronimo.gshell.clp.Option;
+import org.apache.geronimo.gshell.command.CommandAction;
+import org.apache.geronimo.gshell.command.CommandContext;
+import org.apache.geronimo.gshell.i18n.MessageSource;
+import org.apache.geronimo.gshell.io.IO;
+import org.apache.geronimo.gshell.spring.BeanContainer;
+import org.apache.geronimo.gshell.spring.BeanContainerAware;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Start a SSH server.
+ *
+ * @version $Rev: 720411 $ $Date: 2008-11-25 05:32:43 +0100 (Tue, 25 Nov 2008) $
+ */
+public class SshServerAction
+    implements CommandAction, BeanContainerAware
+{
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    @Option(name="-p", aliases={ "--port" })
+    private int port=8101;
+
+    @Option(name="-b", aliases={ "--background"})
+    private boolean background = true;
+
+    private BeanContainer container;
+
+    public void setBeanContainer(final BeanContainer container) {
+        assert container != null;
+
+        this.container = container;
+    }
+
+    public Object execute(final CommandContext context) throws Exception {
+        assert context != null;
+        IO io = context.getIo();
+        MessageSource messages = context.getCommand().getMessages();
+
+        SshServer server = container.getBean("sshServer", SshServer.class);
+
+        log.debug("Created server: {}", server);
+
+        server.setPort(port);
+
+        server.start();
+
+        io.info(messages.format("info.listening", port));
+
+        if (!background) {
+            synchronized (this) {
+                log.debug("Waiting for server to shutdown");
+
+                wait();
+            }
+
+            server.stop();
+        }
+
+        return Result.SUCCESS;
+    }
+}
diff --git a/karaf/gshell/gshell-core/src/main/java/org/apache/geronimo/gshell/commands/text/SortAction.java b/karaf/gshell/gshell-core/src/main/java/org/apache/geronimo/gshell/commands/text/SortAction.java
new file mode 100644
index 0000000..e81b247
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/java/org/apache/geronimo/gshell/commands/text/SortAction.java
@@ -0,0 +1,391 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.geronimo.gshell.commands.text;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.vfs.FileObject;
+import org.apache.geronimo.gshell.clp.Argument;
+import org.apache.geronimo.gshell.clp.Option;
+import org.apache.geronimo.gshell.command.CommandContext;
+import org.apache.geronimo.gshell.io.Closer;
+import org.apache.geronimo.gshell.vfs.FileObjects;
+import org.apache.geronimo.gshell.vfs.support.VfsActionSupport;
+
+/**
+ * Sort lines of text
+ *
+ * TODO: remove this file when gshell is upgraded
+ *
+ */
+public class SortAction extends VfsActionSupport {
+
+    @Option(name = "-f")
+    private boolean caseInsensitive;
+
+    @Option(name = "-r")
+    private boolean reverse;
+
+    @Option(name = "-u")
+    private boolean unique;
+
+    @Option(name = "-t")
+    private String separator;
+
+    @Option(name = "-b")
+    private boolean ignoreBlanks;
+
+    @Option(name = "-k", argumentRequired = true, multiValued = true)
+    private List<String> sortFields;
+
+    @Option(name = "-n")
+    private boolean numeric;
+
+    @Argument(index = 0, required=false)
+    private String path;
+
+
+    public Object execute(CommandContext context) throws Exception {
+        assert context != null;
+
+        if (path != null) {
+            FileObject file = resolveFile(context, path);
+
+            try {
+                sort(context, file);
+            }
+            finally {
+                FileObjects.close(file);
+            }
+        }
+        else {
+            sort(context.getIo().inputStream, context.getIo().out);
+        }
+        return Result.SUCCESS;
+    }
+
+    protected void sort(final CommandContext context, final FileObject file) throws Exception {
+        assert context != null;
+        assert file != null;
+
+        ensureFileExists(file);
+        ensureFileHasContent(file);
+        ensureFileIsReadable(file);
+
+        BufferedInputStream input = new BufferedInputStream(file.getContent().getInputStream());
+        try {
+            sort(input, context.getIo().out);
+        }
+        finally {
+            Closer.close(input);
+        }
+    }
+
+    protected void sort(InputStream input, PrintWriter out) throws Exception {
+        BufferedReader r = new BufferedReader(new InputStreamReader(input));
+        List<String> strings = new ArrayList<String>();
+        for (String s = r.readLine(); s != null; s = r.readLine()) {
+            strings.add(s);
+        }
+        char sep = (separator == null || separator.length() == 0) ? '\0' : separator.charAt(0);
+        Collections.sort(strings, new SortComparator(caseInsensitive, reverse, ignoreBlanks, numeric, sep, sortFields));
+        String last = null;
+        for (String s : strings) {
+            if (last == null) {
+                last = s;
+            } else if (!unique || !s.equals(last)) {
+                out.println(s);
+            }
+        }
+    }
+
+    public static class SortComparator implements Comparator<String> {
+
+        private boolean caseInsensitive;
+        private boolean reverse;
+        private boolean ignoreBlanks;
+        private boolean numeric;
+        private char separator;
+        private List<Key> sortKeys;
+
+        private static Pattern fpPattern;
+        static {
+            final String Digits     = "(\\p{Digit}+)";
+            final String HexDigits  = "(\\p{XDigit}+)";
+            final String Exp        = "[eE][+-]?" + Digits;
+            final String fpRegex    = "([\\x00-\\x20]*[+-]?(NaN|Infinity|(((" + Digits + "(\\.)?(" + Digits + "?)(" + Exp + ")?)|(\\.(" + Digits + ")(" + Exp + ")?)|(((0[xX]" + HexDigits + "(\\.)?)|(0[xX]" + HexDigits + "?(\\.)" + HexDigits + "))[pP][+-]?" + Digits + "))" + "[fFdD]?))[\\x00-\\x20]*)(.*)";
+            fpPattern = Pattern.compile(fpRegex);
+        }
+
+        public SortComparator(boolean caseInsensitive,
+                              boolean reverse,
+                              boolean ignoreBlanks,
+                              boolean numeric,
+                              char separator,
+                              List<String> sortFields) {
+            this.caseInsensitive = caseInsensitive;
+            this.reverse = reverse;
+            this.separator = separator;
+            this.ignoreBlanks = ignoreBlanks;
+            this.numeric = numeric;
+            if (sortFields == null || sortFields.size() == 0) {
+                sortFields = new ArrayList<String>();
+                sortFields.add("1");
+            }
+            sortKeys = new ArrayList<Key>();
+            for (String f : sortFields) {
+                sortKeys.add(new Key(f));
+            }
+        }
+
+        public int compare(String o1, String o2) {
+            int res = 0;
+
+            List<Integer> fi1 = getFieldIndexes(o1);
+            List<Integer> fi2 = getFieldIndexes(o2);
+            for (Key key : sortKeys) {
+                int[] k1 = getSortKey(o1, fi1, key);
+                int[] k2 = getSortKey(o2, fi2, key);
+                if (key.numeric) {
+                    Double d1 = getDouble(o1, k1[0], k1[1]);
+                    Double d2 = getDouble(o2, k2[0], k2[1]);
+                    res = d1.compareTo(d2);
+                } else {
+                    res = compareRegion(o1, k1[0], k1[1], o2, k2[0], k2[1], key.caseInsensitive);
+                }
+                if (res != 0) {
+                    if (key.reverse) {
+                        res = - res;
+                    }
+                    break;
+                }
+            }
+            return res;
+        }
+
+        protected Double getDouble(String s, int start, int end) {
+            Matcher m = fpPattern.matcher(s.substring(start, end));
+            m.find();
+            return new Double(s.substring(0, m.end(1)));
+        }
+
+        protected int compareRegion(String s1, int start1, int end1, String s2, int start2, int end2, boolean caseInsensitive) {
+            int n1 = end1, n2 = end2;
+            for (int i1 = start1, i2 = start2; i1 < end1 && i2 < n2; i1++, i2++) {
+                char c1 = s1.charAt(i1);
+                char c2 = s2.charAt(i2);
+                if (c1 != c2) {
+                    if (caseInsensitive) {
+                        c1 = Character.toUpperCase(c1);
+                        c2 = Character.toUpperCase(c2);
+                        if (c1 != c2) {
+                            c1 = Character.toLowerCase(c1);
+                            c2 = Character.toLowerCase(c2);
+                            if (c1 != c2) {
+                                return c1 - c2;
+                            }
+                        }
+                    } else {
+                        return c1 - c2;
+                    }
+                }
+            }
+            return n1 - n2;
+        }
+
+        protected int[] getSortKey(String str, List<Integer> fields, Key key) {
+            int start;
+            int end;
+            if (key.startField * 2 < fields.size()) {
+                start = fields.get((key.startField - 1) * 2);
+                if (key.ignoreBlanksStart) {
+                    while (start < fields.get((key.startField - 1) * 2 + 1) && Character.isWhitespace(str.charAt(start))) {
+                        start++;
+                    }
+                }
+                if (key.startChar > 0) {
+                    start = Math.min(start + key.startChar - 1, fields.get((key.startField - 1) * 2 + 1));
+                }
+            } else {
+                start = 0;
+            }
+            if (key.endField > 0 && key.endField * 2 < fields.size()) {
+                end =  fields.get((key.endField - 1) * 2);
+                if (key.ignoreBlanksEnd) {
+                    while (end < fields.get((key.endField - 1) * 2 + 1) && Character.isWhitespace(str.charAt(end))) {
+                        end++;
+                    }
+                }
+                if (key.endChar > 0) {
+                    end = Math.min(end + key.endChar - 1, fields.get((key.endField - 1) * 2 + 1));
+                }
+            } else {
+                end = str.length();
+            }
+            return new int[] { start, end };
+        }
+
+        protected List<Integer> getFieldIndexes(String o) {
+            List<Integer> fields = new ArrayList<Integer>();
+            if (o.length() > 0) {
+                if (separator == '\0') {
+                    int i = 0;
+                    fields.add(0);
+                    for (int idx = 1; idx < o.length(); idx++) {
+                        if (Character.isWhitespace(o.charAt(idx)) && !Character.isWhitespace(o.charAt(idx - 1))) {
+                            fields.add(idx - 1);
+                            fields.add(idx);
+                        }
+                    }
+                    fields.add(o.length() - 1);
+                } else {
+                    int last = -1;
+                    for (int idx = o.indexOf(separator); idx >= 0; idx = o.indexOf(separator, idx + 1)) {
+                        if (last >= 0) {
+                            fields.add(last);
+                            fields.add(idx - 1);
+                        } else if (idx > 0) {
+                            fields.add(0);
+                            fields.add(idx - 1);
+                        }
+                        last = idx + 1;
+                    }
+                    if (last < o.length()) {
+                        fields.add(last < 0 ? 0 : last);
+                        fields.add(o.length() - 1);
+                    }
+                }
+            }
+            return fields;
+        }
+
+        public class Key {
+            int startField;
+            int startChar;
+            int endField;
+            int endChar;
+            boolean ignoreBlanksStart;
+            boolean ignoreBlanksEnd;
+            boolean caseInsensitive;
+            boolean reverse;
+            boolean numeric;
+
+            public Key(String str) {
+                boolean modifiers = false;
+                boolean startPart = true;
+                boolean inField = true;
+                boolean inChar = false;
+                for (char c : str.toCharArray()) {
+                    switch (c) {
+                        case '0':
+                        case '1':
+                        case '2':
+                        case '3':
+                        case '4':
+                        case '5':
+                        case '6':
+                        case '7':
+                        case '8':
+                        case '9':
+                            if (!inField && !inChar) {
+                                throw new IllegalArgumentException("Bad field syntax: " + str);
+                            }
+                            if (startPart) {
+                                if (inChar) {
+                                    startChar = startChar * 10 + (c - '0');
+                                } else {
+                                    startField = startField * 10 + (c - '0');
+                                }
+                            } else {
+                                if (inChar) {
+                                    endChar = endChar * 10 + (c - '0');
+                                } else {
+                                    endField = endField * 10 + (c - '0');
+                                }
+                            }
+                            break;
+                        case '.':
+                            if (!inField) {
+                                throw new IllegalArgumentException("Bad field syntax: " + str);
+                            }
+                            inField = false;
+                            inChar = true;
+                            break;
+                        case 'n':
+                            inField = false;
+                            inChar = false;
+                            modifiers = true;
+                            numeric = true;
+                            break;
+                        case 'f':
+                            inField = false;
+                            inChar = false;
+                            modifiers = true;
+                            caseInsensitive = true;
+                            break;
+                        case 'r':
+                            inField = false;
+                            inChar = false;
+                            modifiers = true;
+                            reverse = true;
+                            break;
+                        case 'b':
+                            inField = false;
+                            inChar = false;
+                            modifiers = true;
+                            if (startPart) {
+                                ignoreBlanksStart = true;
+                            } else {
+                                ignoreBlanksEnd = true;
+                            }
+                            break;
+                        case ',':
+                            inField = true;
+                            inChar = false;
+                            startPart = false;
+                            break;
+                        default:
+                            throw new IllegalArgumentException("Bad field syntax: " + str);
+                    }
+                }
+                if (!modifiers) {
+                    ignoreBlanksStart = ignoreBlanksEnd = SortComparator.this.ignoreBlanks;
+                    reverse = SortComparator.this.reverse;
+                    caseInsensitive = SortComparator.this.caseInsensitive;
+                    numeric = SortComparator.this.numeric;
+                }
+                if (startField < 1) {
+                    throw new IllegalArgumentException("Bad field syntax: " + str);
+                }
+            }
+        }
+    }
+
+}
diff --git a/karaf/gshell/gshell-core/src/main/java/org/apache/geronimo/gshell/vfs/provider/meta/MetaFileObject.java b/karaf/gshell/gshell-core/src/main/java/org/apache/geronimo/gshell/vfs/provider/meta/MetaFileObject.java
new file mode 100644
index 0000000..7e71328
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/java/org/apache/geronimo/gshell/vfs/provider/meta/MetaFileObject.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.geronimo.gshell.vfs.provider.meta;
+
+import org.apache.commons.vfs.FileContentInfoFactory;
+import org.apache.commons.vfs.FileName;
+import org.apache.commons.vfs.FileType;
+import org.apache.commons.vfs.FileContent;
+import org.apache.commons.vfs.FileSystemException;
+import org.apache.commons.vfs.provider.AbstractFileObject;
+import org.apache.commons.vfs.provider.DefaultFileContent;
+import org.apache.geronimo.gshell.vfs.provider.meta.data.MetaData;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.Map;
+
+/**
+ * Meta file object.
+ *
+ * TODO: remove this file when gshell version is upgraded
+ *
+ * @version $Rev: 706033 $ $Date: 2008-10-19 17:36:15 +0200 (Sun, 19 Oct 2008) $
+ */
+public class MetaFileObject
+    extends AbstractFileObject
+{
+    private final MetaFileSystem fileSystem;
+
+    private MetaData data;
+    private FileContent content;
+
+    public MetaFileObject(final FileName fileName, final MetaFileSystem fileSystem) {
+        super(fileName, fileSystem);
+
+        // Save for uncasted typed access
+        this.fileSystem = fileSystem;
+    }
+
+    public MetaData getData() {
+        if (data == null) {
+            throw new IllegalStateException("Meta data has not been attached");
+        }
+
+        return data;
+    }
+
+    @Override
+    protected FileType doGetType() throws Exception {
+        return getData().getType();
+    }
+
+    @Override
+    protected long doGetLastModifiedTime() throws Exception {
+        return getData().getLastModified();
+    }
+
+    @Override
+    protected boolean doIsReadable() throws Exception {
+        return data.getBuffer() != null;
+    }
+
+    @Override
+    protected boolean doIsWriteable() throws Exception {
+        return false;
+    }
+
+    @Override
+    protected FileContentInfoFactory getFileContentInfoFactory() {
+        return fileSystem.getFileContentInfoFactory();
+    }
+
+    @Override
+    protected long doGetContentSize() throws Exception {
+        byte[] bytes = data.getBuffer();
+        return bytes != null ? bytes.length : 0;
+    }
+
+    @Override
+    protected InputStream doGetInputStream() throws Exception {
+        byte[] bytes = data.getBuffer();
+        if (bytes != null) {
+            return new ByteArrayInputStream(bytes);
+        }
+
+        return null;
+    }
+
+    @Override
+    protected Map<String,Object> doGetAttributes() {
+        return getData().getAttributes();
+    }
+
+    @Override
+    protected void doSetAttribute(final String name, final Object value) {
+        getData().getAttributes().put(name, value);
+    }
+
+    protected void doRemoveAttribute(final String name) {
+        getData().getAttributes().remove(name);
+    }
+
+    @Override
+    protected String[] doListChildren() throws Exception {
+        return fileSystem.listChildren(getName());
+    }
+
+    @Override
+    protected void doAttach() throws Exception {
+        if (data == null) {
+            data = fileSystem.lookupData(this);
+        }
+        content = new DefaultFileContent(this, getFileContentInfoFactory());
+    }
+
+    @Override
+    protected void doDetach() throws Exception {
+        data = null;
+        content = null;
+    }
+
+    @Override
+    public FileContent getContent() throws FileSystemException {
+        super.getContent();
+        return content;
+    }
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/ApplicationImpl.java b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/ApplicationImpl.java
new file mode 100644
index 0000000..350fd63
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/ApplicationImpl.java
@@ -0,0 +1,143 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.core;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.URL;
+import java.util.Properties;
+
+import org.apache.geronimo.gshell.application.Application;
+import org.apache.geronimo.gshell.application.ClassPath;
+import org.apache.geronimo.gshell.application.model.ApplicationModel;
+import org.apache.geronimo.gshell.artifact.Artifact;
+import org.apache.geronimo.gshell.command.Variables;
+import org.apache.geronimo.gshell.io.IO;
+import org.springframework.beans.factory.InitializingBean; 
+
+public class ApplicationImpl implements Application, InitializingBean  {
+
+	private static final String EMBEDDED_PROPS = "org/apache/servicemix/kernel/version/embedded.properties";
+    private static final String SERVICEMIX_VERSION ="org/apache/servicemix/kernel/gshell/core/servicemix-version.properties";
+    private static final String VERSION_PROPERTY = "version";
+
+    private String id;
+    private IO io;
+    private ApplicationModel model;
+    private Variables variables;
+    private InetAddress localHost;
+    private File homeDir;         
+    private URL embeddedResource = null; 
+
+    public ApplicationImpl() throws Exception {
+        this.localHost = InetAddress.getLocalHost();
+        this.homeDir = detectHomeDir();    
+    }           
+     
+    public void afterPropertiesSet() throws Exception {      	         	    	
+        Properties props = new Properties();
+        props.load(getClass().getClassLoader().getResourceAsStream(SERVICEMIX_VERSION));
+        String kernelVersion = props.getProperty(VERSION_PROPERTY);
+        this.model.setVersion(kernelVersion);
+    	ServiceMixBranding smxBranding = (ServiceMixBranding) this.model.getBranding();
+        smxBranding.setVersion(kernelVersion);
+        
+     	if (this.getClass().getClassLoader().getResource(EMBEDDED_PROPS) != null) {                    
+            embeddedResource = this.getClass().getClassLoader().getResource(EMBEDDED_PROPS);
+            smxBranding.setEmbeddedResource(embeddedResource);
+        }
+    }
+    
+    public URL getEmbeddedResource() {
+    	return embeddedResource;
+    }        
+        
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public IO getIo() {
+        return io;
+    }
+
+    public void setIo(IO io) {
+        this.io = io;
+    }
+
+    public Variables getVariables() {
+        return variables;
+    }
+
+    public void setVariables(Variables variables) {
+        this.variables = variables;
+    }
+
+    public ApplicationModel getModel() {
+        return model;
+    }
+
+    public void setModel(ApplicationModel model) {
+        this.model = model;
+    }
+
+    public ClassPath getClassPath() {
+        throw new UnsupportedOperationException();
+    }
+
+    public File getHomeDir() {
+        if (homeDir == null) {
+            throw new IllegalStateException();
+        }
+        return homeDir;
+    }
+
+    public InetAddress getLocalHost() {
+        return localHost;
+    }
+
+    public String getUserName() {
+        return System.getProperty("user.name");
+    }
+
+    public Artifact getArtifact() {
+        return null;
+    }
+
+    private File detectHomeDir() {
+        String homePath = System.getProperty("user.home");
+        // And now lets resolve this sucker
+        File dir;
+        try {
+            dir = new File(homePath).getCanonicalFile();
+        }
+        catch (IOException e) {
+            throw new RuntimeException("Failed to resolve home directory: " + homePath, e);
+        }
+        // And some basic sanity too
+        if (!dir.exists() || !dir.isDirectory()) {
+            throw new RuntimeException("Home directory configured but is not a valid directory: " + dir);
+        }
+
+        return dir;
+    }
+
+}
diff --git a/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/ApplicationManagerImpl.java b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/ApplicationManagerImpl.java
new file mode 100644
index 0000000..7465900
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/ApplicationManagerImpl.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.core;
+
+import org.apache.geronimo.gshell.application.Application;
+import org.apache.geronimo.gshell.application.ApplicationConfiguration;
+import org.apache.geronimo.gshell.application.ApplicationManager;
+import org.apache.geronimo.gshell.event.EventPublisher;
+import org.apache.geronimo.gshell.io.SystemOutputHijacker;
+import org.apache.geronimo.gshell.shell.Shell;
+import org.apache.geronimo.gshell.wisdom.application.ShellCreatedEvent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+
+public class ApplicationManagerImpl implements ApplicationManager, ApplicationContextAware, InitializingBean, DisposableBean {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    private EventPublisher eventPublisher;
+
+    private Application application;
+
+    private ApplicationContext applicationContext;
+
+    public ApplicationManagerImpl(EventPublisher eventPublisher, Application application) {
+        this.eventPublisher = eventPublisher;
+        this.application = application;
+    }
+
+    public void afterPropertiesSet() throws Exception {
+        if (!SystemOutputHijacker.isInstalled()) {
+            SystemOutputHijacker.install();
+        }
+        //SystemOutputHijacker.register(application.getIo().outputStream, application.getIo().errorStream);
+    }
+
+    public void destroy() {
+        SystemOutputHijacker.uninstall();
+    }
+
+    public void setApplicationContext(ApplicationContext applicationContext) {
+        this.applicationContext = applicationContext;
+    }
+
+    public void configure(ApplicationConfiguration applicationConfiguration) throws Exception {
+        throw new UnsupportedOperationException();
+    }
+
+    public Application getApplication() {
+        return application;
+    }
+
+    public Shell create() throws Exception {
+        final Shell shell = (Shell) applicationContext.getBean("shell");
+
+        log.debug("Created shell instance: {}", shell);
+
+        eventPublisher.publish(new ShellCreatedEvent(shell));
+
+        return shell;
+    }
+
+}
diff --git a/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/BeanContainerAwareProcessor.java b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/BeanContainerAwareProcessor.java
new file mode 100644
index 0000000..7deacb1
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/BeanContainerAwareProcessor.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.servicemix.kernel.gshell.core;
+
+import org.apache.geronimo.gshell.spring.BeanContainer;
+import org.apache.geronimo.gshell.spring.BeanContainerAware;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+
+public class BeanContainerAwareProcessor implements InitializingBean, BeanPostProcessor, ApplicationContextAware {
+
+    private ApplicationContext applicationContext;
+    private BeanContainer container;
+
+    public void setApplicationContext(ApplicationContext applicationContext) {
+        this.applicationContext = applicationContext;
+    }
+
+    public void afterPropertiesSet() throws Exception {
+        this.container = new BeanContainerWrapper(applicationContext);
+    }
+
+    public Object postProcessBeforeInitialization(final Object bean, final String beanName) throws BeansException {
+        assert bean != null;
+
+        if (bean instanceof BeanContainerAware) {
+            ((BeanContainerAware)bean).setBeanContainer(container);
+        }
+
+        return bean;
+    }
+
+    public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException {
+        return bean;
+    }
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/BeanContainerWrapper.java b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/BeanContainerWrapper.java
new file mode 100644
index 0000000..edc15d7
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/BeanContainerWrapper.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.servicemix.kernel.gshell.core;
+
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.geronimo.gshell.spring.BeanContainer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.context.ApplicationContext;
+
+public class BeanContainerWrapper implements BeanContainer {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    private ApplicationContext context;
+
+    public BeanContainerWrapper(ApplicationContext context) {
+        this.context = context;
+    }
+
+    public BeanContainer getParent() {
+        return null;
+    }
+
+    public ClassLoader getClassLoader() {
+        return context.getClassLoader();
+    }
+
+    public void loadBeans(String[] strings) throws Exception {
+        throw new UnsupportedOperationException();
+    }
+
+    public <T> T getBean(Class<T> type) {
+        assert type != null;
+
+        log.trace("Getting bean of type: {}", type);
+
+        String[] names = context.getBeanNamesForType(type);
+
+        if (names.length == 0) {
+            throw new NoSuchBeanDefinitionException(type, "No bean defined for type: " + type);
+        }
+        if (names.length > 1) {
+            throw new NoSuchBeanDefinitionException(type, "No unique bean defined for type: " + type + ", found matches: " + Arrays.asList(names));
+        }
+
+        return getBean(names[0], type);
+    }
+
+    public <T> T getBean(String name, Class<T> requiredType) {
+        assert name != null;
+        assert requiredType != null;
+
+        log.trace("Getting bean named '{}' of type: {}", name, requiredType);
+
+        return (T) context.getBean(name, requiredType);
+    }
+
+    public <T> Map<String, T> getBeans(Class<T> type) {
+        assert type != null;
+
+        log.trace("Getting beans of type: {}", type);
+
+        return (Map<String,T>) context.getBeansOfType(type);
+    }
+
+    public String[] getBeanNames() {
+        log.trace("Getting bean names");
+
+        return context.getBeanDefinitionNames();
+    }
+
+    public String[] getBeanNames(Class type) {
+        assert type != null;
+
+        log.trace("Getting bean names of type: {}", type);
+
+        return context.getBeanNamesForType(type);
+    }
+
+    public BeanContainer createChild(Collection<URL> urls) {
+        throw new UnsupportedOperationException();
+    }
+
+    public BeanContainer createChild() {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/CommandBundle.java b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/CommandBundle.java
new file mode 100644
index 0000000..2111072
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/CommandBundle.java
@@ -0,0 +1,175 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.servicemix.kernel.gshell.core;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.geronimo.gshell.command.Alias;
+import org.apache.geronimo.gshell.command.Command;
+import org.apache.geronimo.gshell.command.Link;
+import org.apache.geronimo.gshell.registry.AliasRegistry;
+import org.apache.geronimo.gshell.registry.CommandRegistry;
+import org.apache.geronimo.gshell.wisdom.command.LinkCommand;
+import org.apache.geronimo.gshell.wisdom.registry.CommandLocationImpl;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.osgi.context.BundleContextAware;
+
+public class CommandBundle implements BundleContextAware, InitializingBean, DisposableBean, ApplicationContextAware {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    private CommandRegistry commandRegistry;
+
+    private AliasRegistry aliasRegistry;
+
+    private BundleContext bundleContext;
+
+    private List<Command> commands;
+
+    private List<Link> links;
+
+    private List<Alias> aliases;
+
+    private ApplicationContext applicationContext;
+
+    private List<ServiceRegistration> registrations = new ArrayList<ServiceRegistration>();
+
+    public CommandBundle() {
+    }
+
+    public void setApplicationContext(ApplicationContext applicationContext) {
+        this.applicationContext = applicationContext;
+    }
+
+    public List<Command> getCommands() {
+        return commands;
+    }
+
+    public void setCommands(final List<Command> commands) {
+        assert commands != null;
+
+        this.commands = commands;
+    }
+
+    public List<Link> getLinks() {
+        return links;
+    }
+
+    public void setLinks(List<Link> links) {
+        assert links != null;
+
+        this.links = links;
+    }
+
+    public List<Alias> getAliases() {
+        return aliases;
+    }
+
+    public void setAliases(List<Alias> aliases) {
+        assert aliases != null;
+
+        this.aliases = aliases;
+    }
+
+    public void setBundleContext(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+
+    public void afterPropertiesSet() throws Exception {
+        log.debug("Initializing command bundle");
+        if (commandRegistry == null) {
+            String[] names = applicationContext.getBeanNamesForType(CommandRegistry.class);
+            if (names.length == 1) {
+                commandRegistry = (CommandRegistry) applicationContext.getBean(names[0], CommandRegistry.class);
+            }
+        }
+        if (aliasRegistry == null) {
+            String[] names = applicationContext.getBeanNamesForType(AliasRegistry.class);
+            if (names.length == 1) {
+                aliasRegistry = (AliasRegistry) applicationContext.getBean(names[0], AliasRegistry.class);
+            }
+        }
+        if (commandRegistry != null && aliasRegistry != null) {
+            log.debug("Command bundle is using the auto wired command/alias registry");
+            if (commands != null) {
+                for (Command command : commands) {
+                    log.debug("Registering command: {}", command.getLocation());
+                    commandRegistry.registerCommand(command);
+                }
+            }
+            if (links != null) {
+                for (Link link : links) {
+                    log.debug("Registering link: {}", link.getName());
+                    LinkCommand cmd = new LinkCommand(commandRegistry, link.getTarget());
+                    cmd.setLocation(new CommandLocationImpl(link.getName()));
+                    commandRegistry.registerCommand(cmd);
+                }
+            }
+            if (aliases != null) {
+                for (Alias alias : aliases) {
+                    log.debug("Registering alias: {}", alias.getName());
+                    aliasRegistry.registerAlias(alias.getName(), alias.getAlias());
+                }
+            }
+        } else if (bundleContext != null) {
+            log.debug("Command bundle is using the OSGi registry");
+            if (commands != null) {
+                for (Command command : commands) {
+                    log.debug("Registering command: {}", command.getLocation());
+                    Dictionary props = new Properties();
+                    props.put(OsgiCommandRegistry.NAME, command.getLocation().getFullPath());
+                    registrations.add(bundleContext.registerService(Command.class.getName(), command, props));
+                }
+            }
+            if (links != null) {
+                for (Link link : links) {
+                    log.debug("Registering link: {}", link.getName());
+                    registrations.add(bundleContext.registerService(Link.class.getName(), link, new Properties()));
+                }
+            }
+            if (aliases != null) {
+                for (Alias alias : aliases) {
+                    log.debug("Registering alias: {}", alias.getName());
+                    Dictionary props = new Properties();
+                    registrations.add(bundleContext.registerService(Alias.class.getName(), alias, new Properties()));
+                }
+            }
+        } else {
+            throw new Exception("Command bundle should be wired to the command/alias registry or be used in an OSGi context");
+        }
+    }
+
+    public void destroy() {
+        log.debug("Destroying command bundle");
+        for (ServiceRegistration reg : registrations) {
+            reg.unregister();
+        }
+    }
+
+}
diff --git a/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/LocalConsole.java b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/LocalConsole.java
new file mode 100644
index 0000000..98c7193
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/LocalConsole.java
@@ -0,0 +1,172 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.servicemix.kernel.gshell.core;
+
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.geronimo.gshell.notification.ExitNotification;
+import org.apache.geronimo.gshell.shell.Shell;
+import org.apache.servicemix.kernel.main.spi.MainService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.FrameworkEvent;
+import org.osgi.framework.FrameworkListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.osgi.context.BundleContextAware;
+
+public class LocalConsole implements Runnable, BundleContextAware {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    private Shell shell;
+
+    private boolean createLocalShell;
+
+    private BundleContext bundleContext;
+
+    private MainService mainService;
+
+    private CountDownLatch frameworkStarted;
+    
+    public BundleContext getBundleContext() {
+        return bundleContext;
+    }
+
+    public void setBundleContext(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+
+    public MainService getMainService() {
+        return mainService;
+    }
+
+    public void setMainService(MainService mainService) {
+        this.mainService = mainService;
+    }
+
+    public Shell getShell() {
+        return shell;
+    }
+
+    public void setShell(Shell shell) {
+        this.shell = shell;
+    }
+
+    public boolean isCreateLocalShell() {
+        return createLocalShell;
+    }
+
+    public void setCreateLocalShell(boolean createLocalShell) {
+        this.createLocalShell = createLocalShell;
+    }
+
+    public void init() {
+        shell.getContext().getVariables().set("gshell.username", "smx");
+        frameworkStarted = new CountDownLatch(1);
+		getBundleContext().addFrameworkListener(new FrameworkListener(){
+			public void frameworkEvent(FrameworkEvent event) {
+				log.debug("Got event: " + event.getType());
+				if( event.getType() == FrameworkEvent.STARTED ) {
+					frameworkStarted.countDown();
+				}
+			}
+		});
+        if (createLocalShell) {
+            new Thread(this, "localShell").start();
+        }
+    }
+
+    public void destroy() {
+        if (createLocalShell) {
+            shell.close();
+        }
+    }
+
+    public void run() {
+        try {
+            String[] args = mainService.getArgs();
+            // If a command was specified on the command line, then just execute that command.
+            if (args != null && args.length > 0) {
+                waitForFrameworkToStart();
+                log.info("Executing Shell with arguments: " + Arrays.toString(args));
+                StringBuilder sb = new StringBuilder();
+                for (String arg : args) {
+                    sb.append(arg).append(" ");
+                }
+                Object value = shell.execute(sb.toString());
+                if (mainService != null) {
+                    if (value instanceof Number) {
+                        mainService.setExitCode(((Number) value).intValue());
+                    } else {
+                        mainService.setExitCode(value != null ? 1 : 0);
+                    }
+                    log.info("Exiting shell due to terminated command");
+                }
+            } else {
+                shell.run();
+            }
+        } catch (ExitNotification e) {
+            if (mainService != null) {
+                mainService.setExitCode(0);
+            }
+            log.info("Exiting shell due received exit notification");
+        } catch (Throwable e) {
+            if (mainService != null) {
+                mainService.setExitCode(-1);
+            }
+            log.error("Exiting shell due to caught exception " + e, e);
+        } finally {
+            try {
+                shell.close();
+            } catch (Throwable t) {}
+            asyncShutdown();
+        }
+    }
+
+    /**
+     * Blocks until the framework has finished starting.  We do this so that any installed
+     * bundles for commands get fully registered.
+     *
+     * @throws InterruptedException
+     */
+    private void waitForFrameworkToStart() throws InterruptedException {
+        log.info("Waiting from framework to start.");
+        if (frameworkStarted.await(60, TimeUnit.SECONDS)) {
+			log.info("System completed startup.");
+		} else {
+			log.warn("System took too long startup... continuing");
+		}
+    }
+
+    private void asyncShutdown() {
+        new Thread() {
+            public void run() {
+                try {
+                    getBundleContext().getBundle(0).stop();
+                } catch (BundleException e) {
+                    log.info("Caught exception while shutting down framework: " + e, e);
+                }
+            }
+        }.start();
+    }
+
+}
diff --git a/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/OsgiAliasRegistry.java b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/OsgiAliasRegistry.java
new file mode 100644
index 0000000..a09ce0b
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/OsgiAliasRegistry.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.servicemix.kernel.gshell.core;
+
+import java.util.Map;
+
+import org.apache.geronimo.gshell.command.Alias;
+import org.apache.geronimo.gshell.registry.AliasRegistry;
+
+public class OsgiAliasRegistry {
+
+    public static final String NAME = "name";
+    public static final String ALIAS = "alias";
+
+    private AliasRegistry aliasRegistry;
+
+    public OsgiAliasRegistry(AliasRegistry aliasRegistry) {
+        this.aliasRegistry = aliasRegistry;
+    }
+
+    public void register(final Alias alias, Map<String, ?> properties) throws Exception {
+        aliasRegistry.registerAlias(alias.getName(), alias.getAlias());
+    }
+
+    public void unregister(final Alias alias, Map<String, ?> properties) throws Exception {
+        aliasRegistry.removeAlias(alias.getName());
+    }
+
+}
diff --git a/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/OsgiCommandRegistry.java b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/OsgiCommandRegistry.java
new file mode 100644
index 0000000..c6817e8
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/OsgiCommandRegistry.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.servicemix.kernel.gshell.core;
+
+import java.util.Map;
+
+import org.apache.geronimo.gshell.command.Command;
+import org.apache.geronimo.gshell.command.Link;
+import org.apache.geronimo.gshell.registry.CommandRegistry;
+import org.apache.geronimo.gshell.wisdom.command.LinkCommand;
+import org.apache.geronimo.gshell.wisdom.registry.CommandLocationImpl;
+
+public class OsgiCommandRegistry {
+
+    public static final String NAME = "name";
+    public static final String TARGET = "target";
+
+    private CommandRegistry commandRegistry;
+
+    public OsgiCommandRegistry(CommandRegistry commandRegistry) {
+        this.commandRegistry = commandRegistry;
+    }
+
+    public void register(final Command command, Map<String, ?> properties) throws Exception {
+        commandRegistry.registerCommand(command);
+    }
+
+    public void unregister(final Command command, Map<String, ?> properties) throws Exception {
+        commandRegistry.removeCommand(command);
+    }
+
+    public void register(final Link link, Map<String, ?> properties) throws Exception {
+        LinkCommand cmd = new LinkCommand(commandRegistry, link.getTarget());
+        cmd.setLocation(new CommandLocationImpl(link.getName()));
+        commandRegistry.registerCommand(cmd);
+    }
+
+    public void unregister(final Link link, Map<String, ?> properties) throws Exception {
+        commandRegistry.removeCommand(commandRegistry.getCommand(link.getName()));
+    }
+
+}
diff --git a/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/OsgiCommandSupport.java b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/OsgiCommandSupport.java
new file mode 100644
index 0000000..e13940a
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/OsgiCommandSupport.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.servicemix.kernel.gshell.core;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.geronimo.gshell.command.CommandAction;
+import org.apache.geronimo.gshell.command.CommandContext;
+import org.apache.geronimo.gshell.command.Variables;
+import org.apache.geronimo.gshell.io.IO;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.springframework.osgi.context.BundleContextAware;
+
+public abstract class OsgiCommandSupport implements CommandAction, BundleContextAware {
+
+    protected Log log = LogFactory.getLog(getClass());
+    protected BundleContext bundleContext;
+    protected CommandContext commandContext;
+    protected IO io;
+    protected Variables variables;
+    protected List<ServiceReference> usedReferences;
+    
+    public Object execute(CommandContext commandContext) throws Exception {
+        this.commandContext = commandContext;
+        this.io = commandContext.getIo();
+        this.variables = commandContext.getVariables();
+        try {
+            return doExecute();
+        } finally {
+            ungetServices();
+        }
+    }
+
+    protected abstract Object doExecute() throws Exception;
+
+    public BundleContext getBundleContext() {
+        return bundleContext;
+    }
+
+    public void setBundleContext(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+
+    protected <T> List<T> getAllServices(Class<T> clazz, String filter) throws Exception {
+        ServiceReference[] references = getBundleContext().getAllServiceReferences(clazz.getName(), filter);
+        if (references == null) {
+            return null;
+        }
+        List<T> services = new ArrayList<T>();
+        for (ServiceReference ref : references) {
+            T t = getService(clazz, ref);
+            services.add(t);
+        }
+        return services;
+    }
+
+    protected <T> T getService(Class<T> clazz, ServiceReference reference) {
+        T t = (T) getBundleContext().getService(reference);
+        if (t != null) {
+            if (usedReferences == null) {
+                usedReferences = new ArrayList<ServiceReference>();
+            }
+            usedReferences.add(reference);
+        }
+        return t;
+    }
+
+    protected void ungetServices() {
+        if (usedReferences != null) {
+            for (ServiceReference ref : usedReferences) {
+                getBundleContext().ungetService(ref);
+            }
+        }
+    }
+
+}
diff --git a/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/ServiceMixBranding.java b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/ServiceMixBranding.java
new file mode 100644
index 0000000..803b511
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/ServiceMixBranding.java
@@ -0,0 +1,188 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.core;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.URL;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+import org.apache.geronimo.gshell.ansi.AnsiBuffer;
+import org.apache.geronimo.gshell.ansi.AnsiCode;
+import org.apache.geronimo.gshell.ansi.AnsiRenderWriter;
+import org.apache.geronimo.gshell.application.model.Branding;
+
+public class ServiceMixBranding extends Branding {		
+   
+    private String prompt; 
+    private String[] banner;
+    private String displayName;
+    private String displayVersion;    
+    private String displayLocation;
+    private String applicationName;
+    private String applicationVersion;
+    private String applicationLocation;
+    
+    private String[] kernelBanner = {
+        " ____                  _          __  __ _      ",
+        "/ ___|  ___ _ ____   _(_) ___ ___|  \\/  (_)_  __",
+        "\\___ \\ / _ \\ '__\\ \\ / / |/ __/ _ \\ |\\/| | \\ \\/ /",
+        " ___) |  __/ |   \\ V /| | (_|  __/ |  | | |>  < ",
+        "|____/ \\___|_|    \\_/ |_|\\___\\___|_|  |_|_/_/\\_\\",
+    };
+
+    public ServiceMixBranding() {
+    	banner = kernelBanner;
+    	displayName = "ServiceMix Kernel";
+    	displayLocation = "http://servicemix.apache.org/kernel/";    	
+    }
+    
+    public void setEmbeddedResource(URL embeddedResource) {    	
+    	Properties brandProps = loadPropertiesFile(embeddedResource);        
+    	String brandBanner = brandProps.getProperty("banner");
+    	int i = 0;
+        char quot = '"';
+
+        StringTokenizer st = new StringTokenizer(brandBanner, ",");
+        banner = new String[st.countTokens()];
+
+        while (st.hasMoreTokens()) {        	
+            banner[i] = st.nextToken();
+            banner[i] = banner[i].substring(1, banner[i].lastIndexOf(quot));        
+            i++;
+        }
+
+    	applicationName = brandProps.getProperty("application.name");  
+    	applicationVersion = brandProps.getProperty("application.version");
+    	applicationLocation = brandProps.getProperty("application.location");
+    }    
+    
+    public String getName() {
+        return "servicemix";
+    }
+        
+    public String getDisplayName() {    	
+        return displayName;
+    }
+        
+    public void setVersion(String version) {
+    	displayVersion = version;
+    }
+    
+    public String getVersion() {
+    	return displayVersion;
+    }        
+    
+    public String getApplicationName() {
+    	return applicationName;
+    }
+
+    public String getApplicationVersion() {
+    	return applicationVersion;
+    }
+    
+    public String getProgramName() {
+        throw new UnsupportedOperationException();
+    }
+
+    public String getPrompt() {
+        return prompt;
+    }
+
+    public void setPrompt(String prompt) {
+        this.prompt = prompt;
+    }
+
+    public String getAboutMessage() {
+        StringWriter writer = new StringWriter();
+        PrintWriter out = new AnsiRenderWriter(writer);
+
+        out.println("For information about @|cyan " + displayName + "|, visit:");
+        out.println("    @|bold " + displayLocation + "| ");
+        out.flush();
+
+        if (applicationName != null && applicationVersion != null) {
+        	out.println();
+        	out.println(applicationName + " " + applicationVersion);
+        	out.println();
+        	if (applicationLocation != null) {
+                out.println("For information about @|cyan " + applicationName + "|, visit:");
+                out.println("    @|bold " + applicationLocation + "| ");
+                out.flush();
+        	}
+        }
+
+        return writer.toString();
+    }      
+    
+    public String getWelcomeMessage() {    	        
+        StringWriter writer = new StringWriter();
+        PrintWriter out = new AnsiRenderWriter(writer);
+    	
+        AnsiBuffer buff = new AnsiBuffer();        
+                
+        for (String line : banner) {
+            buff.attrib(line, AnsiCode.CYAN);
+            out.println(buff);
+        }
+
+        out.println();
+        out.println(" @|bold " + displayName + "| (" + displayVersion + ")");
+        if (applicationName != null && applicationVersion != null) {
+            out.println(" @|bold " + applicationName + "| (" + applicationVersion + ")");
+        }
+        out.println();
+        out.println("Type '@|bold help|' for more information.");
+        out.flush();
+
+        return writer.toString();
+    }
+            
+    private static Properties loadPropertiesFile(URL brandPropURL) {
+        // Read the properties file.
+        Properties brandProps = new Properties();
+        InputStream is = null;
+        try {
+            is = brandPropURL.openConnection().getInputStream();
+            brandProps.load(is);
+            is.close();
+        }
+        catch (FileNotFoundException ex) {
+            // Ignore file not found.
+        }
+        catch (Exception ex) {
+            System.err.println(
+                    "Error loading embedded properties from " + brandPropURL);
+            System.err.println("ServicemixBranding: " + ex);
+            try {
+                if (is != null) is.close();
+            }
+            catch (IOException ex2) {
+                // Nothing we can do.
+            }
+            return null;
+        }
+       
+        return brandProps;
+    }
+    
+}
+
diff --git a/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/ShellWrapper.java b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/ShellWrapper.java
new file mode 100644
index 0000000..ae86534
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/ShellWrapper.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.core;
+
+import org.apache.geronimo.gshell.shell.Shell;
+import org.apache.geronimo.gshell.shell.ShellContext;
+import org.apache.geronimo.gshell.shell.ShellContextHolder;
+
+public class ShellWrapper implements Shell {
+
+    private Shell delegate;
+
+    public ShellWrapper(Shell delegate) {
+        this.delegate = delegate;
+    }
+
+    public ShellContext getContext() {
+        return delegate.getContext();
+    }
+
+    public Object execute(String s) throws Exception {
+        ShellContext ctx = ShellContextHolder.get(true);
+        try {
+            ShellContextHolder.set(getContext());
+            return delegate.execute(s);
+        } finally {
+            ShellContextHolder.set(ctx);
+        }
+    }
+
+    public Object execute(String s, Object[] objects) throws Exception {
+        ShellContext ctx = ShellContextHolder.get(true);
+        try {
+            ShellContextHolder.set(getContext());
+            return delegate.execute(s, objects);
+        } finally {
+            ShellContextHolder.set(ctx);
+        }
+    }
+
+    public Object execute(Object... objects) throws Exception {
+        ShellContext ctx = ShellContextHolder.get(true);
+        try {
+            ShellContextHolder.set(getContext());
+            return delegate.execute(objects);
+        } finally {
+            ShellContextHolder.set(ctx);
+        }
+    }
+
+    public boolean isOpened() {
+        return delegate.isOpened();
+    }
+
+    public void close() {
+        delegate.close();
+    }
+
+    public boolean isInteractive() {
+        return delegate.isInteractive();
+    }
+
+    public void run(Object... objects) throws Exception {
+        ShellContext ctx = ShellContextHolder.get(true);
+        try {
+            ShellContextHolder.set(getContext());
+            delegate.run(objects);
+        } finally {
+            ShellContextHolder.set(ctx);
+        }
+    }
+}
diff --git a/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/WorkAroundAliasCommand.java b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/WorkAroundAliasCommand.java
new file mode 100644
index 0000000..1e52177
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/WorkAroundAliasCommand.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.core;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.apache.geronimo.gshell.command.CommandAction;
+import org.apache.geronimo.gshell.command.CommandContext;
+import org.apache.geronimo.gshell.command.CommandResult;
+import org.apache.geronimo.gshell.command.Variables;
+import org.apache.geronimo.gshell.commandline.CommandLineExecutor;
+import org.apache.geronimo.gshell.io.IO;
+import org.apache.geronimo.gshell.shell.Shell;
+import org.apache.geronimo.gshell.shell.ShellContext;
+import org.apache.geronimo.gshell.shell.ShellContextHolder;
+import org.apache.geronimo.gshell.wisdom.command.AliasCommand;
+
+public class WorkAroundAliasCommand extends AliasCommand {
+
+    private final CommandLineExecutor executor;
+
+    public WorkAroundAliasCommand(CommandLineExecutor executor) {
+        super(executor);
+        this.executor = executor;
+        setAction(new AliasCommandAction());
+    }
+
+    @Override
+    protected void prepareAction(final ShellContext context, final Object[] args) {
+        // HACK: Reset state for proper appendArgs muck
+        assert context != null;
+        assert args != null;
+
+        setAction(new AliasCommandAction());
+        log.trace("Preparing action");
+
+        IO io = context.getIo();
+        CommandAction action = getAction();
+
+        // Setup the command action
+        try {
+            // Process command line options/arguments
+            processArguments(io, action, args);
+        }
+        catch (Exception e) {
+            // Abort if preparation caused a failure
+            throw new AbortExecutionNotification(new CommandResult.FailureResult(e));
+        }
+    }
+
+    private class AliasCommandAction
+        implements CommandAction
+    {
+        @Argument
+        private List<String> appendArgs = null;
+
+        public Object execute(final CommandContext context) throws Exception {
+            assert context != null;
+
+            StringBuilder buff = new StringBuilder();
+            buff.append(getAlias());
+
+            // If we have args to append, then do it
+            if (appendArgs != null && !appendArgs.isEmpty()) {
+                buff.append(" ");
+
+                // Append args quoted as they have already been processed by the parser
+                Iterator iter = appendArgs.iterator();
+                while (iter.hasNext()) {
+                    //
+                    // HACK: Using double quote instead of single quote for now as the parser's handling of single quote is broken
+                    //
+
+                    buff.append('"').append(iter.next()).append('"');
+                    if (iter.hasNext()) {
+                        buff.append(" ");
+                    }
+                }
+            }
+
+            log.debug("Executing alias: {}", buff);
+
+            final Shell shell = ShellContextHolder.get().getShell();
+            ShellContext shellContext = new ShellContext() {
+                public Shell getShell() {
+                    return shell;
+                }
+                public IO getIo() {
+                    return context.getIo();
+                }
+                public Variables getVariables() {
+                    return context.getVariables();
+                }
+            };
+            Object result = executor.execute(shellContext, buff.toString());
+
+            log.debug("Alias result: {}", result);
+
+            return result;
+        }
+    }
+}
diff --git a/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/commands/InfoAction.java b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/commands/InfoAction.java
new file mode 100644
index 0000000..8f3b580
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/commands/InfoAction.java
@@ -0,0 +1,177 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.servicemix.kernel.gshell.core.commands;
+
+import java.lang.management.ClassLoadingMXBean;
+import java.lang.management.GarbageCollectorMXBean;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryMXBean;
+import java.lang.management.OperatingSystemMXBean;
+import java.lang.management.RuntimeMXBean;
+import java.lang.management.ThreadMXBean;
+import java.lang.reflect.Method;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.NumberFormat;
+import java.util.Locale;
+
+import org.apache.geronimo.gshell.ansi.AnsiCode;
+import org.apache.geronimo.gshell.ansi.AnsiRenderer;
+import org.apache.geronimo.gshell.command.CommandAction;
+import org.apache.geronimo.gshell.command.CommandContext;
+import org.apache.geronimo.gshell.io.IO;
+import org.apache.servicemix.kernel.gshell.core.ServiceMixBranding;
+import org.codehaus.plexus.util.StringUtils;
+
+public class InfoAction implements CommandAction {
+
+    private ServiceMixBranding branding;
+
+    private IO io;
+
+    private AnsiRenderer renderer = new AnsiRenderer();
+    private NumberFormat fmtI = new DecimalFormat("###,###", new DecimalFormatSymbols(Locale.ENGLISH));
+    private NumberFormat fmtD = new DecimalFormat("###,##0.000", new DecimalFormatSymbols(Locale.ENGLISH));
+
+    public InfoAction(ServiceMixBranding branding) {
+        this.branding = branding;
+    }
+
+    public Object execute(CommandContext context) throws Exception {
+        int maxNameLen;
+
+        RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
+        OperatingSystemMXBean os = ManagementFactory.getOperatingSystemMXBean();
+        ThreadMXBean threads = ManagementFactory.getThreadMXBean();
+        MemoryMXBean mem = ManagementFactory.getMemoryMXBean();
+        ClassLoadingMXBean cl = ManagementFactory.getClassLoadingMXBean();
+        io = context.getIo();
+
+        //
+        // print ServiceMix informations
+        //
+        maxNameLen = 25;
+        io.out.println("ServiceMix");
+        printValue("ServiceMix home", maxNameLen, System.getProperty("servicemix.home"));
+        printValue("ServiceMix base", maxNameLen, System.getProperty("servicemix.base"));
+        printValue("ServiceMix Kernel version", maxNameLen, branding.getParent().getVersion());
+
+        if (branding.getApplicationName() != null && branding.getApplicationVersion() != null) {
+            printValue(branding.getApplicationName() + " version", maxNameLen, branding.getApplicationVersion());
+        }
+        io.out.println();
+
+        io.out.println("JVM");
+        printValue("Java Virtual Machine", maxNameLen, runtime.getVmName() + " version " + runtime.getVmVersion());
+        printValue("Vendor", maxNameLen, runtime.getVmVendor());
+        printValue("Uptime", maxNameLen, printDuration(runtime.getUptime()));
+        try {
+            printValue("Process CPU time", maxNameLen, printDuration(getSunOsValueAsLong(os, "getProcessCpuTime") / 1000000));
+        } catch (Throwable t) {}
+        printValue("Total compile time", maxNameLen, printDuration(ManagementFactory.getCompilationMXBean().getTotalCompilationTime()));
+
+        io.out.println("Threads");
+        printValue("Live threads", maxNameLen, Integer.toString(threads.getThreadCount()));
+        printValue("Daemon threads", maxNameLen, Integer.toString(threads.getDaemonThreadCount()));
+        printValue("Peak", maxNameLen, Integer.toString(threads.getPeakThreadCount()));
+        printValue("Total started", maxNameLen, Long.toString(threads.getTotalStartedThreadCount()));
+
+        io.out.println("Memory");
+        printValue("Current heap size", maxNameLen, printSizeInKb(mem.getHeapMemoryUsage().getUsed()));
+        printValue("Maximum heap size", maxNameLen, printSizeInKb(mem.getHeapMemoryUsage().getMax()));
+        printValue("Committed heap size", maxNameLen, printSizeInKb(mem.getHeapMemoryUsage().getCommitted()));
+        printValue("Pending objects", maxNameLen, Integer.toString(mem.getObjectPendingFinalizationCount()));
+        for (GarbageCollectorMXBean gc : ManagementFactory.getGarbageCollectorMXBeans()) {
+            String val = "Name = '" + gc.getName() + "', Collections = " + gc.getCollectionCount() + ", Time = " + printDuration(gc.getCollectionTime());
+            printValue("Garbage collector", maxNameLen, val);
+        }
+
+        io.out.println("Classes");
+        printValue("Current classes loaded", maxNameLen, printLong(cl.getLoadedClassCount()));
+        printValue("Total classes loaded", maxNameLen, printLong(cl.getTotalLoadedClassCount()));
+        printValue("Total classes unloaded", maxNameLen, printLong(cl.getUnloadedClassCount()));
+
+        io.out.println("Operating system");
+        printValue("Name", maxNameLen, os.getName() + " version " + os.getVersion());
+        printValue("Architecture", maxNameLen, os.getArch());
+        printValue("Processors", maxNameLen, Integer.toString(os.getAvailableProcessors()));
+        try {
+            printValue("Total physical memory", maxNameLen, printSizeInKb(getSunOsValueAsLong(os, "getTotalPhysicalMemorySize")));
+            printValue("Free physical memory", maxNameLen, printSizeInKb(getSunOsValueAsLong(os, "getFreePhysicalMemorySize")));
+            printValue("Committed virtual memory", maxNameLen, printSizeInKb(getSunOsValueAsLong(os, "getCommittedVirtualMemorySize")));
+            printValue("Total swap space", maxNameLen, printSizeInKb(getSunOsValueAsLong(os, "getTotalSwapSpaceSize")));
+            printValue("Free swap space", maxNameLen, printSizeInKb(getSunOsValueAsLong(os, "getFreeSwapSpaceSize")));
+        } catch (Throwable t) {}
+
+        return null;
+    }
+
+    private long getSunOsValueAsLong(OperatingSystemMXBean os, String name) throws Exception {
+        Method mth = os.getClass().getMethod(name);
+        return (Long) mth.invoke(os);
+    }
+
+    private String printLong(long i) {
+        return fmtI.format(i);
+    }
+
+    private String printSizeInKb(double size) {
+        return fmtI.format((long) (size / 1024)) + " kbytes";
+    }
+
+    private String printDuration(double uptime) {
+        uptime /= 1000;
+        if (uptime < 60) {
+            return fmtD.format(uptime) + " seconds";
+        }
+        uptime /= 60;
+        if (uptime < 60) {
+            long minutes = (long) uptime;
+            String s = fmtI.format(minutes) + (minutes > 1 ? " minutes" : " minute");
+            return s;
+        }
+        uptime /= 60;
+        if (uptime < 24) {
+            long hours = (long) uptime;
+            long minutes = (long) ((uptime - hours) * 60);
+            String s = fmtI.format(hours) + (hours > 1 ? " hours" : " hour");
+            if (minutes != 0) {
+                s += " " + fmtI.format(minutes) + (minutes > 1 ? " minutes" : "minute");
+            }
+            return s;
+        }
+        uptime /= 24;
+        long days = (long) uptime;
+        long hours = (long) ((uptime - days) * 60);
+        String s = fmtI.format(days) + (days > 1 ? " days" : " day");
+        if (hours != 0) {
+            s += " " + fmtI.format(hours) + (hours > 1 ? " hours" : "hour");
+        }
+        return s;
+    }
+
+    void printSysValue(String prop, int pad) {
+        printValue(prop, pad, System.getProperty(prop));
+    }
+
+    void printValue(String name, int pad, String value) {
+        io.out.println("  " + renderer.render(AnsiRenderer.encode(StringUtils.rightPad(name, pad), AnsiCode.BOLD)) + "   " + value);
+    }
+
+}
diff --git a/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/config/CommandParser.java b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/config/CommandParser.java
new file mode 100644
index 0000000..45d9d7d
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/config/CommandParser.java
@@ -0,0 +1,474 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.servicemix.kernel.gshell.core.config;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.w3c.dom.Element;
+
+import org.apache.geronimo.gshell.command.Alias;
+import org.apache.geronimo.gshell.command.Link;
+import org.apache.geronimo.gshell.wisdom.command.AliasImpl;
+import org.apache.geronimo.gshell.wisdom.command.ConfigurableCommandCompleter;
+import org.apache.geronimo.gshell.wisdom.command.LinkImpl;
+import org.apache.geronimo.gshell.wisdom.registry.CommandLocationImpl;
+import org.apache.servicemix.kernel.gshell.core.CommandBundle;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.BeanDefinitionStoreException;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.BeanDefinitionHolder;
+import org.springframework.beans.factory.config.RuntimeBeanReference;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.GenericBeanDefinition;
+import org.springframework.beans.factory.support.ManagedList;
+import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
+import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.util.StringUtils;
+import org.springframework.util.xml.DomUtils;
+
+public class CommandParser extends AbstractBeanDefinitionParser {
+
+    public static final String ID = ID_ATTRIBUTE;
+
+    public static final String DESCRIPTION = "description";
+
+    public static final String PLUGIN_TEMPLATE = "pluginTemplate";
+
+    public static final String ACTION = "action";
+
+    public static final String ACTION_ID = "actionId";
+
+    public static final String COMMAND_TEMPLATE_SUFFIX = "CommandTemplate";
+
+    public static final String COMMAND_BUNDLE = "command-bundle";
+
+    public static final String NAME = "name";
+
+    public static final String LOCATION = "location";
+
+    public static final String COMMANDS = "commands";
+
+    public static final String COMMAND = "command";
+
+    public static final String TYPE = "type";
+
+    public static final String DOCUMENTER = "documenter";
+
+    public static final String COMPLETER = "completer";
+
+    public static final String COMPLETERS = "completers";
+
+    public static final String BEAN = "bean";
+
+    public static final String REF = "ref";
+
+    public static final String NULL = "null";
+
+    public static final String MESSAGE_SOURCE = "message-source";
+
+    public static final String MESSAGES = "messages";
+
+    public static final String PROTOTYPE = "prototype";
+
+    public static final String ALIAS = "alias";
+
+    public static final String ALIASES = "aliases";
+
+    public static final String LINK = "link";
+
+    public static final String LINKS = "links";
+
+    public static final String TARGET = "target";
+
+    @Override
+    protected boolean shouldGenerateId() {
+        return true;
+    }
+
+    @Override
+    protected boolean shouldGenerateIdAsFallback() {
+        return true;
+    }
+
+    protected AbstractBeanDefinition parseInternal(final Element element, final ParserContext context) {
+        assert element != null;
+        assert context != null;
+
+        Builder builder = new Builder(context);
+        BeanDefinitionBuilder plugin = builder.parseCommandBundle(element);
+        return plugin.getBeanDefinition();
+    }
+
+    /**
+     * Helper to deal with command type.
+     */
+    private enum CommandType
+    {
+        STATELESS,
+        STATEFUL;
+
+        public static CommandType parse(final String text) {
+            assert text != null;
+
+            return valueOf(text.toUpperCase());
+        }
+
+        public String getTemplateName() {
+            return name().toLowerCase() + COMMAND_TEMPLATE_SUFFIX;
+        }
+
+        public void wire(final BeanDefinitionBuilder command, final BeanDefinitionHolder action) {
+            assert command != null;
+            assert action != null;
+
+            switch (this) {
+                case STATELESS:
+                    command.addPropertyReference(ACTION, action.getBeanName());
+                    break;
+
+                case STATEFUL:
+                    command.addPropertyValue(ACTION_ID, action.getBeanName());
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Helper to build plugin related bean definitions.
+     */
+    private class Builder
+    {
+        private final Logger log = LoggerFactory.getLogger(getClass());
+
+        private ParserContext context;
+
+        public Builder(final ParserContext context) {
+            assert context != null;
+
+            this.context = context;
+        }
+
+        private String resolveId(final Element element, final BeanDefinition def) throws BeanDefinitionStoreException {
+            assert element != null;
+            assert def != null;
+
+            if (shouldGenerateId()) {
+                return context.getReaderContext().generateBeanName(def);
+            }
+
+            String id = element.getAttribute(ID_ATTRIBUTE);
+
+            if (!StringUtils.hasText(id) && shouldGenerateIdAsFallback()) {
+                id = context.getReaderContext().generateBeanName(def);
+            }
+
+            return id;
+        }
+
+        @SuppressWarnings({"unchecked"})
+        private List<Element> getChildElements(final Element element, final String name) {
+            assert element != null;
+            assert name != null;
+
+            return DomUtils.getChildElementsByTagName(element, name);
+        }
+
+        @SuppressWarnings({"unchecked"})
+        private List<Element> getChildElements(final Element element, final String[] names) {
+            assert element != null;
+            assert names != null;
+
+            return DomUtils.getChildElementsByTagName(element, names);
+        }
+
+        @SuppressWarnings({"unchecked"})
+        private Element getChildElement(final Element element, final String name) {
+            assert element != null;
+            assert name != null;
+
+            List<Element> elements = DomUtils.getChildElementsByTagName(element, name);
+            if (elements != null && !elements.isEmpty()) {
+                return elements.get(0);
+            }
+            return null;
+        }
+
+        private BeanDefinitionParserDelegate createBeanDefinitionParserDelegate(final Element element) {
+            assert element != null;
+
+            BeanDefinitionParserDelegate parser = new BeanDefinitionParserDelegate(context.getReaderContext());
+            parser.initDefaults(element.getOwnerDocument().getDocumentElement());
+            return parser;
+        }
+
+        private BeanDefinitionHolder parseBeanDefinitionElement(final Element element) {
+            assert element != null;
+
+            BeanDefinitionParserDelegate parser = createBeanDefinitionParserDelegate(element);
+            return parser.parseBeanDefinitionElement(element);
+        }
+
+        private void parseAndApplyDescription(final Element element, final BeanDefinition def) {
+            assert element != null;
+            assert def != null;
+
+            Element desc = getChildElement(element, DESCRIPTION);
+            if (desc != null) {
+                if (def instanceof AbstractBeanDefinition) {
+                    ((AbstractBeanDefinition)def).setDescription(desc.getTextContent());
+                }
+            }
+        }
+
+        private void parseAndApplyDescription(final Element element, final BeanDefinitionBuilder builder) {
+            assert element != null;
+            assert builder != null;
+
+            parseAndApplyDescription(element, builder.getRawBeanDefinition());
+        }
+
+        private BeanDefinitionHolder register(final BeanDefinitionHolder holder) {
+            assert holder != null;
+
+            registerBeanDefinition(holder, context.getRegistry());
+            return holder;
+        }
+
+        private BeanDefinitionHolder register(final BeanDefinition def, final String id) {
+            assert def != null;
+            assert id != null;
+
+            BeanDefinitionHolder holder = new BeanDefinitionHolder(def, id);
+            return register(holder);
+        }
+
+        //
+        // <gshell:command-bundle>
+        //
+
+        private BeanDefinitionBuilder parseCommandBundle(final Element element) {
+            assert element != null;
+
+            log.trace("Parse command bundle; element; {}", element);
+
+            BeanDefinitionBuilder bundle = BeanDefinitionBuilder.rootBeanDefinition(CommandBundle.class);
+            parseAndApplyDescription(element, bundle);
+
+            //
+            // TODO: Figure out how we can save the order of <gshell:command> and <gshell:link> so that 'help' displays them in the order they are defined
+            //
+
+            ManagedList commands = new ManagedList();
+            commands.addAll(parseCommands(element));
+            bundle.addPropertyValue(COMMANDS, commands);
+
+            ManagedList links = new ManagedList();
+            links.addAll(parseLinks(element));
+            bundle.addPropertyValue(LINKS, links);
+
+            ManagedList aliases = new ManagedList();
+            aliases.addAll(parseAliases(element));
+            bundle.addPropertyValue(ALIASES, aliases);
+
+            return bundle;
+        }
+
+        //
+        // <gshell:command>
+        //
+
+        private List<BeanDefinition> parseCommands(final Element element) {
+            assert element != null;
+
+            log.trace("Parse commands; element; {}", element);
+
+            List<BeanDefinition> commands = new ArrayList<BeanDefinition>();
+
+            List<Element> children = getChildElements(element, COMMAND);
+
+            for (Element child : children) {
+                BeanDefinitionBuilder command = parseCommand(child);
+                commands.add(command.getBeanDefinition());
+            }
+
+            return commands;
+        }
+
+        private BeanDefinitionBuilder parseCommand(final Element element) {
+            assert element != null;
+
+            log.trace("Parse command; element; {}", element);
+
+            CommandType type = CommandType.parse(element.getAttribute(TYPE));
+            BeanDefinitionBuilder command = BeanDefinitionBuilder.childBeanDefinition(type.getTemplateName());
+            parseAndApplyDescription(element, command);
+
+            Element child;
+
+            // Required children elements
+
+            String name = element.getAttribute(NAME);
+            BeanDefinition def = new GenericBeanDefinition();
+            def.setBeanClassName(CommandLocationImpl.class.getName());
+            def.getConstructorArgumentValues().addGenericArgumentValue(name);
+            command.addPropertyValue(LOCATION, def);
+
+            child = getChildElement(element, ACTION);
+            BeanDefinitionHolder action = parseCommandAction(child);
+            type.wire(command, action);
+
+            // Optional children elements
+
+            child = getChildElement(element, DOCUMENTER);
+            if (child != null) {
+                BeanDefinitionHolder holder = parseBeanDefinitionElement(child);
+                command.addPropertyValue(DOCUMENTER, holder.getBeanDefinition());
+            }
+
+            child = getChildElement(element, COMPLETER);
+            if (child != null) {
+                BeanDefinitionHolder holder = parseBeanDefinitionElement(child);
+                command.addPropertyValue(COMPLETER, holder.getBeanDefinition());
+            }
+
+            child = getChildElement(element, COMPLETERS);
+            if (child != null) {
+                BeanDefinitionBuilder completer = parseCommandCompleters(child);
+                command.addPropertyValue(COMPLETER, completer.getBeanDefinition());
+            }
+
+            child = getChildElement(element, MESSAGE_SOURCE);
+            if (child != null) {
+                BeanDefinitionHolder holder = parseBeanDefinitionElement(child);
+                command.addPropertyValue(MESSAGES, holder.getBeanDefinition());
+            }
+
+            //String id = resolveId(element, command.getBeanDefinition());
+            //BeanDefinitionHolder holder = register(command.getBeanDefinition(), id);
+
+            return command;
+        }
+
+        //
+        // <gshell:completers>
+        //
+
+        private BeanDefinitionBuilder parseCommandCompleters(final Element element) {
+            assert element != null;
+
+            BeanDefinitionBuilder completer = BeanDefinitionBuilder.rootBeanDefinition(ConfigurableCommandCompleter.class);
+
+            ManagedList completers = new ManagedList();
+
+            List<Element> children = getChildElements(element, new String[] {BEAN, REF, NULL});
+
+            for (Element child : children) {
+                if (DomUtils.nodeNameEquals(child, BEAN)) {
+                    BeanDefinitionHolder holder = parseBeanDefinitionElement(child);
+                    // noinspection unchecked
+                    completers.add(holder.getBeanDefinition());
+                }
+                else if (DomUtils.nodeNameEquals(child, REF)) {
+                    BeanDefinitionParserDelegate parser = createBeanDefinitionParserDelegate(child);
+                    RuntimeBeanReference ref = (RuntimeBeanReference) parser.parsePropertySubElement(child, completer.getRawBeanDefinition());
+                    // noinspection unchecked
+                    completers.add(ref);
+                }
+                else if (DomUtils.nodeNameEquals(child, NULL)) {
+                    // noinspection unchecked
+                    completers.add(null);
+                }
+            }
+
+            completer.addConstructorArgValue(completers);
+
+            return completer;
+        }
+
+        //
+        // <gshell:action>
+        //
+
+        private BeanDefinitionHolder parseCommandAction(final Element element) {
+            assert element != null;
+
+            log.trace("Parse command action; element; {}", element);
+
+            // Construct the action
+            BeanDefinition action = parseBeanDefinitionElement(element).getBeanDefinition();
+
+            // All actions are configured as prototypes
+            action.setScope(PROTOTYPE);
+
+            // Generate id and register the bean
+            String id = resolveId(element, action);
+            return register(action, id);
+        }
+
+        //
+        // <gshell:link>
+        //
+
+        private List<Link> parseLinks(final Element element) {
+            assert element != null;
+
+            log.trace("Parse links; element; {}", element);
+
+            List<Link> links = new ArrayList<Link>();
+
+            List<Element> children = getChildElements(element, LINK);
+
+            for (Element child : children) {
+                String name = child.getAttribute(NAME);
+                String target = child.getAttribute(TARGET);
+
+                links.add(new LinkImpl(name, target));
+            }
+
+            return links;
+        }
+
+        //
+        // <gshell:alias>
+        //
+
+        private List<Alias> parseAliases(final Element element) {
+            assert element != null;
+
+            log.trace("Parse aliases; element; {}", element);
+
+            List<Alias> aliases = new ArrayList<Alias>();
+
+            List<Element> children = getChildElements(element, ALIAS);
+
+            for (Element child : children) {
+                String name = child.getAttribute(NAME);
+                String alias = child.getAttribute(ALIAS);
+
+                aliases.add(new AliasImpl(name, alias));
+            }
+
+            return aliases;
+        }
+    }
+}
diff --git a/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/config/NamespaceHandler.java b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/config/NamespaceHandler.java
new file mode 100644
index 0000000..3e464d3
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/config/NamespaceHandler.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.servicemix.kernel.gshell.core.config;
+
+import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
+
+public class NamespaceHandler extends NamespaceHandlerSupport {
+
+    public void init() {
+        registerBeanDefinitionParser(CommandParser.COMMAND_BUNDLE, new CommandParser());
+    }
+
+}
diff --git a/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/sshd/BogusPasswordAuthenticator.java b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/sshd/BogusPasswordAuthenticator.java
new file mode 100644
index 0000000..34e2527
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/sshd/BogusPasswordAuthenticator.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.servicemix.kernel.gshell.core.sshd;
+
+import org.apache.sshd.server.PasswordAuthenticator;
+
+public class BogusPasswordAuthenticator implements PasswordAuthenticator {
+
+    public Object authenticate(String username, String password) {
+        return (username != null && username.equals(password)) ? username : null;
+    }
+
+}
diff --git a/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/sshd/SshServerFactory.java b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/sshd/SshServerFactory.java
new file mode 100644
index 0000000..fbf9041
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/sshd/SshServerFactory.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.servicemix.kernel.gshell.core.sshd;
+
+import org.apache.sshd.SshServer;
+
+public class SshServerFactory {
+
+    private SshServer server;
+
+    private boolean start;
+
+    public SshServerFactory(SshServer server) {
+        this.server = server;
+    }
+
+    public boolean isStart() {
+        return start;
+    }
+
+    public void setStart(boolean start) {
+        this.start = start;
+    }
+
+    public void start() throws Exception {
+        if (start) {
+            try {
+                server.start();
+            } catch (Exception e) {
+                e.printStackTrace();
+                throw e;
+            }
+        }
+    }
+
+    public void stop() throws Exception {
+        if (start) {
+            server.stop();
+        }
+    }
+
+}
diff --git a/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/vfs/mvn/MvnFileObject.java b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/vfs/mvn/MvnFileObject.java
new file mode 100644
index 0000000..41a2bb8
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/vfs/mvn/MvnFileObject.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.servicemix.kernel.gshell.core.vfs.mvn;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.apache.commons.httpclient.URIException;
+import org.apache.commons.vfs.FileName;
+import org.apache.commons.vfs.FileSystemException;
+import org.apache.commons.vfs.provider.URLFileName;
+import org.apache.commons.vfs.provider.url.UrlFileObject;
+
+public class MvnFileObject extends UrlFileObject {
+
+    public MvnFileObject(MvnFileSystem fs, FileName fileName) {
+        super(fs, fileName);
+    }
+
+    protected URL createURL(final FileName name) throws MalformedURLException, FileSystemException, URIException
+    {
+        String url;
+        if (name instanceof URLFileName)
+        {
+            URLFileName urlName = (URLFileName) getName();
+
+            // TODO: charset
+            url = urlName.getURIEncoded(null);
+        }
+        else
+        {
+            url = getName().getURI();
+        }
+        if (url.startsWith("mvn:///")) {
+            url = "mvn:" + url.substring("mvn:///".length());
+        }
+        return new URL(url);
+    }
+
+}
diff --git a/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/vfs/mvn/MvnFileProvider.java b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/vfs/mvn/MvnFileProvider.java
new file mode 100644
index 0000000..7d88cd6
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/vfs/mvn/MvnFileProvider.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.servicemix.kernel.gshell.core.vfs.mvn;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.apache.commons.vfs.FileName;
+import org.apache.commons.vfs.FileObject;
+import org.apache.commons.vfs.FileSystem;
+import org.apache.commons.vfs.FileSystemException;
+import org.apache.commons.vfs.FileSystemOptions;
+import org.apache.commons.vfs.provider.url.UrlFileProvider;
+
+public class MvnFileProvider extends UrlFileProvider {
+
+    /**
+     * Locates a file object, by absolute URI.
+     */
+    public synchronized FileObject findFile(final FileObject baseFile,
+                                            final String uri,
+                                            final FileSystemOptions fileSystemOptions)
+        throws FileSystemException
+    {
+        try
+        {
+            final URL url = new URL(uri);
+
+            URL rootUrl = new URL(url, "/");
+            final String key = this.getClass().getName() + rootUrl.toString();
+            FileSystem fs = findFileSystem(key, fileSystemOptions);
+            if (fs == null)
+            {
+                String extForm = rootUrl.toExternalForm();
+                final FileName rootName = getContext().parseURI(extForm);
+                // final FileName rootName =
+                //    new BasicFileName(rootUrl, FileName.ROOT_PATH);
+                fs = new MvnFileSystem(rootName, fileSystemOptions);
+                addFileSystem(key, fs);
+            }
+            return fs.resolveFile(url.getPath());
+        }
+        catch (final MalformedURLException e)
+        {
+            throw new FileSystemException("vfs.provider.url/badly-formed-uri.error", uri, e);
+        }
+    }
+
+
+}
diff --git a/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/vfs/mvn/MvnFileSystem.java b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/vfs/mvn/MvnFileSystem.java
new file mode 100644
index 0000000..7583eb5
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/vfs/mvn/MvnFileSystem.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.servicemix.kernel.gshell.core.vfs.mvn;
+
+import org.apache.commons.vfs.FileName;
+import org.apache.commons.vfs.FileObject;
+import org.apache.commons.vfs.FileSystemOptions;
+import org.apache.commons.vfs.provider.url.UrlFileSystem;
+
+public class MvnFileSystem extends UrlFileSystem {
+
+    protected MvnFileSystem(FileName fileName, FileSystemOptions fileSystemOptions) {
+        super(fileName, fileSystemOptions);
+    }
+
+    protected FileObject createFile(FileName fileName) {
+        return new MvnFileObject(this, fileName);
+    }
+}
diff --git a/karaf/gshell/gshell-core/src/main/resources/META-INF/spring.handlers b/karaf/gshell/gshell-core/src/main/resources/META-INF/spring.handlers
new file mode 100644
index 0000000..2315764
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/resources/META-INF/spring.handlers
@@ -0,0 +1,24 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 697807 $ $Date: 2008-09-22 20:12:04 +0700 (Mon, 22 Sep 2008) $
+##
+
+http\://servicemix.apache.org/schema/servicemix-gshell=org.apache.servicemix.kernel.gshell.core.config.NamespaceHandler
\ No newline at end of file
diff --git a/karaf/gshell/gshell-core/src/main/resources/META-INF/spring.schemas b/karaf/gshell/gshell-core/src/main/resources/META-INF/spring.schemas
new file mode 100644
index 0000000..67eca68
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/resources/META-INF/spring.schemas
@@ -0,0 +1,24 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 697807 $ $Date: 2008-09-22 20:12:04 +0700 (Mon, 22 Sep 2008) $
+##
+
+http\://servicemix.apache.org/schema/servicemix-gshell/servicemix-gshell.xsd=org/apache/servicemix/kernel/gshell/core/servicemix-gshell.xsd
diff --git a/karaf/gshell/gshell-core/src/main/resources/META-INF/spring/gshell-commands.xml b/karaf/gshell/gshell-core/src/main/resources/META-INF/spring/gshell-commands.xml
new file mode 100644
index 0000000..dbcafd3
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/resources/META-INF/spring/gshell-commands.xml
@@ -0,0 +1,277 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xmlns:gshell="http://servicemix.apache.org/schema/servicemix-gshell"
+       xsi:schemaLocation="
+  http://www.springframework.org/schema/beans
+  http://www.springframework.org/schema/beans/spring-beans.xsd
+  http://www.springframework.org/schema/util
+  http://www.springframework.org/schema/util/spring-util.xsd
+  http://servicemix.apache.org/schema/servicemix-gshell
+  http://servicemix.apache.org/schema/servicemix-gshell/servicemix-gshell.xsd"
+       default-autowire="no"
+       default-dependency-check="none"
+       default-init-method="init"
+       default-destroy-method="destroy">
+
+    <import resource="classpath:org/apache/servicemix/kernel/gshell/core/commands.xml" />
+
+    <bean id="vfsCommandActionTemplate" abstract="true">
+        <property name="fileSystemAccess" ref="fileSystemAccess"/>
+    </bean>
+
+    <gshell:command-bundle>
+        <gshell:command name="about">
+            <gshell:action class="org.apache.geronimo.gshell.commands.builtin.AboutAction">
+                <constructor-arg ref="application"/>
+            </gshell:action>
+        </gshell:command>
+
+        <gshell:command name="help">
+            <gshell:action class="org.apache.geronimo.gshell.commands.builtin.HelpAction">
+                <constructor-arg ref="commandResolver"/>
+            </gshell:action>
+            <gshell:completers>
+                <bean class="org.apache.geronimo.gshell.console.completer.AggregateCompleter">
+                    <constructor-arg>
+                        <list>
+                            <ref bean="aliasNameCompleter"/>
+                            <ref bean="commandNameCompleter"/>
+                        </list>
+                    </constructor-arg>
+                </bean>
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+
+        <gshell:command name="exit">
+            <gshell:action class="org.apache.geronimo.gshell.commands.builtin.ExitAction"/>
+        </gshell:command>
+
+        <gshell:link name="quit" target="exit"/>
+
+        <gshell:command name="echo">
+            <gshell:action class="org.apache.geronimo.gshell.commands.builtin.EchoAction"/>
+        </gshell:command>
+
+        <gshell:command name="clear" type="stateless">
+            <gshell:action class="org.apache.geronimo.gshell.commands.builtin.ClearAction"/>
+        </gshell:command>
+
+        <gshell:command name="source">
+            <gshell:action class="org.apache.geronimo.gshell.commands.builtin.SourceAction">
+                <constructor-arg ref="commandLineExecutor"/>
+                <constructor-arg ref="fileSystemAccess"/>
+            </gshell:action>
+            <gshell:completers>
+                <ref bean="fileObjectNameCompleter"/>
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+
+        <gshell:command name="set">
+            <gshell:action class="org.apache.geronimo.gshell.commands.builtin.SetAction"/>
+        </gshell:command>
+
+        <gshell:command name="unset">
+            <gshell:action class="org.apache.geronimo.gshell.commands.builtin.UnsetAction"/>
+            <gshell:completers>
+                <ref bean="variableNameCompleter"/>
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+
+        <gshell:command name="alias">
+            <gshell:action class="org.apache.geronimo.gshell.commands.builtin.AliasAction">
+                <constructor-arg ref="aliasRegistry"/>
+            </gshell:action>
+        </gshell:command>
+
+        <gshell:command name="unalias">
+            <gshell:action class="org.apache.geronimo.gshell.commands.builtin.UnaliasAction">
+                <constructor-arg ref="aliasRegistry"/>
+            </gshell:action>
+            <gshell:completers>
+                <ref bean="aliasNameCompleter"/>
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+
+        <gshell:command name="history">
+            <gshell:action class="org.apache.geronimo.gshell.commands.builtin.HistoryAction"/>
+        </gshell:command>
+
+        <gshell:command name="info">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.core.commands.InfoAction">
+                <constructor-arg ref="branding" />
+            </gshell:action>
+        </gshell:command>
+    </gshell:command-bundle>
+
+    <gshell:command-bundle>
+        <gshell:command name="ssh">
+            <gshell:action class="org.apache.geronimo.gshell.commands.ssh.SshAction"/>
+        </gshell:command>
+
+        <gshell:command name="sshd">
+            <gshell:action class="org.apache.geronimo.gshell.commands.ssh.SshServerAction"/>
+        </gshell:command>
+    </gshell:command-bundle>
+
+    <gshell:command-bundle>
+        <gshell:command name="exec">
+            <gshell:action class="org.apache.geronimo.gshell.commands.shell.ExecuteAction"/>
+        </gshell:command>
+
+        <gshell:command name="java">
+            <gshell:action class="org.apache.geronimo.gshell.commands.shell.JavaAction"/>
+        </gshell:command>
+
+        <gshell:command name="sleep">
+            <gshell:action class="org.apache.geronimo.gshell.commands.shell.SleepAction"/>
+        </gshell:command>
+
+        <gshell:command name="date">
+            <gshell:action class="org.apache.geronimo.gshell.commands.shell.DateAction"/>
+        </gshell:command>
+
+        <gshell:command name="edit">
+            <gshell:action class="org.apache.geronimo.gshell.commands.shell.EditAction">
+                <property name="fileSystemAccess" ref="fileSystemAccess"/>
+            </gshell:action>
+            <gshell:completers>
+                <ref bean="fileObjectNameCompleter"/>
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+
+        <gshell:command name="find">
+            <gshell:action class="org.apache.geronimo.gshell.commands.shell.FindAction">
+                <property name="fileSystemAccess" ref="fileSystemAccess"/>
+            </gshell:action>
+            <gshell:completers>
+                <ref bean="fileObjectNameCompleter"/>
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+
+        <gshell:command name="sort">
+            <gshell:action class="org.apache.geronimo.gshell.commands.text.SortAction">
+                <property name="fileSystemAccess" ref="fileSystemAccess"/>
+            </gshell:action>
+            <gshell:completers>
+                <ref bean="fileObjectNameCompleter"/>
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+    </gshell:command-bundle>
+
+    <gshell:command-bundle>
+        <gshell:command name="hostname">
+            <gshell:action class="org.apache.geronimo.gshell.commands.network.HostnameAction"/>
+        </gshell:command>
+    </gshell:command-bundle>
+
+    <gshell:command-bundle>
+        <gshell:link name="print" target="echo"/>
+
+        <gshell:command name="printf">
+            <gshell:action class="org.apache.geronimo.gshell.commands.text.PrintfAction"/>
+        </gshell:command>
+
+        <gshell:command name="cat">
+            <gshell:action class="org.apache.geronimo.gshell.commands.text.CatAction">
+                <property name="fileSystemAccess" ref="fileSystemAccess"/>
+            </gshell:action>
+            <gshell:completers>
+                <ref bean="fileObjectNameCompleter"/>
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+
+        <gshell:command name="grep">
+            <gshell:action class="org.apache.geronimo.gshell.commands.text.GrepAction"/>
+        </gshell:command>
+    </gshell:command-bundle>
+
+    <gshell:command-bundle>
+        <gshell:command name="cd">
+            <gshell:action class="org.apache.geronimo.gshell.commands.file.ChangeDirectoryAction" parent="vfsCommandActionTemplate"/>
+            <gshell:completers>
+                <ref bean="fileObjectNameCompleter"/>
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+
+        <gshell:command name="pwd" type="stateless">
+            <gshell:action class="org.apache.geronimo.gshell.commands.file.CurrentDirectoryAction" parent="vfsCommandActionTemplate"/>
+        </gshell:command>
+
+        <gshell:command name="ls">
+            <gshell:action class="org.apache.geronimo.gshell.commands.file.ListDirectoryAction" parent="vfsCommandActionTemplate"/>
+            <gshell:completers>
+                <ref bean="fileObjectNameCompleter"/>
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+
+        <gshell:link name="dir" target="ls"/>
+
+        <gshell:command name="cp">
+            <gshell:action class="org.apache.geronimo.gshell.commands.file.CopyAction" parent="vfsCommandActionTemplate"/>
+            <gshell:completers>
+                <ref bean="fileObjectNameCompleter"/>
+                <ref bean="fileObjectNameCompleter"/>
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+
+        <gshell:link name="copy" target="cp"/>
+
+        <gshell:command name="rm">
+            <gshell:action class="org.apache.geronimo.gshell.commands.file.RemoveAction" parent="vfsCommandActionTemplate"/>
+            <gshell:completers>
+                <ref bean="fileObjectNameCompleter"/>
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+
+        <gshell:link name="del" target="rm"/>
+
+        <gshell:command name="fileinfo">
+            <gshell:action class="org.apache.geronimo.gshell.commands.file.FileInfoAction" parent="vfsCommandActionTemplate"/>
+            <gshell:completers>
+                <ref bean="fileObjectNameCompleter"/>
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+
+        <gshell:command name="touch">
+            <gshell:action class="org.apache.geronimo.gshell.commands.file.TouchAction" parent="vfsCommandActionTemplate"/>
+            <gshell:completers>
+                <ref bean="fileObjectNameCompleter"/>
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+    </gshell:command-bundle>
+
+</beans>
diff --git a/karaf/gshell/gshell-core/src/main/resources/META-INF/spring/gshell-local.xml b/karaf/gshell/gshell-core/src/main/resources/META-INF/spring/gshell-local.xml
new file mode 100644
index 0000000..a047339
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/resources/META-INF/spring/gshell-local.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xmlns:osgi="http://www.springframework.org/schema/osgi"
+       xsi:schemaLocation="
+  http://www.springframework.org/schema/beans
+  http://www.springframework.org/schema/beans/spring-beans.xsd
+  http://www.springframework.org/schema/util
+  http://www.springframework.org/schema/util/spring-util.xsd
+  http://www.springframework.org/schema/osgi
+  http://www.springframework.org/schema/osgi/spring-osgi.xsd"
+       default-autowire="no"
+       default-dependency-check="none"
+       default-init-method="init"
+       default-destroy-method="destroy">
+
+    <bean id="localShellWrapped" parent="shell" init-method="init" destroy-method="close"/>
+
+    <bean id="localShell" class="org.apache.servicemix.kernel.gshell.core.ShellWrapper">
+        <constructor-arg ref="localShellWrapped" />
+    </bean>
+
+    <osgi:reference id="mainService" interface="org.apache.servicemix.kernel.main.spi.MainService"/>
+
+    <bean id="localConsole" class="org.apache.servicemix.kernel.gshell.core.LocalConsole">
+        <property name="createLocalShell" value="${servicemix.startLocalConsole}"/>
+        <property name="shell" ref="localShell"/>
+        <property name="mainService" ref="mainService" />
+    </bean>
+
+</beans>
\ No newline at end of file
diff --git a/karaf/gshell/gshell-core/src/main/resources/META-INF/spring/gshell-osgi.xml b/karaf/gshell/gshell-core/src/main/resources/META-INF/spring/gshell-osgi.xml
new file mode 100644
index 0000000..b99626a
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/resources/META-INF/spring/gshell-osgi.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:ctx="http://www.springframework.org/schema/context"
+       xmlns:osgi="http://www.springframework.org/schema/osgi"
+       xmlns:osgix="http://www.springframework.org/schema/osgi-compendium"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xsi:schemaLocation="
+  http://www.springframework.org/schema/beans
+  http://www.springframework.org/schema/beans/spring-beans.xsd
+  http://www.springframework.org/schema/context
+  http://www.springframework.org/schema/context/spring-context.xsd
+  http://www.springframework.org/schema/util
+  http://www.springframework.org/schema/util/spring-util.xsd
+  http://www.springframework.org/schema/osgi
+  http://www.springframework.org/schema/osgi/spring-osgi.xsd
+  http://www.springframework.org/schema/osgi-compendium
+  http://www.springframework.org/schema/osgi-compendium/spring-osgi-compendium.xsd"
+       default-autowire="no"
+       default-dependency-check="none"
+       default-init-method="init"
+       default-destroy-method="destroy">
+
+    <bean id="osgiCommandRegistry" class="org.apache.servicemix.kernel.gshell.core.OsgiCommandRegistry">
+        <constructor-arg ref="commandRegistry" />
+    </bean>
+
+    <bean id="osgiAliasRegistry" class="org.apache.servicemix.kernel.gshell.core.OsgiAliasRegistry">
+        <constructor-arg ref="aliasRegistry" />
+    </bean>
+
+    <osgi:list id="osgiCommands" interface="org.apache.geronimo.gshell.command.Command" cardinality="0..N">
+        <osgi:listener ref="osgiCommandRegistry" bind-method="register" unbind-method="unregister" />
+    </osgi:list>
+
+    <osgi:list id="osgiLinkCommands" interface="org.apache.geronimo.gshell.command.Link" cardinality="0..N">
+        <osgi:listener ref="osgiCommandRegistry" bind-method="register" unbind-method="unregister" />
+    </osgi:list>
+
+    <osgi:list id="osgiAliases" interface="org.apache.geronimo.gshell.command.Alias" cardinality="0..N">
+        <osgi:listener ref="osgiAliasRegistry" bind-method="register" unbind-method="unregister" />
+    </osgi:list>
+
+    <osgi:service ref="localShell" interface="org.apache.geronimo.gshell.shell.Shell">
+    </osgi:service>
+
+    <osgi:service ref="commandLineExecutor" interface="org.apache.geronimo.gshell.commandline.CommandLineExecutor">
+    </osgi:service>
+
+    <osgix:cm-properties id="cmProps" persistent-id="org.apache.servicemix.shell">
+        <prop key="sshPort">8101</prop>
+        <prop key="sshRealm">servicemix</prop>
+        <prop key="hostKey">${servicemix.base}/etc/host.key</prop>
+    </osgix:cm-properties>
+
+    <ctx:property-placeholder properties-ref="cmProps" />
+    
+</beans>
\ No newline at end of file
diff --git a/karaf/gshell/gshell-core/src/main/resources/META-INF/spring/gshell-remote.xml b/karaf/gshell/gshell-core/src/main/resources/META-INF/spring/gshell-remote.xml
new file mode 100644
index 0000000..d68ee51
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/resources/META-INF/spring/gshell-remote.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xmlns:osgi="http://www.springframework.org/schema/osgi"
+       xmlns:jaas="http://servicemix.apache.org/jaas"
+       xsi:schemaLocation="
+  http://www.springframework.org/schema/beans
+  http://www.springframework.org/schema/beans/spring-beans.xsd
+  http://www.springframework.org/schema/util
+  http://www.springframework.org/schema/util/spring-util.xsd
+  http://www.springframework.org/schema/osgi
+  http://www.springframework.org/schema/osgi/spring-osgi.xsd
+  http://servicemix.apache.org/jaas
+  http://servicemix.apache.org/schema/servicemix-jaas.xsd"
+       default-autowire="no"
+       default-dependency-check="none"
+       default-init-method="init"
+       default-destroy-method="destroy">
+
+    <bean name="sshClient" class="org.apache.sshd.SshClient" factory-method="setUpDefaultClient" init-method="start" destroy-method="stop">
+    </bean>
+
+    <bean name="sshServer" class="org.apache.sshd.SshServer" factory-method="setUpDefaultServer" scope="prototype">
+        <property name="port" value="${sshPort}" />
+        <property name="shellFactory">
+            <bean class="org.apache.geronimo.gshell.commands.ssh.ShellFactoryImpl">
+                <property name="application" ref="application" />
+                <property name="completers">
+                    <list>
+                        <ref bean="commandsCompleter"/>
+                        <ref bean="aliasNameCompleter"/>
+                    </list>
+                </property>
+                <property name="executor" ref="commandLineExecutor" />
+                <property name="prompter">
+                    <bean class="org.apache.geronimo.gshell.wisdom.shell.ConsolePrompterImpl">
+                        <constructor-arg ref="application"/>
+                    </bean>
+                </property>
+                <property name="errorHandler">
+                    <bean class="org.apache.geronimo.gshell.wisdom.shell.ConsoleErrorHandlerImpl" />
+                </property>
+                <property name="history">
+                    <bean class="org.apache.geronimo.gshell.wisdom.shell.HistoryImpl">
+                        <constructor-arg ref="application"/>
+                    </bean>
+                </property>
+            </bean>
+        </property>
+        <property name="keyPairProvider" ref="keyPairProvider" />
+        <property name="passwordAuthenticator" ref="passwordAuthenticator" />
+    </bean>
+
+    <bean name="keyPairProvider" class="org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider">
+        <property name="path" value="${hostKey}" />
+    </bean>
+    <bean name="passwordAuthenticator" class="org.apache.sshd.server.jaas.JaasPasswordAuthenticator">
+        <property name="domain" value="${sshRealm}" />
+    </bean>
+
+    <bean id="sshServerFactory" class="org.apache.servicemix.kernel.gshell.core.sshd.SshServerFactory" init-method="start" destroy-method="stop">
+        <constructor-arg ref="sshServer" />
+        <property name="start" value="${servicemix.startRemoteShell}" />
+    </bean>
+
+    <!--
+    <jaas:config id="SshServer" rank="-1">
+        <jaas:module className="org.apache.geronimo.gshell.remote.server.auth.BogusLoginModule" flags="required" />
+    </jaas:config>
+    -->
+
+</beans>
\ No newline at end of file
diff --git a/karaf/gshell/gshell-core/src/main/resources/META-INF/spring/gshell-vfs.xml b/karaf/gshell/gshell-core/src/main/resources/META-INF/spring/gshell-vfs.xml
new file mode 100644
index 0000000..3992f54
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/resources/META-INF/spring/gshell-vfs.xml
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xsi:schemaLocation="
+  http://www.springframework.org/schema/beans
+  http://www.springframework.org/schema/beans/spring-beans.xsd
+  http://www.springframework.org/schema/util
+  http://www.springframework.org/schema/util/spring-util.xsd
+  http://servicemix.apache.org/schema/servicemix-gshell
+  http://servicemix.apache.org/schema/servicemix-gshell/servicemix-gshell.xsd"
+       default-autowire="no"
+       default-dependency-check="none"
+       default-init-method="init"
+       default-destroy-method="destroy">
+
+    <bean id="fileSystemAccess" class="org.apache.geronimo.gshell.vfs.FileSystemAccessImpl">
+        <constructor-arg ref="fileSystemManager"/>
+    </bean>
+
+    <bean id="fileObjectNameCompleter" class="org.apache.geronimo.gshell.vfs.FileObjectNameCompleter">
+        <constructor-arg ref="fileSystemAccess"/>
+    </bean>
+
+    <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
+        <property name="customEditors">
+            <map>
+                <entry key="org.apache.commons.vfs.CacheStrategy">
+                    <bean class="org.apache.geronimo.gshell.vfs.config.CacheStrategyEditor"/>
+                </entry>
+            </map>
+        </property>
+    </bean>
+
+    <!--
+    TODO: Set tempDir File arg in constructor to set the temporary location, may need 2 replicators?
+    -->
+    <bean id="defaultFileReplicator" class="org.apache.commons.vfs.impl.DefaultFileReplicator"/>
+
+    <bean id="fileSystemManager" class="org.apache.geronimo.gshell.vfs.config.FileSystemManagerFactoryBean">
+        <property name="filesCache">
+            <bean class="org.apache.commons.vfs.cache.SoftRefFilesCache"/>
+        </property>
+
+        <property name="cacheStrategy" value="ON_RESOLVE"/>
+
+        <property name="fileReplicator">
+            <bean class="org.apache.commons.vfs.impl.PrivilegedFileReplicator">
+                <constructor-arg ref="defaultFileReplicator"/>
+            </bean>
+        </property>
+
+        <!--
+        TODO: Try and root the temporary store under ${gshell.home}/tmp or something
+        -->
+        <property name="temporaryFileStore">
+            <ref bean="defaultFileReplicator"/>
+        </property>
+
+        <property name="fileContentInfoFactory">
+            <bean class="org.apache.commons.vfs.impl.FileContentInfoFilenameFactory"/>
+        </property>
+
+        <property name="defaultProvider">
+            <bean class="org.apache.commons.vfs.provider.url.UrlFileProvider"/>
+        </property>
+    </bean>
+
+    <bean class="org.apache.geronimo.gshell.vfs.config.FileProviderConfigurer">
+        <property name="fileSystemManager" ref="fileSystemManager"/>
+        <property name="scheme" value="tmp"/>
+        <property name="provider">
+            <bean class="org.apache.commons.vfs.provider.temp.TemporaryFileProvider"/>
+        </property>
+    </bean>
+
+    <bean class="org.apache.geronimo.gshell.vfs.config.FileProviderConfigurer">
+        <property name="fileSystemManager" ref="fileSystemManager"/>
+        <property name="scheme" value="ram"/>
+        <property name="provider">
+            <bean class="org.apache.commons.vfs.provider.ram.RamFileProvider"/>
+        </property>
+    </bean>
+
+    <bean class="org.apache.geronimo.gshell.vfs.config.FileProviderConfigurer">
+        <property name="fileSystemManager" ref="fileSystemManager"/>
+        <property name="scheme" value="file"/>
+        <property name="provider">
+            <bean class="org.apache.commons.vfs.provider.local.DefaultLocalFileProvider"/>
+        </property>
+    </bean>
+
+    <bean class="org.apache.geronimo.gshell.vfs.config.FileProviderConfigurer">
+        <property name="fileSystemManager" ref="fileSystemManager"/>
+        <property name="scheme" value="mvn"/>
+        <property name="provider">
+            <bean class="org.apache.servicemix.kernel.gshell.core.vfs.mvn.MvnFileProvider"/>
+        </property>
+    </bean>
+
+    <bean id="metaDataRegistry" class="org.apache.geronimo.gshell.vfs.provider.meta.data.MetaDataRegistryImpl">
+        <constructor-arg ref="eventManager" />
+    </bean>
+
+    <bean id="metaFileProviderConfigurer" class="org.apache.geronimo.gshell.vfs.config.FileProviderConfigurer">
+        <property name="fileSystemManager" ref="fileSystemManager"/>
+        <property name="scheme" value="meta"/>
+        <property name="provider">
+            <bean class="org.apache.geronimo.gshell.vfs.provider.meta.MetaFileProvider">
+                <constructor-arg ref="metaDataRegistry"/>
+            </bean>
+        </property>
+    </bean>
+
+</beans>
\ No newline at end of file
diff --git a/karaf/gshell/gshell-core/src/main/resources/META-INF/spring/gshell.xml b/karaf/gshell/gshell-core/src/main/resources/META-INF/spring/gshell.xml
new file mode 100644
index 0000000..8bc494e
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/resources/META-INF/spring/gshell.xml
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:util="http://www.springframework.org/schema/util" xmlns:osgi="http://www.springframework.org/schema/osgi"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+  http://www.springframework.org/schema/beans/spring-beans.xsd
+  http://www.springframework.org/schema/util
+  http://www.springframework.org/schema/util/spring-util.xsd
+  http://servicemix.apache.org/schema/servicemix-gshell
+  http://servicemix.apache.org/schema/servicemix-gshell/servicemix-gshell.xsd
+  http://www.springframework.org/schema/osgi
+  http://www.springframework.org/schema/osgi/spring-osgi-1.0.xsd"
+       default-autowire="no"
+       default-dependency-check="none"
+       default-init-method="init"
+       default-destroy-method="destroy">
+
+    <bean id="io" class="org.apache.geronimo.gshell.io.IO">
+        <property name="verbosity" value="DEBUG"/>
+    </bean>
+
+    <bean id="branding" class="org.apache.servicemix.kernel.gshell.core.ServiceMixBranding">
+        <property name="prompt" value="@|bold %{gshell.username}|@%{application.id}:@|bold %{gshell.group}|> " />
+    </bean>
+
+    <bean id="application" class="org.apache.servicemix.kernel.gshell.core.ApplicationImpl">
+        <property name="id" value="${servicemix.name}"/>
+        <property name="io" ref="io"/>
+        <property name="model">
+            <bean class="org.apache.geronimo.gshell.application.model.ApplicationModel">
+                <property name="branding" ref="branding"/>
+            </bean>
+        </property>
+        <property name="variables">
+            <bean class="org.apache.geronimo.gshell.command.Variables"/>
+        </property>
+    </bean>
+
+    <bean id="eventManager" class="org.apache.geronimo.gshell.event.EventManagerImpl"/>
+
+    <bean id="applicationManager" class="org.apache.servicemix.kernel.gshell.core.ApplicationManagerImpl">
+        <constructor-arg ref="eventManager" />
+        <constructor-arg ref="application" />
+    </bean>
+
+    <bean id="commandLineParser" class="org.apache.geronimo.gshell.parser.CommandLineParser"/>
+
+    <bean id="aliasRegistry" class="org.apache.geronimo.gshell.wisdom.registry.AliasRegistryImpl">
+        <constructor-arg ref="eventManager"/>
+    </bean>
+
+    <bean id="aliasMetaMapper" class="org.apache.geronimo.gshell.wisdom.registry.AliasMetaMapper">
+        <constructor-arg ref="eventManager"/>
+        <constructor-arg ref="metaDataRegistry"/>
+        <constructor-arg ref="aliasRegistry"/>
+    </bean>
+
+    <bean id="commandRegistry" class="org.apache.geronimo.gshell.wisdom.registry.CommandRegistryImpl">
+        <constructor-arg ref="eventManager"/>
+    </bean>
+
+    <bean id="commandMetaMapper" class="org.apache.geronimo.gshell.wisdom.registry.CommandMetaMapper">
+        <constructor-arg ref="eventManager"/>
+        <constructor-arg ref="metaDataRegistry"/>
+        <constructor-arg ref="commandRegistry"/>
+    </bean>
+
+    <bean id="groupDirResolver" class="org.apache.geronimo.gshell.wisdom.registry.GroupDirectoryResolver">
+        <constructor-arg ref="fileSystemAccess"/>
+    </bean>
+
+    <bean id="commandResolver" class="org.apache.geronimo.gshell.wisdom.registry.CommandResolverImpl">
+        <constructor-arg ref="fileSystemAccess"/>
+        <constructor-arg ref="groupDirResolver"/>
+    </bean>
+
+    <bean class="org.apache.servicemix.kernel.gshell.core.WorkAroundAliasCommand" scope="prototype">
+        <constructor-arg ref="commandLineExecutor"/>
+    </bean>
+
+    <bean class="org.apache.geronimo.gshell.wisdom.command.GroupCommand" scope="prototype"/>
+
+    <bean id="commandLineBuilder" class="org.apache.geronimo.gshell.wisdom.shell.CommandLineBuilderImpl">
+        <constructor-arg ref="commandLineParser"/>
+    </bean>
+
+    <bean id="commandLineExecutor" class="org.apache.geronimo.gshell.wisdom.shell.CommandLineExecutorImpl">
+        <constructor-arg ref="commandResolver"/>
+        <constructor-arg ref="commandLineBuilder"/>
+    </bean>
+
+    <bean id="shell" class="org.apache.geronimo.gshell.wisdom.shell.ShellImpl" scope="prototype" init-method="init" destroy-method="close">
+        <constructor-arg ref="application"/>
+        <constructor-arg ref="commandLineExecutor"/>
+
+        <property name="completers">
+            <list>
+                <ref bean="commandsCompleter"/>
+                <ref bean="aliasNameCompleter"/>
+            </list>
+        </property>
+        <property name="prompter">
+            <bean class="org.apache.geronimo.gshell.wisdom.shell.ConsolePrompterImpl">
+                <constructor-arg ref="application"/>
+            </bean>
+        </property>
+        <property name="errorHandler">
+            <bean class="org.apache.geronimo.gshell.wisdom.shell.ConsoleErrorHandlerImpl" />
+        </property>
+        <property name="history">
+            <bean class="org.apache.geronimo.gshell.wisdom.shell.HistoryImpl">
+                <constructor-arg ref="application"/>
+            </bean>
+        </property>
+    </bean>
+
+    <bean id="commandNameCompleter" class="org.apache.geronimo.gshell.wisdom.completer.CommandNameCompleter"
+          lazy-init="true">
+        <constructor-arg ref="eventManager"/>
+        <constructor-arg ref="commandRegistry"/>
+    </bean>
+
+    <bean id="aliasNameCompleter" class="org.apache.geronimo.gshell.wisdom.completer.AliasNameCompleter"
+          lazy-init="true">
+        <constructor-arg ref="eventManager"/>
+        <constructor-arg ref="aliasRegistry"/>
+    </bean>
+
+    <bean id="commandsCompleter" class="org.apache.geronimo.gshell.wisdom.completer.CommandsCompleter" lazy-init="true">
+        <constructor-arg ref="eventManager"/>
+        <constructor-arg ref="commandRegistry"/>
+    </bean>
+
+    <bean id="variableNameCompleter" class="org.apache.geronimo.gshell.wisdom.completer.VariableNameCompleter" lazy-init="true">
+    </bean>
+
+</beans>
\ No newline at end of file
diff --git a/karaf/gshell/gshell-core/src/main/resources/org/apache/geronimo/gshell/commands/text/SortAction.properties b/karaf/gshell/gshell-core/src/main/resources/org/apache/geronimo/gshell/commands/text/SortAction.properties
new file mode 100644
index 0000000..e4e787d
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/resources/org/apache/geronimo/gshell/commands/text/SortAction.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Sort lines of text.
+
+command.manual=\
+  TODO: about manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-core/src/main/resources/org/apache/servicemix/kernel/gshell/core/commands.xml b/karaf/gshell/gshell-core/src/main/resources/org/apache/servicemix/kernel/gshell/core/commands.xml
new file mode 100644
index 0000000..8b91ee1
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/resources/org/apache/servicemix/kernel/gshell/core/commands.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xsi:schemaLocation="
+  http://www.springframework.org/schema/beans
+  http://www.springframework.org/schema/beans/spring-beans.xsd
+  http://www.springframework.org/schema/util
+  http://www.springframework.org/schema/util/spring-util.xsd">
+
+    <bean class="org.apache.servicemix.kernel.gshell.core.BeanContainerAwareProcessor" />
+
+    <bean id="statelessCommandTemplate" class="org.apache.geronimo.gshell.wisdom.command.StatelessCommand" abstract="true">
+        <property name="documenter">
+            <bean class="org.apache.geronimo.gshell.wisdom.command.MessageSourceCommandDocumenter"/>
+        </property>
+
+        <property name="messages">
+            <bean class="org.apache.geronimo.gshell.wisdom.command.CommandMessageSource"/>
+        </property>
+    </bean>
+
+    <bean id="statefulCommandTemplate" class="org.apache.geronimo.gshell.wisdom.command.StatefulCommand" abstract="true">
+        <property name="documenter">
+            <bean class="org.apache.geronimo.gshell.wisdom.command.MessageSourceCommandDocumenter"/>
+        </property>
+
+        <property name="messages">
+            <bean class="org.apache.geronimo.gshell.wisdom.command.CommandMessageSource"/>
+        </property>
+    </bean>
+
+</beans>
\ No newline at end of file
diff --git a/karaf/gshell/gshell-core/src/main/resources/org/apache/servicemix/kernel/gshell/core/commands/InfoAction.properties b/karaf/gshell/gshell-core/src/main/resources/org/apache/servicemix/kernel/gshell/core/commands/InfoAction.properties
new file mode 100644
index 0000000..755f0c8
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/resources/org/apache/servicemix/kernel/gshell/core/commands/InfoAction.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Display JVM informations about the current application.
+
+command.manual=\
+  TODO: about manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-core/src/main/resources/org/apache/servicemix/kernel/gshell/core/servicemix-gshell.xsd b/karaf/gshell/gshell-core/src/main/resources/org/apache/servicemix/kernel/gshell/core/servicemix-gshell.xsd
new file mode 100644
index 0000000..36a1e1d
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/main/resources/org/apache/servicemix/kernel/gshell/core/servicemix-gshell.xsd
@@ -0,0 +1,270 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+-->
+
+<!-- $Rev: 699828 $ $Date: 2008-09-28 16:35:27 +0200 (Sun, 28 Sep 2008) $ -->
+
+<xsd:schema xmlns="http://servicemix.apache.org/schema/servicemix-gshell"
+        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+        xmlns:beans="http://www.springframework.org/schema/beans"
+        targetNamespace="http://servicemix.apache.org/schema/servicemix-gshell"
+        elementFormDefault="qualified"
+        attributeFormDefault="unqualified">
+
+    <xsd:import namespace="http://www.springframework.org/schema/beans"/>
+
+    <xsd:annotation>
+        <xsd:documentation>
+            Defines the configuration elements for Apache ServiceMix Kernel commands support.
+        </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:element name="command-bundle">
+        <xsd:complexType>
+            <xsd:annotation>
+                <xsd:documentation>
+                    Defines a command bundle.
+                </xsd:documentation>
+            </xsd:annotation>
+            <xsd:sequence>
+                <xsd:element ref="beans:description" minOccurs="0" maxOccurs="1"/>
+                <xsd:choice minOccurs="0" maxOccurs="unbounded">
+					<xsd:element ref="command"/>
+					<xsd:element ref="alias"/>
+                    <xsd:element ref="link"/>
+				</xsd:choice>
+            </xsd:sequence>
+        </xsd:complexType>
+    </xsd:element>
+
+    <xsd:element name="command">
+        <xsd:complexType>
+            <xsd:annotation>
+                <xsd:documentation>
+                    Defines a command.
+                </xsd:documentation>
+            </xsd:annotation>
+            <xsd:sequence>
+                <xsd:element ref="beans:description" minOccurs="0" maxOccurs="1"/>
+                <!--
+                NOTE: Not using an xsd:choice here, as I can't seem to figure out how to get it to properly
+                      validate the min/max of the containted elements.  W/o the xsd:choice the validation
+                      works, though have to define elements in order :-(
+                -->
+                <xsd:element ref="action" minOccurs="1" maxOccurs="1"/>
+                <xsd:element ref="documenter" minOccurs="0" maxOccurs="1"/>
+                <xsd:choice minOccurs="0" maxOccurs="1">
+                    <xsd:element ref="completer"/>
+                    <xsd:element ref="completers"/>
+                </xsd:choice>
+                <xsd:element ref="message-source" minOccurs="0" maxOccurs="1"/>
+            </xsd:sequence>
+            <xsd:attribute name="name" type="xsd:string" use="required"/>
+            <xsd:attribute name="type" use="optional" default="stateful">
+                <xsd:annotation>
+                    <xsd:documentation>
+                        The command type.
+                    </xsd:documentation>
+                </xsd:annotation>
+                <xsd:simpleType>
+                    <xsd:restriction base="xsd:string">
+                        <xsd:enumeration value="stateless"/>
+                        <xsd:enumeration value="stateful"/>
+                    </xsd:restriction>
+                </xsd:simpleType>
+            </xsd:attribute>
+        </xsd:complexType>
+    </xsd:element>
+
+    <xsd:element name="link">
+        <xsd:complexType>
+            <xsd:annotation>
+                <xsd:documentation>
+                    Defines a link command.
+                </xsd:documentation>
+            </xsd:annotation>
+            <xsd:sequence>
+                <xsd:element ref="beans:description" minOccurs="0" maxOccurs="1"/>
+            </xsd:sequence>
+            <xsd:attribute name="name" type="xsd:string" use="required"/>
+            <xsd:attribute name="target" type="xsd:string" use="required"/>
+        </xsd:complexType>
+    </xsd:element>
+
+    <xsd:group name="commandComponentElements">
+        <xsd:annotation>
+            <xsd:documentation>
+                Defines the valid elements for command components.  This is based on beans:beanElements,
+                stripping off the bits which are not valid in the command component context.
+            </xsd:documentation>
+        </xsd:annotation>
+		<xsd:sequence>
+			<xsd:element ref="beans:description" minOccurs="0"/>
+			<xsd:choice minOccurs="0" maxOccurs="unbounded">
+				<xsd:element ref="beans:meta"/>
+				<xsd:element ref="beans:constructor-arg"/>
+				<xsd:element ref="beans:property"/>
+				<xsd:element ref="beans:qualifier"/>
+				<xsd:element ref="beans:lookup-method"/>
+				<xsd:element ref="beans:replaced-method"/>
+				<!--
+				NOTE: This seems to cause schema validation problems... not really sure why
+				<xsd:any namespace="##other" processContents="strict" minOccurs="0" maxOccurs="unbounded"/>
+				-->
+			</xsd:choice>
+		</xsd:sequence>
+	</xsd:group>
+
+    <xsd:attributeGroup name="commandComponentAttributes">
+        <xsd:annotation>
+            <xsd:documentation>
+                Defines the valid attributes for command components.  This is based on beans:beanAttributes,
+                stripping off the bits which are not valid in the command component context.
+            </xsd:documentation>
+        </xsd:annotation>
+		<xsd:attribute name="class" type="xsd:string"/>
+		<xsd:attribute name="parent" type="xsd:string"/>
+		<xsd:attribute name="autowire" default="default">
+			<xsd:simpleType>
+				<xsd:restriction base="xsd:NMTOKEN">
+					<xsd:enumeration value="default"/>
+					<xsd:enumeration value="no"/>
+					<xsd:enumeration value="byName"/>
+					<xsd:enumeration value="byType"/>
+					<xsd:enumeration value="constructor"/>
+					<xsd:enumeration value="autodetect"/>
+				</xsd:restriction>
+			</xsd:simpleType>
+		</xsd:attribute>
+		<xsd:attribute name="dependency-check" default="default">
+			<xsd:simpleType>
+				<xsd:restriction base="xsd:NMTOKEN">
+					<xsd:enumeration value="default"/>
+					<xsd:enumeration value="none"/>
+					<xsd:enumeration value="simple"/>
+					<xsd:enumeration value="objects"/>
+					<xsd:enumeration value="all"/>
+				</xsd:restriction>
+			</xsd:simpleType>
+		</xsd:attribute>
+		<xsd:attribute name="depends-on" type="xsd:string"/>
+		<xsd:attribute name="autowire-candidate" default="default" type="beans:defaultable-boolean"/>
+		<xsd:attribute name="primary" type="xsd:boolean"/>
+		<xsd:attribute name="init-method" type="xsd:string"/>
+		<xsd:attribute name="destroy-method" type="xsd:string"/>
+		<xsd:attribute name="factory-method" type="xsd:string"/>
+		<xsd:attribute name="factory-bean" type="xsd:string"/>
+		<xsd:anyAttribute namespace="##other" processContents="lax"/>
+	</xsd:attributeGroup>
+
+    <xsd:complexType name="commandComponent" abstract="true">
+        <xsd:annotation>
+            <xsd:documentation>
+                Support for command component elements, which are all basically just beans.
+            </xsd:documentation>
+        </xsd:annotation>
+        <xsd:group ref="commandComponentElements"/>
+        <xsd:attributeGroup ref="commandComponentAttributes"/>
+    </xsd:complexType>
+
+    <xsd:element name="action">
+        <xsd:complexType>
+            <xsd:annotation>
+                <xsd:documentation>
+                    Defines a command action.
+                </xsd:documentation>
+            </xsd:annotation>
+            <xsd:complexContent>
+                <xsd:extension base="commandComponent"/>
+            </xsd:complexContent>
+        </xsd:complexType>
+    </xsd:element>
+
+    <xsd:element name="documenter">
+        <xsd:complexType>
+            <xsd:annotation>
+                <xsd:documentation>
+                    Defines a command documenter.
+                </xsd:documentation>
+            </xsd:annotation>
+            <xsd:complexContent>
+                <xsd:extension base="commandComponent"/>
+            </xsd:complexContent>
+        </xsd:complexType>
+    </xsd:element>
+
+    <xsd:element name="completer">
+        <xsd:complexType>
+            <xsd:annotation>
+                <xsd:documentation>
+                    Defines a command completer.
+                </xsd:documentation>
+            </xsd:annotation>
+            <xsd:complexContent>
+                <xsd:extension base="commandComponent"/>
+            </xsd:complexContent>
+        </xsd:complexType>
+    </xsd:element>
+
+    <xsd:element name="completers">
+        <xsd:complexType>
+            <xsd:annotation>
+                <xsd:documentation>
+                    Defines a configurable command completer with a set of completers.
+                </xsd:documentation>
+            </xsd:annotation>
+            <xsd:sequence>
+                <xsd:choice minOccurs="1" maxOccurs="unbounded">
+                    <xsd:element ref="beans:bean"/>
+                    <xsd:element ref="beans:ref"/>
+                    <xsd:element ref="beans:null"/>
+                </xsd:choice>
+            </xsd:sequence>
+        </xsd:complexType>
+    </xsd:element>
+
+    <xsd:element name="message-source">
+        <xsd:complexType>
+            <xsd:annotation>
+                <xsd:documentation>
+                    Defines a command message source.
+                </xsd:documentation>
+            </xsd:annotation>
+            <xsd:complexContent>
+                <xsd:extension base="commandComponent"/>
+            </xsd:complexContent>
+        </xsd:complexType>
+    </xsd:element>
+
+    <xsd:element name="alias">
+        <xsd:complexType>
+            <xsd:annotation>
+                <xsd:documentation>
+                    Defines a command alias.
+                </xsd:documentation>
+            </xsd:annotation>
+            <xsd:sequence>
+                <xsd:element ref="beans:description" minOccurs="0" maxOccurs="1"/>
+            </xsd:sequence>
+            <xsd:attribute name="name" type="xsd:string" use="required"/>
+            <xsd:attribute name="alias" type="xsd:string" use="required"/>
+        </xsd:complexType>
+    </xsd:element>
+
+</xsd:schema>
\ No newline at end of file
diff --git a/karaf/gshell/gshell-core/src/test/java/org/apache/geronimo/gshell/commands/text/SortTest.java b/karaf/gshell/gshell-core/src/test/java/org/apache/geronimo/gshell/commands/text/SortTest.java
new file mode 100644
index 0000000..90e405e
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/test/java/org/apache/geronimo/gshell/commands/text/SortTest.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.geronimo.gshell.commands.text;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Collections;
+
+import junit.framework.TestCase;
+
+/**
+ * TODO: remove this file when gshell is upgraded
+ */
+public class SortTest extends TestCase {
+
+    public void testFieldIndexesDefaultSep() {
+        SortAction.SortComparator comparator = new SortAction.SortComparator(false, false, false, false, '\0', null);
+        List<Integer> indexes = comparator.getFieldIndexes(" ad  re  t ");
+        assertTrue(Arrays.asList(0, 2, 3, 6, 7, 9, 10, 10).equals(indexes));
+    }
+
+    public void testFieldIndexesWithSep() {
+        SortAction.SortComparator comparator = new SortAction.SortComparator(false, false, false, false, '[', null);
+        List<Integer> indexes = comparator.getFieldIndexes("[  10] [Active     ] [       ] [    8] OPS4J Pax Logging - Service (1.3.0)");
+        assertTrue(Arrays.asList(1, 6, 8, 20, 22, 30, 32, 73 ).equals(indexes));
+
+        indexes = comparator.getFieldIndexes(" ad  re  t ");
+        assertTrue(Arrays.asList(0, 10).equals(indexes));
+    }
+
+    public void testSort() {
+        String s0 = "0321   abcd  ddcba   a";
+        String s1 = " 57t   bcad  ddacb   b";
+        String s2 = "  128  cab   ddbac   c";
+        List<String> strings = Arrays.asList(s0, s1, s2);
+
+        Collections.sort(strings, new SortAction.SortComparator(false, false, false, false, '\0', Arrays.asList("2")));
+        assertTrue(Arrays.asList(s0, s1, s2).equals(strings));
+
+        Collections.sort(strings, new SortAction.SortComparator(false, false, false, false, '\0', Arrays.asList("2.2b")));
+        assertTrue(Arrays.asList(s2, s0, s1).equals(strings));
+
+        Collections.sort(strings, new SortAction.SortComparator(false, false, false, true, '\0', null));
+        assertTrue(Arrays.asList(s1, s2, s0).equals(strings));
+    }
+
+}
diff --git a/karaf/gshell/gshell-core/src/test/java/org/apache/servicemix/kernel/gshell/core/Test.java b/karaf/gshell/gshell-core/src/test/java/org/apache/servicemix/kernel/gshell/core/Test.java
new file mode 100644
index 0000000..0983b12
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/test/java/org/apache/servicemix/kernel/gshell/core/Test.java
@@ -0,0 +1,154 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.core;
+
+import junit.framework.TestCase;
+import org.apache.geronimo.gshell.application.ApplicationManager;
+import org.apache.geronimo.gshell.shell.Shell;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+public class Test extends TestCase {
+
+    public void test() throws Exception {
+        System.setProperty("startLocalConsole", "true");
+        System.setProperty("servicemix.name", "root");
+
+        ClassPathXmlApplicationContext context = null;
+        try {
+            context = new ClassPathXmlApplicationContext(
+                    new String[] { "META-INF/spring/gshell.xml",
+                                   "META-INF/spring/gshell-vfs.xml",
+                                   "META-INF/spring/gshell-commands.xml",
+                                   "org/apache/servicemix/kernel/gshell/core/gshell-test.xml" });
+            ApplicationManager appMgr = (ApplicationManager) context.getBean("applicationManager");
+            assertNotNull(appMgr);
+            Shell shell = appMgr.create();
+            assertNotNull(shell);
+            shell.execute("help");
+        } finally {
+            if (context != null) {
+                context.destroy();
+            }
+        }
+    }
+
+    public void testBanner() throws Exception {
+        System.setProperty("startLocalConsole", "true");
+        System.setProperty("servicemix.name", "root");
+
+        ClassPathXmlApplicationContext context = null;
+        try {
+            context = new ClassPathXmlApplicationContext(
+                    new String[] { "META-INF/spring/gshell.xml",
+                                   "META-INF/spring/gshell-vfs.xml",
+                                   "META-INF/spring/gshell-commands.xml",
+                                   "org/apache/servicemix/kernel/gshell/core/gshell-test.xml"});
+            ApplicationManager appMgr = (ApplicationManager) context.getBean("applicationManager");
+            assertNotNull(appMgr);
+            Shell shell = appMgr.create();
+            ServiceMixBranding smxBrandng = (ServiceMixBranding)appMgr.getApplication().getModel().getBranding();
+            assertNotNull(smxBrandng.getWelcomeMessage());
+            System.out.println(smxBrandng.getWelcomeMessage());
+            assertNotNull(shell);
+            shell.execute("about");
+        } finally {
+            if (context != null) {
+                context.destroy();
+            }
+        }
+    }
+
+    public void testLs() throws Exception {
+        System.setProperty("startLocalConsole", "true");
+        System.setProperty("servicemix.name", "root");
+
+        ClassPathXmlApplicationContext context = null;
+        try {
+            context = new ClassPathXmlApplicationContext(
+                    new String[] { "META-INF/spring/gshell.xml",
+                                   "META-INF/spring/gshell-vfs.xml",
+                                   "org/apache/servicemix/kernel/gshell/core/gshell-test-commands.xml",
+                                   "org/apache/servicemix/kernel/gshell/core/gshell-test.xml"});
+            ApplicationManager appMgr = (ApplicationManager) context.getBean("applicationManager");
+            assertNotNull(appMgr);
+            Shell shell = appMgr.create();
+            ServiceMixBranding smxBrandng = (ServiceMixBranding)appMgr.getApplication().getModel().getBranding();
+            assertNotNull(smxBrandng.getWelcomeMessage());
+            System.out.println(smxBrandng.getWelcomeMessage());
+            assertNotNull(shell);
+            shell.execute("vfs/ls meta:/commands/");
+        } finally {
+            if (context != null) {
+                context.destroy();
+            }
+        }
+    }
+
+    public void testCommandGroups() throws Exception {
+        System.setProperty("startLocalConsole", "true");
+        System.setProperty("servicemix.name", "root");
+
+        ClassPathXmlApplicationContext context = null;
+        try {
+            context = new ClassPathXmlApplicationContext(
+                    new String[] { "META-INF/spring/gshell.xml",
+                                   "META-INF/spring/gshell-vfs.xml",
+                                   "org/apache/servicemix/kernel/gshell/core/gshell-test-commands.xml",
+                                   "org/apache/servicemix/kernel/gshell/core/gshell-test.xml"});
+            ApplicationManager appMgr = (ApplicationManager) context.getBean("applicationManager");
+            assertNotNull(appMgr);
+            Shell shell = appMgr.create();
+            ServiceMixBranding smxBrandng = (ServiceMixBranding)appMgr.getApplication().getModel().getBranding();
+            assertNotNull(smxBrandng.getWelcomeMessage());
+            System.out.println(smxBrandng.getWelcomeMessage());
+            assertNotNull(shell);
+
+            shell.execute("vfs");
+            shell.execute("help");
+            shell.execute("..");
+        } finally {
+            if (context != null) {
+                context.destroy();
+            }
+        }
+    }
+
+    public void testFileAccessCommands() throws Exception {
+        System.setProperty("startLocalConsole", "true");
+        System.setProperty("servicemix.name", "root");
+
+        ClassPathXmlApplicationContext context = null;
+        try {
+            context = new ClassPathXmlApplicationContext(
+                    new String[] { "META-INF/spring/gshell.xml",
+                                   "META-INF/spring/gshell-vfs.xml",
+                                   "org/apache/servicemix/kernel/gshell/core/gshell-test-commands.xml",
+                                   "org/apache/servicemix/kernel/gshell/core/gshell-test.xml"});
+            ApplicationManager appMgr = (ApplicationManager) context.getBean("applicationManager");
+            assertNotNull(appMgr);
+            Shell shell = appMgr.create();            
+            assertNotNull(shell);
+            shell.execute("optional/cat src/test/resources/org/apache/servicemix/kernel/gshell/core/gshell-test.xml");
+            shell.execute("optional/find src/test/resources/org/apache/servicemix/kernel/gshell/core/gshell-test.xml");
+        } finally {
+            if (context != null) {
+                context.destroy();
+            }
+        }
+    }
+
+}
diff --git a/karaf/gshell/gshell-core/src/test/resources/log4j.properties b/karaf/gshell/gshell-core/src/test/resources/log4j.properties
new file mode 100644
index 0000000..8cc85f8
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/test/resources/log4j.properties
@@ -0,0 +1,33 @@
+################################################################################
+#
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+################################################################################
+
+# Root logger
+log4j.rootLogger=INFO, stdout
+
+# CONSOLE appender not used by default
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} | %-5.5p | %-16.16t | %-32.32c{1} | %-32.32C %4L | %m%n
+
+# File appender
+log4j.appender.out=org.apache.log4j.FileAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.out.layout.ConversionPattern=%d{ABSOLUTE} | %-5.5p | %-16.16t | %-32.32c{1} | %-32.32C %4L | %m%n
+log4j.appender.out.file=${servicemix.base}/data/log/servicemix.log
+log4j.appender.out.append=true
diff --git a/karaf/gshell/gshell-core/src/test/resources/org/apache/servicemix/kernel/gshell/core/gshell-test-commands.xml b/karaf/gshell/gshell-core/src/test/resources/org/apache/servicemix/kernel/gshell/core/gshell-test-commands.xml
new file mode 100644
index 0000000..25e4de1
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/test/resources/org/apache/servicemix/kernel/gshell/core/gshell-test-commands.xml
@@ -0,0 +1,162 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xmlns:gshell="http://servicemix.apache.org/schema/servicemix-gshell"
+       xsi:schemaLocation="
+  http://www.springframework.org/schema/beans
+  http://www.springframework.org/schema/beans/spring-beans.xsd
+  http://www.springframework.org/schema/util
+  http://www.springframework.org/schema/util/spring-util.xsd
+  http://servicemix.apache.org/schema/servicemix-gshell
+  http://servicemix.apache.org/schema/servicemix-gshell/servicemix-gshell.xsd"
+       default-autowire="no"
+       default-dependency-check="none"
+       default-init-method="init"
+       default-destroy-method="destroy">
+
+    <import resource="classpath:org/apache/servicemix/kernel/gshell/core/commands.xml" />
+
+    <bean id="vfsCommandActionTemplate" abstract="true">
+        <property name="fileSystemAccess" ref="fileSystemAccess"/>
+    </bean>
+
+    <gshell:command-bundle>
+        <gshell:command name="about">
+            <gshell:action class="org.apache.geronimo.gshell.commands.builtin.AboutAction">
+                <constructor-arg ref="application"/>
+            </gshell:action>
+        </gshell:command>
+
+        <gshell:command name="help">
+            <gshell:action class="org.apache.geronimo.gshell.commands.builtin.HelpAction">
+                <constructor-arg ref="commandResolver"/>
+            </gshell:action>
+            <gshell:completers>
+                <bean class="org.apache.geronimo.gshell.console.completer.AggregateCompleter">
+                    <constructor-arg>
+                        <list>
+                            <ref bean="aliasNameCompleter"/>
+                            <ref bean="commandNameCompleter"/>
+                        </list>
+                    </constructor-arg>
+                </bean>
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+
+        <gshell:command name="exit">
+            <gshell:action class="org.apache.geronimo.gshell.commands.builtin.ExitAction"/>
+        </gshell:command>
+
+        <gshell:link name="quit" target="exit"/>
+
+        <gshell:command name="echo">
+            <gshell:action class="org.apache.geronimo.gshell.commands.builtin.EchoAction"/>
+        </gshell:command>
+
+        <gshell:command name="clear" type="stateless">
+            <gshell:action class="org.apache.geronimo.gshell.commands.builtin.ClearAction"/>
+        </gshell:command>
+
+        <gshell:command name="source">
+            <gshell:action class="org.apache.geronimo.gshell.commands.builtin.SourceAction">
+                <constructor-arg ref="commandLineExecutor"/>
+                <constructor-arg ref="fileSystemAccess"/>
+            </gshell:action>
+            <gshell:completers>
+                <ref bean="fileObjectNameCompleter"/>
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+
+        <gshell:command name="set">
+            <gshell:action class="org.apache.geronimo.gshell.commands.builtin.SetAction"/>
+        </gshell:command>
+
+        <gshell:command name="unset">
+            <gshell:action class="org.apache.geronimo.gshell.commands.builtin.UnsetAction"/>
+            <gshell:completers>
+                <ref bean="variableNameCompleter"/>
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+
+        <gshell:command name="alias">
+            <gshell:action class="org.apache.geronimo.gshell.commands.builtin.AliasAction">
+                <constructor-arg ref="aliasRegistry"/>
+            </gshell:action>
+        </gshell:command>
+
+        <gshell:command name="unalias">
+            <gshell:action class="org.apache.geronimo.gshell.commands.builtin.UnaliasAction">
+                <constructor-arg ref="aliasRegistry"/>
+            </gshell:action>
+            <gshell:completers>
+                <ref bean="aliasNameCompleter"/>
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+
+        <gshell:command name="history">
+            <gshell:action class="org.apache.geronimo.gshell.commands.builtin.HistoryAction"/>
+        </gshell:command>
+
+        <gshell:command name="info">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.core.commands.InfoAction">
+                <constructor-arg ref="branding" />
+            </gshell:action>
+        </gshell:command>
+    </gshell:command-bundle>
+
+    <gshell:command-bundle>
+        <gshell:command name="vfs/ls">
+            <gshell:action class="org.apache.geronimo.gshell.commands.file.ListDirectoryAction" parent="vfsCommandActionTemplate"/>
+            <gshell:completers>
+                <ref bean="fileObjectNameCompleter"/>
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+   </gshell:command-bundle>
+
+    <gshell:command-bundle>
+        <gshell:command name="optional/cat">
+            <gshell:action class="org.apache.geronimo.gshell.commands.text.CatAction">
+                <property name="fileSystemAccess" ref="fileSystemAccess"/>
+            </gshell:action>
+            <gshell:completers>
+                <ref bean="fileObjectNameCompleter"/>
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+
+        <gshell:command name="optional/find">
+            <gshell:action class="org.apache.geronimo.gshell.commands.shell.FindAction">
+                <property name="fileSystemAccess" ref="fileSystemAccess"/>
+            </gshell:action>
+            <gshell:completers>
+                <ref bean="fileObjectNameCompleter"/>
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+    </gshell:command-bundle>
+
+</beans>
diff --git a/karaf/gshell/gshell-core/src/test/resources/org/apache/servicemix/kernel/gshell/core/gshell-test.xml b/karaf/gshell/gshell-core/src/test/resources/org/apache/servicemix/kernel/gshell/core/gshell-test.xml
new file mode 100644
index 0000000..127543f
--- /dev/null
+++ b/karaf/gshell/gshell-core/src/test/resources/org/apache/servicemix/kernel/gshell/core/gshell-test.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xmlns:gshell="http://servicemix.apache.org/schema/servicemix-gshell"
+       xsi:schemaLocation="
+  http://www.springframework.org/schema/beans
+  http://www.springframework.org/schema/beans/spring-beans.xsd
+  http://www.springframework.org/schema/util
+  http://www.springframework.org/schema/util/spring-util.xsd
+  http://servicemix.apache.org/schema/servicemix-gshell
+  http://servicemix.apache.org/schema/servicemix-gshell/servicemix-gshell.xsd">
+
+    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" />
+
+</beans>
\ No newline at end of file
diff --git a/karaf/gshell/gshell-features/pom.xml b/karaf/gshell/gshell-features/pom.xml
new file mode 100644
index 0000000..f53d9a8
--- /dev/null
+++ b/karaf/gshell/gshell-features/pom.xml
@@ -0,0 +1,114 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <!--
+
+        Licensed to the Apache Software Foundation (ASF) under one or more
+        contributor license agreements.  See the NOTICE file distributed with
+        this work for additional information regarding copyright ownership.
+        The ASF licenses this file to You under the Apache License, Version 2.0
+        (the "License"); you may not use this file except in compliance with
+        the License.  You may obtain a copy of the License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software
+        distributed under the License is distributed on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        See the License for the specific language governing permissions and
+        limitations under the License.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.servicemix.kernel.gshell</groupId>
+        <artifactId>gshell</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.servicemix.kernel.gshell</groupId>
+    <artifactId>org.apache.servicemix.kernel.gshell.features</artifactId>
+    <packaging>bundle</packaging>
+    <version>1.2.0-SNAPSHOT</version>
+    <name>Apache ServiceMix Kernel :: GShell Features</name>
+
+    <description>
+        Provides Features in GShell
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.bundlerepository</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.servicemix.kernel.gshell</groupId>
+            <artifactId>org.apache.servicemix.kernel.gshell.core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.servicemix.kernel.gshell</groupId>
+            <artifactId>org.apache.servicemix.kernel.gshell.obr</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.servicemix.kernel</groupId>
+            <artifactId>org.apache.servicemix.kernel.filemonitor</artifactId>
+        </dependency>
+        
+        <dependency>
+            <groupId>org.springframework.osgi</groupId>
+            <artifactId>spring-osgi-core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymock</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>${artifactId}</Bundle-SymbolicName>
+                        <Export-Package>org.apache.servicemix.kernel.gshell.features*;version=${project.version}
+                        </Export-Package>
+                        <Import-Package>
+                            org.apache.geronimo.gshell.wisdom.command,
+                            org.apache.servicemix.kernel.gshell.core,
+                            org.apache.geronimo.gshell.wisdom.registry,
+                            org.springframework.beans.factory.config,
+                            *
+                        </Import-Package>
+                        <Private-Package>!*</Private-Package>
+                        <Spring-Context>*;publish-context:=false;create-asynchronously:=false</Spring-Context>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/Feature.java b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/Feature.java
new file mode 100644
index 0000000..45e8aa1
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/Feature.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.features;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A feature is a list of bundles associated identified by its name.
+ */
+public interface Feature {
+
+    String getId();
+
+    String getName();
+
+    String getVersion();
+
+    List<Feature> getDependencies();
+
+    List<String> getBundles();
+
+    Map<String, Map<String, String>> getConfigurations();
+
+}
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/FeaturesRegistry.java b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/FeaturesRegistry.java
new file mode 100644
index 0000000..33e1f6e
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/FeaturesRegistry.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.features;
+
+/**
+ * Main interface for a Feature Registry which tracks available and installed features.
+ * Tracks features and repositories.
+ */
+public interface FeaturesRegistry {
+    void register(Feature feature);
+
+    void unregister(Feature feature);
+
+    void registerInstalled(Feature feature);
+
+    void unregisterInstalled(Feature feature);
+
+    void register(Repository repository);
+
+    void unregister(Repository repository);
+}
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/FeaturesService.java b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/FeaturesService.java
new file mode 100644
index 0000000..1226016
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/FeaturesService.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.features;
+
+import java.net.URI;
+
+/**
+ * The service managing features repositories.
+ */
+public interface FeaturesService {
+
+    void addRepository(URI url) throws Exception;
+
+    void removeRepository(URI url);
+
+    Repository[] listRepositories();
+
+    void installFeature(String name) throws Exception;
+    
+    void installFeature(String name, String version) throws Exception;
+
+    void uninstallFeature(String name) throws Exception;
+    
+    void uninstallFeature(String name, String version) throws Exception;
+
+    String[] listFeatures() throws Exception;
+
+    String[] listInstalledFeatures();
+
+}
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/Repository.java b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/Repository.java
new file mode 100644
index 0000000..2bfbc99
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/Repository.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.features;
+
+import java.net.URI;
+
+/**
+ * A repository of features.
+ */
+public interface Repository {
+
+    URI getURI();
+
+    URI[] getRepositories() throws Exception;
+
+    Feature[] getFeatures() throws Exception;
+
+}
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/commands/AddUrlCommand.java b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/commands/AddUrlCommand.java
new file mode 100644
index 0000000..213e1e5
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/commands/AddUrlCommand.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.features.commands;
+
+import java.net.URI;
+import java.util.List;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.apache.servicemix.kernel.gshell.features.FeaturesService;
+
+public class AddUrlCommand extends FeaturesCommandSupport {
+
+    @Argument(required = true, multiValued = true, description = "Repository URLs")
+    List<String> urls;
+
+    protected void doExecute(FeaturesService admin) throws Exception {
+        for (String url : urls) {
+            admin.addRepository(new URI(url));
+        }
+    }
+}
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/commands/FeaturesCommandSupport.java b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/commands/FeaturesCommandSupport.java
new file mode 100644
index 0000000..06e0636
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/commands/FeaturesCommandSupport.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.features.commands;
+
+import org.apache.servicemix.kernel.gshell.core.OsgiCommandSupport;
+import org.apache.servicemix.kernel.gshell.features.FeaturesService;
+import org.osgi.framework.ServiceReference;
+
+public abstract class FeaturesCommandSupport extends OsgiCommandSupport {
+
+    protected Object doExecute() throws Exception {
+        // Get repository admin service.
+        ServiceReference ref = getBundleContext().getServiceReference(FeaturesService.class.getName());
+        if (ref == null) {
+            io.out.println("FeaturesService service is unavailable.");
+            return null;
+        }
+        try {
+            FeaturesService admin = (FeaturesService) getBundleContext().getService(ref);
+            if (admin == null) {
+                io.out.println("FeaturesService service is unavailable.");
+                return null;
+            }
+
+            doExecute(admin);
+        }
+        finally {
+            getBundleContext().ungetService(ref);
+        }
+        return null;
+    }
+
+    protected abstract void doExecute(FeaturesService admin) throws Exception;
+
+}
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/commands/InstallFeatureCommand.java b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/commands/InstallFeatureCommand.java
new file mode 100644
index 0000000..a170f3c
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/commands/InstallFeatureCommand.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.features.commands;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.apache.servicemix.kernel.gshell.features.FeaturesService;
+
+public class InstallFeatureCommand extends FeaturesCommandSupport {
+
+    @Argument(required = true, description = "The name of the feature")
+    String name;
+    @Argument(description = "The version of the feature", index = 1)
+    String version;
+
+    protected void doExecute(FeaturesService admin) throws Exception {
+    	if (version != null && version.length() > 0) {
+    		admin.installFeature(name, version);
+    	} else {
+    		admin.installFeature(name);
+    	}
+    }
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/commands/ListFeaturesCommand.java b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/commands/ListFeaturesCommand.java
new file mode 100644
index 0000000..fba0475
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/commands/ListFeaturesCommand.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.features.commands;
+
+import org.apache.geronimo.gshell.clp.Option;
+import org.apache.servicemix.kernel.gshell.features.FeaturesService;
+
+public class ListFeaturesCommand extends FeaturesCommandSupport {
+
+    @Option(name = "-i", aliases={"--installed"}, description="Display the list of installed features")
+    boolean installed;
+
+    protected void doExecute(FeaturesService admin) throws Exception {
+        String[] features;
+        if (installed) {
+            features = admin.listInstalledFeatures();
+        } else {
+        	// Print column headers.
+        	io.out.println("  State          Version       Name");
+            features = admin.listFeatures();
+        }
+        if ((features != null) && (features.length > 0)) {
+            for (int i = 0; i < features.length; i++) {
+                io.out.println(features[i]);
+            }
+        } else {
+            if (installed) {
+                io.out.println("No features installed.");
+            } else {
+                io.out.println("No features available.");
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/commands/ListUrlCommand.java b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/commands/ListUrlCommand.java
new file mode 100644
index 0000000..4c84e09
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/commands/ListUrlCommand.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.features.commands;
+
+import org.apache.servicemix.kernel.gshell.features.FeaturesService;
+import org.apache.servicemix.kernel.gshell.features.Repository;
+
+public class ListUrlCommand extends FeaturesCommandSupport {
+
+    protected void doExecute(FeaturesService admin) throws Exception {
+        Repository[] repos = admin.listRepositories();
+        if ((repos != null) && (repos.length > 0)) {
+            for (int i = 0; i < repos.length; i++) {
+                io.out.println(repos[i].getURI());
+            }
+        } else {
+            io.out.println("No repository URLs are set.");
+        }
+    }
+}
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/commands/RefreshUrlCommand.java b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/commands/RefreshUrlCommand.java
new file mode 100644
index 0000000..cd594b1
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/commands/RefreshUrlCommand.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.features.commands;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.apache.servicemix.kernel.gshell.features.FeaturesService;
+import org.apache.servicemix.kernel.gshell.features.Repository;
+
+public class RefreshUrlCommand extends FeaturesCommandSupport {
+
+    @Argument(required = false, multiValued = true, description = "Repository URLs (leave empty for all)")
+    List<String> urls;
+
+    protected void doExecute(FeaturesService admin) throws Exception {
+        if (urls == null || urls.isEmpty()) {
+            urls = new ArrayList<String>();
+            for (Repository repo : admin.listRepositories()) {
+                urls.add(repo.getURI().toString());
+            }
+        }
+        for (String strUri : urls) {
+            URI uri = new URI(strUri);
+            admin.removeRepository(uri);
+            admin.addRepository(uri);
+        }
+    }
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/commands/RemoveUrlCommand.java b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/commands/RemoveUrlCommand.java
new file mode 100644
index 0000000..d7e6e01
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/commands/RemoveUrlCommand.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.features.commands;
+
+import java.net.URI;
+import java.util.List;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.apache.servicemix.kernel.gshell.features.FeaturesService;
+
+public class RemoveUrlCommand extends FeaturesCommandSupport {
+
+    @Argument(required = true, multiValued = true, description = "Repository URLs")
+    List<String> urls;
+
+    protected void doExecute(FeaturesService admin) throws Exception {
+        for (String url : urls) {
+            admin.removeRepository(new URI(url));
+        }
+    }
+}
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/commands/UninstallFeatureCommand.java b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/commands/UninstallFeatureCommand.java
new file mode 100644
index 0000000..522c721
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/commands/UninstallFeatureCommand.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.features.commands;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.apache.servicemix.kernel.gshell.features.FeaturesService;
+
+public class UninstallFeatureCommand extends FeaturesCommandSupport {
+
+    @Argument(required = true, description = "The name of the feature")
+    String name;
+    @Argument(description = "The version of the feature", index = 1)
+    String version;
+
+    protected void doExecute(FeaturesService admin) throws Exception {
+    	if (version != null && version.length() > 0) {
+    		admin.uninstallFeature(name, version);
+    	} else {
+    		admin.uninstallFeature(name );
+    	}
+    }
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/completers/AvailableFeatureCompleter.java b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/completers/AvailableFeatureCompleter.java
new file mode 100644
index 0000000..991ba59
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/completers/AvailableFeatureCompleter.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.features.completers;
+
+import java.util.Collection;
+import java.util.List;
+
+import jline.Completor;
+import org.apache.geronimo.gshell.console.completer.StringsCompleter;
+import org.apache.servicemix.kernel.gshell.features.management.ManagedFeature;
+import org.apache.servicemix.kernel.gshell.features.management.ManagedFeaturesRegistry;
+
+/**
+ * {@link jline.Completor} for available features.
+ *
+ * Displays a list of available features from installed repositories.
+ *
+ */
+public class AvailableFeatureCompleter implements Completor {
+
+    private ManagedFeaturesRegistry featuresRegistry;
+    private StringsCompleter delegate;
+
+    public void setFeaturesRegistry(ManagedFeaturesRegistry featuresRegistry) {
+        this.featuresRegistry = featuresRegistry;
+    }
+
+    public int complete(final String buffer, final int cursor, final List candidates) {
+
+        Collection<ManagedFeature> features = featuresRegistry.getAvailableFeatures().values();
+        delegate = new StringsCompleter();
+
+        for (ManagedFeature feature : features) {
+            delegate.getStrings().add(feature.getName());
+        }
+        
+        return delegate.complete(buffer, cursor, candidates);
+    }
+
+
+}
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/completers/FeatureRepositoryCompleter.java b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/completers/FeatureRepositoryCompleter.java
new file mode 100644
index 0000000..461ca32
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/completers/FeatureRepositoryCompleter.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.features.completers;
+
+import java.util.List;
+
+import jline.Completor;
+import org.apache.geronimo.gshell.console.completer.StringsCompleter;
+import org.apache.servicemix.kernel.gshell.features.management.ManagedFeaturesRegistry;
+
+/**
+ * {@link jline.Completor} for Feature Repository URLs.
+ *
+ * Displays a list of currently installed Feature repositories.
+ *
+ */
+
+public class FeatureRepositoryCompleter implements Completor {
+
+    private ManagedFeaturesRegistry featuresRegistry;
+
+    public void setFeaturesRegistry(ManagedFeaturesRegistry featuresRegistry) {
+        this.featuresRegistry = featuresRegistry;
+    }
+
+    public int complete(final String buffer, final int cursor, final List candidates) {
+        StringsCompleter delegate = new StringsCompleter(featuresRegistry.getRepositories().keySet());
+        return delegate.complete(buffer, cursor, candidates);
+    }
+
+}
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/completers/InstalledFeatureCompleter.java b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/completers/InstalledFeatureCompleter.java
new file mode 100644
index 0000000..6a121a6
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/completers/InstalledFeatureCompleter.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.features.completers;
+
+import java.util.Collection;
+import java.util.List;
+
+import jline.Completor;
+import org.apache.geronimo.gshell.console.completer.StringsCompleter;
+import org.apache.servicemix.kernel.gshell.features.management.ManagedFeature;
+import org.apache.servicemix.kernel.gshell.features.management.ManagedFeaturesRegistry;
+
+/**
+ * {@link jline.Completor} for installed features.
+ *
+ * Displays a list of currently installed features.
+ *
+ */
+public class InstalledFeatureCompleter implements Completor {
+
+    private ManagedFeaturesRegistry featuresRegistry;
+    private StringsCompleter delegate;
+
+    public void setFeaturesRegistry(ManagedFeaturesRegistry featuresRegistry) {
+        this.featuresRegistry = featuresRegistry;
+    }
+
+    public int complete(final String buffer, final int cursor, final List candidates) {
+        Collection<ManagedFeature> features = featuresRegistry.getInstalledFeatures().values();
+        delegate = new StringsCompleter();
+
+        for (ManagedFeature feature : features) {
+            delegate.getStrings().add(feature.getName());
+        }
+
+        return delegate.complete(buffer, cursor, candidates);
+    }
+
+
+}
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/internal/FeatureDeploymentListener.java b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/internal/FeatureDeploymentListener.java
new file mode 100644
index 0000000..e4a036b
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/internal/FeatureDeploymentListener.java
@@ -0,0 +1,267 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.features.internal;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.zip.ZipEntry;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.w3c.dom.Document;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.servicemix.kernel.filemonitor.DeploymentListener;
+import org.apache.servicemix.kernel.gshell.features.Feature;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.Constants;
+import org.osgi.framework.SynchronousBundleListener;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.osgi.context.BundleContextAware;
+
+/**
+ * A deployment listener able to hot deploy a feature descriptor
+ */
+public class FeatureDeploymentListener implements DeploymentListener, SynchronousBundleListener, BundleContextAware,
+                                                        InitializingBean, DisposableBean {
+
+    public static final String FEATURE_PATH = "org.apache.servicemix.kernel.gshell.features";
+
+    private static final Log LOGGER = LogFactory.getLog(FeatureDeploymentListener.class);
+
+    private DocumentBuilderFactory dbf;
+    private FeaturesServiceImpl featuresService;
+    private BundleContext bundleContext;
+
+    public void setFeaturesService(FeaturesServiceImpl featuresService) {
+        this.featuresService = featuresService;
+    }
+
+    public FeaturesServiceImpl getFeaturesService() {
+        return featuresService;
+    }
+
+    public BundleContext getBundleContext() {
+        return bundleContext;
+    }
+
+    public void setBundleContext(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+
+    public void afterPropertiesSet() throws Exception {
+        bundleContext.addBundleListener(this);
+        for (Bundle bundle : bundleContext.getBundles()) {
+            bundleChanged(new BundleEvent(BundleEvent.INSTALLED, bundle));
+        }
+    }
+
+    public void destroy() throws Exception {
+        bundleContext.removeBundleListener(this);
+    }
+
+    public boolean canHandle(File artifact) {
+        try {
+            if (artifact.isFile() && artifact.getName().endsWith(".xml")) {
+                Document doc = parse(artifact);
+                String name = doc.getDocumentElement().getLocalName();
+                String uri  = doc.getDocumentElement().getNamespaceURI();
+                if ("features".equals(name) && (uri == null || "".equals(uri))) {
+                    return true;
+                }
+            }
+        } catch (Exception e) {
+            LOGGER.error("Unable to parse deployed file " + artifact.getAbsolutePath(), e);
+        }
+        return false;
+    }
+
+    public File handle(File artifact, File tmpDir) {
+        // We can't really install the feature right now and just return nothing.
+        // We would not be aware of the fact that the bundle has been uninstalled
+        // and therefore require the feature to be uninstalled.
+        // So instead, create a fake bundle with the file inside, which will be listened by
+        // this deployer: installation / uninstallation of the feature will be done
+        // while the bundle is installed / uninstalled.
+        try {
+            File destFile = new File(tmpDir, artifact.getName() + ".jar");
+            OutputStream os = new BufferedOutputStream(new FileOutputStream(destFile));
+
+            String name = artifact.getCanonicalPath();
+            int idx = name.lastIndexOf('/');
+            if (idx >= 0) {
+                name = name.substring(idx + 1);
+            }
+            String[] str = extractNameVersionType(name);
+            // Create manifest
+            Manifest m = new Manifest();
+            m.getMainAttributes().putValue("Manifest-Version", "2");
+            m.getMainAttributes().putValue(Constants.BUNDLE_MANIFESTVERSION, "2");
+            m.getMainAttributes().putValue(Constants.BUNDLE_SYMBOLICNAME, str[0]);
+            m.getMainAttributes().putValue(Constants.BUNDLE_VERSION, str[1]);
+            // Put content
+            JarOutputStream out = new JarOutputStream(os);
+            ZipEntry e = new ZipEntry(JarFile.MANIFEST_NAME);
+            out.putNextEntry(e);
+            m.write(out);
+            out.closeEntry();
+            e = new ZipEntry("META-INF/");
+            out.putNextEntry(e);
+            e = new ZipEntry("META-INF/" + FEATURE_PATH + "/");
+            out.putNextEntry(e);
+            out.closeEntry();
+            e = new ZipEntry("META-INF/" + FEATURE_PATH + "/" + name);
+            out.putNextEntry(e);
+            InputStream fis = new BufferedInputStream(new FileInputStream(artifact));
+            copyInputStream(fis, out);
+            fis.close();
+            out.closeEntry();
+            out.close();
+            os.close();
+            return destFile;
+        } catch (Exception e) {
+            LOGGER.error("Unable to build spring application bundle", e);
+            return null;
+        }
+    }
+
+    public void bundleChanged(BundleEvent bundleEvent) {
+        try {
+            Bundle bundle = bundleEvent.getBundle();
+            if (bundleEvent.getType() == BundleEvent.INSTALLED) {
+                Enumeration featuresUrlEnumeration = bundle.findEntries("/META-INF/" + FEATURE_PATH + "/", "*.xml", false);
+                while (featuresUrlEnumeration != null && featuresUrlEnumeration.hasMoreElements()) {
+                    URL url = (URL) featuresUrlEnumeration.nextElement();
+                    RepositoryImpl repo = featuresService.internalAddRepository(url.toURI());
+                    for (Feature f : repo.getFeatures()) {
+                        featuresService.installFeature(f.getName(), f.getVersion());
+                    }
+                    featuresService.internalRemoveRepository(url.toURI());
+                }
+            } else if (bundleEvent.getType() == BundleEvent.UNINSTALLED) {
+                Enumeration featuresUrlEnumeration = bundle.findEntries("/META-INF/" + FEATURE_PATH + "/", "*.xml", false);
+                while (featuresUrlEnumeration != null && featuresUrlEnumeration.hasMoreElements()) {
+                    URL url = (URL) featuresUrlEnumeration.nextElement();
+                    RepositoryImpl repo = featuresService.internalAddRepository(url.toURI());
+                    for (Feature f : repo.getFeatures()) {
+                        featuresService.uninstallFeature(f.getName(), f.getVersion());
+                    }
+                    featuresService.internalRemoveRepository(url.toURI());
+                }
+            }
+        } catch (Exception e) {
+            LOGGER.error("Unable to install / uninstall feature", e);
+        }
+    }
+
+    protected Document parse(File artifact) throws Exception {
+        if (dbf == null) {
+            dbf = DocumentBuilderFactory.newInstance();
+            dbf.setNamespaceAware(true);
+        }
+        DocumentBuilder db = dbf.newDocumentBuilder();
+        return db.parse(artifact);
+    }
+
+    private static void copyInputStream(InputStream in, OutputStream out) throws IOException {
+        byte[] buffer = new byte[8192];
+        int len = in.read(buffer);
+        while (len >= 0) {
+            out.write(buffer, 0, len);
+            len = in.read(buffer);
+        }
+    }
+    private static final String DEFAULT_VERSION = "0.0.0";
+
+    private static final Pattern ARTIFACT_MATCHER = Pattern.compile("(.+)(?:-(\\d+)(?:\\.(\\d+)(?:\\.(\\d+))?)?(?:[^a-zA-Z0-9](.*))?)(?:\\.([^\\.]+))", Pattern.DOTALL);
+    private static final Pattern FUZZY_MODIFIDER = Pattern.compile("(?:\\d+[.-])*(.*)", Pattern.DOTALL);
+
+    public static String[] extractNameVersionType(String url) {
+        Matcher m = ARTIFACT_MATCHER.matcher(url);
+        if (!m.matches()) {
+            return new String[] { url, DEFAULT_VERSION };
+        }
+        else {
+            //System.err.println(m.groupCount());
+            //for (int i = 1; i <= m.groupCount(); i++) {
+            //    System.err.println("Group " + i + ": " + m.group(i));
+            //}
+
+            StringBuffer v = new StringBuffer();
+            String d1 = m.group(1);
+            String d2 = m.group(2);
+            String d3 = m.group(3);
+            String d4 = m.group(4);
+            String d5 = m.group(5);
+            String d6 = m.group(6);
+            if (d2 != null) {
+                v.append(d2);
+                if (d3 != null) {
+                    v.append('.');
+                    v.append(d3);
+                    if (d4 != null) {
+                        v.append('.');
+                        v.append(d4);
+                        if (d5 != null) {
+                            v.append(".");
+                            cleanupModifier(v, d5);
+                        }
+                    } else if (d5 != null) {
+                        v.append(".0.");
+                        cleanupModifier(v, d5);
+                    }
+                } else if (d5 != null) {
+                    v.append(".0.0.");
+                    cleanupModifier(v, d5);
+                }
+            }
+            return new String[] { d1, v.toString(), d6 };
+        }
+    }
+
+    private static void cleanupModifier(StringBuffer result, String modifier) {
+        Matcher m = FUZZY_MODIFIDER.matcher(modifier);
+        if (m.matches()) {
+            modifier = m.group(1);
+        }
+        for (int i = 0; i < modifier.length(); i++) {
+            char c = modifier.charAt(i);
+            if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c == '-') {
+                result.append(c);
+            }
+        }
+    }
+
+}
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/internal/FeatureImpl.java b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/internal/FeatureImpl.java
new file mode 100644
index 0000000..07806d3
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/internal/FeatureImpl.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.features.internal;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.servicemix.kernel.gshell.features.Feature;
+import org.springframework.jmx.export.annotation.ManagedAttribute;
+import org.springframework.jmx.export.annotation.ManagedResource;
+
+/**
+ * A feature
+ */
+@ManagedResource(description = "Managed Feature", currencyTimeLimit = 15)
+public class FeatureImpl implements Feature {
+
+    private String id;
+    private String name;
+    private String version;
+    private List<Feature> dependencies = new ArrayList<Feature>();
+    private List<String> bundles = new ArrayList<String>();
+    private Map<String, Map<String,String>> configs = new HashMap<String, Map<String,String>>();
+    public static String SPLIT_FOR_NAME_AND_VERSION = "_split_for_name_and_version_";
+    public static String DEFAULT_VERSION = "0.0.0";
+    
+    public FeatureImpl(String name) {
+        this(name, DEFAULT_VERSION);
+    }
+    
+    public FeatureImpl(String name, String version) {
+    	this.name = name;
+    	this.version = version;
+        this.id = name + "-" + version;
+    }
+
+    @ManagedAttribute(description = "Feature Unique ID")
+    public String getId() {
+        return id;
+    }
+
+    @ManagedAttribute(description = "Feature Name")
+    public String getName() {
+        return name;
+    }
+
+    @ManagedAttribute(description = "Feature Version")
+    public String getVersion() {
+		return version;
+	}
+    
+	public void setVersion(String version) {
+		this.version = version;
+	}
+
+    @ManagedAttribute(description = "List of Dependencies")
+    public List<Feature> getDependencies() {
+        return dependencies;
+    }
+
+    public List<String> getBundles() {
+        return bundles;
+    }
+
+    public Map<String, Map<String, String>> getConfigurations() {
+        return configs;
+    }
+
+    public void addDependency(Feature dependency) {
+        dependencies.add(dependency);
+    }
+
+    public void addBundle(String bundle) {
+        bundles.add(bundle);
+    }
+
+    public void addConfig(String name, Map<String,String> properties) {
+        configs.put(name, properties);
+    }
+
+    public String toString() {
+    	String ret = getName() + SPLIT_FOR_NAME_AND_VERSION + getVersion();
+    	return ret;
+    }
+    
+    public static Feature valueOf(String str) {
+    	if (str.indexOf(SPLIT_FOR_NAME_AND_VERSION) >= 0) {
+    		String strName = str.substring(0, str.indexOf(SPLIT_FOR_NAME_AND_VERSION));
+        	String strVersion = str.substring(str.indexOf(SPLIT_FOR_NAME_AND_VERSION) 
+        			+ SPLIT_FOR_NAME_AND_VERSION.length(), str.length());
+        	return new FeatureImpl(strName, strVersion);
+    	} else {
+    		return new FeatureImpl(str);
+    	}
+    			
+    	
+    }
+
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        FeatureImpl feature = (FeatureImpl) o;
+
+        if (!name.equals(feature.name)) return false;
+        if (!version.equals(feature.version)) return false;
+
+        return true;
+    }
+
+    public int hashCode() {
+        int result = name.hashCode();
+        result = 31 * result + version.hashCode();
+        return result;
+    }
+}
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/internal/FeaturesServiceImpl.java b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/internal/FeaturesServiceImpl.java
new file mode 100644
index 0000000..1c03515
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/internal/FeaturesServiceImpl.java
@@ -0,0 +1,599 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.features.internal;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.jar.JarInputStream;
+import java.util.jar.Manifest;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.servicemix.kernel.gshell.features.Feature;
+import org.apache.servicemix.kernel.gshell.features.FeaturesRegistry;
+import org.apache.servicemix.kernel.gshell.features.FeaturesService;
+import org.apache.servicemix.kernel.gshell.features.Repository;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.Version;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.prefs.BackingStoreException;
+import org.osgi.service.prefs.Preferences;
+import org.osgi.service.prefs.PreferencesService;
+import org.springframework.osgi.context.BundleContextAware;
+
+/**
+ * The Features service implementation.
+ * Adding a repository url will load the features contained in this repository and
+ * create dummy sub shells.  When invoked, these commands will prompt the user for
+ * installing the needed bundles.
+ *
+ */
+public class FeaturesServiceImpl implements FeaturesService, BundleContextAware {
+
+    private static final String ALIAS_KEY = "_alias_factory_pid";
+
+    private static final Log LOGGER = LogFactory.getLog(FeaturesServiceImpl.class);
+
+    private BundleContext bundleContext;
+    private ConfigurationAdmin configAdmin;
+    private PreferencesService preferences;
+    private Set<URI> uris;
+    private Map<URI, RepositoryImpl> repositories = new HashMap<URI, RepositoryImpl>();
+    private Map<String, Map<String, Feature>> features;
+    private Map<Feature, Set<Long>> installed = new HashMap<Feature, Set<Long>>();
+    private String boot;
+    private boolean bootFeaturesInstalled;
+    private FeaturesRegistry featuresRegistry;
+
+    public BundleContext getBundleContext() {
+        return bundleContext;
+    }
+
+    public void setBundleContext(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+
+    public ConfigurationAdmin getConfigAdmin() {
+        return configAdmin;
+    }
+
+    public void setConfigAdmin(ConfigurationAdmin configAdmin) {
+        this.configAdmin = configAdmin;
+    }
+
+    public PreferencesService getPreferences() {
+        return preferences;
+    }
+
+    public void setPreferences(PreferencesService preferences) {
+        this.preferences = preferences;
+    }
+
+    public void setFeaturesServiceRegistry(FeaturesRegistry featuresRegistry) {
+        this.featuresRegistry = featuresRegistry;
+    }
+
+    public void setUrls(String uris) throws URISyntaxException {
+        String[] s = uris.split(",");
+        this.uris = new HashSet<URI>();
+        for (int i = 0; i < s.length; i++) {
+            this.uris.add(new URI(s[i]));
+        }
+    }
+
+    public void setBoot(String boot) {
+        this.boot = boot;
+    }
+
+    public void addRepository(URI uri) throws Exception {
+        if (!repositories.values().contains(uri)) {
+            internalAddRepository(uri);
+            saveState();
+        }
+    }
+
+    protected RepositoryImpl internalAddRepository(URI uri) throws Exception {
+        RepositoryImpl repo = new RepositoryImpl(uri);
+        repositories.put(uri, repo);
+        featuresRegistry.register(repo);
+        features = null;
+        return repo;
+    }
+
+    public void removeRepository(URI uri) {
+        if (repositories.containsKey(uri)) {
+            internalRemoveRepository(uri);
+            saveState();
+        }
+    }
+
+    public void internalRemoveRepository(URI uri) {
+        featuresRegistry.unregister(repositories.get(uri));
+        repositories.remove(uri);
+        features = null;
+    }
+
+    public Repository[] listRepositories() {
+        Collection<RepositoryImpl> repos = repositories.values();
+        return repos.toArray(new Repository[repos.size()]);
+    }
+
+    public void installAllFeatures(URI uri) throws Exception {
+        RepositoryImpl repo = internalAddRepository(uri);
+        for (Feature f : repo.getFeatures()) {
+            installFeature(f.getName(), f.getVersion());
+        }
+        internalRemoveRepository(uri);            
+    }
+
+    public void uninstallAllFeatures(URI uri) throws Exception {
+        RepositoryImpl repo = internalAddRepository(uri);
+        for (Feature f : repo.getFeatures()) {
+            uninstallFeature(f.getName(), f.getVersion());
+        }
+        internalRemoveRepository(uri);            
+    }
+
+    public void installFeature(String name) throws Exception {
+    	installFeature(name, FeatureImpl.DEFAULT_VERSION);
+    }
+
+    public void installFeature(String name, String version) throws Exception {
+        Feature f = getFeature(name, version);
+        if (f == null) {
+            throw new Exception("No feature named '" + name 
+            		+ "' with version '" + version + "' available");
+        }
+        for (Feature dependency : f.getDependencies()) {
+        	installFeature(dependency.getName(), dependency.getVersion());
+        }
+        for (String config : f.getConfigurations().keySet()) {
+            Dictionary<String,String> props = new Hashtable<String, String>(f.getConfigurations().get(config));
+            String[] pid = parsePid(config);
+            if (pid[1] != null) {
+                props.put(ALIAS_KEY, pid[1]);
+            }
+            Configuration cfg = getConfiguration(configAdmin, pid[0], pid[1]);
+            if (cfg.getBundleLocation() != null) {
+                cfg.setBundleLocation(null);
+            }
+            cfg.update(props);
+        }
+        Set<Long> bundles = new HashSet<Long>();
+        for (String bundleLocation : f.getBundles()) {
+            Bundle b = installBundleIfNeeded(bundleLocation);
+            bundles.add(b.getBundleId());
+        }
+        for (long id : bundles) {
+            bundleContext.getBundle(id).start();
+        }
+
+        featuresRegistry.registerInstalled(f);
+        installed.put(f, bundles);
+        saveState();
+    }
+    protected Bundle installBundleIfNeeded(String bundleLocation) throws IOException, BundleException {
+        LOGGER.debug("Checking " + bundleLocation);
+        InputStream is = null;
+        try {
+            is = new BufferedInputStream(new URL(bundleLocation).openStream());
+        } catch (RuntimeException e) {
+            LOGGER.error(e.getMessage());
+            throw e;
+        }
+        try {
+            is.mark(256 * 1024);
+            JarInputStream jar = new JarInputStream(is);
+            Manifest m = jar.getManifest();
+            String sn = m.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME);
+            String vStr = m.getMainAttributes().getValue(Constants.BUNDLE_VERSION);
+            Version v = vStr == null ? Version.emptyVersion : Version.parseVersion(vStr);
+            for (Bundle b : bundleContext.getBundles()) {
+                if (b.getSymbolicName() != null && b.getSymbolicName().equals(sn)) {
+                    vStr = (String) b.getHeaders().get(Constants.BUNDLE_VERSION);
+                    Version bv = vStr == null ? Version.emptyVersion : Version.parseVersion(vStr);
+                    if (v.equals(bv)) {
+                        LOGGER.debug("  found installed bundle: " + b);
+                        return b;
+                    }
+                }
+            }
+            try {
+                is.reset();
+            } catch (IOException e) {
+                is.close();
+                is = new BufferedInputStream(new URL(bundleLocation).openStream());
+            }
+            LOGGER.debug("Installing bundle " + bundleLocation);
+            return getBundleContext().installBundle(bundleLocation, is);
+        } finally {
+            is.close();
+        }
+    }
+
+    public void uninstallFeature(String name) throws Exception {
+        List<String> versions = new ArrayList<String>();
+        for (Feature f : installed.keySet()) {
+            if (name.equals(f.getName())) {
+                versions.add(f.getVersion());
+            }
+        }
+        if (versions.size() == 0) {
+            throw new Exception("Feature named '" + name + "' is not installed");
+        } else if (versions.size() > 1) {
+            StringBuilder sb = new StringBuilder();
+            sb.append("Feature named '" + name + "' has multiple versions installed (");
+            for (int i = 0; i < versions.size(); i++) {
+                if (i > 0) {
+                    sb.append(", ");
+                }
+                sb.append(versions.get(i));
+            }
+            sb.append("). Please specify the version to uninstall.");
+            throw new Exception(sb.toString());
+        }
+        uninstallFeature(name, versions.get(0));
+    }
+    
+    public void uninstallFeature(String name, String version) throws Exception {
+    	Feature feature = getFeature(name, version);
+        if (feature == null || !installed.containsKey(feature)) {
+            throw new Exception("Feature named '" + name 
+            		+ "' with version '" + version + "' is not installed");
+        }
+        // Grab all the bundles installed by this feature
+        // and remove all those who will still be in use.
+        // This gives this list of bundles to uninstall.
+        Set<Long> bundles = installed.remove(feature);
+        for (Set<Long> b : installed.values()) {
+            bundles.removeAll(b);
+        }
+        for (long bundleId : bundles) {
+            getBundleContext().getBundle(bundleId).uninstall();
+        }
+        featuresRegistry.unregisterInstalled(feature);
+        saveState();
+    }
+
+    public String[] listFeatures() throws Exception {
+        Collection<String> features = new ArrayList<String>();
+        for (Map<String, Feature> featureWithDifferentVersion : getFeatures()
+				.values()) {
+			for (Feature f : featureWithDifferentVersion.values()) {
+				String installStatus = installed.containsKey(f) ? "installed  "
+						: "uninstalled";
+				String version = f.getVersion();
+				switch (version.length()) {
+				case 1:
+					version = "       " + version;
+				case 2:
+					version = "      " + version;
+				case 3:
+					version = "     " + version;
+				case 4:
+					version = "    " + version;
+				case 5:
+					version = "   " + version;
+				case 6:
+					version = "  " + version;
+				case 7:
+					version = " " + version;
+				}
+				features.add("[" + installStatus + "] " + " [" + version + "] "
+						+ f.getName());
+			}
+		}
+        return features.toArray(new String[features.size()]);
+    }
+
+    public String[] listInstalledFeatures() {
+        List<String> result = new ArrayList<String>();
+        for (Feature feature : installed.keySet()) {
+            result.add(feature.getName());
+        }
+        return result.toArray(new String[result.size()]);
+    }
+
+    protected Feature getFeature(String name, String version) throws Exception {
+        Map<String, Feature> versions = getFeatures().get(name);
+        if (versions == null || versions.isEmpty()) {
+            return null;
+        } else {
+            Feature feature = versions.get(version);
+            if (feature == null && FeatureImpl.DEFAULT_VERSION.equals(version)) {
+                Version latest = new Version(cleanupVersion(version));
+                for (String available : versions.keySet()) {
+                    Version availableVersion = new Version(cleanupVersion(available));
+                    if (availableVersion.compareTo(latest) > 0) {
+                        feature = versions.get(available);
+                        latest = availableVersion;
+                    }
+                }
+            }
+            return feature;
+        }
+    }
+
+    protected Map<String, Map<String, Feature>> getFeatures() throws Exception {
+        if (features == null) {
+        	//the outer map's key is feature name, the inner map's key is feature version       
+            Map<String, Map<String, Feature>> map = new HashMap<String, Map<String, Feature>>();
+            // Two phase load:
+            // * first load dependent repositories
+            for (;;) {
+                boolean newRepo = false;
+                for (Repository repo : listRepositories()) {
+                    for (URI uri : repo.getRepositories()) {
+                        if (!repositories.keySet().contains(uri)) {
+                            internalAddRepository(uri);
+                            newRepo = true;
+                        }
+                    }
+                }
+                if (!newRepo) {
+                    break;
+                }
+            }
+            // * then load all features
+            for (Repository repo : repositories.values()) {
+                for (Feature f : repo.getFeatures()) {
+                	if (map.get(f.getName()) == null) {
+                		Map<String, Feature> versionMap = new HashMap<String, Feature>();
+                		versionMap.put(f.getVersion(), f);
+                		map.put(f.getName(), versionMap);
+                	} else {
+                		map.get(f.getName()).put(f.getVersion(), f);
+                	}
+                }
+            }
+            features = map;
+        }
+        return features;
+    }
+
+    public void start() throws Exception {
+        if (!loadState()) {
+            if (uris != null) {
+                for (URI uri : uris) {
+                    internalAddRepository(uri);
+                }
+            }
+            saveState();
+        }
+        if (boot != null && !bootFeaturesInstalled) {
+            new Thread() {
+                public void run() {
+                    String[] list = boot.split(",");
+                    for (String f : list) {
+                        if (f.length() > 0) {
+                            try {
+                                installFeature(f);
+                            } catch (Exception e) {
+                                LOGGER.error("Error installing boot feature " + f, e);
+                            }
+                        }
+                    }
+                    bootFeaturesInstalled = true;
+                    saveState();
+                }
+            }.start();
+        }
+    }
+
+    public void stop() throws Exception {
+        uris = new HashSet<URI>(repositories.keySet());
+        while (!repositories.isEmpty()) {
+            internalRemoveRepository(repositories.keySet().iterator().next());
+        }
+    }
+
+    protected String[] parsePid(String pid) {
+        int n = pid.indexOf('-');
+        if (n > 0) {
+            String factoryPid = pid.substring(n + 1);
+            pid = pid.substring(0, n);
+            return new String[]{pid, factoryPid};
+        } else {
+            return new String[]{pid, null};
+        }
+    }
+
+    protected Configuration getConfiguration(ConfigurationAdmin configurationAdmin,
+                                             String pid, String factoryPid) throws IOException, InvalidSyntaxException {
+        if (factoryPid != null) {
+            Configuration[] configs = configurationAdmin.listConfigurations("(|(" + ALIAS_KEY + "=" + pid + ")(.alias_factory_pid=" + factoryPid + "))");
+            if (configs == null || configs.length == 0) {
+                return configurationAdmin.createFactoryConfiguration(pid, null);
+            } else {
+                return configs[0];
+            }
+        } else {
+            return configurationAdmin.getConfiguration(pid, null);
+        }
+    }
+    
+    protected void saveState() {
+        try {
+            Preferences prefs = preferences.getUserPreferences("FeaturesServiceState");
+            saveSet(prefs.node("repositories"), repositories.keySet());
+            saveMap(prefs.node("features"), installed);
+            prefs.putBoolean("bootFeaturesInstalled", bootFeaturesInstalled);
+            prefs.flush();
+        } catch (Exception e) {
+            LOGGER.error("Error persisting FeaturesService state", e);
+        }
+    }
+
+    protected boolean loadState() {
+        try {
+            Preferences prefs = preferences.getUserPreferences("FeaturesServiceState");
+            if (prefs.nodeExists("repositories")) {
+                Set<URI> repositories = loadSet(prefs.node("repositories"));
+                for (URI repo : repositories) {
+                    internalAddRepository(repo);
+                }
+                installed = loadMap(prefs.node("features"));
+                for (Feature f : installed.keySet()) {
+                    featuresRegistry.registerInstalled(f);
+                }
+                bootFeaturesInstalled = prefs.getBoolean("bootFeaturesInstalled", false);
+                return true;
+            }
+        } catch (Exception e) {
+            LOGGER.error("Error loading FeaturesService state", e);
+        }
+        return false;
+    }
+
+    protected void saveSet(Preferences node, Set<URI> set) throws BackingStoreException {
+        List<URI> l = new ArrayList<URI>(set);
+        node.clear();
+        node.putInt("count", l.size());
+        for (int i = 0; i < l.size(); i++) {
+            node.put("item." + i, l.get(i).toString());
+        }
+    }
+
+    protected Set<URI> loadSet(Preferences node) {
+        Set<URI> l = new HashSet<URI>();
+        int count = node.getInt("count", 0);
+        for (int i = 0; i < count; i++) {
+            l.add(URI.create(node.get("item." + i, null)));
+        }
+        return l;
+    }
+
+    protected void saveMap(Preferences node, Map<Feature, Set<Long>> map) throws BackingStoreException {
+        node.clear();
+        for (Map.Entry<Feature, Set<Long>> entry : map.entrySet()) {
+            Feature key = entry.getKey();
+            String val = createValue(entry.getValue());
+            node.put(key.toString(), val);
+        }
+    }
+
+    protected Map<Feature, Set<Long>> loadMap(Preferences node) throws BackingStoreException {
+        Map<Feature, Set<Long>> map = new HashMap<Feature, Set<Long>>();
+        for (String key : node.keys()) {
+            String val = node.get(key, null);
+            Set<Long> set = readValue(val);
+            map.put(FeatureImpl.valueOf(key), set);
+        }
+        return map;
+    }
+
+    protected String createValue(Set<Long> set) {
+        StringBuilder sb = new StringBuilder();
+        for (long i : set) {
+            if (sb.length() > 0) {
+                sb.append(",");
+            }
+            sb.append(i);
+        }
+        return sb.toString();
+    }
+
+    protected Set<Long> readValue(String val) {
+        Set<Long> set = new HashSet<Long>();
+        for (String str : val.split(",")) {
+            set.add(Long.parseLong(str));
+        }
+        return set;
+    }
+
+    /**
+     * Clean up version parameters. Other builders use more fuzzy definitions of
+     * the version syntax. This method cleans up such a version to match an OSGi
+     * version.
+     *
+     * @param version
+     * @return
+     */
+    static Pattern fuzzyVersion  = Pattern.compile("(\\d+)(\\.(\\d+)(\\.(\\d+))?)?([^a-zA-Z0-9](.*))?",
+                                                   Pattern.DOTALL);
+    static Pattern fuzzyModifier = Pattern.compile("(\\d+[.-])*(.*)",
+                                                   Pattern.DOTALL);
+
+    static public String cleanupVersion(String version) {
+        Matcher m = fuzzyVersion.matcher(version);
+        if (m.matches()) {
+            StringBuffer result = new StringBuffer();
+            String d1 = m.group(1);
+            String d2 = m.group(3);
+            String d3 = m.group(5);
+            String qualifier = m.group(7);
+
+            if (d1 != null) {
+                result.append(d1);
+                if (d2 != null) {
+                    result.append(".");
+                    result.append(d2);
+                    if (d3 != null) {
+                        result.append(".");
+                        result.append(d3);
+                        if (qualifier != null) {
+                            result.append(".");
+                            cleanupModifier(result, qualifier);
+                        }
+                    } else if (qualifier != null) {
+                        result.append(".0.");
+                        cleanupModifier(result, qualifier);
+                    }
+                } else if (qualifier != null) {
+                    result.append(".0.0.");
+                    cleanupModifier(result, qualifier);
+                }
+                return result.toString();
+            }
+        }
+        return version;
+    }
+
+    static void cleanupModifier(StringBuffer result, String modifier) {
+        Matcher m = fuzzyModifier.matcher(modifier);
+        if (m.matches())
+            modifier = m.group(2);
+
+        for (int i = 0; i < modifier.length(); i++) {
+            char c = modifier.charAt(i);
+            if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z')
+                    || (c >= 'A' && c <= 'Z') || c == '_' || c == '-')
+                result.append(c);
+        }
+    }
+
+}
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/internal/RepositoryImpl.java b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/internal/RepositoryImpl.java
new file mode 100644
index 0000000..485c3d4
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/internal/RepositoryImpl.java
@@ -0,0 +1,168 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.features.internal;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import org.apache.servicemix.kernel.gshell.features.Feature;
+import org.apache.servicemix.kernel.gshell.features.Repository;
+import org.springframework.jmx.export.annotation.ManagedAttribute;
+import org.springframework.jmx.export.annotation.ManagedOperation;
+import org.springframework.jmx.export.annotation.ManagedResource;
+import org.xml.sax.SAXException;
+
+/**
+ * The repository implementation.
+ */
+@ManagedResource
+public class RepositoryImpl implements Repository {
+
+    private URI uri;
+    private List<Feature> features;
+    private List<URI> repositories;
+
+    public RepositoryImpl(URI uri) {
+        this.uri = uri;
+    }
+
+    @ManagedAttribute
+    public URI getURI() {
+        return uri;
+    }
+
+    @ManagedOperation
+    public URI[] getRepositories() throws Exception {
+        if (repositories == null) {
+            load();
+        }
+        return repositories.toArray(new URI[repositories.size()]);
+    }
+
+    @ManagedOperation(description = "List of Features provided by this repository")
+    public Feature[] getFeatures() throws Exception {
+        if (features == null) {
+            load();
+        }
+        return features.toArray(new Feature[features.size()]);
+    }
+
+    public void load() throws IOException {
+        try {
+            repositories = new ArrayList<URI>();
+            features = new ArrayList<Feature>();
+            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+            Document doc = factory.newDocumentBuilder().parse(uri.toURL().openStream());
+            NodeList nodes = doc.getDocumentElement().getChildNodes();
+            for (int i = 0; i < nodes.getLength(); i++) {
+                Node node = nodes.item(i);
+                if (!(node instanceof Element)) {
+                    continue;
+                }
+                if ("repository".equals(node.getNodeName())) {
+                    Element e = (Element) nodes.item(i);
+                    repositories.add(new URI(e.getTextContent()));
+                } else if ("feature".equals(node.getNodeName())) {
+                    Element e = (Element) nodes.item(i);
+                    String name = e.getAttribute("name");
+                    String version = e.getAttribute("version");
+                    FeatureImpl f;
+                    if (version != null && version.length() > 0) {
+                        f = new FeatureImpl(name, version);
+                    } else {
+                        f = new FeatureImpl(name);
+                    }
+
+                    NodeList featureNodes = e.getElementsByTagName("feature");
+                    for (int j = 0; j < featureNodes.getLength(); j++) {
+                        Element b = (Element) featureNodes.item(j);
+                        String dependencyFeatureVersion = b.getAttribute("version");
+                        if (dependencyFeatureVersion != null && dependencyFeatureVersion.length() > 0) {
+                        	f.addDependency(new FeatureImpl(b.getTextContent(), dependencyFeatureVersion));
+                        } else {
+                        	f.addDependency(new FeatureImpl(b.getTextContent()));
+                        }
+                    }
+                    NodeList configNodes = e.getElementsByTagName("config");
+                    for (int j = 0; j < configNodes.getLength(); j++) {
+                        Element c = (Element) configNodes.item(j);
+                        String cfgName = c.getAttribute("name");
+                        String data = c.getTextContent();
+                        Properties properties = new Properties();
+                        properties.load(new ByteArrayInputStream(data.getBytes()));
+                        interpolation(properties);
+                        Map<String, String> hashtable = new Hashtable<String, String>();
+                        for (Object key : properties.keySet()) {
+                            String n = key.toString();
+                            hashtable.put(n, properties.getProperty(n));
+                        }
+                        f.addConfig(cfgName, hashtable);
+                    }
+                    NodeList bundleNodes = e.getElementsByTagName("bundle");
+                    for (int j = 0; j < bundleNodes.getLength(); j++) {
+                        Element b = (Element) bundleNodes.item(j);
+                        f.addBundle(b.getTextContent());
+                    }
+                    features.add(f);
+                }
+            }
+        } catch (SAXException e) {
+            throw (IOException) new IOException().initCause(e);
+        } catch (ParserConfigurationException e) {
+            throw (IOException) new IOException().initCause(e);
+        } catch (URISyntaxException e) {
+            throw (IOException) new IOException(e.getMessage() + " : " + uri).initCause(e);
+        } catch (IllegalArgumentException e) {
+            throw (IOException) new IOException(e.getMessage() + " : " + uri).initCause(e);
+        }
+    }
+
+    protected void interpolation(Properties properties) {
+        for (Enumeration e = properties.propertyNames(); e.hasMoreElements();) {
+            String key = (String)e.nextElement();
+            String val = properties.getProperty(key);
+            Matcher matcher = Pattern.compile("\\$\\{([^}]+)\\}").matcher(val);
+            while (matcher.find()) {
+                String rep = System.getProperty(matcher.group(1));
+                if (rep != null) {
+                    val = val.replace(matcher.group(0), rep);
+                    matcher.reset(val);
+                }
+            }
+            properties.put(key, val);
+        }
+    }
+
+}
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/management/DefaultNamingStrategy.java b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/management/DefaultNamingStrategy.java
new file mode 100644
index 0000000..6bee5fc
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/management/DefaultNamingStrategy.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.features.management;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.apache.servicemix.kernel.gshell.features.FeaturesRegistry;
+
+/**
+ * Naming strategy for JMX MBeans.
+ */
+public class DefaultNamingStrategy implements NamingStrategy {
+
+    private String jmxDomainName;
+
+    public String getJmxDomainName() {
+        return jmxDomainName;
+    }
+
+    public void setJmxDomainName(String jmxDomainName) {
+        this.jmxDomainName = jmxDomainName;
+    }
+
+    public ObjectName getObjectName(ManagedFeature feature) throws MalformedObjectNameException {
+        return getObjectName(feature, false);
+    }
+
+    public ObjectName getObjectName(ManagedFeature feature, boolean installed) throws MalformedObjectNameException {
+        StringBuffer sb = new StringBuffer();
+        sb.append(jmxDomainName).append(":Service=Features,");
+
+        if (installed) {
+            sb.append("Type=Installed,");
+        } else {
+            sb.append("Type=Available,");
+        }
+
+        sb.append("Name=").append(sanitize(feature.getName())).append(",")
+          .append("FeatureVersion=").append(sanitize(feature.getVersion()));
+
+        return new ObjectName(sb.toString());
+    }
+
+    public ObjectName getObjectName(ManagedRepository repository) throws MalformedObjectNameException {
+        return new ObjectName(jmxDomainName + ":" +
+                                    "Service=Features," +
+                                    "Type=Repositories," +
+                                    "Name=" + sanitize(repository.getUri().toString())); // + "," +
+    }
+
+    public ObjectName getObjectName(FeaturesRegistry featuresRegistry) throws MalformedObjectNameException {
+        return new ObjectName(jmxDomainName + ":" +
+                                    "Service=Features," +
+                                    "Name=FeaturesService");
+    }
+
+    private String sanitize(String in) {
+        String result = null;
+        if (in != null) {
+            result = in.replace(':', '_');
+            result = result.replace('/', '_');
+            result = result.replace('\\', '_');
+            result = result.replace('?', '_');
+            result = result.replace('=', '_');
+            result = result.replace(',', '_');
+        }
+        return result;
+    }
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/management/ManagedFeature.java b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/management/ManagedFeature.java
new file mode 100644
index 0000000..1da589b
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/management/ManagedFeature.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.features.management;
+
+import java.util.List;
+
+import org.apache.servicemix.kernel.gshell.features.Feature;
+import org.apache.servicemix.kernel.gshell.features.FeaturesService;
+import org.springframework.jmx.export.annotation.ManagedAttribute;
+import org.springframework.jmx.export.annotation.ManagedOperation;
+import org.springframework.jmx.export.annotation.ManagedResource;
+
+/**
+ * Managed Repository MBean
+ */
+@ManagedResource(description = "Feature")
+public class ManagedFeature {
+    private Feature feature;
+    private FeaturesService featuresService;
+    private String id;
+
+    public ManagedFeature(Feature feature, FeaturesService featuresService) {
+        this.feature = feature;
+        id = feature.getName() + "-" + feature.getVersion();
+        this.featuresService = featuresService;
+    }
+
+    @ManagedAttribute
+    public String getId() {
+        return id;    
+    }
+
+    @ManagedAttribute
+    public String getName() {
+        return feature.getName();
+    }
+
+    @ManagedAttribute
+    public String getVersion() {
+        return feature.getVersion();
+    }
+
+    @ManagedAttribute
+    public List<Feature> getDependencies() {
+        return feature.getDependencies();
+    }
+
+    @ManagedAttribute
+    public List<String> getBundles() {
+        return feature.getBundles();
+    }
+
+    @ManagedOperation
+    public void uninstallFeature() throws Exception {
+        featuresService.uninstallFeature(feature.getName(), feature.getVersion());
+    }
+
+    @ManagedOperation
+    public void installFeature() throws Exception {
+        featuresService.installFeature(feature.getName(), feature.getVersion());
+    }
+
+}
+
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/management/ManagedFeaturesRegistry.java b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/management/ManagedFeaturesRegistry.java
new file mode 100644
index 0000000..9fbdb46
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/management/ManagedFeaturesRegistry.java
@@ -0,0 +1,210 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.features.management;
+
+import java.net.URI;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.management.MBeanServer;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.servicemix.kernel.gshell.features.Feature;
+import org.apache.servicemix.kernel.gshell.features.FeaturesRegistry;
+import org.apache.servicemix.kernel.gshell.features.FeaturesService;
+import org.apache.servicemix.kernel.gshell.features.Repository;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.jmx.export.annotation.ManagedOperation;
+import org.springframework.jmx.export.annotation.ManagedResource;
+
+/**
+ * The FeaturesServiceRegistry maintains the managed Features and Repositories
+ * for JMX management.
+ */
+@ManagedResource(description = "Features Service Registry and Management")
+public class ManagedFeaturesRegistry implements InitializingBean, FeaturesRegistry {
+
+    private static final transient Log LOG = LogFactory.getLog(ManagedFeaturesRegistry.class);
+
+    private NamingStrategy namingStrategy;
+    private ManagementAgent managementAgent;
+    private Map<String, ManagedFeature> availableFeatures;
+    private Map<String, ManagedFeature> installedFeatures;
+    private Map<String, ManagedRepository> repositories;
+    private boolean mbeanServerInitialized;
+    private FeaturesService featuresService;
+
+    @ManagedOperation
+    public void installFeature(String name) throws Exception {
+        featuresService.installFeature(name);
+    }
+
+    @ManagedOperation
+    public void installFeature(String name, String version) throws Exception {
+        featuresService.installFeature(name, version);
+    }
+
+    @ManagedOperation
+    public void installRepository(String repositoryUri) throws Exception {
+        featuresService.addRepository(new URI(repositoryUri));
+    }
+
+    public ManagedFeaturesRegistry() {
+        availableFeatures = new ConcurrentHashMap<String, ManagedFeature>();
+        installedFeatures = new ConcurrentHashMap<String, ManagedFeature>();
+        repositories = new ConcurrentHashMap<String, ManagedRepository>();
+    }
+
+    public Map<String, ManagedFeature> getAvailableFeatures() {
+        return availableFeatures;
+    }
+
+    public Map<String, ManagedFeature> getInstalledFeatures() {
+        return installedFeatures;
+    }
+
+    public Map<String, ManagedRepository> getRepositories() {
+        return repositories;
+    }
+
+    public void setFeaturesService(FeaturesService featuresService) {
+        this.featuresService = featuresService;
+    }
+
+    public void setNamingStrategy(NamingStrategy namingStrategy) {
+        this.namingStrategy = namingStrategy;
+    }
+
+    public void setManagementAgent(ManagementAgent managementAgent) {
+        this.managementAgent = managementAgent;
+    }
+
+    public void register(Feature feature) {
+        try {
+            ManagedFeature mf = new ManagedFeature(feature, featuresService);
+            availableFeatures.put(feature.getId(), mf);
+            if ( mbeanServerInitialized ) {
+                managementAgent.register(mf, namingStrategy.getObjectName(mf));
+            }
+        } catch (Exception e) {
+            LOG.warn("Unable to register managed feature: " + e, e);
+        }
+    }
+
+    public void unregister(Feature feature) {
+        try {
+            ManagedFeature mf = availableFeatures.remove(feature.getId());
+            if ( mbeanServerInitialized ) {
+                managementAgent.unregister(namingStrategy.getObjectName(mf));
+            }
+        } catch (Exception e) {
+            LOG.warn("Unable to unregister managed feature: " + e, e);
+        }
+    }
+
+    public void registerInstalled(Feature feature) {
+        try {
+            ManagedFeature mf = new ManagedFeature(feature, featuresService);
+            installedFeatures.put(feature.getId(), mf);
+            if ( mbeanServerInitialized ) {
+                managementAgent.register(mf, namingStrategy.getObjectName(mf, true));
+            }
+        } catch (Exception e) {
+            LOG.warn("Unable to register managed feature: " + e, e);
+        }
+    }
+
+    public void unregisterInstalled(Feature feature) {
+        try {
+            ManagedFeature mf = installedFeatures.remove(feature.getId());
+            if ( mbeanServerInitialized ) {
+                managementAgent.unregister(namingStrategy.getObjectName(mf, true));
+            }
+        } catch (Exception e) {
+            LOG.warn("Unable to unregister managed feature: " + e, e);
+        }
+    }
+
+    public void register(Repository repository) {
+        try {
+            ManagedRepository mr = new ManagedRepository(repository, featuresService);
+            repositories.put(repository.getURI().toString(), mr);
+
+            for (Feature f : repository.getFeatures()) {
+                // TODO: Associate the feature with the Repo?
+                register(f);
+            }
+
+            if ( mbeanServerInitialized ) {
+                managementAgent.register(mr, namingStrategy.getObjectName(mr));
+            }
+        } catch (Exception e) {
+            LOG.warn("Unable to register managed repository: " + e, e);
+        }
+    }
+
+    public void unregister(Repository repository) {
+        try {
+            ManagedRepository mr = repositories.remove(repository.getURI().toString());
+
+            for (Feature f : repository.getFeatures()) {
+                // TODO: Associate the feature with the Repo?
+                unregister(f);
+            }
+
+            if ( mbeanServerInitialized ) {
+                managementAgent.unregister(namingStrategy.getObjectName(mr));
+            }
+        } catch (Exception e) {
+            LOG.warn("Unable to unregister managed repository: " + e, e);
+        }
+    }
+
+    public void afterPropertiesSet() throws Exception {
+        if (managementAgent == null) {
+            throw new IllegalArgumentException("managementAgent must not be null");
+        }
+        if (namingStrategy == null) {
+            throw new IllegalArgumentException("namingStrategy must not be null");
+        }
+    }
+
+    public void registerMBeanServer(MBeanServer mbeanServer, Map props ) throws Exception {
+        if (mbeanServer != null) {
+            mbeanServerInitialized = true;
+        }
+
+        managementAgent.register(this, namingStrategy.getObjectName(this));
+
+        for (ManagedRepository repository : repositories.values()) {
+            managementAgent.register(repository, namingStrategy.getObjectName(repository));
+        }
+
+        for (ManagedFeature feature : availableFeatures.values()) {
+            managementAgent.register(feature, namingStrategy.getObjectName(feature));
+        }
+
+        for (ManagedFeature feature : installedFeatures.values()) {
+            installedFeatures.put(feature.getId(), feature);
+            managementAgent.register(feature, namingStrategy.getObjectName(feature, true));
+        }
+
+    }
+
+    
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/management/ManagedRepository.java b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/management/ManagedRepository.java
new file mode 100644
index 0000000..2d3ae17
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/management/ManagedRepository.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.features.management;
+
+import java.net.URI;
+
+import org.apache.servicemix.kernel.gshell.features.Feature;
+import org.apache.servicemix.kernel.gshell.features.FeaturesService;
+import org.apache.servicemix.kernel.gshell.features.Repository;
+import org.springframework.jmx.export.annotation.ManagedAttribute;
+import org.springframework.jmx.export.annotation.ManagedOperation;
+import org.springframework.jmx.export.annotation.ManagedResource;
+
+@ManagedResource(description = "Features Repository")
+public class ManagedRepository {
+    private Repository repository;
+    private FeaturesService featuresService;
+
+    public ManagedRepository(Repository repository, FeaturesService featuresService) {
+        this.repository = repository;
+        this.featuresService = featuresService;
+    }
+
+    @ManagedAttribute
+    public URI getUri() {
+        return repository.getURI();
+    }
+
+    @ManagedAttribute
+    public URI[] getRepositories() throws Exception {
+        return repository.getRepositories();
+    }
+
+    @ManagedAttribute
+    public Feature[] getFeatures() throws Exception {
+        return repository.getFeatures();
+    }
+
+    @ManagedOperation
+    public void removeRepository() throws Exception {
+        featuresService.removeRepository(repository.getURI());
+    }
+}
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/management/ManagementAgent.java b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/management/ManagementAgent.java
new file mode 100644
index 0000000..611ec6b
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/management/ManagementAgent.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.features.management;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.JMException;
+import javax.management.MBeanServer;
+import javax.management.NotCompliantMBeanException;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.modelmbean.InvalidTargetObjectTypeException;
+import javax.management.modelmbean.ModelMBeanInfo;
+import javax.management.modelmbean.RequiredModelMBean;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource;
+import org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler;
+
+/**
+ * Management Agent that registers MBeans with JMX MBeanServer.
+ */
+public class ManagementAgent implements DisposableBean {
+
+    private static final transient Log LOG = LogFactory.getLog(ManagementAgent.class);
+
+    private MBeanServer mbeanServer;
+    private MetadataMBeanInfoAssembler assembler;
+    private Set<ObjectName> mbeans = new HashSet<ObjectName>();
+
+    public ManagementAgent() {
+        assembler = new MetadataMBeanInfoAssembler();
+        assembler.setAttributeSource(new AnnotationJmxAttributeSource());
+    }
+
+    public MBeanServer getMbeanServer() {
+        return mbeanServer;
+    }
+
+    public void setMbeanServer(MBeanServer mbeanServer) {
+        this.mbeanServer = mbeanServer;
+    }
+
+    public void destroy() throws Exception {
+        // Using the array to hold the busMBeans to avoid the
+        // CurrentModificationException
+        Object[] mBeans = mbeans.toArray();
+        int caught = 0;
+        for (Object name : mBeans) {
+            mbeans.remove((ObjectName)name);
+            try {
+                unregister((ObjectName)name);
+            } catch (JMException jmex) {
+                LOG.info("Exception unregistering MBean", jmex);
+                caught++;
+            }
+        }
+        if (caught > 0) {
+            LOG.warn("A number of " + caught
+                     + " exceptions caught while unregistering MBeans during stop operation.  "
+                     + "See INFO log for details.");
+        }
+    }
+
+    public void register(Object obj, ObjectName name) throws JMException {
+        register(obj, name, false);
+    }
+
+    public void register(Object obj, ObjectName name, boolean forceRegistration) throws JMException {
+        try {
+            registerMBeanWithServer(obj, name, forceRegistration);
+        } catch (NotCompliantMBeanException e) {
+            // If this is not a "normal" MBean, then try to deploy it using JMX
+            // annotations
+            ModelMBeanInfo mbi = assembler.getMBeanInfo(obj, name.toString());
+            RequiredModelMBean mbean = (RequiredModelMBean) mbeanServer.instantiate(RequiredModelMBean.class.getName());
+            mbean.setModelMBeanInfo(mbi);
+            try {
+                mbean.setManagedResource(obj, "ObjectReference");
+            } catch (InvalidTargetObjectTypeException itotex) {
+                throw new JMException(itotex.getMessage());
+            }
+            registerMBeanWithServer(mbean, name, forceRegistration);
+        }
+    }
+
+    public synchronized void unregister(ObjectName name) throws JMException {
+        if (mbeans.contains(name)) {
+            //check if this bean already get removed in destory method
+            mbeanServer.unregisterMBean(name);
+        }
+    }
+
+    private void registerMBeanWithServer(Object obj, ObjectName name, boolean forceRegistration) throws JMException {
+        ObjectInstance instance = null;
+        try {
+            instance = mbeanServer.registerMBean(obj, name);
+        } catch (InstanceAlreadyExistsException e) {
+            if (forceRegistration) {
+                mbeanServer.unregisterMBean(name);
+                instance = mbeanServer.registerMBean(obj, name);
+            } 
+        } catch (NotCompliantMBeanException e) {
+            throw e;
+        }
+
+        if (instance != null) {
+            mbeans.add(name);
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/management/NamingStrategy.java b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/management/NamingStrategy.java
new file mode 100644
index 0000000..7a03399
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/java/org/apache/servicemix/kernel/gshell/features/management/NamingStrategy.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.features.management;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.apache.servicemix.kernel.gshell.features.FeaturesRegistry;
+
+public interface NamingStrategy {
+
+    ObjectName getObjectName(ManagedFeature feature) throws MalformedObjectNameException;
+
+    ObjectName getObjectName(ManagedFeature feature, boolean installed) throws MalformedObjectNameException;
+
+    ObjectName getObjectName(ManagedRepository component) throws MalformedObjectNameException;
+
+    String getJmxDomainName();
+
+    ObjectName getObjectName(FeaturesRegistry features) throws MalformedObjectNameException;
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-features/src/main/resources/META-INF/spring/gshell-features.xml b/karaf/gshell/gshell-features/src/main/resources/META-INF/spring/gshell-features.xml
new file mode 100644
index 0000000..d45b6be
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/resources/META-INF/spring/gshell-features.xml
@@ -0,0 +1,139 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:ctx="http://www.springframework.org/schema/context"
+       xmlns:osgi="http://www.springframework.org/schema/osgi"
+       xmlns:osgix="http://www.springframework.org/schema/osgi-compendium"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xmlns:gshell="http://servicemix.apache.org/schema/servicemix-gshell"
+       xsi:schemaLocation="
+  http://www.springframework.org/schema/beans
+  http://www.springframework.org/schema/beans/spring-beans.xsd
+  http://www.springframework.org/schema/context
+  http://www.springframework.org/schema/context/spring-context.xsd
+  http://www.springframework.org/schema/osgi
+  http://www.springframework.org/schema/osgi/spring-osgi.xsd
+  http://www.springframework.org/schema/osgi-compendium
+  http://www.springframework.org/schema/osgi-compendium/spring-osgi-compendium.xsd
+  http://www.springframework.org/schema/util
+  http://www.springframework.org/schema/util/spring-util.xsd
+  http://servicemix.apache.org/schema/servicemix-gshell
+  http://servicemix.apache.org/schema/servicemix-gshell/servicemix-gshell.xsd">
+
+    <import resource="classpath:org/apache/servicemix/kernel/gshell/core/commands.xml" />
+    
+    <bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
+      <property name="location" value="file:${servicemix.home}/etc/org.apache.servicemix.features.cfg"/>
+    </bean>
+
+    <gshell:command-bundle>
+        <gshell:command name="features/addUrl">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.features.commands.AddUrlCommand" />
+        </gshell:command>
+        <gshell:command name="features/listUrl">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.features.commands.ListUrlCommand" />
+        </gshell:command>
+        <gshell:command name="features/removeUrl">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.features.commands.RemoveUrlCommand" />
+            <gshell:completers>
+                <ref bean="removeUrlCompleter" />
+            </gshell:completers>
+        </gshell:command>
+        <gshell:command name="features/refreshUrl">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.features.commands.RefreshUrlCommand" />
+        </gshell:command>
+        <gshell:command name="features/install">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.features.commands.InstallFeatureCommand" />
+            <gshell:completers>
+                <ref bean="installFeatureCompleter" /> 
+            </gshell:completers>
+        </gshell:command>
+        <gshell:command name="features/uninstall">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.features.commands.UninstallFeatureCommand" />
+            <gshell:completers>
+                <ref bean="uninstallFeatureCompleter" />
+            </gshell:completers>
+        </gshell:command>
+        <gshell:command name="features/list">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.features.commands.ListFeaturesCommand" />
+        </gshell:command>
+    </gshell:command-bundle>
+
+    <bean id="featuresService" class="org.apache.servicemix.kernel.gshell.features.internal.FeaturesServiceImpl" init-method="start" destroy-method="stop">
+        <property name="urls" value="${featuresRepositories}" />
+        <property name="boot" value="${featuresBoot}" />
+        <property name="configAdmin" ref="configAdmin" />
+        <property name="preferences" ref="preferences" />
+        <property name="featuresServiceRegistry" ref="featureServiceRegistry" />
+    </bean>
+
+    <bean id="featureDeploymentListener" class="org.apache.servicemix.kernel.gshell.features.internal.FeatureDeploymentListener">
+        <property name="featuresService" ref="featuresService" />
+    </bean>
+
+    <bean id="namingStrategy" class="org.apache.servicemix.kernel.gshell.features.management.DefaultNamingStrategy">
+        <property name="jmxDomainName" value="org.apache.servicemix" />
+    </bean>
+
+    <bean id="managementAgent" class="org.apache.servicemix.kernel.gshell.features.management.ManagementAgent">
+        <property name="mbeanServer" ref="mbeanServer" />
+    </bean>
+
+    <bean id="featureServiceRegistry" class="org.apache.servicemix.kernel.gshell.features.management.ManagedFeaturesRegistry">
+        <property name="managementAgent" ref="managementAgent" />
+        <property name="namingStrategy" ref="namingStrategy" />
+        <property name="featuresService" ref="featuresService" />
+    </bean>
+
+    <osgi:reference id="configAdmin" interface="org.osgi.service.cm.ConfigurationAdmin" />
+
+    <osgi:reference id="preferences" interface="org.osgi.service.prefs.PreferencesService" cardinality="0..1" />
+
+    <osgi:service ref="featuresService" interface="org.apache.servicemix.kernel.gshell.features.FeaturesService" />
+
+    <osgi:service ref="featureDeploymentListener" interface="org.apache.servicemix.kernel.filemonitor.DeploymentListener" />
+
+    <osgix:cm-properties id="cmProps" persistent-id="org.apache.servicemix.features">
+        <prop key="featuresRepositories"></prop>
+        <prop key="featuresBoot"></prop>
+    </osgix:cm-properties>
+
+    <!-- <ctx:property-placeholder properties-ref="cmProps" /> -->
+
+    <osgi:reference id="mbeanServer"
+                    interface="javax.management.MBeanServer"
+                    cardinality="0..1" >
+        <osgi:listener ref="featureServiceRegistry" bind-method="registerMBeanServer" />
+    </osgi:reference>
+
+    <bean id="installFeatureCompleter" class="org.apache.servicemix.kernel.gshell.features.completers.AvailableFeatureCompleter">
+        <property name="featuresRegistry" ref="featureServiceRegistry" />
+    </bean>
+
+    <bean id="uninstallFeatureCompleter" class="org.apache.servicemix.kernel.gshell.features.completers.InstalledFeatureCompleter">
+        <property name="featuresRegistry" ref="featureServiceRegistry" />
+    </bean>
+
+    <bean id="removeUrlCompleter" class="org.apache.servicemix.kernel.gshell.features.completers.FeatureRepositoryCompleter">
+        <property name="featuresRegistry" ref="featureServiceRegistry" />
+    </bean>
+
+</beans>
\ No newline at end of file
diff --git a/karaf/gshell/gshell-features/src/main/resources/org/apache/servicemix/kernel/gshell/features/commands/AddUrlCommand.properties b/karaf/gshell/gshell-features/src/main/resources/org/apache/servicemix/kernel/gshell/features/commands/AddUrlCommand.properties
new file mode 100644
index 0000000..cf92ffe
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/resources/org/apache/servicemix/kernel/gshell/features/commands/AddUrlCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Add a list of repository URLs to the features service.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-features/src/main/resources/org/apache/servicemix/kernel/gshell/features/commands/InstallFeatureCommand.properties b/karaf/gshell/gshell-features/src/main/resources/org/apache/servicemix/kernel/gshell/features/commands/InstallFeatureCommand.properties
new file mode 100644
index 0000000..97fcbe0
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/resources/org/apache/servicemix/kernel/gshell/features/commands/InstallFeatureCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Install a feature.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-features/src/main/resources/org/apache/servicemix/kernel/gshell/features/commands/ListFeaturesCommand.properties b/karaf/gshell/gshell-features/src/main/resources/org/apache/servicemix/kernel/gshell/features/commands/ListFeaturesCommand.properties
new file mode 100644
index 0000000..4c807af
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/resources/org/apache/servicemix/kernel/gshell/features/commands/ListFeaturesCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=List existing features.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-features/src/main/resources/org/apache/servicemix/kernel/gshell/features/commands/ListUrlCommand.properties b/karaf/gshell/gshell-features/src/main/resources/org/apache/servicemix/kernel/gshell/features/commands/ListUrlCommand.properties
new file mode 100644
index 0000000..a544da9
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/resources/org/apache/servicemix/kernel/gshell/features/commands/ListUrlCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Display the repository URLs currently associated with the features service.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-features/src/main/resources/org/apache/servicemix/kernel/gshell/features/commands/RefreshUrlCommand.properties b/karaf/gshell/gshell-features/src/main/resources/org/apache/servicemix/kernel/gshell/features/commands/RefreshUrlCommand.properties
new file mode 100644
index 0000000..12687fd
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/resources/org/apache/servicemix/kernel/gshell/features/commands/RefreshUrlCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Reload the repositories to obtain a fresh list of features.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-features/src/main/resources/org/apache/servicemix/kernel/gshell/features/commands/RemoveUrlCommand.properties b/karaf/gshell/gshell-features/src/main/resources/org/apache/servicemix/kernel/gshell/features/commands/RemoveUrlCommand.properties
new file mode 100644
index 0000000..34c2126
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/resources/org/apache/servicemix/kernel/gshell/features/commands/RemoveUrlCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Remove a list of repository URLs from the features service.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-features/src/main/resources/org/apache/servicemix/kernel/gshell/features/commands/UninstallFeatureCommand.properties b/karaf/gshell/gshell-features/src/main/resources/org/apache/servicemix/kernel/gshell/features/commands/UninstallFeatureCommand.properties
new file mode 100644
index 0000000..ab3348e
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/main/resources/org/apache/servicemix/kernel/gshell/features/commands/UninstallFeatureCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Uninstall a feature.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-features/src/test/java/org/apache/servicemix/kernel/gshell/features/FeatureTest.java b/karaf/gshell/gshell-features/src/test/java/org/apache/servicemix/kernel/gshell/features/FeatureTest.java
new file mode 100644
index 0000000..97d6332
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/test/java/org/apache/servicemix/kernel/gshell/features/FeatureTest.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.features;
+
+import junit.framework.TestCase;
+import org.apache.servicemix.kernel.gshell.features.internal.FeatureImpl;
+
+public class FeatureTest extends TestCase {
+	
+	public void testValueOf() {
+		Feature feature = FeatureImpl.valueOf("name" + FeatureImpl.SPLIT_FOR_NAME_AND_VERSION + "version");
+		assertEquals(feature.getName(), "name");
+		assertEquals(feature.getVersion(), "version");
+		feature = FeatureImpl.valueOf("name");
+		assertEquals(feature.getName(), "name");
+		assertEquals(feature.getVersion(), FeatureImpl.DEFAULT_VERSION);
+	}
+	
+}
diff --git a/karaf/gshell/gshell-features/src/test/java/org/apache/servicemix/kernel/gshell/features/FeaturesServiceTest.java b/karaf/gshell/gshell-features/src/test/java/org/apache/servicemix/kernel/gshell/features/FeaturesServiceTest.java
new file mode 100644
index 0000000..5909722
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/test/java/org/apache/servicemix/kernel/gshell/features/FeaturesServiceTest.java
@@ -0,0 +1,700 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.features;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.net.URI;
+
+import junit.framework.TestCase;
+import org.apache.servicemix.kernel.gshell.features.internal.FeatureImpl;
+import org.apache.servicemix.kernel.gshell.features.internal.FeaturesServiceImpl;
+import org.apache.servicemix.kernel.gshell.features.management.ManagedFeaturesRegistry;
+import org.easymock.EasyMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.isA;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.reset;
+import static org.easymock.EasyMock.verify;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.prefs.Preferences;
+import org.osgi.service.prefs.PreferencesService;
+import org.springframework.context.ApplicationContext;
+
+public class FeaturesServiceTest extends TestCase {
+
+    public void testInstallFeature() throws Exception {
+
+        String name = ApplicationContext.class.getName();
+        name = name.replace(".", "/")  + ".class";
+        name = getClass().getClassLoader().getResource(name).toString();
+        name = name.substring("jar:".length(), name.indexOf('!'));
+
+        File tmp = File.createTempFile("smx", ".feature");
+        PrintWriter pw = new PrintWriter(new FileWriter(tmp));
+        pw.println("<features>");
+        pw.println("  <feature name=\"f1\">");
+        pw.println("    <bundle>" + name + "</bundle>");
+        pw.println("  </feature>");
+        pw.println("</features>");
+        pw.close();
+
+        URI uri = tmp.toURI();
+
+        Preferences prefs = EasyMock.createMock(Preferences.class);
+        PreferencesService preferencesService = EasyMock.createMock(PreferencesService.class);
+        Preferences repositoriesNode = EasyMock.createMock(Preferences.class);
+        Preferences featuresNode = EasyMock.createMock(Preferences.class);
+        BundleContext bundleContext = EasyMock.createMock(BundleContext.class);
+        Bundle installedBundle = EasyMock.createMock(Bundle.class);
+        FeaturesRegistry featuresRegistry = EasyMock.createNiceMock(FeaturesRegistry.class);
+
+        expect(preferencesService.getUserPreferences("FeaturesServiceState")).andStubReturn(prefs);
+        expect(prefs.node("repositories")).andReturn(repositoriesNode);
+        repositoriesNode.clear();
+        repositoriesNode.putInt("count", 1);
+        repositoriesNode.put("item.0", uri.toString());
+        expect(prefs.node("features")).andReturn(featuresNode);
+        featuresNode.clear();
+        prefs.putBoolean("bootFeaturesInstalled", false);
+        prefs.flush();
+        featuresRegistry.register(isA(Repository.class));
+
+        replay(preferencesService, prefs, repositoriesNode, featuresNode, bundleContext, installedBundle, featuresRegistry);
+
+        FeaturesServiceImpl svc = new FeaturesServiceImpl();
+        svc.setPreferences(preferencesService);
+        svc.setBundleContext(bundleContext);
+        svc.setFeaturesServiceRegistry(featuresRegistry);
+        svc.addRepository(uri);
+        
+        Repository[] repositories = svc.listRepositories();
+        assertNotNull(repositories);
+        assertEquals(1, repositories.length);
+        assertNotNull(repositories[0]);
+        Feature[] features = repositories[0].getFeatures();
+        assertNotNull(features);
+        assertEquals(1, features.length);
+        assertNotNull(features[0]);
+        assertEquals("f1", features[0].getName());
+        assertNotNull(features[0].getDependencies());
+        assertEquals(0, features[0].getDependencies().size());
+        assertNotNull(features[0].getBundles());
+        assertEquals(1, features[0].getBundles().size());
+        assertEquals(name, features[0].getBundles().get(0));
+
+        verify(preferencesService, prefs, repositoriesNode, featuresNode, bundleContext, installedBundle, featuresRegistry);
+
+        reset(preferencesService, prefs, repositoriesNode, featuresNode, bundleContext, installedBundle, featuresRegistry);
+
+        expect(bundleContext.getBundles()).andReturn(new Bundle[0]);
+        expect(bundleContext.installBundle(isA(String.class),
+                                           isA(InputStream.class))).andReturn(installedBundle);
+        expect(installedBundle.getBundleId()).andReturn(12345L);
+        expect(bundleContext.getBundle(12345L)).andReturn(installedBundle);
+        installedBundle.start();
+
+        expect(preferencesService.getUserPreferences("FeaturesServiceState")).andStubReturn(prefs);
+        expect(prefs.node("repositories")).andReturn(repositoriesNode);
+        repositoriesNode.clear();
+        repositoriesNode.putInt("count", 1);
+        repositoriesNode.put("item.0", uri.toString());
+        expect(prefs.node("features")).andReturn(featuresNode);
+        featuresNode.clear();
+        featuresNode.put("f1" + FeatureImpl.SPLIT_FOR_NAME_AND_VERSION + FeatureImpl.DEFAULT_VERSION, "12345");
+        prefs.putBoolean("bootFeaturesInstalled", false);
+        prefs.flush();
+
+        replay(preferencesService, prefs, repositoriesNode, featuresNode, bundleContext, installedBundle);
+
+        svc.installFeature("f1");
+        
+        String[] installed = svc.listInstalledFeatures();
+        assertEquals(1, installed.length);
+        assertEquals("f1", installed[0]);
+    }
+
+    public void testUninstallFeature() throws Exception {
+    	
+        String name = ApplicationContext.class.getName();
+        name = name.replace(".", "/")  + ".class";
+        name = getClass().getClassLoader().getResource(name).toString();
+        name = name.substring("jar:".length(), name.indexOf('!'));
+
+        File tmp = File.createTempFile("smx", ".feature");
+        PrintWriter pw = new PrintWriter(new FileWriter(tmp));
+        pw.println("<features>");
+        pw.println("  <feature name=\"f1\" version=\"0.1\">");
+        pw.println("    <bundle>" + name + "</bundle>");
+        pw.println("  </feature>");
+        pw.println("  <feature name=\"f1\" version=\"0.2\">");
+        pw.println("    <bundle>" + name + "</bundle>");
+        pw.println("  </feature>");
+        pw.println("</features>");
+        pw.close();
+
+        URI uri = tmp.toURI();
+        
+        Preferences prefs = EasyMock.createMock(Preferences.class);
+        PreferencesService preferencesService = EasyMock.createMock(PreferencesService.class);
+        Preferences repositoriesNode = EasyMock.createMock(Preferences.class);
+        Preferences featuresNode = EasyMock.createMock(Preferences.class);
+        BundleContext bundleContext = EasyMock.createMock(BundleContext.class);
+        Bundle installedBundle = EasyMock.createMock(Bundle.class);
+        FeaturesRegistry featuresRegistry = EasyMock.createNiceMock(FeaturesRegistry.class);
+
+        expect(preferencesService.getUserPreferences("FeaturesServiceState")).andStubReturn(prefs);
+        expect(prefs.node("repositories")).andReturn(repositoriesNode);
+        repositoriesNode.clear();
+        repositoriesNode.putInt("count", 1);
+        repositoriesNode.put("item.0", uri.toString());
+        expect(prefs.node("features")).andReturn(featuresNode);
+        featuresNode.clear();
+        prefs.putBoolean("bootFeaturesInstalled", false);
+        prefs.flush();
+        featuresRegistry.register(isA(Repository.class));
+
+        replay(preferencesService, prefs, repositoriesNode, featuresNode, bundleContext, installedBundle, featuresRegistry);
+
+        FeaturesServiceImpl svc = new FeaturesServiceImpl();
+        svc.setPreferences(preferencesService);
+        svc.setBundleContext(bundleContext);
+        svc.setFeaturesServiceRegistry(featuresRegistry);
+        svc.addRepository(uri);
+        
+        verify(preferencesService, prefs, repositoriesNode, featuresNode, bundleContext, installedBundle, featuresRegistry);
+
+        reset(preferencesService, prefs, repositoriesNode, featuresNode, bundleContext, installedBundle, featuresRegistry);
+
+        // Installs f1 and 0.1
+        expect(bundleContext.getBundles()).andReturn(new Bundle[0]);
+        expect(bundleContext.installBundle(isA(String.class),
+                                           isA(InputStream.class))).andReturn(installedBundle);
+        expect(installedBundle.getBundleId()).andReturn(12345L);
+        expect(bundleContext.getBundle(12345L)).andReturn(installedBundle);
+        installedBundle.start();
+
+        expect(preferencesService.getUserPreferences("FeaturesServiceState")).andStubReturn(prefs);
+        expect(prefs.node("repositories")).andReturn(repositoriesNode);
+        repositoriesNode.clear();
+        repositoriesNode.putInt("count", 1);
+        repositoriesNode.put("item.0", uri.toString());
+        expect(prefs.node("features")).andReturn(featuresNode);
+        featuresNode.clear();
+        featuresNode.put("f1" + FeatureImpl.SPLIT_FOR_NAME_AND_VERSION + "0.1", "12345");
+        prefs.putBoolean("bootFeaturesInstalled", false);
+        prefs.flush();
+        
+        // Installs f1 and 0.2
+        expect(bundleContext.getBundles()).andReturn(new Bundle[0]);
+        expect(bundleContext.installBundle(isA(String.class),
+                                           isA(InputStream.class))).andReturn(installedBundle);
+        expect(installedBundle.getBundleId()).andReturn(123456L);
+        expect(bundleContext.getBundle(123456L)).andReturn(installedBundle);
+        installedBundle.start();
+
+        expect(preferencesService.getUserPreferences("FeaturesServiceState")).andStubReturn(prefs);
+        expect(prefs.node("repositories")).andReturn(repositoriesNode);
+        repositoriesNode.clear();
+        repositoriesNode.putInt("count", 1);
+        repositoriesNode.put("item.0", uri.toString());
+        expect(prefs.node("features")).andReturn(featuresNode);
+        featuresNode.clear();
+        featuresNode.put("f1" + FeatureImpl.SPLIT_FOR_NAME_AND_VERSION + "0.1", "12345");
+        featuresNode.put("f1" + FeatureImpl.SPLIT_FOR_NAME_AND_VERSION + "0.2", "123456");
+        prefs.putBoolean("bootFeaturesInstalled", false);
+        prefs.flush();
+
+        // UnInstalls f1 and 0.1
+        expect(bundleContext.getBundle(12345)).andReturn(installedBundle);
+        installedBundle.uninstall();
+
+        expect(preferencesService.getUserPreferences("FeaturesServiceState")).andStubReturn(prefs);
+        expect(prefs.node("repositories")).andReturn(repositoriesNode);
+        repositoriesNode.clear();
+        repositoriesNode.putInt("count", 1);
+        repositoriesNode.put("item.0", uri.toString());
+        expect(prefs.node("features")).andReturn(featuresNode);
+        featuresNode.clear();
+        featuresNode.put("f1" + FeatureImpl.SPLIT_FOR_NAME_AND_VERSION + "0.2", "123456");
+        prefs.putBoolean("bootFeaturesInstalled", false);
+        prefs.flush();
+
+        // UnInstalls f1 and 0.2
+        expect(bundleContext.getBundle(123456)).andReturn(installedBundle);
+        installedBundle.uninstall();
+
+        expect(preferencesService.getUserPreferences("FeaturesServiceState")).andStubReturn(prefs);
+        expect(prefs.node("repositories")).andReturn(repositoriesNode);
+        repositoriesNode.clear();
+        repositoriesNode.putInt("count", 1);
+        repositoriesNode.put("item.0", uri.toString());
+        expect(prefs.node("features")).andReturn(featuresNode);
+        featuresNode.clear();
+        prefs.putBoolean("bootFeaturesInstalled", false);
+        prefs.flush();
+
+        replay(preferencesService, prefs, repositoriesNode, featuresNode, bundleContext, installedBundle);
+
+        try {
+            svc.uninstallFeature("f1");
+            fail("Uninstall should have failed as feature is not installed");
+        } catch (Exception e) {
+            // ok
+        }
+
+        svc.installFeature("f1", "0.1");
+        svc.installFeature("f1", "0.2");
+
+        try {
+            svc.uninstallFeature("f1");
+            fail("Uninstall should have failed as feature is installed in multiple versions");
+        } catch (Exception e) {
+            // ok
+        }
+
+        svc.uninstallFeature("f1", "0.1");
+        svc.uninstallFeature("f1");
+    }    
+    
+    // Tests Add and Remove Repository
+    public void testAddAndRemoveRepository() throws Exception {        
+
+    	String name = ApplicationContext.class.getName();
+        name = name.replace(".", "/")  + ".class";
+        name = getClass().getClassLoader().getResource(name).toString();
+        name = name.substring("jar:".length(), name.indexOf('!'));        
+
+        File tmp = File.createTempFile("smx", ".feature");
+        PrintWriter pw = new PrintWriter(new FileWriter(tmp));
+        pw.println("<features>");
+        pw.println("  <feature name=\"f1\" version=\"0.1\">");
+        pw.println("    <bundle>" + name + "</bundle>");
+        pw.println("  </feature>");
+        pw.println("  <feature name=\"f1\" version=\"0.2\">");
+        pw.println("    <bundle>" + name + "</bundle>");
+        pw.println("  </feature>");
+        pw.println("  <feature name=\"f2\" version=\"0.2\">");
+        pw.println("    <bundle>" + name + "</bundle>");
+        pw.println("  </feature>");
+        pw.println("</features>");
+        pw.close();
+
+        URI uri = tmp.toURI();
+
+        // loads the state
+        Preferences prefs = EasyMock.createMock(Preferences.class);
+        PreferencesService preferencesService = EasyMock.createMock(PreferencesService.class);
+        Preferences repositoriesNode = EasyMock.createMock(Preferences.class);
+        Preferences featuresNode = EasyMock.createMock(Preferences.class);
+        BundleContext bundleContext = EasyMock.createMock(BundleContext.class);        
+        Bundle installedBundle = EasyMock.createMock(Bundle.class);        
+        FeaturesRegistry featuresRegistry = EasyMock.createNiceMock(FeaturesRegistry.class);
+
+        expect(preferencesService.getUserPreferences("FeaturesServiceState")).andStubReturn(prefs);
+        expect(prefs.node("repositories")).andReturn(repositoriesNode);
+        repositoriesNode.clear();
+        repositoriesNode.putInt("count", 1);
+        repositoriesNode.put("item.0", uri.toString());        
+        expect(prefs.node("features")).andReturn(featuresNode);
+        featuresNode.clear();               
+        prefs.putBoolean("bootFeaturesInstalled", false);
+        prefs.flush();
+        
+        featuresRegistry.register(isA(Repository.class));
+        
+        // SaveState for addRepository
+        expect(preferencesService.getUserPreferences("FeaturesServiceState")).andStubReturn(prefs);
+        expect(prefs.node("repositories")).andReturn(repositoriesNode);
+        repositoriesNode.clear();
+        repositoriesNode.putInt("count", 1);
+        repositoriesNode.put("item.0", uri.toString());        
+        expect(prefs.node("features")).andReturn(featuresNode);
+        featuresNode.clear();
+        prefs.putBoolean("bootFeaturesInstalled", false);
+        prefs.flush();
+        
+        // SaveState for removeRepository
+        expect(preferencesService.getUserPreferences("FeaturesServiceState")).andStubReturn(prefs);
+        expect(prefs.node("repositories")).andReturn(repositoriesNode);
+        repositoriesNode.clear();
+        repositoriesNode.putInt("count", 0);              
+        expect(prefs.node("features")).andReturn(featuresNode);
+        featuresNode.clear();        
+        prefs.putBoolean("bootFeaturesInstalled", false);
+        prefs.flush();
+        replay(preferencesService, prefs, repositoriesNode, featuresNode, bundleContext, installedBundle, featuresRegistry);
+
+        FeaturesServiceImpl svc = new FeaturesServiceImpl();
+        svc.setPreferences(preferencesService);
+        svc.setBundleContext(bundleContext);        
+        svc.setFeaturesServiceRegistry(featuresRegistry);
+        
+        // Adds Repository
+        svc.addRepository(uri);                                                     
+        
+        // Removes Repository
+        svc.removeRepository(uri);        
+    }
+
+    // Tests installing all features in a repo and uninstalling
+    // all features in a repo
+    public void testInstallUninstallAllFeatures() throws Exception {        
+
+    	String name = ApplicationContext.class.getName();
+        name = name.replace(".", "/")  + ".class";
+        name = getClass().getClassLoader().getResource(name).toString();
+        name = name.substring("jar:".length(), name.indexOf('!'));        
+
+        File tmp = File.createTempFile("smx", ".feature");
+        PrintWriter pw = new PrintWriter(new FileWriter(tmp));
+        pw.println("<features>");
+        pw.println("  <feature name=\"f1\" version=\"0.1\">");
+        pw.println("    <bundle>" + name + "</bundle>");
+        pw.println("  </feature>");
+        pw.println("  <feature name=\"f1\" version=\"0.2\">");
+        pw.println("    <bundle>" + name + "</bundle>");
+        pw.println("  </feature>");
+        pw.println("  <feature name=\"f2\" version=\"0.2\">");
+        pw.println("    <bundle>" + name + "</bundle>");
+        pw.println("  </feature>");
+        pw.println("</features>");
+        pw.close();
+
+        URI uri = tmp.toURI();
+
+        // loads the state
+        Preferences prefs = EasyMock.createMock(Preferences.class);
+        PreferencesService preferencesService = EasyMock.createMock(PreferencesService.class);
+        Preferences repositoriesNode = EasyMock.createMock(Preferences.class);
+        Preferences featuresNode = EasyMock.createMock(Preferences.class);
+        BundleContext bundleContext = EasyMock.createMock(BundleContext.class);        
+        Bundle installedBundle = EasyMock.createMock(Bundle.class);        
+        FeaturesRegistry featuresRegistry = EasyMock.createNiceMock(FeaturesRegistry.class);
+
+        expect(preferencesService.getUserPreferences("FeaturesServiceState")).andStubReturn(prefs);
+        expect(prefs.node("repositories")).andReturn(repositoriesNode);
+        repositoriesNode.clear();
+        repositoriesNode.putInt("count", 1);
+        repositoriesNode.put("item.0", uri.toString());        
+        expect(prefs.node("features")).andReturn(featuresNode);
+        featuresNode.clear();
+        prefs.putBoolean("bootFeaturesInstalled", false);
+        prefs.flush();
+        
+        // Installs first feature name = f1, version = 0.1 
+        expect(bundleContext.getBundles()).andReturn(new Bundle[0]);
+        expect(bundleContext.installBundle(isA(String.class),
+                                           isA(InputStream.class))).andReturn(installedBundle);
+        expect(installedBundle.getBundleId()).andReturn(12345L);
+        expect(bundleContext.getBundle(12345L)).andReturn(installedBundle);
+        installedBundle.start();
+        
+        expect(preferencesService.getUserPreferences("FeaturesServiceState")).andStubReturn(prefs);
+        expect(prefs.node("repositories")).andReturn(repositoriesNode);
+        repositoriesNode.clear();
+        repositoriesNode.putInt("count", 1);
+        repositoriesNode.put("item.0", uri.toString());        
+        expect(prefs.node("features")).andReturn(featuresNode);
+        featuresNode.clear();
+        featuresNode.put("f1" + FeatureImpl.SPLIT_FOR_NAME_AND_VERSION + "0.1", "12345");
+        prefs.putBoolean("bootFeaturesInstalled", false);
+        prefs.flush();
+        
+        // Installs second feature name = f1, version = 0.2
+        expect(bundleContext.getBundles()).andReturn(new Bundle[0]);
+        expect(bundleContext.installBundle(isA(String.class),
+                                           isA(InputStream.class))).andReturn(installedBundle);
+        expect(installedBundle.getBundleId()).andReturn(123456L);
+        expect(bundleContext.getBundle(123456L)).andReturn(installedBundle);
+        installedBundle.start();
+        
+        expect(preferencesService.getUserPreferences("FeaturesServiceState")).andStubReturn(prefs);
+        expect(prefs.node("repositories")).andReturn(repositoriesNode);
+        repositoriesNode.clear();
+        repositoriesNode.putInt("count", 1);
+        repositoriesNode.put("item.0", uri.toString());        
+        expect(prefs.node("features")).andReturn(featuresNode);
+        featuresNode.clear();
+        featuresNode.put("f1" + FeatureImpl.SPLIT_FOR_NAME_AND_VERSION + "0.1", "12345");
+        featuresNode.put("f1" + FeatureImpl.SPLIT_FOR_NAME_AND_VERSION + "0.2", "123456");
+        prefs.putBoolean("bootFeaturesInstalled", false);
+        prefs.flush();
+        
+        // Installs third feature name = f2, version = 0.2
+        expect(bundleContext.getBundles()).andReturn(new Bundle[0]);
+        expect(bundleContext.installBundle(isA(String.class),
+                                           isA(InputStream.class))).andReturn(installedBundle);
+        expect(installedBundle.getBundleId()).andReturn(1234567L);
+        expect(bundleContext.getBundle(1234567L)).andReturn(installedBundle);
+        installedBundle.start();
+        
+        expect(preferencesService.getUserPreferences("FeaturesServiceState")).andStubReturn(prefs);
+        expect(prefs.node("repositories")).andReturn(repositoriesNode);
+        repositoriesNode.clear();
+        repositoriesNode.putInt("count", 1);
+        repositoriesNode.put("item.0", uri.toString());        
+        expect(prefs.node("features")).andReturn(featuresNode);
+        featuresNode.clear();
+        featuresNode.put("f1" + FeatureImpl.SPLIT_FOR_NAME_AND_VERSION + "0.1", "12345");
+        featuresNode.put("f1" + FeatureImpl.SPLIT_FOR_NAME_AND_VERSION + "0.2", "123456");
+        featuresNode.put("f2" + FeatureImpl.SPLIT_FOR_NAME_AND_VERSION + "0.2", "1234567");
+        prefs.putBoolean("bootFeaturesInstalled", false);
+        prefs.flush();
+        
+        expect(preferencesService.getUserPreferences("FeaturesServiceState")).andStubReturn(prefs);
+        expect(prefs.node("repositories")).andReturn(repositoriesNode);
+        repositoriesNode.clear();
+        repositoriesNode.putInt("count", 0);
+        repositoriesNode.put("item.0", uri.toString());        
+        expect(prefs.node("features")).andReturn(featuresNode);
+        featuresNode.clear();
+        featuresNode.put("f1" + FeatureImpl.SPLIT_FOR_NAME_AND_VERSION + "0.1", "12345");
+        featuresNode.put("f1" + FeatureImpl.SPLIT_FOR_NAME_AND_VERSION + "0.2", "123456");
+        featuresNode.put("f2" + FeatureImpl.SPLIT_FOR_NAME_AND_VERSION + "0.2", "1234567");
+        prefs.putBoolean("bootFeaturesInstalled", false);
+        prefs.flush();
+
+        // uninstallAllFeatures 
+        
+        expect(preferencesService.getUserPreferences("FeaturesServiceState")).andStubReturn(prefs);
+        expect(prefs.node("repositories")).andReturn(repositoriesNode);
+        repositoriesNode.clear();
+        repositoriesNode.putInt("count", 1);
+        repositoriesNode.put("item.0", uri.toString());        
+        expect(prefs.node("features")).andReturn(featuresNode);
+        featuresNode.clear();
+        featuresNode.put("f1" + FeatureImpl.SPLIT_FOR_NAME_AND_VERSION + "0.1", "12345");
+        featuresNode.put("f1" + FeatureImpl.SPLIT_FOR_NAME_AND_VERSION + "0.2", "123456");
+        featuresNode.put("f2" + FeatureImpl.SPLIT_FOR_NAME_AND_VERSION + "0.2", "1234567");
+        prefs.putBoolean("bootFeaturesInstalled", false);
+        prefs.flush();
+        
+        // uninstalls first feature name = f1, version = 0.1
+        expect(bundleContext.getBundle(12345)).andReturn(installedBundle);
+        installedBundle.uninstall();
+
+        expect(preferencesService.getUserPreferences("FeaturesServiceState")).andStubReturn(prefs);
+        expect(prefs.node("repositories")).andReturn(repositoriesNode);
+        repositoriesNode.clear();
+        repositoriesNode.putInt("count", 1);
+        repositoriesNode.put("item.0", uri.toString());        
+        expect(prefs.node("features")).andReturn(featuresNode);
+        featuresNode.clear();
+        featuresNode.put("f1" + FeatureImpl.SPLIT_FOR_NAME_AND_VERSION + "0.2", "123456");
+        featuresNode.put("f2" + FeatureImpl.SPLIT_FOR_NAME_AND_VERSION + "0.2", "1234567");
+        prefs.putBoolean("bootFeaturesInstalled", false);
+        prefs.flush();
+        
+        // uninstalls third feature name = f2, version = 0.2
+        expect(bundleContext.getBundle(1234567)).andReturn(installedBundle);
+        installedBundle.uninstall();
+
+        expect(preferencesService.getUserPreferences("FeaturesServiceState")).andStubReturn(prefs);
+        expect(prefs.node("repositories")).andReturn(repositoriesNode);
+        repositoriesNode.clear();
+        repositoriesNode.putInt("count", 1);
+        repositoriesNode.put("item.0", uri.toString());        
+        expect(prefs.node("features")).andReturn(featuresNode);
+        featuresNode.clear();        
+        featuresNode.put("f1" + FeatureImpl.SPLIT_FOR_NAME_AND_VERSION + "0.2", "123456");
+        prefs.putBoolean("bootFeaturesInstalled", false);
+        prefs.flush();
+
+        // uninstalls second feature name = f1, version = 0.2
+        expect(bundleContext.getBundle(123456)).andReturn(installedBundle);
+        installedBundle.uninstall();
+
+        expect(preferencesService.getUserPreferences("FeaturesServiceState")).andStubReturn(prefs);
+        expect(prefs.node("repositories")).andReturn(repositoriesNode);
+        repositoriesNode.clear();
+        repositoriesNode.putInt("count", 1);
+        repositoriesNode.put("item.0", uri.toString());        
+        expect(prefs.node("features")).andReturn(featuresNode);
+        featuresNode.clear();        
+        prefs.putBoolean("bootFeaturesInstalled", false);
+        prefs.flush();
+
+        expect(preferencesService.getUserPreferences("FeaturesServiceState")).andStubReturn(prefs);
+        expect(prefs.node("repositories")).andReturn(repositoriesNode);
+        repositoriesNode.clear();
+        repositoriesNode.putInt("count", 0);
+        repositoriesNode.put("item.0", uri.toString());        
+        expect(prefs.node("features")).andReturn(featuresNode);
+        featuresNode.clear();
+        prefs.putBoolean("bootFeaturesInstalled", false);
+        prefs.flush();
+
+        replay(preferencesService, prefs, repositoriesNode, featuresNode, bundleContext, installedBundle, featuresRegistry);
+
+        FeaturesServiceImpl svc = new FeaturesServiceImpl();
+        svc.setPreferences(preferencesService);
+        svc.setBundleContext(bundleContext);        
+        svc.setFeaturesServiceRegistry(featuresRegistry);                
+        svc.installAllFeatures(uri);                            
+        
+        // Uninstalls features with versions.
+        svc.uninstallAllFeatures(uri);    
+    }    
+
+
+    // Tests install of a Repository that includes a feature 
+    // with a feature dependency  
+    // The dependant feature is in the same repository 
+    // Tests uninstall of features
+    public void testInstallFeatureWithDependantFeatures() throws Exception {          
+
+    	String name = ApplicationContext.class.getName();
+        name = name.replace(".", "/")  + ".class";
+        name = getClass().getClassLoader().getResource(name).toString();
+        name = name.substring("jar:".length(), name.indexOf('!'));        
+
+        File tmp = File.createTempFile("smx", ".feature");
+        PrintWriter pw = new PrintWriter(new FileWriter(tmp));
+        pw.println("<features>");
+        pw.println("  <feature name=\"f1\" version=\"0.1\">");
+        pw.println("  <feature version=\"0.1\">f2</feature>");
+        pw.println("    <bundle>" + name + "</bundle>");
+        pw.println("  </feature>");
+        pw.println("  <feature name=\"f2\" version=\"0.1\">");
+        pw.println("    <bundle>" + name + "</bundle>");
+        pw.println("  </feature>");
+        pw.println("</features>");
+        pw.close();
+
+        URI uri = tmp.toURI();
+
+        // loads the state
+        Preferences prefs = EasyMock.createMock(Preferences.class);
+        PreferencesService preferencesService = EasyMock.createMock(PreferencesService.class);
+        Preferences repositoriesNode = EasyMock.createMock(Preferences.class);
+        Preferences repositoriesAvailableNode = EasyMock.createMock(Preferences.class);
+        Preferences featuresNode = EasyMock.createMock(Preferences.class);
+        BundleContext bundleContext = EasyMock.createMock(BundleContext.class);        
+        Bundle installedBundle = EasyMock.createMock(Bundle.class);        
+        FeaturesRegistry featuresRegistry = EasyMock.createNiceMock(FeaturesRegistry.class);        
+
+        // savestate from addRepository
+        expect(preferencesService.getUserPreferences("FeaturesServiceState")).andStubReturn(prefs);
+        expect(prefs.node("repositories")).andReturn(repositoriesNode);
+        repositoriesNode.clear();
+        repositoriesNode.putInt("count", 1);
+        repositoriesNode.put("item.0", uri.toString());        
+        expect(prefs.node("features")).andReturn(featuresNode);
+        featuresNode.clear();
+        prefs.putBoolean("bootFeaturesInstalled", false);
+        prefs.flush();
+
+        // Installs feature f1 with dependency on f2
+        // so will install f2 first
+        expect(bundleContext.getBundles()).andReturn(new Bundle[0]);
+        expect(bundleContext.installBundle(isA(String.class),
+                                           isA(InputStream.class))).andReturn(installedBundle);
+        expect(installedBundle.getBundleId()).andReturn(12345L);
+        expect(bundleContext.getBundle(12345L)).andReturn(installedBundle);
+        installedBundle.start();
+        
+        expect(preferencesService.getUserPreferences("FeaturesServiceState")).andStubReturn(prefs);
+        expect(prefs.node("repositories")).andReturn(repositoriesNode);
+        repositoriesNode.clear();
+        repositoriesNode.putInt("count", 1);
+        repositoriesNode.put("item.0", uri.toString());        
+        expect(prefs.node("features")).andReturn(featuresNode);
+        featuresNode.clear();
+        featuresNode.put("f2" + FeatureImpl.SPLIT_FOR_NAME_AND_VERSION + "0.1", "12345");
+        prefs.putBoolean("bootFeaturesInstalled", false);
+        prefs.flush();
+        
+        // Then installs f1
+        expect(bundleContext.getBundles()).andReturn(new Bundle[0]);
+        expect(bundleContext.installBundle(isA(String.class),
+                                           isA(InputStream.class))).andReturn(installedBundle);
+        expect(installedBundle.getBundleId()).andReturn(1234L);
+        expect(bundleContext.getBundle(1234L)).andReturn(installedBundle);
+        installedBundle.start();
+        
+        expect(preferencesService.getUserPreferences("FeaturesServiceState")).andStubReturn(prefs);
+        expect(prefs.node("repositories")).andReturn(repositoriesNode);
+        repositoriesNode.clear();
+        repositoriesNode.putInt("count", 1);
+        repositoriesNode.put("item.0", uri.toString());        
+        expect(prefs.node("features")).andReturn(featuresNode);
+        featuresNode.clear();
+        featuresNode.put("f2" + FeatureImpl.SPLIT_FOR_NAME_AND_VERSION + "0.1", "12345");
+        featuresNode.put("f1" + FeatureImpl.SPLIT_FOR_NAME_AND_VERSION + "0.1", "1234");
+        prefs.putBoolean("bootFeaturesInstalled", false);
+        prefs.flush();                      
+
+        // uninstalls first feature name = f1, version = 0.1
+        expect(bundleContext.getBundle(1234)).andReturn(installedBundle);
+        installedBundle.uninstall();
+
+        expect(preferencesService.getUserPreferences("FeaturesServiceState")).andStubReturn(prefs);
+        expect(prefs.node("repositories")).andReturn(repositoriesNode);
+        repositoriesNode.clear();
+        repositoriesNode.putInt("count", 1);
+        repositoriesNode.put("item.0", uri.toString());        
+        expect(prefs.node("features")).andReturn(featuresNode);
+        featuresNode.clear();
+        featuresNode.put("f2" + FeatureImpl.SPLIT_FOR_NAME_AND_VERSION + "0.1", "12345");        
+        prefs.putBoolean("bootFeaturesInstalled", false);
+        prefs.flush();
+        
+       // uninstalls first feature name = f2, version = 0.1
+        expect(bundleContext.getBundle(12345)).andReturn(installedBundle);
+        installedBundle.uninstall();
+
+        expect(preferencesService.getUserPreferences("FeaturesServiceState")).andStubReturn(prefs);
+        expect(prefs.node("repositories")).andReturn(repositoriesNode);
+        repositoriesNode.clear();
+        repositoriesNode.putInt("count", 1);
+        repositoriesNode.put("item.0", uri.toString());        
+        expect(prefs.node("features")).andReturn(featuresNode);
+        featuresNode.clear();        
+        prefs.putBoolean("bootFeaturesInstalled", false);
+        prefs.flush();                        
+        
+        expect(preferencesService.getUserPreferences("FeaturesServiceState")).andStubReturn(prefs);
+        expect(prefs.node("repositories")).andReturn(repositoriesNode);
+        repositoriesNode.clear();
+        repositoriesNode.putInt("count", 0);
+        repositoriesNode.put("item.0", uri.toString());        
+        expect(prefs.node("features")).andReturn(featuresNode);
+        featuresNode.clear();        
+        prefs.putBoolean("bootFeaturesInstalled", false);
+        prefs.flush();                        
+        
+        replay(preferencesService, prefs, repositoriesNode, featuresNode, bundleContext, installedBundle, featuresRegistry);
+
+        FeaturesServiceImpl svc = new FeaturesServiceImpl();
+        svc.setPreferences(preferencesService);
+        svc.setBundleContext(bundleContext);        
+        svc.setFeaturesServiceRegistry(featuresRegistry);                
+        svc.addRepository(uri);    
+
+        svc.installFeature("f1", "0.1");
+                
+        // Uninstall repository
+        svc.uninstallFeature("f1", "0.1");
+        svc.uninstallFeature("f2", "0.1");
+        
+    }
+
+}
diff --git a/karaf/gshell/gshell-features/src/test/java/org/apache/servicemix/kernel/gshell/features/RepositoryTest.java b/karaf/gshell/gshell-features/src/test/java/org/apache/servicemix/kernel/gshell/features/RepositoryTest.java
new file mode 100644
index 0000000..e8cfffd
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/test/java/org/apache/servicemix/kernel/gshell/features/RepositoryTest.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.features;
+
+import java.net.URI;
+
+import junit.framework.TestCase;
+import org.apache.servicemix.kernel.gshell.features.internal.FeatureImpl;
+import org.apache.servicemix.kernel.gshell.features.internal.RepositoryImpl;
+
+
+public class RepositoryTest extends TestCase {
+
+    public void testLoad() throws Exception {
+        RepositoryImpl r = new RepositoryImpl(getClass().getResource("repo1.xml").toURI());
+        // Check repo
+        URI[] repos = r.getRepositories();
+        assertNotNull(repos);
+        assertEquals(1, repos.length);
+        assertEquals(URI.create("urn:r1"), repos[0]);
+        // Check features
+        Feature[] features = r.getFeatures();
+        assertNotNull(features);
+        assertEquals(2, features.length);
+        assertNotNull(features[0]);
+        assertEquals("f1", features[0].getName());
+        assertNotNull(features[0].getConfigurations());
+        assertEquals(1, features[0].getConfigurations().size());
+        assertNotNull(features[0].getConfigurations().get("c1"));
+        assertEquals(1, features[0].getConfigurations().get("c1").size());
+        assertEquals("v", features[0].getConfigurations().get("c1").get("k"));
+        assertNotNull(features[0].getDependencies());
+        assertEquals(0, features[0].getDependencies().size());
+        assertNotNull(features[0].getBundles());
+        assertEquals(2, features[0].getBundles().size());
+        assertEquals("b1", features[0].getBundles().get(0));
+        assertEquals("b2", features[0].getBundles().get(1));
+        assertNotNull(features[1]);
+        assertEquals("f2", features[1].getName());
+        assertNotNull(features[1].getConfigurations());
+        assertEquals(0, features[1].getConfigurations().size());
+        assertNotNull(features[1].getDependencies());
+        assertEquals(1, features[1].getDependencies().size());
+        assertEquals("f1" + FeatureImpl.SPLIT_FOR_NAME_AND_VERSION + FeatureImpl.DEFAULT_VERSION, features[1].getDependencies().get(0).toString());
+        assertNotNull(features[1].getBundles());
+        assertEquals(1, features[1].getBundles().size());
+        assertEquals("b3", features[1].getBundles().get(0));
+    }
+    
+    public void testShowWrongUriInException() throws Exception {
+        String uri = "src/test/resources/org/apache/servicemix/kernel/gshell/features/repo1.xml";
+        RepositoryImpl r = new RepositoryImpl(new URI(uri));
+        try {
+            r.load();
+        } catch (Exception e) {
+            assertTrue(e.getMessage().contains(uri));
+        }
+    }
+}
diff --git a/karaf/gshell/gshell-features/src/test/java/org/apache/servicemix/kernel/gshell/features/internal/FeaturesServiceImplTest.java b/karaf/gshell/gshell-features/src/test/java/org/apache/servicemix/kernel/gshell/features/internal/FeaturesServiceImplTest.java
new file mode 100644
index 0000000..8ee87de
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/test/java/org/apache/servicemix/kernel/gshell/features/internal/FeaturesServiceImplTest.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.features.internal;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+import org.apache.servicemix.kernel.gshell.features.Feature;
+
+/**
+ * Test cases for {@link FeaturesServiceImpl}
+ */
+public class FeaturesServiceImplTest extends TestCase {
+    
+    public void testGetFeature() throws Exception {
+        final Map<String, Map<String, Feature>> features = new HashMap<String, Map<String,Feature>>();
+        Map<String, Feature> versions = new HashMap<String, Feature>();
+        FeatureImpl feature = new FeatureImpl("transaction");
+        versions.put("1.0.0", feature);
+        features.put("transaction", versions);
+        final FeaturesServiceImpl impl = new FeaturesServiceImpl() {
+            protected Map<String,Map<String,Feature>> getFeatures() throws Exception {
+                return features;
+            };
+        };
+        assertNotNull(impl.getFeature("transaction", FeatureImpl.DEFAULT_VERSION));
+        assertSame(feature, impl.getFeature("transaction", FeatureImpl.DEFAULT_VERSION));
+    }
+    
+    public void testGetFeatureNotAvailable() throws Exception {
+        final Map<String, Map<String, Feature>> features = new HashMap<String, Map<String,Feature>>();
+        Map<String, Feature> versions = new HashMap<String, Feature>();
+        versions.put("1.0.0", new FeatureImpl("transaction"));
+        features.put("transaction", versions);
+        final FeaturesServiceImpl impl = new FeaturesServiceImpl() {
+            protected Map<String,Map<String,Feature>> getFeatures() throws Exception {
+                return features;
+            };
+        };
+        assertNull(impl.getFeature("activemq", FeatureImpl.DEFAULT_VERSION));
+    }
+    
+    public void testGetFeatureHighestAvailable() throws Exception {
+        final Map<String, Map<String, Feature>> features = new HashMap<String, Map<String,Feature>>();
+        Map<String, Feature> versions = new HashMap<String, Feature>();
+        versions.put("1.0.0", new FeatureImpl("transaction", "1.0.0"));
+        versions.put("2.0.0", new FeatureImpl("transaction", "2.0.0"));
+        features.put("transaction", versions);
+        final FeaturesServiceImpl impl = new FeaturesServiceImpl() {
+            protected Map<String,Map<String,Feature>> getFeatures() throws Exception {
+                return features;
+            };
+        };
+        assertNotNull(impl.getFeature("transaction", FeatureImpl.DEFAULT_VERSION));
+        assertSame("2.0.0", impl.getFeature("transaction", FeatureImpl.DEFAULT_VERSION).getVersion());
+    }
+
+}
diff --git a/karaf/gshell/gshell-features/src/test/resources/org/apache/servicemix/kernel/gshell/features/repo1.xml b/karaf/gshell/gshell-features/src/test/resources/org/apache/servicemix/kernel/gshell/features/repo1.xml
new file mode 100644
index 0000000..ea21df9
--- /dev/null
+++ b/karaf/gshell/gshell-features/src/test/resources/org/apache/servicemix/kernel/gshell/features/repo1.xml
@@ -0,0 +1,31 @@
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<features>
+    <repository>urn:r1</repository>
+    <feature name="f1">
+        <config name="c1">
+            k=v
+        </config>
+        <bundle>b1</bundle>
+        <bundle>b2</bundle>
+    </feature>
+    <feature name="f2">
+        <feature>f1</feature>
+        <bundle>b3</bundle>
+    </feature>
+</features>
\ No newline at end of file
diff --git a/karaf/gshell/gshell-log/pom.xml b/karaf/gshell/gshell-log/pom.xml
new file mode 100644
index 0000000..04ca7bd
--- /dev/null
+++ b/karaf/gshell/gshell-log/pom.xml
@@ -0,0 +1,95 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <!--
+
+        Licensed to the Apache Software Foundation (ASF) under one or more
+        contributor license agreements.  See the NOTICE file distributed with
+        this work for additional information regarding copyright ownership.
+        The ASF licenses this file to You under the Apache License, Version 2.0
+        (the "License"); you may not use this file except in compliance with
+        the License.  You may obtain a copy of the License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software
+        distributed under the License is distributed on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        See the License for the specific language governing permissions and
+        limitations under the License.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.servicemix.kernel.gshell</groupId>
+        <artifactId>gshell</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.servicemix.kernel.gshell</groupId>
+    <artifactId>org.apache.servicemix.kernel.gshell.log</artifactId>
+    <packaging>bundle</packaging>
+    <version>1.2.0-SNAPSHOT</version>
+    <name>Apache ServiceMix Kernel :: GShell Log Commands</name>
+
+    <description>
+        Provides the OSGi Log commands
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel.gshell</groupId>
+            <artifactId>org.apache.servicemix.kernel.gshell.core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.osgi</groupId>
+            <artifactId>spring-osgi-core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.ops4j.pax.logging</groupId>
+            <artifactId>pax-logging-service</artifactId>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>${artifactId}</Bundle-SymbolicName>
+                        <Export-Package>
+                            org.apache.servicemix.kernel.gshell.log*;version=${project.version};-split-package:=merge-first
+                        </Export-Package>
+                        <Import-Package>
+                            org.apache.geronimo.gshell.wisdom.command,
+                            org.apache.geronimo.gshell.wisdom.registry,
+                            org.apache.servicemix.kernel.gshell.core,
+                            org.ops4j.pax.logging,
+                            *
+                        </Import-Package>
+                        <Private-Package>!*</Private-Package>
+                        <Spring-Context>*;publish-context:=false;create-asynchronously:=false</Spring-Context>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/DisplayException.java b/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/DisplayException.java
new file mode 100644
index 0000000..917e01c
--- /dev/null
+++ b/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/DisplayException.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.log;
+
+import org.apache.servicemix.kernel.gshell.core.OsgiCommandSupport;
+import org.ops4j.pax.logging.spi.PaxLoggingEvent;
+
+public class DisplayException extends OsgiCommandSupport {
+
+    protected LruList<PaxLoggingEvent> events;
+
+    public LruList<PaxLoggingEvent> getEvents() {
+        return events;
+    }
+
+    public void setEvents(LruList<PaxLoggingEvent> events) {
+        this.events = events;
+    }
+
+    protected Object doExecute() throws Exception {
+        PaxLoggingEvent throwableEvent = null;
+        Iterable<PaxLoggingEvent> le = events.getElements(Integer.MAX_VALUE);
+        for (PaxLoggingEvent event : le) {
+            if (event.getThrowableStrRep() != null) {
+                throwableEvent = event;
+                // Do not break, as we iterate from the oldest to the newest event
+            }
+        }
+        if (throwableEvent != null) {
+            for (String r : throwableEvent.getThrowableStrRep()) {
+                io.out.println(r);
+            }
+            io.out.println();
+        }
+        return Result.SUCCESS;
+    }
+
+}
diff --git a/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/DisplayLog.java b/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/DisplayLog.java
new file mode 100644
index 0000000..3beff07
--- /dev/null
+++ b/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/DisplayLog.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.log;
+
+import org.apache.geronimo.gshell.clp.Option;
+import org.apache.servicemix.kernel.gshell.core.OsgiCommandSupport;
+import org.apache.servicemix.kernel.gshell.log.layout.PatternConverter;
+import org.apache.servicemix.kernel.gshell.log.layout.PatternParser;
+import org.ops4j.pax.logging.spi.PaxLoggingEvent;
+
+/**
+ * Displays the last log entries
+ */
+public class DisplayLog extends OsgiCommandSupport {
+
+    @Option(name = "-n", description="Number of entries to display")
+    protected int entries;
+
+    @Option(name = "-p", description="Output formatting pattern")
+    protected String overridenPattern;
+
+    protected String pattern;
+
+    protected LruList<PaxLoggingEvent> events;
+
+    public LruList<PaxLoggingEvent> getEvents() {
+        return events;
+    }
+
+    public void setEvents(LruList<PaxLoggingEvent> events) {
+        this.events = events;
+    }
+
+    public String getPattern() {
+        return pattern;
+    }
+
+    public void setPattern(String pattern) {
+        this.pattern = pattern;
+    }
+
+    protected Object doExecute() throws Exception {
+        PatternConverter cnv = new PatternParser(overridenPattern != null ? overridenPattern : pattern).parse();
+
+        Iterable<PaxLoggingEvent> le = events.getElements(entries == 0 ? Integer.MAX_VALUE : entries);
+        StringBuffer sb = new StringBuffer();
+        for (PaxLoggingEvent event : le) {
+            sb.setLength(0);
+            for (PatternConverter pc = cnv; pc != null; pc = pc.next) {
+                pc.format(sb, event);
+            }
+            io.out.print(sb.toString());
+            if (event.getThrowableStrRep() != null) {
+                for (String r : event.getThrowableStrRep()) {
+                    io.out.println(r);
+                }
+            }
+        }
+        io.out.println();
+        
+        return Result.SUCCESS;
+    }
+
+}
diff --git a/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/GetLogLevel.java b/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/GetLogLevel.java
new file mode 100644
index 0000000..cf93797
--- /dev/null
+++ b/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/GetLogLevel.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.log;
+
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.apache.servicemix.kernel.gshell.core.OsgiCommandSupport;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+/**
+ * Get the log level for a given logger
+ */
+public class GetLogLevel extends OsgiCommandSupport {
+
+    @Argument(required = false, description = "Logger name, ALL or ROOT (default)")
+    String logger;
+
+    static final String CONFIGURATION_PID  = "org.ops4j.pax.logging";
+    static final String ROOT_LOGGER_PREFIX = "log4j.rootLogger";
+    static final String LOGGER_PREFIX      = "log4j.logger.";
+    static final String ALL_LOGGER         = "ALL";
+    static final String ROOT_LOGGER        = "ROOT";
+
+    protected Object doExecute() throws Exception {
+        ConfigurationAdmin cfgAdmin = getConfigAdmin();
+        Configuration cfg = cfgAdmin.getConfiguration(CONFIGURATION_PID, null);
+        Dictionary props = cfg.getProperties();
+
+        if (ROOT_LOGGER.equalsIgnoreCase(this.logger)) {
+            this.logger = null;
+        }
+        if (ALL_LOGGER.equalsIgnoreCase(logger)) {
+            String root = getLevel((String) props.get(ROOT_LOGGER_PREFIX));
+            Map<String, String> loggers = new TreeMap<String, String>();
+            for (Enumeration e = props.keys(); e.hasMoreElements();) {
+                String prop = (String) e.nextElement();
+                if (prop.startsWith(LOGGER_PREFIX)) {
+                    String val = getLevel((String) props.get(prop));
+                    loggers.put(prop.substring(LOGGER_PREFIX.length()), val);
+                }
+            }
+            io.out.println("ROOT: " + root);
+            for (String logger : loggers.keySet()) {
+                io.out.println(logger + ": " + loggers.get(logger));
+            }
+        } else {
+            String logger = this.logger;
+            String val;
+            for (;;) {
+                String prop;
+                if (logger == null) {
+                    prop = ROOT_LOGGER_PREFIX;
+                } else {
+                    prop = LOGGER_PREFIX + logger;
+                }
+                val = (String) props.get(prop);
+                val = getLevel(val);
+                if (val != null || logger == null) {
+                    break;
+                }
+                int idx = logger.lastIndexOf('.');
+                if (idx < 0) {
+                    logger = null;
+                } else {
+                    logger = logger.substring(0, idx);
+                }
+            }
+            String st = "Level: " + val;
+            if (logger != this.logger) {
+                st += " (inherited from " + (logger != null ? logger : "ROOT") + ")";
+            }
+            io.out.println(st);
+        }
+        return Result.SUCCESS;
+    }
+
+    protected String getLevel(String prop) {
+        if (prop == null) {
+            return null;
+        } else {
+            String val = prop.trim();
+            int idx = val.indexOf(",");
+            if (idx == 0) {
+                val = null;
+            } else if (idx > 0) {
+                val = val.substring(0, idx);
+            }
+            return val;
+        }
+    }
+
+    protected ConfigurationAdmin getConfigAdmin() {
+        ServiceReference ref = getBundleContext().getServiceReference(ConfigurationAdmin.class.getName());
+        return getService(ConfigurationAdmin.class, ref);
+    }
+
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/LruList.java b/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/LruList.java
new file mode 100644
index 0000000..a214a17
--- /dev/null
+++ b/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/LruList.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.servicemix.kernel.gshell.log;
+
+import java.util.Arrays;
+
+/**
+ * A list that only keep the last N elements added
+ */
+public class LruList<E> {
+
+    private E[] elements;
+    private transient int start = 0;
+    private transient int end = 0;
+    private transient boolean full = false;
+    private final int maxElements;
+
+    public LruList(int size) {
+        if (size <= 0) {
+            throw new IllegalArgumentException("The size must be greater than 0");
+        }
+        elements = (E[]) new Object[size];
+        maxElements = elements.length;
+    }
+
+    public int size() {
+        synchronized (elements) {
+            int size = 0;
+            if (end < start) {
+                size = maxElements - start + end;
+            } else if (end == start) {
+                size = (full ? maxElements : 0);
+            } else {
+                size = end - start;
+            }
+            return size;
+        }
+    }
+
+    public void add(E element) {
+        synchronized (elements) {
+            if (null == element) {
+                 throw new NullPointerException("Attempted to add null object to buffer");
+            }
+            if (size() == maxElements) {
+                Object e = elements[start];
+                if (null != e) {
+                    elements[start++] = null;
+                    if (start >= maxElements) {
+                        start = 0;
+                    }
+                    full = false;
+                }
+            }
+            elements[end++] = element;
+            if (end >= maxElements) {
+                end = 0;
+            }
+            if (end == start) {
+                full = true;
+            }
+        }
+    }
+
+    public Iterable<E> getElements() {
+        synchronized (elements) {
+            return getElements(size());
+        }
+    }
+
+    public Iterable<E> getElements(int nb) {
+        synchronized (elements) {
+            int s = size();
+            nb = Math.min(Math.max(0, nb), s);
+            E[] e = (E[]) new Object[nb];
+            for (int i = 0; i < nb; i++) {
+                e[i] = elements[(i + s - nb + start) % maxElements];
+            }
+            return Arrays.asList(e);
+        }
+    }
+
+}
diff --git a/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/SetLogLevel.java b/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/SetLogLevel.java
new file mode 100644
index 0000000..7da0f7f
--- /dev/null
+++ b/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/SetLogLevel.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.log;
+
+import java.util.Dictionary;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.apache.servicemix.kernel.gshell.core.OsgiCommandSupport;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+/**
+ * Set the log level for a given logger
+ */
+public class SetLogLevel extends OsgiCommandSupport {
+
+    @Argument(index = 0, required = true, description = "Level (TRACE, DEBUG, INFO, WARN, ERROR or - to unset")
+    String level;
+
+    @Argument(index = 1, required = false, description = "Logger name or ROOT (default)")
+    String logger;
+
+    static final String CONFIGURATION_PID  = "org.ops4j.pax.logging";
+    static final String ROOT_LOGGER_PREFIX = "log4j.rootLogger";
+    static final String LOGGER_PREFIX      = "log4j.logger.";
+    static final String ROOT_LOGGER        = "ROOT";
+
+    static final String TRACE = "TRACE";
+    static final String DEBUG = "DEBUG";
+    static final String INFO = "INFO";
+    static final String WARN = "WARN";
+    static final String ERROR = "ERROR";
+    static final String INHERITED = "-";
+
+    protected Object doExecute() throws Exception {
+        if (ROOT_LOGGER.equalsIgnoreCase(this.logger)) {
+            this.logger = null;
+        }
+        if (!TRACE.equals(level) &&
+                !DEBUG.equals(level) &&
+                !INFO.equals(level) &&
+                !WARN.equals(level) &&
+                !ERROR.equals(level) &&
+                !INHERITED.equals(level)) {
+            io.err.println("level must be set to TRACE, DEBUG, INFO, WARN or ERROR (or - to unset it)");
+            return Result.FAILURE;
+        }
+        if (INHERITED.equals(level) && logger == null) {
+            io.err.println("Can not unset the ROOT logger");
+            return Result.FAILURE;
+        }
+
+        ConfigurationAdmin cfgAdmin = getConfigAdmin();
+        Configuration cfg = cfgAdmin.getConfiguration(CONFIGURATION_PID, null);
+        Dictionary props = cfg.getProperties();
+
+        String logger = this.logger;
+        String val;
+        String prop;
+        if (logger == null) {
+            prop = ROOT_LOGGER_PREFIX;
+        } else {
+            prop = LOGGER_PREFIX + logger;
+        }
+        val = (String) props.get(prop);
+        if (INHERITED.equals(level)) {
+            if (val != null) {
+                val = val.trim();
+                int idx = val.indexOf(",");
+                if (idx > 0) {
+                    val = val.substring(idx);
+                } else {
+                    val = null;
+                }
+            }
+        } else {
+            if (val == null) {
+                val = level;
+            } else {
+                val = val.trim();
+                int idx = val.indexOf(",");
+                if (idx == 0) {
+                    val = level + val;
+                } else if (idx > 0) {
+                    val = level + val.substring(idx);
+                }
+            }
+        }
+        if (val == null) {
+            props.remove(prop);
+        } else {
+            props.put(prop, val);
+        }
+        cfg.update(props);
+
+        return Result.SUCCESS;
+    }
+
+    protected ConfigurationAdmin getConfigAdmin() {
+        ServiceReference ref = getBundleContext().getServiceReference(ConfigurationAdmin.class.getName());
+        return getService(ConfigurationAdmin.class, ref);
+    }
+
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/VmLogAppender.java b/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/VmLogAppender.java
new file mode 100644
index 0000000..a1607b4
--- /dev/null
+++ b/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/VmLogAppender.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.servicemix.kernel.gshell.log;
+
+import org.ops4j.pax.logging.spi.PaxAppender;
+import org.ops4j.pax.logging.spi.PaxLoggingEvent;
+
+/**
+ * A Pax Logging appender that keep a list of last events
+ */
+public class VmLogAppender implements PaxAppender {
+
+    protected LruList<PaxLoggingEvent> events;
+
+    public LruList<PaxLoggingEvent> getEvents() {
+        return events;
+    }
+
+    public void setEvents(LruList<PaxLoggingEvent> events) {
+        this.events = events;
+    }
+
+    public void doAppend(PaxLoggingEvent event) {
+        if (events != null) {
+            events.add(event);
+        }
+    }
+
+}
diff --git a/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/layout/AbsoluteTimeDateFormat.java b/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/layout/AbsoluteTimeDateFormat.java
new file mode 100644
index 0000000..03b81ff
--- /dev/null
+++ b/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/layout/AbsoluteTimeDateFormat.java
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.log.layout;
+
+import java.text.DateFormat;
+import java.text.FieldPosition;
+import java.text.ParsePosition;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
+
+/**
+ * Copied from log4j
+ */
+/**
+   Formats a {@link Date} in the format "HH:mm:ss,SSS" for example,
+   "15:49:37,459".
+
+   @author Ceki G&uuml;lc&uuml;
+   @author Andrew Vajoczki
+
+   @since 0.7.5
+*/
+public class AbsoluteTimeDateFormat extends DateFormat {
+
+  /**
+     String constant used to specify {@link
+     org.apache.log4j.helpers.AbsoluteTimeDateFormat} in layouts. Current
+     value is <b>ABSOLUTE</b>.  */
+  public final static String ABS_TIME_DATE_FORMAT = "ABSOLUTE";
+
+  /**
+     String constant used to specify {@link
+     org.apache.log4j.helpers.DateTimeDateFormat} in layouts.  Current
+     value is <b>DATE</b>.
+  */
+  public final static String DATE_AND_TIME_DATE_FORMAT = "DATE";
+
+  /**
+     String constant used to specify {@link
+     org.apache.log4j.helpers.ISO8601DateFormat} in layouts. Current
+     value is <b>ISO8601</b>.
+  */
+  public final static String ISO8601_DATE_FORMAT = "ISO8601";
+
+  public
+  AbsoluteTimeDateFormat() {
+    setCalendar(Calendar.getInstance());
+  }
+
+  public
+  AbsoluteTimeDateFormat(TimeZone timeZone) {
+    setCalendar(Calendar.getInstance(timeZone));
+  }
+
+  private static long   previousTime;
+  private static char[] previousTimeWithoutMillis = new char[9]; // "HH:mm:ss."
+
+  /**
+     Appends to <code>sbuf</code> the time in the format
+     "HH:mm:ss,SSS" for example, "15:49:37,459"
+
+     @param date the date to format
+     @param sbuf the string buffer to write to
+     @param fieldPosition remains untouched
+    */
+  public
+  StringBuffer format(Date date, StringBuffer sbuf,
+		      FieldPosition fieldPosition) {
+
+    long now = date.getTime();
+    int millis = (int)(now % 1000);
+
+    if ((now - millis) != previousTime) {
+      // We reach this point at most once per second
+      // across all threads instead of each time format()
+      // is called. This saves considerable CPU time.
+
+      calendar.setTime(date);
+
+      int start = sbuf.length();
+
+      int hour = calendar.get(Calendar.HOUR_OF_DAY);
+      if(hour < 10) {
+	sbuf.append('0');
+      }
+      sbuf.append(hour);
+      sbuf.append(':');
+
+      int mins = calendar.get(Calendar.MINUTE);
+      if(mins < 10) {
+	sbuf.append('0');
+      }
+      sbuf.append(mins);
+      sbuf.append(':');
+
+      int secs = calendar.get(Calendar.SECOND);
+      if(secs < 10) {
+	sbuf.append('0');
+      }
+      sbuf.append(secs);
+      sbuf.append(',');
+
+      // store the time string for next time to avoid recomputation
+      sbuf.getChars(start, sbuf.length(), previousTimeWithoutMillis, 0);
+
+      previousTime = now - millis;
+    }
+    else {
+      sbuf.append(previousTimeWithoutMillis);
+    }
+
+
+
+    if(millis < 100)
+      sbuf.append('0');
+    if(millis < 10)
+      sbuf.append('0');
+
+    sbuf.append(millis);
+    return sbuf;
+  }
+
+  /**
+     This method does not do anything but return <code>null</code>.
+   */
+  public
+  Date parse(String s, ParsePosition pos) {
+    return null;
+  }
+}
diff --git a/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/layout/DateTimeDateFormat.java b/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/layout/DateTimeDateFormat.java
new file mode 100644
index 0000000..0412ac8
--- /dev/null
+++ b/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/layout/DateTimeDateFormat.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.log.layout;
+
+import java.text.DateFormatSymbols;
+import java.text.FieldPosition;
+import java.text.ParsePosition;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
+
+/**
+ * Copied from log4j
+ */
+/**
+   Formats a {@link Date} in the format "dd MMM yyyy HH:mm:ss,SSS" for example,
+   "06 Nov 1994 15:49:37,459".
+
+   @author Ceki G&uuml;lc&uuml;
+   @since 0.7.5
+*/
+public class DateTimeDateFormat extends AbsoluteTimeDateFormat {
+
+  String[] shortMonths;
+
+  public
+  DateTimeDateFormat() {
+    super();
+    shortMonths = new DateFormatSymbols().getShortMonths();
+  }
+
+  public
+  DateTimeDateFormat(TimeZone timeZone) {
+    this();
+    setCalendar(Calendar.getInstance(timeZone));
+  }
+
+  /**
+     Appends to <code>sbuf</code> the date in the format "dd MMM yyyy
+     HH:mm:ss,SSS" for example, "06 Nov 1994 08:49:37,459".
+
+     @param sbuf the string buffer to write to
+  */
+  public
+  StringBuffer format(Date date, StringBuffer sbuf,
+		      FieldPosition fieldPosition) {
+
+    calendar.setTime(date);
+
+    int day = calendar.get(Calendar.DAY_OF_MONTH);
+    if(day < 10)
+      sbuf.append('0');
+    sbuf.append(day);
+    sbuf.append(' ');
+    sbuf.append(shortMonths[calendar.get(Calendar.MONTH)]);
+    sbuf.append(' ');
+
+    int year =  calendar.get(Calendar.YEAR);
+    sbuf.append(year);
+    sbuf.append(' ');
+
+    return super.format(date, sbuf, fieldPosition);
+  }
+
+  /**
+     This method does not do anything but return <code>null</code>.
+   */
+  public
+  Date parse(java.lang.String s, ParsePosition pos) {
+    return null;
+  }
+}
diff --git a/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/layout/FormattingInfo.java b/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/layout/FormattingInfo.java
new file mode 100644
index 0000000..b5d9dff
--- /dev/null
+++ b/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/layout/FormattingInfo.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.log.layout;
+
+
+/**
+ * Copied from log4j
+ */
+/**
+   FormattingInfo instances contain the information obtained when parsing
+   formatting modifiers in conversion modifiers.
+
+   @author <a href=mailto:jim_cakalic@na.biomerieux.com>Jim Cakalic</a>
+   @author Ceki G&uuml;lc&uuml;
+
+   @since 0.8.2
+ */
+public class FormattingInfo {
+  int min = -1;
+  int max = 0x7FFFFFFF;
+  boolean leftAlign = false;
+
+  void reset() {
+    min = -1;
+    max = 0x7FFFFFFF;
+    leftAlign = false;
+  }
+
+  void dump() {
+    //LogLog.debug("min="+min+", max="+max+", leftAlign="+leftAlign);
+  }
+}
+
diff --git a/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/layout/ISO8601DateFormat.java b/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/layout/ISO8601DateFormat.java
new file mode 100644
index 0000000..f19b8bd
--- /dev/null
+++ b/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/layout/ISO8601DateFormat.java
@@ -0,0 +1,155 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.log.layout;
+
+import java.text.FieldPosition;
+import java.text.ParsePosition;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
+
+/**
+ * Copied from log4j
+ */
+// Contributors: Arndt Schoenewald <arndt@ibm23093i821.mc.schoenewald.de>
+/**
+   Formats a {@link Date} in the format "yyyy-MM-dd HH:mm:ss,SSS" for example
+   "1999-11-27 15:49:37,459".
+
+   <p>Refer to the <a
+   href=http://www.cl.cam.ac.uk/~mgk25/iso-time.html>summary of the
+   International Standard Date and Time Notation</a> for more
+   information on this format.
+
+   @author Ceki G&uuml;lc&uuml;
+   @author Andrew Vajoczki
+
+   @since 0.7.5
+*/
+public class ISO8601DateFormat extends AbsoluteTimeDateFormat {
+
+  public
+  ISO8601DateFormat() {
+  }
+
+  public
+  ISO8601DateFormat(TimeZone timeZone) {
+    super(timeZone);
+  }
+
+  static private long   lastTime;
+  static private char[] lastTimeString = new char[20];
+
+  /**
+     Appends a date in the format "YYYY-mm-dd HH:mm:ss,SSS"
+     to <code>sbuf</code>. For example: "1999-11-27 15:49:37,459".
+
+     @param sbuf the <code>StringBuffer</code> to write to
+  */
+  public
+  StringBuffer format(Date date, StringBuffer sbuf,
+		      FieldPosition fieldPosition) {
+
+    long now = date.getTime();
+    int millis = (int)(now % 1000);
+
+    if ((now - millis) != lastTime) {
+      // We reach this point at most once per second
+      // across all threads instead of each time format()
+      // is called. This saves considerable CPU time.
+
+      calendar.setTime(date);
+
+      int start = sbuf.length();
+
+      int year =  calendar.get(Calendar.YEAR);
+      sbuf.append(year);
+
+      String month;
+      switch(calendar.get(Calendar.MONTH)) {
+      case Calendar.JANUARY: month = "-01-"; break;
+      case Calendar.FEBRUARY: month = "-02-";  break;
+      case Calendar.MARCH: month = "-03-"; break;
+      case Calendar.APRIL: month = "-04-";  break;
+      case Calendar.MAY: month = "-05-"; break;
+      case Calendar.JUNE: month = "-06-";  break;
+      case Calendar.JULY: month = "-07-"; break;
+      case Calendar.AUGUST: month = "-08-";  break;
+      case Calendar.SEPTEMBER: month = "-09-"; break;
+      case Calendar.OCTOBER: month = "-10-"; break;
+      case Calendar.NOVEMBER: month = "-11-";  break;
+      case Calendar.DECEMBER: month = "-12-";  break;
+      default: month = "-NA-"; break;
+      }
+      sbuf.append(month);
+
+      int day = calendar.get(Calendar.DAY_OF_MONTH);
+      if(day < 10)
+	sbuf.append('0');
+      sbuf.append(day);
+
+      sbuf.append(' ');
+
+      int hour = calendar.get(Calendar.HOUR_OF_DAY);
+      if(hour < 10) {
+	sbuf.append('0');
+      }
+      sbuf.append(hour);
+      sbuf.append(':');
+
+      int mins = calendar.get(Calendar.MINUTE);
+      if(mins < 10) {
+	sbuf.append('0');
+      }
+      sbuf.append(mins);
+      sbuf.append(':');
+
+      int secs = calendar.get(Calendar.SECOND);
+      if(secs < 10) {
+	sbuf.append('0');
+      }
+      sbuf.append(secs);
+
+      sbuf.append(',');
+
+      // store the time string for next time to avoid recomputation
+      sbuf.getChars(start, sbuf.length(), lastTimeString, 0);
+      lastTime = now - millis;
+    }
+    else {
+      sbuf.append(lastTimeString);
+    }
+
+
+    if (millis < 100)
+      sbuf.append('0');
+    if (millis < 10)
+      sbuf.append('0');
+
+    sbuf.append(millis);
+    return sbuf;
+  }
+
+  /**
+    This method does not do anything but return <code>null</code>.
+   */
+  public
+  Date parse(java.lang.String s, ParsePosition pos) {
+    return null;
+  }
+}
+
diff --git a/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/layout/PatternConverter.java b/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/layout/PatternConverter.java
new file mode 100644
index 0000000..1652d57
--- /dev/null
+++ b/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/layout/PatternConverter.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.log.layout;
+
+import org.ops4j.pax.logging.spi.PaxLoggingEvent;
+
+/**
+
+   <p>PatternConverter is an abtract class that provides the
+   formatting functionality that derived classes need.
+
+   <p>Conversion specifiers in a conversion patterns are parsed to
+   individual PatternConverters. Each of which is responsible for
+   converting a logging event in a converter specific manner.
+
+   @author <a href="mailto:cakalijp@Maritz.com">James P. Cakalic</a>
+   @author Ceki G&uuml;lc&uuml;
+
+   @since 0.8.2
+ */
+public abstract class PatternConverter {
+  public PatternConverter next;
+  int min = -1;
+  int max = 0x7FFFFFFF;
+  boolean leftAlign = false;
+
+  protected
+  PatternConverter() {  }
+
+  protected
+  PatternConverter(FormattingInfo fi) {
+    min = fi.min;
+    max = fi.max;
+    leftAlign = fi.leftAlign;
+  }
+
+  /**
+     Derived pattern converters must override this method in order to
+     convert conversion specifiers in the correct way.
+  */
+  abstract
+  protected
+  String convert(PaxLoggingEvent event);
+
+  /**
+     A template method for formatting in a converter specific way.
+   */
+  public
+  void format(StringBuffer sbuf, PaxLoggingEvent e) {
+    String s = convert(e);
+
+    if(s == null) {
+      if(0 < min)
+	spacePad(sbuf, min);
+      return;
+    }
+
+    int len = s.length();
+
+    if(len > max)
+      sbuf.append(s.substring(len-max));
+    else if(len < min) {
+      if(leftAlign) {
+	sbuf.append(s);
+	spacePad(sbuf, min-len);
+      }
+      else {
+	spacePad(sbuf, min-len);
+	sbuf.append(s);
+      }
+    }
+    else
+      sbuf.append(s);
+  }
+
+  static String[] SPACES = {" ", "  ", "    ", "        ", //1,2,4,8 spaces
+			    "                ", // 16 spaces
+			    "                                " }; // 32 spaces
+
+  /**
+     Fast space padding method.
+  */
+  public
+  void spacePad(StringBuffer sbuf, int length) {
+    while(length >= 32) {
+      sbuf.append(SPACES[5]);
+      length -= 32;
+    }
+
+    for(int i = 4; i >= 0; i--) {
+      if((length & (1<<i)) != 0) {
+	sbuf.append(SPACES[i]);
+      }
+    }
+  }
+}
diff --git a/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/layout/PatternParser.java b/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/layout/PatternParser.java
new file mode 100644
index 0000000..4a74fd1
--- /dev/null
+++ b/karaf/gshell/gshell-log/src/main/java/org/apache/servicemix/kernel/gshell/log/layout/PatternParser.java
@@ -0,0 +1,527 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.log.layout;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.apache.log4j.spi.LoggingEvent;
+import org.ops4j.pax.logging.spi.PaxLocationInfo;
+import org.ops4j.pax.logging.spi.PaxLoggingEvent;
+
+/**
+ * Copied from log4j
+ */
+// Contributors:   Nelson Minar <(nelson@monkey.org>
+//                 Igor E. Poteryaev <jah@mail.ru>
+//                 Reinhard Deschler <reinhard.deschler@web.de>
+/**
+   Most of the work of the {@link org.apache.log4j.PatternLayout} class
+   is delegated to the PatternParser class.
+
+   @author <a href=mailto:"cakalijp@Maritz.com">James P. Cakalic</a>
+   @author Ceki G&uuml;lc&uuml;
+   @author Anders Kristensen
+
+   @since 0.8.2
+*/
+public class PatternParser {
+
+  private static final String LINE_SEP = System.getProperty("line.separator");
+
+  private static final char ESCAPE_CHAR = '%';
+
+  private static final int LITERAL_STATE = 0;
+  private static final int CONVERTER_STATE = 1;
+  private static final int MINUS_STATE = 2;
+  private static final int DOT_STATE = 3;
+  private static final int MIN_STATE = 4;
+  private static final int MAX_STATE = 5;
+
+  static final int FULL_LOCATION_CONVERTER = 1000;
+  static final int METHOD_LOCATION_CONVERTER = 1001;
+  static final int CLASS_LOCATION_CONVERTER = 1002;
+  static final int LINE_LOCATION_CONVERTER = 1003;
+  static final int FILE_LOCATION_CONVERTER = 1004;
+
+  static final int RELATIVE_TIME_CONVERTER = 2000;
+  static final int THREAD_CONVERTER = 2001;
+  static final int LEVEL_CONVERTER = 2002;
+  static final int NDC_CONVERTER = 2003;
+  static final int MESSAGE_CONVERTER = 2004;
+
+  int state;
+  protected StringBuffer currentLiteral = new StringBuffer(32);
+  protected int patternLength;
+  protected int i;
+  PatternConverter head;
+  PatternConverter tail;
+  protected FormattingInfo formattingInfo = new FormattingInfo();
+  protected String pattern;
+
+  public
+  PatternParser(String pattern) {
+    this.pattern = pattern;
+    patternLength =  pattern.length();
+    state = LITERAL_STATE;
+  }
+
+  private
+  void  addToList(PatternConverter pc) {
+    if(head == null) {
+      head = tail = pc;
+    } else {
+      tail.next = pc;
+      tail = pc;
+    }
+  }
+
+  protected
+  String extractOption() {
+    if((i < patternLength) && (pattern.charAt(i) == '{')) {
+      int end = pattern.indexOf('}', i);
+      if (end > i) {
+	String r = pattern.substring(i + 1, end);
+	i = end+1;
+	return r;
+      }
+    }
+    return null;
+  }
+
+
+  /**
+     The option is expected to be in decimal and positive. In case of
+     error, zero is returned.  */
+  protected
+  int extractPrecisionOption() {
+    String opt = extractOption();
+    int r = 0;
+    if(opt != null) {
+      try {
+	r = Integer.parseInt(opt);
+	if(r <= 0) {
+	    //LogLog.error("Precision option (" + opt + ") isn't a positive integer.");
+	    r = 0;
+	}
+      }
+      catch (NumberFormatException e) {
+	//LogLog.error("Category option \""+opt+"\" not a decimal integer.", e);
+      }
+    }
+    return r;
+  }
+
+  public
+  PatternConverter parse() {
+    char c;
+    i = 0;
+    while(i < patternLength) {
+      c = pattern.charAt(i++);
+      switch(state) {
+      case LITERAL_STATE:
+        // In literal state, the last char is always a literal.
+        if(i == patternLength) {
+          currentLiteral.append(c);
+          continue;
+        }
+        if(c == ESCAPE_CHAR) {
+          // peek at the next char.
+          switch(pattern.charAt(i)) {
+          case ESCAPE_CHAR:
+            currentLiteral.append(c);
+            i++; // move pointer
+            break;
+          case 'n':
+            currentLiteral.append(LINE_SEP);
+            i++; // move pointer
+            break;
+          default:
+            if(currentLiteral.length() != 0) {
+              addToList(new LiteralPatternConverter(
+                                                  currentLiteral.toString()));
+              //LogLog.debug("Parsed LITERAL converter: \""
+              //           +currentLiteral+"\".");
+            }
+            currentLiteral.setLength(0);
+            currentLiteral.append(c); // append %
+            state = CONVERTER_STATE;
+            formattingInfo.reset();
+          }
+        }
+        else {
+          currentLiteral.append(c);
+        }
+        break;
+      case CONVERTER_STATE:
+	currentLiteral.append(c);
+	switch(c) {
+	case '-':
+	  formattingInfo.leftAlign = true;
+	  break;
+	case '.':
+	  state = DOT_STATE;
+	  break;
+	default:
+	  if(c >= '0' && c <= '9') {
+	    formattingInfo.min = c - '0';
+	    state = MIN_STATE;
+	  }
+	  else
+	    finalizeConverter(c);
+	} // switch
+	break;
+      case MIN_STATE:
+	currentLiteral.append(c);
+	if(c >= '0' && c <= '9')
+	  formattingInfo.min = formattingInfo.min*10 + (c - '0');
+	else if(c == '.')
+	  state = DOT_STATE;
+	else {
+	  finalizeConverter(c);
+	}
+	break;
+      case DOT_STATE:
+	currentLiteral.append(c);
+	if(c >= '0' && c <= '9') {
+	  formattingInfo.max = c - '0';
+	   state = MAX_STATE;
+	}
+	else {
+	  //LogLog.error("Error occured in position "+i+".\n Was expecting digit, instead got char \""+c+"\".");
+	  state = LITERAL_STATE;
+	}
+	break;
+      case MAX_STATE:
+	currentLiteral.append(c);
+	if(c >= '0' && c <= '9')
+	  formattingInfo.max = formattingInfo.max*10 + (c - '0');
+	else {
+	  finalizeConverter(c);
+	  state = LITERAL_STATE;
+	}
+	break;
+      } // switch
+    } // while
+    if(currentLiteral.length() != 0) {
+      addToList(new LiteralPatternConverter(currentLiteral.toString()));
+      //LogLog.debug("Parsed LITERAL converter: \""+currentLiteral+"\".");
+    }
+    return head;
+  }
+
+  protected
+  void finalizeConverter(char c) {
+    PatternConverter pc = null;
+    switch(c) {
+    case 'c':
+      pc = new CategoryPatternConverter(formattingInfo,
+					extractPrecisionOption());
+      //LogLog.debug("CATEGORY converter.");
+      //formattingInfo.dump();
+      currentLiteral.setLength(0);
+      break;
+    case 'C':
+      pc = new ClassNamePatternConverter(formattingInfo,
+					 extractPrecisionOption());
+      //LogLog.debug("CLASS_NAME converter.");
+      //formattingInfo.dump();
+      currentLiteral.setLength(0);
+      break;
+    case 'd':
+      String dateFormatStr = AbsoluteTimeDateFormat.ISO8601_DATE_FORMAT;
+      DateFormat df;
+      String dOpt = extractOption();
+      if(dOpt != null)
+	dateFormatStr = dOpt;
+
+      if(dateFormatStr.equalsIgnoreCase(
+                                    AbsoluteTimeDateFormat.ISO8601_DATE_FORMAT))
+	df = new  ISO8601DateFormat();
+      else if(dateFormatStr.equalsIgnoreCase(
+                                   AbsoluteTimeDateFormat.ABS_TIME_DATE_FORMAT))
+	df = new AbsoluteTimeDateFormat();
+      else if(dateFormatStr.equalsIgnoreCase(
+                              AbsoluteTimeDateFormat.DATE_AND_TIME_DATE_FORMAT))
+	df = new DateTimeDateFormat();
+      else {
+	try {
+	  df = new SimpleDateFormat(dateFormatStr);
+	}
+	catch (IllegalArgumentException e) {
+	  //LogLog.error("Could not instantiate SimpleDateFormat with " + dateFormatStr, e);
+	  df = new ISO8601DateFormat();
+	}
+      }
+      pc = new DatePatternConverter(formattingInfo, df);
+      //LogLog.debug("DATE converter {"+dateFormatStr+"}.");
+      //formattingInfo.dump();
+      currentLiteral.setLength(0);
+      break;
+    case 'F':
+      pc = new LocationPatternConverter(formattingInfo,
+					FILE_LOCATION_CONVERTER);
+      //LogLog.debug("File name converter.");
+      //formattingInfo.dump();
+      currentLiteral.setLength(0);
+      break;
+    /*case 'l':
+      pc = new LocationPatternConverter(formattingInfo,
+					FULL_LOCATION_CONVERTER);
+      //LogLog.debug("Location converter.");
+      //formattingInfo.dump();
+      currentLiteral.setLength(0);
+      break;*/
+    case 'L':
+      pc = new LocationPatternConverter(formattingInfo,
+					LINE_LOCATION_CONVERTER);
+      //LogLog.debug("LINE NUMBER converter.");
+      //formattingInfo.dump();
+      currentLiteral.setLength(0);
+      break;
+    case 'm':
+      pc = new BasicPatternConverter(formattingInfo, MESSAGE_CONVERTER);
+      //LogLog.debug("MESSAGE converter.");
+      //formattingInfo.dump();
+      currentLiteral.setLength(0);
+      break;
+    case 'M':
+      pc = new LocationPatternConverter(formattingInfo,
+					METHOD_LOCATION_CONVERTER);
+      //LogLog.debug("METHOD converter.");
+      //formattingInfo.dump();
+      currentLiteral.setLength(0);
+      break;
+    case 'p':
+      pc = new BasicPatternConverter(formattingInfo, LEVEL_CONVERTER);
+      //LogLog.debug("LEVEL converter.");
+      //formattingInfo.dump();
+      currentLiteral.setLength(0);
+      break;
+    case 'r':
+      pc = new BasicPatternConverter(formattingInfo,
+					 RELATIVE_TIME_CONVERTER);
+      //LogLog.debug("RELATIVE time converter.");
+      //formattingInfo.dump();
+      currentLiteral.setLength(0);
+      break;
+    case 't':
+      pc = new BasicPatternConverter(formattingInfo, THREAD_CONVERTER);
+      //LogLog.debug("THREAD converter.");
+      //formattingInfo.dump();
+      currentLiteral.setLength(0);
+      break;
+      /*case 'u':
+      if(i < patternLength) {
+	char cNext = pattern.charAt(i);
+	if(cNext >= '0' && cNext <= '9') {
+	  pc = new UserFieldPatternConverter(formattingInfo, cNext - '0');
+	  LogLog.debug("USER converter ["+cNext+"].");
+	  formattingInfo.dump();
+	  currentLiteral.setLength(0);
+	  i++;
+	}
+	else
+	  LogLog.error("Unexpected char" +cNext+" at position "+i);
+      }
+      break;*/
+    /*case 'x':
+      pc = new BasicPatternConverter(formattingInfo, NDC_CONVERTER);
+      //LogLog.debug("NDC converter.");
+      currentLiteral.setLength(0);
+      break;
+    case 'X':
+      String xOpt = extractOption();
+      pc = new MDCPatternConverter(formattingInfo, xOpt);
+      currentLiteral.setLength(0);
+      break;*/
+    default:
+      //LogLog.error("Unexpected char [" +c+"] at position "+i+" in conversion patterrn.");
+      pc = new LiteralPatternConverter(currentLiteral.toString());
+      currentLiteral.setLength(0);
+    }
+
+    addConverter(pc);
+  }
+
+  protected
+  void addConverter(PatternConverter pc) {
+    currentLiteral.setLength(0);
+    // Add the pattern converter to the list.
+    addToList(pc);
+    // Next pattern is assumed to be a literal.
+    state = LITERAL_STATE;
+    // Reset formatting info
+    formattingInfo.reset();
+  }
+
+  // ---------------------------------------------------------------------
+  //                      PatternConverters
+  // ---------------------------------------------------------------------
+
+  private static class BasicPatternConverter extends PatternConverter {
+    int type;
+
+    BasicPatternConverter(FormattingInfo formattingInfo, int type) {
+      super(formattingInfo);
+      this.type = type;
+    }
+
+    public
+    String convert(PaxLoggingEvent event) {
+      switch(type) {
+      case RELATIVE_TIME_CONVERTER:
+	return (Long.toString(event.getTimeStamp() - LoggingEvent.getStartTime()));
+      case THREAD_CONVERTER:
+	return event.getThreadName();
+      case LEVEL_CONVERTER:
+	return event.getLevel().toString();
+    //  case NDC_CONVERTER:
+	//return event.getNDC();
+      case MESSAGE_CONVERTER: {
+	return event.getRenderedMessage();
+      }
+      default: return null;
+      }
+    }
+  }
+
+  private static class LiteralPatternConverter extends PatternConverter {
+    private String literal;
+
+    LiteralPatternConverter(String value) {
+      literal = value;
+    }
+
+    public
+    final
+    void format(StringBuffer sbuf, LoggingEvent event) {
+      sbuf.append(literal);
+    }
+
+    public
+    String convert(PaxLoggingEvent event) {
+      return literal;
+    }
+  }
+
+  private static class DatePatternConverter extends PatternConverter {
+    private DateFormat df;
+    private Date date;
+
+    DatePatternConverter(FormattingInfo formattingInfo, DateFormat df) {
+      super(formattingInfo);
+      date = new Date();
+      this.df = df;
+    }
+
+    public
+    String convert(PaxLoggingEvent event) {
+      date.setTime(event.getTimeStamp());
+      String converted = null;
+      try {
+        converted = df.format(date);
+      }
+      catch (Exception ex) {
+        //LogLog.error("Error occured while converting date.", ex);
+      }
+      return converted;
+    }
+  }
+
+  private class LocationPatternConverter extends PatternConverter {
+    int type;
+
+    LocationPatternConverter(FormattingInfo formattingInfo, int type) {
+      super(formattingInfo);
+      this.type = type;
+    }
+
+    public
+    String convert(PaxLoggingEvent event) {
+      PaxLocationInfo locationInfo = event.getLocationInformation();
+      switch(type) {
+      /*case FULL_LOCATION_CONVERTER:
+	return locationInfo.fullInfo;*/
+      case METHOD_LOCATION_CONVERTER:
+	return locationInfo.getMethodName();
+      case LINE_LOCATION_CONVERTER:
+	return locationInfo.getLineNumber();
+      case FILE_LOCATION_CONVERTER:
+	return locationInfo.getFileName();
+      default: return null;
+      }
+    }
+  }
+
+  private static abstract class NamedPatternConverter extends PatternConverter {
+    int precision;
+
+    NamedPatternConverter(FormattingInfo formattingInfo, int precision) {
+      super(formattingInfo);
+      this.precision =  precision;
+    }
+
+    abstract
+    String getFullyQualifiedName(PaxLoggingEvent event);
+
+    public
+    String convert(PaxLoggingEvent event) {
+      String n = getFullyQualifiedName(event);
+      if(precision <= 0)
+	return n;
+      else {
+	int len = n.length();
+
+	// We substract 1 from 'len' when assigning to 'end' to avoid out of
+	// bounds exception in return r.substring(end+1, len). This can happen if
+	// precision is 1 and the category name ends with a dot.
+	int end = len -1 ;
+	for(int i = precision; i > 0; i--) {
+	  end = n.lastIndexOf('.', end-1);
+	  if(end == -1)
+	    return n;
+	}
+	return n.substring(end+1, len);
+      }
+    }
+  }
+
+  private class ClassNamePatternConverter extends NamedPatternConverter {
+
+    ClassNamePatternConverter(FormattingInfo formattingInfo, int precision) {
+      super(formattingInfo, precision);
+    }
+
+    String getFullyQualifiedName(PaxLoggingEvent event) {
+      return event.getLocationInformation().getClassName();
+    }
+  }
+
+  private class CategoryPatternConverter extends NamedPatternConverter {
+
+    CategoryPatternConverter(FormattingInfo formattingInfo, int precision) {
+      super(formattingInfo, precision);
+    }
+
+    String getFullyQualifiedName(PaxLoggingEvent event) {
+      return event.getLoggerName();
+    }
+  }
+}
+
diff --git a/karaf/gshell/gshell-log/src/main/resources/META-INF/spring/gshell-log.xml b/karaf/gshell/gshell-log/src/main/resources/META-INF/spring/gshell-log.xml
new file mode 100644
index 0000000..2055fe4
--- /dev/null
+++ b/karaf/gshell/gshell-log/src/main/resources/META-INF/spring/gshell-log.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:ctx="http://www.springframework.org/schema/context"
+       xmlns:osgi="http://www.springframework.org/schema/osgi"
+       xmlns:osgix="http://www.springframework.org/schema/osgi-compendium"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xmlns:gshell="http://servicemix.apache.org/schema/servicemix-gshell"
+       xsi:schemaLocation="
+  http://www.springframework.org/schema/beans
+  http://www.springframework.org/schema/beans/spring-beans.xsd
+  http://www.springframework.org/schema/context
+  http://www.springframework.org/schema/context/spring-context.xsd
+  http://www.springframework.org/schema/osgi
+  http://www.springframework.org/schema/osgi/spring-osgi.xsd
+  http://www.springframework.org/schema/osgi-compendium
+  http://www.springframework.org/schema/osgi-compendium/spring-osgi-compendium.xsd
+  http://www.springframework.org/schema/util
+  http://www.springframework.org/schema/util/spring-util.xsd
+  http://servicemix.apache.org/schema/servicemix-gshell
+  http://servicemix.apache.org/schema/servicemix-gshell/servicemix-gshell.xsd">
+
+    <import resource="classpath:org/apache/servicemix/kernel/gshell/core/commands.xml" />
+
+    <gshell:command-bundle>
+        <gshell:command name="log/display">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.log.DisplayLog">
+                <property name="events" ref="events" />
+                <property name="pattern" value="${pattern}" />
+            </gshell:action>
+        </gshell:command>
+        <gshell:link name="log/d" target="log/display" />
+        <gshell:command name="log/display-exception">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.log.DisplayException">
+                <property name="events" ref="events" />
+            </gshell:action>
+        </gshell:command>
+        <gshell:link name="log/de" target="log/display-exception" />
+        <gshell:command name="log/get">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.log.GetLogLevel" />
+        </gshell:command>
+        <gshell:command name="log/set">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.log.SetLogLevel" />
+        </gshell:command>
+
+        <gshell:alias name="ld" alias="log/d" />
+        <gshell:alias name="lde" alias="log/de" />
+    </gshell:command-bundle>
+
+    <bean id="vmLogAppender" class="org.apache.servicemix.kernel.gshell.log.VmLogAppender">
+        <property name="events" ref="events" />
+    </bean>
+
+    <bean id="events" class="org.apache.servicemix.kernel.gshell.log.LruList">
+        <constructor-arg value="${size}" />
+    </bean>
+
+    <osgi:service ref="vmLogAppender" interface="org.ops4j.pax.logging.spi.PaxAppender">
+        <osgi:service-properties>
+            <entry>
+                <key><util:constant static-field="org.ops4j.pax.logging.PaxLoggingService.APPENDER_NAME_PROPERTY"/></key>
+                <value>VmLogAppender</value>
+            </entry>
+        </osgi:service-properties>
+    </osgi:service>
+
+    <osgix:cm-properties id="cmProps" persistent-id="org.apache.servicemix.log">
+        <prop key="size">500</prop>
+        <prop key="pattern">%d{ABSOLUTE} | %-5.5p | %-16.16t | %-32.32c{1} | %-32.32C %4L | %m%n</prop>
+    </osgix:cm-properties>
+
+    <ctx:property-placeholder properties-ref="cmProps" />
+
+</beans>
\ No newline at end of file
diff --git a/karaf/gshell/gshell-log/src/main/resources/org/apache/servicemix/kernel/gshell/log/DisplayException.properties b/karaf/gshell/gshell-log/src/main/resources/org/apache/servicemix/kernel/gshell/log/DisplayException.properties
new file mode 100644
index 0000000..ff84091
--- /dev/null
+++ b/karaf/gshell/gshell-log/src/main/resources/org/apache/servicemix/kernel/gshell/log/DisplayException.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Display the last exception from the log.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-log/src/main/resources/org/apache/servicemix/kernel/gshell/log/DisplayLog.properties b/karaf/gshell/gshell-log/src/main/resources/org/apache/servicemix/kernel/gshell/log/DisplayLog.properties
new file mode 100644
index 0000000..d360b1a
--- /dev/null
+++ b/karaf/gshell/gshell-log/src/main/resources/org/apache/servicemix/kernel/gshell/log/DisplayLog.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Display log entries.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-log/src/main/resources/org/apache/servicemix/kernel/gshell/log/GetLogLevel.properties b/karaf/gshell/gshell-log/src/main/resources/org/apache/servicemix/kernel/gshell/log/GetLogLevel.properties
new file mode 100644
index 0000000..94ee1d3
--- /dev/null
+++ b/karaf/gshell/gshell-log/src/main/resources/org/apache/servicemix/kernel/gshell/log/GetLogLevel.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Show log level.
+
+command.manual=\
+  TODO: date manual
diff --git a/karaf/gshell/gshell-log/src/main/resources/org/apache/servicemix/kernel/gshell/log/SetLogLevel.properties b/karaf/gshell/gshell-log/src/main/resources/org/apache/servicemix/kernel/gshell/log/SetLogLevel.properties
new file mode 100644
index 0000000..511734b
--- /dev/null
+++ b/karaf/gshell/gshell-log/src/main/resources/org/apache/servicemix/kernel/gshell/log/SetLogLevel.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Set log level.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-obr/pom.xml b/karaf/gshell/gshell-obr/pom.xml
new file mode 100644
index 0000000..58cc9e8
--- /dev/null
+++ b/karaf/gshell/gshell-obr/pom.xml
@@ -0,0 +1,85 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <!--
+
+        Licensed to the Apache Software Foundation (ASF) under one or more
+        contributor license agreements.  See the NOTICE file distributed with
+        this work for additional information regarding copyright ownership.
+        The ASF licenses this file to You under the Apache License, Version 2.0
+        (the "License"); you may not use this file except in compliance with
+        the License.  You may obtain a copy of the License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software
+        distributed under the License is distributed on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        See the License for the specific language governing permissions and
+        limitations under the License.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.servicemix.kernel.gshell</groupId>
+        <artifactId>gshell</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.servicemix.kernel.gshell</groupId>
+    <artifactId>org.apache.servicemix.kernel.gshell.obr</artifactId>
+    <packaging>bundle</packaging>
+    <version>1.2.0-SNAPSHOT</version>
+    <name>Apache ServiceMix Kernel :: GShell OBR Commands</name>
+
+    <description>
+        Provides the OBR GShell commands
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.bundlerepository</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.servicemix.kernel.gshell</groupId>
+            <artifactId>org.apache.servicemix.kernel.gshell.core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.osgi</groupId>
+            <artifactId>spring-osgi-core</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>${artifactId}</Bundle-SymbolicName>
+                        <Export-Package>org.apache.servicemix.kernel.gshell.obr*;version=${project.version}</Export-Package>
+                        <Import-Package>
+                            org.apache.geronimo.gshell.wisdom.command,
+                            org.apache.geronimo.gshell.wisdom.registry,
+                            org.apache.servicemix.kernel.gshell.core,
+                            *
+                        </Import-Package>
+                        <Private-Package>!*</Private-Package>
+                        <Spring-Context>*;publish-context:=false;create-asynchronously:=false</Spring-Context>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/AddUrlCommand.java b/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/AddUrlCommand.java
new file mode 100644
index 0000000..d416674
--- /dev/null
+++ b/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/AddUrlCommand.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.obr;
+
+import java.net.URL;
+import java.util.List;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.osgi.service.obr.RepositoryAdmin;
+
+public class AddUrlCommand extends ObrCommandSupport {
+
+    @Argument(required = true, multiValued = true, description = "Repository URLs")
+    List<String> urls;
+
+    protected void doExecute(RepositoryAdmin admin) throws Exception {
+        for (String url : urls) {
+            admin.addRepository(new URL(url));
+        }
+    }
+}
diff --git a/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/DeployCommand.java b/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/DeployCommand.java
new file mode 100644
index 0000000..7bbd1dc
--- /dev/null
+++ b/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/DeployCommand.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.obr;
+
+import java.util.List;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.osgi.service.obr.RepositoryAdmin;
+
+public class DeployCommand extends ObrCommandSupport {
+
+    @Argument(required = true, multiValued = true, description = "List of bundles")
+    protected List<String> bundles;
+
+    protected void doExecute(RepositoryAdmin admin) throws Exception {
+        doDeploy(admin, bundles, false);
+    }
+
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/FileUtil.java b/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/FileUtil.java
new file mode 100644
index 0000000..344e592
--- /dev/null
+++ b/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/FileUtil.java
@@ -0,0 +1,177 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.servicemix.kernel.gshell.obr;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+
+public class FileUtil
+{
+    public static void downloadSource(
+        PrintWriter out, PrintWriter err,
+        URL srcURL, String dirStr, boolean extract)
+    {
+        // Get the file name from the URL.
+        String fileName = (srcURL.getFile().lastIndexOf('/') > 0)
+            ? srcURL.getFile().substring(srcURL.getFile().lastIndexOf('/') + 1)
+            : srcURL.getFile();
+
+        try
+        {
+            out.println("Connecting...");
+
+            File dir = new File(dirStr);
+            if (!dir.exists())
+            {
+                err.println("Destination directory does not exist.");
+            }
+            File file = new File(dir, fileName);
+
+            OutputStream os = new FileOutputStream(file);
+            URLConnection conn = srcURL.openConnection();
+            int total = conn.getContentLength();
+            InputStream is = conn.getInputStream();
+
+            if (total > 0)
+            {
+                out.println("Downloading " + fileName
+                    + " ( " + total + " bytes ).");
+            }
+            else
+            {
+                out.println("Downloading " + fileName + ".");
+            }
+            byte[] buffer = new byte[4096];
+            int count = 0;
+            for (int len = is.read(buffer); len > 0; len = is.read(buffer))
+            {
+                count += len;
+                os.write(buffer, 0, len);
+            }
+
+            os.close();
+            is.close();
+
+            if (extract)
+            {
+                is = new FileInputStream(file);
+                JarInputStream jis = new JarInputStream(is);
+                out.println("Extracting...");
+                unjar(jis, dir);
+                jis.close();
+                file.delete();
+            }
+        }
+        catch (Exception ex)
+        {
+            err.println(ex);
+        }
+    }
+
+    public static void unjar(JarInputStream jis, File dir)
+        throws IOException
+    {
+        // Reusable buffer.
+        byte[] buffer = new byte[4096];
+
+        // Loop through JAR entries.
+        for (JarEntry je = jis.getNextJarEntry();
+             je != null;
+             je = jis.getNextJarEntry())
+        {
+            if (je.getName().startsWith("/"))
+            {
+                throw new IOException("JAR resource cannot contain absolute paths.");
+            }
+
+            File target = new File(dir, je.getName());
+
+            // Check to see if the JAR entry is a directory.
+            if (je.isDirectory())
+            {
+                if (!target.exists())
+                {
+                    if (!target.mkdirs())
+                    {
+                        throw new IOException("Unable to create target directory: "
+                            + target);
+                    }
+                }
+                // Just continue since directories do not have content to copy.
+                continue;
+            }
+
+            int lastIndex = je.getName().lastIndexOf('/');
+            String name = (lastIndex >= 0) ?
+                je.getName().substring(lastIndex + 1) : je.getName();
+            String destination = (lastIndex >= 0) ?
+                je.getName().substring(0, lastIndex) : "";
+
+            // JAR files use '/', so convert it to platform separator.
+            destination = destination.replace('/', File.separatorChar);
+            copy(jis, dir, name, destination, buffer);
+        }
+    }
+
+    public static void copy(
+        InputStream is, File dir, String destName, String destDir, byte[] buffer)
+        throws IOException
+    {
+        if (destDir == null)
+        {
+            destDir = "";
+        }
+
+        // Make sure the target directory exists and
+        // that is actually a directory.
+        File targetDir = new File(dir, destDir);
+        if (!targetDir.exists())
+        {
+            if (!targetDir.mkdirs())
+            {
+                throw new IOException("Unable to create target directory: "
+                    + targetDir);
+            }
+        }
+        else if (!targetDir.isDirectory())
+        {
+            throw new IOException("Target is not a directory: "
+                + targetDir);
+        }
+
+        BufferedOutputStream bos = new BufferedOutputStream(
+            new FileOutputStream(new File(targetDir, destName)));
+        int count = 0;
+        while ((count = is.read(buffer)) > 0)
+        {
+            bos.write(buffer, 0, count);
+        }
+        bos.close();
+    }
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/InfoCommand.java b/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/InfoCommand.java
new file mode 100644
index 0000000..50ede86
--- /dev/null
+++ b/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/InfoCommand.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.obr;
+
+import java.io.PrintWriter;
+import java.lang.reflect.Array;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.osgi.service.obr.Capability;
+import org.osgi.service.obr.RepositoryAdmin;
+import org.osgi.service.obr.Requirement;
+import org.osgi.service.obr.Resource;
+
+public class InfoCommand extends ObrCommandSupport {
+
+    @Argument(required = true, multiValued = true)
+    List<String> bundles;
+
+    protected void doExecute(RepositoryAdmin admin) throws Exception {
+        for (String bundle : bundles) {
+            String[] target = getTarget(bundle);
+            Resource[] resources = searchRepository(admin, target[0], target[1]);
+            if (resources == null)
+            {
+                io.err.println("Unknown bundle and/or version: "
+                    + target[0]);
+            }
+            else
+            {
+                for (int resIdx = 0; resIdx < resources.length; resIdx++)
+                {
+                    if (resIdx > 0)
+                    {
+                        io.out.println("");
+                    }
+                    printResource(io.out, resources[resIdx]);
+                }
+            }
+        }
+    }
+
+    private void printResource(PrintWriter out, Resource resource)
+    {
+        printUnderline(out, resource.getPresentationName().length());
+        out.println(resource.getPresentationName());
+        printUnderline(out, resource.getPresentationName().length());
+
+        Map map = resource.getProperties();
+        for (Iterator iter = map.entrySet().iterator(); iter.hasNext(); )
+        {
+            Map.Entry entry = (Map.Entry) iter.next();
+            if (entry.getValue().getClass().isArray())
+            {
+                out.println(entry.getKey() + ":");
+                for (int j = 0; j < Array.getLength(entry.getValue()); j++)
+                {
+                    out.println("   " + Array.get(entry.getValue(), j));
+                }
+            }
+            else
+            {
+                out.println(entry.getKey() + ": " + entry.getValue());
+            }
+        }
+
+        Requirement[] reqs = resource.getRequirements();
+        if ((reqs != null) && (reqs.length > 0))
+        {
+            out.println("Requires:");
+            for (int i = 0; i < reqs.length; i++)
+            {
+                out.println("   " + reqs[i].getFilter());
+            }
+        }
+
+        Capability[] caps = resource.getCapabilities();
+        if ((caps != null) && (caps.length > 0))
+        {
+            out.println("Capabilities:");
+            for (int i = 0; i < caps.length; i++)
+            {
+                out.println("   " + caps[i].getProperties());
+            }
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/ListCommand.java b/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/ListCommand.java
new file mode 100644
index 0000000..37ff08f
--- /dev/null
+++ b/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/ListCommand.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.obr;
+
+import java.util.List;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.osgi.framework.Version;
+import org.osgi.service.obr.RepositoryAdmin;
+import org.osgi.service.obr.Resource;
+
+public class ListCommand extends ObrCommandSupport {
+
+    @Argument(required = false, multiValued = true)
+    List<String> args;
+
+    protected void doExecute(RepositoryAdmin admin) throws Exception {
+        String substr = null;
+
+        if (args != null) {
+            for (String arg : args)
+            {
+                // Add a space in between tokens.
+                if (substr == null)
+                {
+                    substr = "";
+                }
+                else
+                {
+                    substr += " ";
+                }
+
+                substr += arg;
+            }
+        }
+        
+        StringBuffer sb = new StringBuffer();
+        if ((substr == null) || (substr.length() == 0))
+        {
+            sb.append("(|(presentationname=*)(symbolicname=*))");
+        }
+        else
+        {
+            sb.append("(|(presentationname=*");
+            sb.append(substr);
+            sb.append("*)(symbolicname=*");
+            sb.append(substr);
+            sb.append("*))");
+        }
+        Resource[] resources = admin.discoverResources(sb.toString());
+        for (int resIdx = 0; (resources != null) && (resIdx < resources.length); resIdx++)
+        {
+            String name = resources[resIdx].getPresentationName();
+            Version version = resources[resIdx].getVersion();
+            if (version != null)
+            {
+                io.out.println(name + " (" + version + ")");
+            }
+            else
+            {
+                io.out.println(name);
+            }
+        }
+
+        if (resources == null)
+        {
+            io.out.println("No matching bundles.");
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/ListUrlCommand.java b/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/ListUrlCommand.java
new file mode 100644
index 0000000..ae8eaa2
--- /dev/null
+++ b/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/ListUrlCommand.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.obr;
+
+import org.osgi.service.obr.Repository;
+import org.osgi.service.obr.RepositoryAdmin;
+
+public class ListUrlCommand extends ObrCommandSupport {
+
+    protected void doExecute(RepositoryAdmin admin) {
+        Repository[] repos = admin.listRepositories();
+        if ((repos != null) && (repos.length > 0)) {
+            for (int i = 0; i < repos.length; i++) {
+                io.out.println(repos[i].getURL());
+            }
+        } else {
+            io.out.println("No repository URLs are set.");
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/ObrCommandSupport.java b/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/ObrCommandSupport.java
new file mode 100644
index 0000000..dd6af1a
--- /dev/null
+++ b/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/ObrCommandSupport.java
@@ -0,0 +1,221 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.obr;
+
+import java.io.PrintWriter;
+import java.util.List;
+
+import org.apache.servicemix.kernel.gshell.core.OsgiCommandSupport;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.Version;
+import org.osgi.service.obr.RepositoryAdmin;
+import org.osgi.service.obr.Requirement;
+import org.osgi.service.obr.Resolver;
+import org.osgi.service.obr.Resource;
+
+public abstract class ObrCommandSupport extends OsgiCommandSupport {
+
+    protected static final char VERSION_DELIM = ',';
+
+    protected Object doExecute() throws Exception {
+        // Get repository admin service.
+        ServiceReference ref = getBundleContext().getServiceReference(RepositoryAdmin.class.getName());
+        if (ref == null) {
+            io.out.println("RepositoryAdmin service is unavailable.");
+            return null;
+        }
+        try {
+            RepositoryAdmin admin = (RepositoryAdmin) getBundleContext().getService(ref);
+            if (admin == null) {
+                io.out.println("RepositoryAdmin service is unavailable.");
+                return null;
+            }
+
+            doExecute(admin);
+        }
+        finally {
+            getBundleContext().ungetService(ref);
+        }
+        return null;
+    }
+
+    protected abstract void doExecute(RepositoryAdmin admin) throws Exception;
+
+    protected Resource[] searchRepository(RepositoryAdmin admin, String targetId, String targetVersion)
+    {
+        // Try to see if the targetId is a bundle ID.
+        try
+        {
+            Bundle bundle = getBundleContext().getBundle(Long.parseLong(targetId));
+            targetId = bundle.getSymbolicName();
+        }
+        catch (NumberFormatException ex)
+        {
+            // It was not a number, so ignore.
+        }
+
+        // The targetId may be a bundle name or a bundle symbolic name,
+        // so create the appropriate LDAP query.
+        StringBuffer sb = new StringBuffer("(|(presentationname=");
+        sb.append(targetId);
+        sb.append(")(symbolicname=");
+        sb.append(targetId);
+        sb.append("))");
+        if (targetVersion != null)
+        {
+            sb.insert(0, "(&");
+            sb.append("(version=");
+            sb.append(targetVersion);
+            sb.append("))");
+        }
+        return admin.discoverResources(sb.toString());
+    }
+
+    public Resource selectNewestVersion(Resource[] resources)
+    {
+        int idx = -1;
+        Version v = null;
+        for (int i = 0; (resources != null) && (i < resources.length); i++)
+        {
+            if (i == 0)
+            {
+                idx = 0;
+                v = resources[i].getVersion();
+            }
+            else
+            {
+                Version vtmp = resources[i].getVersion();
+                if (vtmp.compareTo(v) > 0)
+                {
+                    idx = i;
+                    v = vtmp;
+                }
+            }
+        }
+        return (idx < 0) ? null : resources[idx];
+    }
+
+    protected String[] getTarget(String bundle) {
+        String[] target;
+        int idx = bundle.indexOf(VERSION_DELIM);
+        if (idx > 0) {
+            target = new String[] { bundle.substring(0, idx), bundle.substring(idx) };
+        }
+        else
+        {
+            target = new String[] { bundle, null };
+        }
+        return target;
+    }
+
+    protected void printUnderline(PrintWriter out, int length)
+    {
+        for (int i = 0; i < length; i++)
+        {
+            out.print('-');
+        }
+        out.println("");
+    }
+
+    protected void doDeploy(RepositoryAdmin admin, List<String> bundles, boolean start) throws Exception {
+        Resolver resolver = admin.resolver();
+        for (String bundle : bundles) {
+            String[] target = getTarget(bundle);
+            Resource resource = selectNewestVersion(searchRepository(admin, target[0], target[1]));
+            if (resource != null)
+            {
+                resolver.add(resource);
+            }
+            else
+            {
+                io.err.println("Unknown bundle - " + target[0]);
+            }
+        }
+        if ((resolver.getAddedResources() != null) &&
+            (resolver.getAddedResources().length > 0))
+        {
+            if (resolver.resolve())
+            {
+                io.out.println("Target resource(s):");
+                printUnderline(io.out, 19);
+                Resource[] resources = resolver.getAddedResources();
+                for (int resIdx = 0; (resources != null) && (resIdx < resources.length); resIdx++)
+                {
+                    io.out.println("   " + resources[resIdx].getPresentationName()
+                        + " (" + resources[resIdx].getVersion() + ")");
+                }
+                resources = resolver.getRequiredResources();
+                if ((resources != null) && (resources.length > 0))
+                {
+                    io.out.println("\nRequired resource(s):");
+                    printUnderline(io.out, 21);
+                    for (int resIdx = 0; resIdx < resources.length; resIdx++)
+                    {
+                        io.out.println("   " + resources[resIdx].getPresentationName()
+                            + " (" + resources[resIdx].getVersion() + ")");
+                    }
+                }
+                resources = resolver.getOptionalResources();
+                if ((resources != null) && (resources.length > 0))
+                {
+                    io.out.println("\nOptional resource(s):");
+                    printUnderline(io.out, 21);
+                    for (int resIdx = 0; resIdx < resources.length; resIdx++)
+                    {
+                        io.out.println("   " + resources[resIdx].getPresentationName()
+                            + " (" + resources[resIdx].getVersion() + ")");
+                    }
+                }
+
+                try
+                {
+                    io.out.print("\nDeploying...");
+                    resolver.deploy(start);
+                    io.out.println("done.");
+                }
+                catch (IllegalStateException ex)
+                {
+                    io.err.println(ex);
+                }
+            }
+            else
+            {
+                Requirement[] reqs = resolver.getUnsatisfiedRequirements();
+                if ((reqs != null) && (reqs.length > 0))
+                {
+                    io.out.println("Unsatisfied requirement(s):");
+                    printUnderline(io.out, 27);
+                    for (int reqIdx = 0; reqIdx < reqs.length; reqIdx++)
+                    {
+                        io.out.println("   " + reqs[reqIdx].getFilter());
+                        Resource[] resources = resolver.getResources(reqs[reqIdx]);
+                        for (int resIdx = 0; resIdx < resources.length; resIdx++)
+                        {
+                            io.out.println("      " + resources[resIdx].getPresentationName());
+                        }
+                    }
+                }
+                else
+                {
+                    io.out.println("Could not resolve targets.");
+                }
+            }
+        }
+
+    }
+}
diff --git a/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/RefreshUrlCommand.java b/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/RefreshUrlCommand.java
new file mode 100644
index 0000000..056d094
--- /dev/null
+++ b/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/RefreshUrlCommand.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.obr;
+
+import java.net.URL;
+import java.util.List;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.osgi.service.obr.Repository;
+import org.osgi.service.obr.RepositoryAdmin;
+
+public class RefreshUrlCommand extends ObrCommandSupport {
+
+    @Argument(required = false, multiValued = true, description = "Repository URLs (leave empty for all)")
+    List<String> urls;
+
+
+    protected void doExecute(RepositoryAdmin admin) throws Exception {
+		if (urls != null || urls.isEmpty()) {
+			for (String url : urls) {
+				admin.removeRepository(new URL(url));
+				admin.addRepository(new URL(url));
+			}
+		} else {
+			Repository[] repos = admin.listRepositories();
+			if ((repos != null) && (repos.length > 0)) {
+				for (int i = 0; i < repos.length; i++) {
+					admin.removeRepository(repos[i].getURL());
+					admin.addRepository(repos[i].getURL());
+				}
+			}
+		}
+    }
+
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/RemoveUrlCommand.java b/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/RemoveUrlCommand.java
new file mode 100644
index 0000000..d122706
--- /dev/null
+++ b/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/RemoveUrlCommand.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.obr;
+
+import java.net.URL;
+import java.util.List;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.osgi.service.obr.RepositoryAdmin;
+
+public class RemoveUrlCommand extends ObrCommandSupport {
+
+    @Argument(required = true, multiValued = true, description = "Repository URLs")
+    List<String> urls;
+
+    protected void doExecute(RepositoryAdmin admin) throws Exception {
+        for (String url : urls) {
+            admin.removeRepository(new URL(url));
+        }
+    }
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/SourceCommand.java b/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/SourceCommand.java
new file mode 100644
index 0000000..f15db46
--- /dev/null
+++ b/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/SourceCommand.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.obr;
+
+import java.net.URL;
+import java.util.List;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.apache.geronimo.gshell.clp.Option;
+import org.osgi.service.obr.RepositoryAdmin;
+import org.osgi.service.obr.Resource;
+
+public class SourceCommand extends ObrCommandSupport {
+
+    @Option(name = "-x", description = "Extract")
+    boolean extract;
+
+    @Argument(required = true, index = 0, description = "Local directory")
+    String localDir;
+
+    @Argument(required = true, index = 1, multiValued = true, description = "List of bundles")
+    List<String> bundles;
+
+    protected void doExecute(RepositoryAdmin admin) throws Exception {
+        for (String bundle : bundles) {
+            String[] target = getTarget(bundle);
+            Resource resource = selectNewestVersion(searchRepository(admin, target[0], target[1]));
+            if (resource == null)
+            {
+                io.err.println("Unknown bundle and/or version: " + target[0]);
+            }
+            else
+            {
+                URL srcURL = (URL) resource.getProperties().get(Resource.SOURCE_URL);
+                if (srcURL != null)
+                {
+                    FileUtil.downloadSource(io.out, io.err, srcURL, localDir, extract);
+                }
+                else
+                {
+                    io.err.println("Missing source URL: " + target[0]);
+                }
+            }
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/StartCommand.java b/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/StartCommand.java
new file mode 100644
index 0000000..1a34e26
--- /dev/null
+++ b/karaf/gshell/gshell-obr/src/main/java/org/apache/servicemix/kernel/gshell/obr/StartCommand.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.obr;
+
+import org.osgi.service.obr.RepositoryAdmin;
+
+public class StartCommand extends DeployCommand {
+
+    protected void doExecute(RepositoryAdmin admin) throws Exception {
+        doDeploy(admin, bundles, true);
+    }
+
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-obr/src/main/resources/META-INF/spring/gshell-obr.xml b/karaf/gshell/gshell-obr/src/main/resources/META-INF/spring/gshell-obr.xml
new file mode 100644
index 0000000..250051f
--- /dev/null
+++ b/karaf/gshell/gshell-obr/src/main/resources/META-INF/spring/gshell-obr.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<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:osgix="http://www.springframework.org/schema/osgi-compendium"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xmlns:gshell="http://servicemix.apache.org/schema/servicemix-gshell"
+       xsi:schemaLocation="
+  http://www.springframework.org/schema/beans
+  http://www.springframework.org/schema/beans/spring-beans.xsd
+  http://www.springframework.org/schema/osgi
+  http://www.springframework.org/schema/osgi/spring-osgi.xsd
+  http://www.springframework.org/schema/osgi-compendium
+  http://www.springframework.org/schema/osgi-compendium/spring-osgi-compendium.xsd
+  http://www.springframework.org/schema/util
+  http://www.springframework.org/schema/util/spring-util.xsd
+  http://servicemix.apache.org/schema/servicemix-gshell
+  http://servicemix.apache.org/schema/servicemix-gshell/servicemix-gshell.xsd">
+
+    <import resource="classpath:org/apache/servicemix/kernel/gshell/core/commands.xml" />
+
+    <gshell:command-bundle>
+        <gshell:command name="obr/addUrl">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.obr.AddUrlCommand" />
+        </gshell:command>
+        <gshell:command name="obr/deploy">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.obr.DeployCommand" />
+        </gshell:command>
+        <gshell:command name="obr/info">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.obr.InfoCommand" />
+        </gshell:command>
+        <gshell:command name="obr/list">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.obr.ListCommand" />
+        </gshell:command>
+        <gshell:command name="obr/listUrl">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.obr.ListUrlCommand" />
+        </gshell:command>
+        <gshell:command name="obr/removeUrl">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.obr.RemoveUrlCommand" />
+        </gshell:command>
+        <gshell:command name="obr/refreshUrl">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.obr.RefreshUrlCommand" />
+        </gshell:command>
+        <gshell:command name="obr/source">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.obr.SourceCommand" />
+        </gshell:command>
+        <gshell:command name="obr/start">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.obr.StartCommand" />
+        </gshell:command>
+    </gshell:command-bundle>
+
+</beans>
\ No newline at end of file
diff --git a/karaf/gshell/gshell-obr/src/main/resources/org/apache/servicemix/kernel/gshell/obr/AddUrlCommand.properties b/karaf/gshell/gshell-obr/src/main/resources/org/apache/servicemix/kernel/gshell/obr/AddUrlCommand.properties
new file mode 100644
index 0000000..acf1131
--- /dev/null
+++ b/karaf/gshell/gshell-obr/src/main/resources/org/apache/servicemix/kernel/gshell/obr/AddUrlCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Add a list of repository URLs to the OBR service.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-obr/src/main/resources/org/apache/servicemix/kernel/gshell/obr/DeployCommand.properties b/karaf/gshell/gshell-obr/src/main/resources/org/apache/servicemix/kernel/gshell/obr/DeployCommand.properties
new file mode 100644
index 0000000..d518148
--- /dev/null
+++ b/karaf/gshell/gshell-obr/src/main/resources/org/apache/servicemix/kernel/gshell/obr/DeployCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Deploy a list of bundles using OBR
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-obr/src/main/resources/org/apache/servicemix/kernel/gshell/obr/InfoCommand.properties b/karaf/gshell/gshell-obr/src/main/resources/org/apache/servicemix/kernel/gshell/obr/InfoCommand.properties
new file mode 100644
index 0000000..23a2f59
--- /dev/null
+++ b/karaf/gshell/gshell-obr/src/main/resources/org/apache/servicemix/kernel/gshell/obr/InfoCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Print informations about OBR bundles
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-obr/src/main/resources/org/apache/servicemix/kernel/gshell/obr/ListCommand.properties b/karaf/gshell/gshell-obr/src/main/resources/org/apache/servicemix/kernel/gshell/obr/ListCommand.properties
new file mode 100644
index 0000000..d73f3b7
--- /dev/null
+++ b/karaf/gshell/gshell-obr/src/main/resources/org/apache/servicemix/kernel/gshell/obr/ListCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=List OBR bundles
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-obr/src/main/resources/org/apache/servicemix/kernel/gshell/obr/ListUrlCommand.properties b/karaf/gshell/gshell-obr/src/main/resources/org/apache/servicemix/kernel/gshell/obr/ListUrlCommand.properties
new file mode 100644
index 0000000..40b9fc6
--- /dev/null
+++ b/karaf/gshell/gshell-obr/src/main/resources/org/apache/servicemix/kernel/gshell/obr/ListUrlCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Display the repository URLs currently associated with the OBR service.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-obr/src/main/resources/org/apache/servicemix/kernel/gshell/obr/RefreshUrlCommand.properties b/karaf/gshell/gshell-obr/src/main/resources/org/apache/servicemix/kernel/gshell/obr/RefreshUrlCommand.properties
new file mode 100644
index 0000000..0a4553f
--- /dev/null
+++ b/karaf/gshell/gshell-obr/src/main/resources/org/apache/servicemix/kernel/gshell/obr/RefreshUrlCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Reload the repositories to obtain a fresh list of bundles.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-obr/src/main/resources/org/apache/servicemix/kernel/gshell/obr/RemoveUrlCommand.properties b/karaf/gshell/gshell-obr/src/main/resources/org/apache/servicemix/kernel/gshell/obr/RemoveUrlCommand.properties
new file mode 100644
index 0000000..259dfa1
--- /dev/null
+++ b/karaf/gshell/gshell-obr/src/main/resources/org/apache/servicemix/kernel/gshell/obr/RemoveUrlCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Remove a list of repository URLs from the OBR service.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-obr/src/main/resources/org/apache/servicemix/kernel/gshell/obr/SourceCommand.properties b/karaf/gshell/gshell-obr/src/main/resources/org/apache/servicemix/kernel/gshell/obr/SourceCommand.properties
new file mode 100644
index 0000000..76b6888
--- /dev/null
+++ b/karaf/gshell/gshell-obr/src/main/resources/org/apache/servicemix/kernel/gshell/obr/SourceCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Download the sources for an OBR bundle
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-obr/src/main/resources/org/apache/servicemix/kernel/gshell/obr/StartCommand.properties b/karaf/gshell/gshell-obr/src/main/resources/org/apache/servicemix/kernel/gshell/obr/StartCommand.properties
new file mode 100644
index 0000000..809ab4d
--- /dev/null
+++ b/karaf/gshell/gshell-obr/src/main/resources/org/apache/servicemix/kernel/gshell/obr/StartCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Deploy and start a list of bundles using OBR
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-osgi/pom.xml b/karaf/gshell/gshell-osgi/pom.xml
new file mode 100644
index 0000000..d232750
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/pom.xml
@@ -0,0 +1,87 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <!--
+
+        Licensed to the Apache Software Foundation (ASF) under one or more
+        contributor license agreements.  See the NOTICE file distributed with
+        this work for additional information regarding copyright ownership.
+        The ASF licenses this file to You under the Apache License, Version 2.0
+        (the "License"); you may not use this file except in compliance with
+        the License.  You may obtain a copy of the License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software
+        distributed under the License is distributed on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        See the License for the specific language governing permissions and
+        limitations under the License.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.servicemix.kernel.gshell</groupId>
+        <artifactId>gshell</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.servicemix.kernel.gshell</groupId>
+    <artifactId>org.apache.servicemix.kernel.gshell.osgi</artifactId>
+    <packaging>bundle</packaging>
+    <version>1.2.0-SNAPSHOT</version>
+    <name>Apache ServiceMix Kernel :: GShell OSGi Commands</name>
+
+    <description>
+        Provides the OSGi GShell commands
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel.gshell</groupId>
+            <artifactId>org.apache.servicemix.kernel.gshell.core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.osgi</groupId>
+            <artifactId>spring-osgi-core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.osgi</groupId>
+            <artifactId>spring-osgi-extender</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>${artifactId}</Bundle-SymbolicName>
+                        <Export-Package>
+                            org.apache.servicemix.kernel.gshell.osgi*;version=${project.version};-split-package:=merge-first
+                        </Export-Package>
+                        <Import-Package>
+                            org.apache.geronimo.gshell.wisdom.command,
+                            org.apache.geronimo.gshell.wisdom.registry,
+                            org.apache.servicemix.kernel.gshell.core,
+                            *
+                        </Import-Package>
+                        <Private-Package>!*</Private-Package>
+                        <Spring-Context>*;publish-context:=false;create-asynchronously:=false</Spring-Context>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/BundleCommand.java b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/BundleCommand.java
new file mode 100644
index 0000000..5a3fd3f
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/BundleCommand.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.osgi;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.apache.geronimo.gshell.clp.Option;
+import org.apache.servicemix.kernel.gshell.core.OsgiCommandSupport;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.startlevel.StartLevel;
+
+public abstract class BundleCommand extends OsgiCommandSupport {
+
+    @Argument(required = true, index = 0)
+    long id;
+
+    @Option(name = "--force")
+    boolean force;
+
+    protected Object doExecute() throws Exception {
+        Bundle bundle = getBundleContext().getBundle(id);
+        if (bundle == null) {
+            io.out.println("Bundle " + id + " not found");
+            return Result.FAILURE;
+        }
+        if (!force) {
+            ServiceReference ref = getBundleContext().getServiceReference(StartLevel.class.getName());
+            if (ref != null) {
+                StartLevel sl = getService(StartLevel.class, ref);
+                if (sl != null) {
+                    int level = sl.getBundleStartLevel(bundle);
+                    if (level < 50) {
+                        for (;;) {
+                            StringBuffer sb = new StringBuffer();
+                            io.err.print("You are about to access a system bundle.  Do you want to continue (yes/no): ");
+                            io.err.flush();
+                            for (;;) {
+                                int c = io.in.read();
+                                if (c < 0) {
+                                    return Result.FAILURE;
+                                }
+                                io.err.print((char) c);
+                                if (c == '\r' || c == '\n') {
+                                    break;
+                                }
+                                sb.append((char) c);
+                            }
+                            String str = sb.toString();
+                            if ("yes".equals(str)) {
+                                break;
+                            }
+                            if ("no".equals(str)) {
+                                return Result.FAILURE;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        doExecute(bundle);
+        return Result.SUCCESS;
+    }
+
+    protected abstract void doExecute(Bundle bundle) throws Exception;
+}
diff --git a/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/BundleLevel.java b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/BundleLevel.java
new file mode 100644
index 0000000..cf64476
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/BundleLevel.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.osgi;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.startlevel.StartLevel;
+
+public class BundleLevel extends BundleCommand {
+
+    @Argument(required = false, index = 1)
+    Integer level;
+
+    protected void doExecute(Bundle bundle) throws Exception {
+        // Get package admin service.
+        ServiceReference ref = getBundleContext().getServiceReference(StartLevel.class.getName());
+        if (ref == null) {
+            io.out.println("StartLevel service is unavailable.");
+            return;
+        }
+        StartLevel sl = getService(StartLevel.class, ref);
+        if (sl == null) {
+            io.out.println("StartLevel service is unavailable.");
+            return;
+        }
+
+        if (level == null) {
+            io.out.println("Level " + sl.getBundleStartLevel(bundle));
+        }
+        else if ((level < 50) && sl.getBundleStartLevel(bundle) > 50){
+            for (;;) {
+                StringBuffer sb = new StringBuffer();
+                io.err.println("You are about to designate bundle as a system bundle.  Do you want to continue (yes/no): ");
+                io.err.flush();
+                for (;;) {
+                    int c = io.in.read();
+                    if (c < 0) {
+                        return;
+                    }
+                    io.err.println((char) c);
+                    if (c == '\r' || c == '\n') {
+                        break;
+                    }
+                    sb.append((char) c);
+                }
+                String str = sb.toString();
+                if ("yes".equals(str)) {
+                    sl.setBundleStartLevel(bundle, level);
+                    break;
+                } else if ("no".equals(str)) {
+                    break;
+                }
+            }
+        } else {
+            sl.setBundleStartLevel(bundle, level);
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/BundlesCommand.java b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/BundlesCommand.java
new file mode 100644
index 0000000..7b937ee
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/BundlesCommand.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.osgi;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.apache.servicemix.kernel.gshell.core.OsgiCommandSupport;
+import org.osgi.framework.Bundle;
+
+public abstract class BundlesCommand extends OsgiCommandSupport {
+
+    @Argument(required = false, multiValued = true, description = "Bundle IDs")
+    List<Long> ids;
+
+    protected Object doExecute() throws Exception {
+        List<Bundle> bundles = new ArrayList<Bundle>();
+        if (ids != null && !ids.isEmpty()) {
+            for (long id : ids) {
+                Bundle bundle = getBundleContext().getBundle(id);
+                if (bundle == null) {
+                    io.err.println("Bundle ID" + id + " is invalid");
+                } else {
+                    bundles.add(bundle);
+                }
+            }
+        }
+        doExecute(bundles);
+        return Result.SUCCESS;
+    }
+
+    protected abstract void doExecute(List<Bundle> bundles) throws Exception;
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/Headers.java b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/Headers.java
new file mode 100644
index 0000000..0acf414
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/Headers.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.osgi;
+
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.List;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.apache.servicemix.kernel.gshell.core.OsgiCommandSupport;
+import org.osgi.framework.Bundle;
+
+public class Headers extends OsgiCommandSupport {
+
+    @Argument(required = false, multiValued = true, description = "Bundles ids")
+    List<Long> ids;
+
+    protected Object doExecute() throws Exception {
+        if (ids != null && !ids.isEmpty()) {
+            for (long id : ids) {
+                Bundle bundle = getBundleContext().getBundle(id);
+                if (bundle != null) {
+                    printHeaders(bundle);
+                }
+                else {
+                    io.err.println("Bundle ID " + id + " is invalid.");
+                }
+            }
+        }
+        else {
+            Bundle[] bundles = getBundleContext().getBundles();
+            for (int i = 0; i < bundles.length; i++) {
+                printHeaders(bundles[i]);
+            }
+        }
+        return Result.SUCCESS;
+    }
+
+    protected void printHeaders(Bundle bundle) throws Exception {
+        String title = Util.getBundleName(bundle);
+        io.out.println("\n" + title);
+        io.out.println(Util.getUnderlineString(title));
+        Dictionary dict = bundle.getHeaders();
+        Enumeration keys = dict.keys();
+        while (keys.hasMoreElements())
+        {
+            Object k = (String) keys.nextElement();
+            Object v = dict.get(k);
+            io.out.println(k + " = " + Util.getValueString(v));
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/InstallBundle.java b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/InstallBundle.java
new file mode 100644
index 0000000..ad8d526
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/InstallBundle.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.osgi;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.apache.geronimo.gshell.clp.Option;
+import org.apache.servicemix.kernel.gshell.core.OsgiCommandSupport;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+
+public class InstallBundle extends OsgiCommandSupport {
+
+    @Argument(required = true, multiValued = true, description = "Bundle URLs")
+    List<String> urls;
+
+    @Option(name = "-s", aliases={"--start"}, description="Start the bundles after installation")
+    boolean start;
+
+    protected Object doExecute() throws Exception {
+        List<Bundle> bundles = new ArrayList<Bundle>();
+        StringBuffer sb = new StringBuffer();
+        for (String url : urls) {
+            Bundle bundle = install(url, io.out, io.err);
+            if (bundle != null) {
+                bundles.add(bundle);
+                if (sb.length() > 0) {
+                    sb.append(", ");
+                }
+                sb.append(bundle.getBundleId());
+            }
+        }
+        if (start) {
+            for (Bundle bundle : bundles) {
+                bundle.start();
+            }
+        }
+        if (sb.toString().indexOf(',') > 0) {
+            io.out.println("Bundle IDs: " + sb.toString());
+        } else if (sb.length() > 0) {
+            io.out.println("Bundle ID: " + sb.toString());
+        }
+        return Result.SUCCESS;
+    }
+
+    protected Bundle install(String location, PrintWriter out, PrintWriter err) {
+        try {
+            return getBundleContext().installBundle(location, null);
+        } catch (IllegalStateException ex) {
+            err.println(ex.toString());
+        } catch (BundleException ex) {
+            if (ex.getNestedException() != null) {
+                err.println(ex.getNestedException().toString());
+            } else {
+                err.println(ex.toString());
+            }
+        } catch (Exception ex) {
+            err.println(ex.toString());
+        }
+        return null;
+    }
+
+}
diff --git a/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/ListBundles.java b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/ListBundles.java
new file mode 100644
index 0000000..00604f3
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/ListBundles.java
@@ -0,0 +1,203 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.osgi;
+
+import org.apache.geronimo.gshell.clp.Option;
+import org.apache.servicemix.kernel.gshell.core.OsgiCommandSupport;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.packageadmin.PackageAdmin;
+import org.osgi.service.startlevel.StartLevel;
+
+public class ListBundles extends OsgiCommandSupport {
+
+    @Option(name = "-l", description = "Show locations")
+    boolean showLoc;
+
+    @Option(name = "-s", description = "Show symbolic name")
+    boolean showSymbolic;
+
+    @Option(name = "-u", description = "Show update")
+    boolean showUpdate;
+
+    private SpringApplicationListener springApplicationListener;
+
+    public SpringApplicationListener getSpringApplicationListener() {
+        return springApplicationListener;
+    }
+
+    public void setSpringApplicationListener(SpringApplicationListener springApplicationListener) {
+        this.springApplicationListener = springApplicationListener;
+    }
+
+    protected Object doExecute() throws Exception {
+        ServiceReference ref = getBundleContext().getServiceReference(StartLevel.class.getName());
+        StartLevel sl = null;
+        if (ref != null) {
+            sl = (StartLevel) getBundleContext().getService(ref);
+        }
+        if (sl == null) {
+            io.out.println("StartLevel service is unavailable.");
+        }
+
+        ServiceReference pkgref = getBundleContext().getServiceReference(PackageAdmin.class.getName());
+        PackageAdmin admin = null;
+        if (pkgref != null) {
+            admin = (PackageAdmin) getBundleContext().getService(pkgref);
+            if (admin == null) {
+                io.out.println("PackageAdmin service is unavailable.");
+            }
+        }
+
+        Bundle[] bundles = getBundleContext().getBundles();
+        if (bundles != null) {
+            // Display active start level.
+            if (sl != null) {
+                io.out.println("START LEVEL " + sl.getStartLevel());
+            }
+
+            // Print column headers.
+            String msg = " Name";
+            if (showLoc) {
+               msg = " Location";
+            }
+            else if (showSymbolic) {
+               msg = " Symbolic name";
+            }
+            else if (showUpdate) {
+               msg = " Update location";
+            }
+            String level = (sl == null) ? "" : "  Level ";
+            io.out.println("   ID   State         Spring   " + level + msg);
+            for (int i = 0; i < bundles.length; i++) {
+                // Get the bundle name or location.
+                String name = (String) bundles[i].getHeaders().get(Constants.BUNDLE_NAME);
+                // If there is no name, then default to symbolic name.
+                name = (name == null) ? bundles[i].getSymbolicName() : name;
+                // If there is no symbolic name, resort to location.
+                name = (name == null) ? bundles[i].getLocation() : name;
+
+                // Overwrite the default value is the user specifically
+                // requested to display one or the other.
+                if (showLoc) {
+                    name = bundles[i].getLocation();
+                }
+                else if (showSymbolic) {
+                    name = bundles[i].getSymbolicName();
+                    name = (name == null) ? "<no symbolic name>" : name;
+                }
+                else if (showUpdate) {
+                    name = (String) bundles[i].getHeaders().get(Constants.BUNDLE_UPDATELOCATION);
+                    name = (name == null) ? bundles[i].getLocation() : name;
+                }
+                // Show bundle version if not showing location.
+                String version = (String) bundles[i].getHeaders().get(Constants.BUNDLE_VERSION);
+                name = (!showLoc && !showUpdate && (version != null)) ? name + " (" + version + ")" : name;
+                long l = bundles[i].getBundleId();
+                String id = String.valueOf(l);
+                if (sl == null) {
+                    level = "1";
+                }
+                else {
+                    level = String.valueOf(sl.getBundleStartLevel(bundles[i]));
+                }
+                while (level.length() < 5) {
+                    level = " " + level;
+                }
+                while (id.length() < 4) {
+                    id = " " + id;
+                }
+                io.out.println("[" + id + "] ["
+                    + getStateString(bundles[i])
+                    + "] [" + getSpringStateString(bundles[i])
+                    + "] [" + level + "] " + name);
+
+                if (admin != null) {
+                    Bundle[] fragments = admin.getFragments(bundles[i]);
+                    Bundle[] hosts = admin.getHosts(bundles[i]);
+
+                    if (fragments != null) {
+                        io.out.print("                                       Fragments: ");
+                        int ii = 0;
+                        for (Bundle fragment : fragments) {
+                            ii++;
+                            io.out.print(fragment.getBundleId());
+                            if ((fragments.length > 1) && ii < (fragments.length)) {
+                                io.out.print(",");
+                            }
+                        }
+                        io.out.println();
+                    }
+
+                    if (hosts != null) {
+                        io.out.print("                                       Hosts: ");
+                        int ii = 0;
+                        for (Bundle host : hosts) {
+                            ii++;
+                            io.out.print(host.getBundleId());
+                            if ((hosts.length > 1) && ii < (hosts.length)) {
+                                io.out.print(",");
+                            }
+                        }
+                        io.out.println();
+                    }
+
+                }
+            }
+        }
+        else {
+            io.out.println("There are no installed bundles.");
+        }
+
+        getBundleContext().ungetService(ref);
+        getBundleContext().ungetService(pkgref);
+
+        return Result.SUCCESS;
+    }
+
+    public String getStateString(Bundle bundle)
+    {
+        int state = bundle.getState();
+        if (state == Bundle.ACTIVE) {
+            return "Active     ";
+        } else if (state == Bundle.INSTALLED) {
+            return "Installed  ";
+        } else if (state == Bundle.RESOLVED) {
+            return "Resolved   ";
+        } else if (state == Bundle.STARTING) {
+            return "Starting   ";
+        } else if (state == Bundle.STOPPING) {
+            return "Stopping   ";
+        } else {
+            return "Unknown    ";
+        }
+    }
+
+    public String getSpringStateString(Bundle bundle) {
+        SpringApplicationListener.SpringState state = springApplicationListener.getSpringState(bundle);
+        if (state == SpringApplicationListener.SpringState.Waiting) {
+            return "Waiting";
+        } else if (state == SpringApplicationListener.SpringState.Started) {
+            return "Started";
+        } else if (state == SpringApplicationListener.SpringState.Failed) {
+            return "Failed ";
+        } else {
+            return "       ";
+        }
+    }
+}
diff --git a/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/ListServices.java b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/ListServices.java
new file mode 100644
index 0000000..3753e1a
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/ListServices.java
@@ -0,0 +1,174 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.osgi;
+
+import java.util.List;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.apache.geronimo.gshell.clp.Option;
+import org.apache.geronimo.gshell.command.Command;
+import org.apache.servicemix.kernel.gshell.core.OsgiCommandSupport;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceReference;
+
+public class ListServices extends OsgiCommandSupport {
+
+    @Option(name = "-a", description = "Show all")
+    boolean showAll;
+
+    @Option(name = "-u", description = "Show in use")
+    boolean inUse;
+
+    @Argument(required = false, multiValued = true, description = "Bundles ids")
+    List<Long> ids;
+
+    protected Object doExecute() throws Exception {
+        if (ids != null && !ids.isEmpty()) {
+            for (long id : ids) {
+                Bundle bundle = getBundleContext().getBundle(id);
+                if (bundle != null) {
+                    boolean headerPrinted = false;
+                    boolean needSeparator = false;
+                    ServiceReference[] refs = null;
+
+                    // Get registered or in-use services.
+                    if (inUse) {
+                        refs = bundle.getServicesInUse();
+                    } else {
+                        refs = bundle.getRegisteredServices();
+                    }
+
+                    // Print properties for each service.
+                    for (int refIdx = 0;
+                         (refs != null) && (refIdx < refs.length);
+                         refIdx++) {
+                        String[] objectClass = (String[])
+                                refs[refIdx].getProperty("objectClass");
+
+                        // Determine if we need to print the service, depending
+                        // on whether it is a command service or not.
+                        boolean print = true;
+                        for (int ocIdx = 0;
+                             !showAll && (ocIdx < objectClass.length);
+                             ocIdx++) {
+                            if (objectClass[ocIdx].equals(Command.class.getName())) {
+                                print = false;
+                            }
+                        }
+
+                        // Print header if we have not already done so.
+                        if (!headerPrinted) {
+                            headerPrinted = true;
+                            String title = Util.getBundleName(bundle);
+                            title = (inUse)
+                                    ? title + " uses:"
+                                    : title + " provides:";
+                            io.out.println("");
+                            io.out.println(title);
+                            io.out.println(Util.getUnderlineString(title));
+                        }
+
+                        if (showAll || print) {
+                            // Print service separator if necessary.
+                            if (needSeparator) {
+                                io.out.println("----");
+                            }
+
+                            // Print service properties.
+                            String[] keys = refs[refIdx].getPropertyKeys();
+                            for (int keyIdx = 0;
+                                 (keys != null) && (keyIdx < keys.length);
+                                 keyIdx++) {
+                                Object v = refs[refIdx].getProperty(keys[keyIdx]);
+                                io.out.println(
+                                        keys[keyIdx] + " = " + Util.getValueString(v));
+                            }
+
+                            needSeparator = true;
+                        }
+                    }
+                } else {
+                    io.err.println("Bundle ID " + id + " is invalid.");
+                }
+            }
+        }
+        else
+        {
+            Bundle[] bundles = getBundleContext().getBundles();
+            if (bundles != null)
+            {
+                // TODO: Sort list.
+                for (int bundleIdx = 0; bundleIdx < bundles.length; bundleIdx++)
+                {
+                    boolean headerPrinted = false;
+                    ServiceReference[] refs = null;
+
+                    // Get registered or in-use services.
+                    if (inUse)
+                    {
+                        refs = bundles[bundleIdx].getServicesInUse();
+                    }
+                    else
+                    {
+                        refs = bundles[bundleIdx].getRegisteredServices();
+                    }
+
+                    for (int refIdx = 0; (refs != null) && (refIdx < refs.length); refIdx++)
+                    {
+                        String[] objectClass = (String[])
+                            refs[refIdx].getProperty("objectClass");
+
+                        // Determine if we need to print the service, depending
+                        // on whether it is a command service or not.
+                        boolean print = true;
+                        for (int ocIdx = 0;
+                            !showAll && (ocIdx < objectClass.length);
+                            ocIdx++)
+                        {
+                            if (objectClass[ocIdx].equals(Command.class.getName()))
+                            {
+                                print = false;
+                            }
+                        }
+
+                        // Print the service if necessary.
+                        if (showAll || print)
+                        {
+                            if (!headerPrinted)
+                            {
+                                headerPrinted = true;
+                                String title = Util.getBundleName(bundles[bundleIdx]);
+                                title = (inUse)
+                                    ? title + " uses:"
+                                    : title + " provides:";
+                                io.out.println("\n" + title);
+                                io.out.println(Util.getUnderlineString(title));
+                            }
+                            io.out.println(Util.getValueString(objectClass));
+                        }
+                    }
+                }
+            }
+            else
+            {
+                io.out.println("There are no registered services.");
+            }
+        }
+        return Result.SUCCESS;
+    }
+
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/RefreshBundle.java b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/RefreshBundle.java
new file mode 100644
index 0000000..e554b3c
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/RefreshBundle.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.osgi;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.apache.servicemix.kernel.gshell.core.OsgiCommandSupport;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+public class RefreshBundle extends OsgiCommandSupport {
+
+    @Argument(required = false)
+    Long id;
+
+    protected Object doExecute() throws Exception {
+        // Get package admin service.
+        ServiceReference ref = getBundleContext().getServiceReference(PackageAdmin.class.getName());
+        if (ref == null) {
+            io.out.println("PackageAdmin service is unavailable.");
+            return Result.FAILURE;
+        }
+        try {
+            PackageAdmin pa = (PackageAdmin) getBundleContext().getService(ref);
+            if (pa == null) {
+                io.out.println("PackageAdmin service is unavailable.");
+                return Result.FAILURE;
+            }
+            if (id == null) {
+                pa.refreshPackages(null);
+            }
+            else {
+                Bundle bundle = getBundleContext().getBundle(id);
+                if (bundle == null) {
+                    io.out.println("Bundle " + id + " not found");
+                    return Result.FAILURE;
+                }
+                pa.refreshPackages(new Bundle[] { bundle });
+            }
+        }
+        finally {
+            getBundleContext().ungetService(ref);
+        }
+        return Result.SUCCESS;
+    }
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/ResolveBundle.java b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/ResolveBundle.java
new file mode 100644
index 0000000..607ef91
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/ResolveBundle.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.osgi;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+public class ResolveBundle extends BundleCommand {
+
+    protected void doExecute(Bundle bundle) throws Exception {
+        // Get package admin service.
+        ServiceReference ref = getBundleContext().getServiceReference(PackageAdmin.class.getName());
+        if (ref == null) {
+            io.out.println("PackageAdmin service is unavailable.");
+            return;
+        }
+        try {
+            PackageAdmin pa = (PackageAdmin) getBundleContext().getService(ref);
+            if (pa == null) {
+                io.out.println("PackageAdmin service is unavailable.");
+                return;
+            }
+            pa.resolveBundles(new Bundle[] { bundle });
+        }
+        finally {
+            getBundleContext().ungetService(ref);
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/RestartBundle.java b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/RestartBundle.java
new file mode 100644
index 0000000..6793ecb
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/RestartBundle.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.osgi;
+
+import org.osgi.framework.Bundle;
+
+public class RestartBundle extends BundleCommand {
+
+    protected void doExecute(Bundle bundle) throws Exception {
+        bundle.stop();
+        bundle.start();
+    }
+
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/Shutdown.java b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/Shutdown.java
new file mode 100644
index 0000000..76e8081
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/Shutdown.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.osgi;
+
+import org.apache.servicemix.kernel.gshell.core.OsgiCommandSupport;
+import org.osgi.framework.Bundle;
+
+/**
+ * Command to shut down ServiceMix Kernel
+ */
+public class Shutdown extends OsgiCommandSupport {
+
+    protected Object doExecute() throws Exception {
+        new Thread() {
+            public void run() {
+                try {
+                    Bundle bundle = getBundleContext().getBundle(0);
+                    bundle.stop();
+                } catch (Exception e) {
+                    log.error("Error when shutting down ServiceMix Kernel", e);
+                }
+            }
+        }.start();
+        return Result.SUCCESS;
+    }
+
+}
diff --git a/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/SpringApplicationListener.java b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/SpringApplicationListener.java
new file mode 100644
index 0000000..240bd0a
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/SpringApplicationListener.java
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.osgi;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleListener;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.osgi.context.BundleContextAware;
+import org.springframework.osgi.context.event.OsgiBundleApplicationContextEvent;
+import org.springframework.osgi.context.event.OsgiBundleApplicationContextListener;
+import org.springframework.osgi.context.event.OsgiBundleContextFailedEvent;
+import org.springframework.osgi.context.event.OsgiBundleContextRefreshedEvent;
+import org.springframework.osgi.extender.event.BootstrappingDependencyEvent;
+import org.springframework.osgi.service.importer.event.OsgiServiceDependencyEvent;
+import org.springframework.osgi.service.importer.event.OsgiServiceDependencyWaitStartingEvent;
+
+public class SpringApplicationListener implements OsgiBundleApplicationContextListener,
+                                                  BundleListener, BundleContextAware,
+                                                  InitializingBean, DisposableBean {
+
+    public static enum SpringState {
+        Unknown,
+        Waiting,
+        Started,
+        Failed,
+    }
+
+    private static final Log LOG = LogFactory.getLog(SpringApplicationListener.class);
+
+    private final Map<Long, SpringState> states;
+    private BundleContext bundleContext;
+
+    public SpringApplicationListener() {
+        this.states = new ConcurrentHashMap<Long, SpringState>();
+    }
+
+    public SpringState getSpringState(Bundle bundle) {
+        SpringState state = states.get(bundle.getBundleId());
+        if (state == null || bundle.getState() != Bundle.ACTIVE) {
+            state = SpringState.Unknown;
+        }
+        return state;
+    }
+
+    public void onOsgiApplicationEvent(OsgiBundleApplicationContextEvent event) {
+        SpringState state = null;
+        if (event instanceof BootstrappingDependencyEvent) {
+            OsgiServiceDependencyEvent de = ((BootstrappingDependencyEvent) event).getDependencyEvent();
+            if (de instanceof OsgiServiceDependencyWaitStartingEvent) {
+                state = SpringState.Waiting;
+            }
+        } else if (event instanceof OsgiBundleContextFailedEvent) {
+            state = SpringState.Failed;
+        } else if (event instanceof OsgiBundleContextRefreshedEvent) {
+            state = SpringState.Started;
+        }
+        if (state != null) {
+            LOG.debug("Spring app state changed to " + state + " for bundle " + event.getBundle().getBundleId());
+            states.put(event.getBundle().getBundleId(), state);
+        }
+    }
+
+    public void bundleChanged(BundleEvent event) {
+        if (event.getType() == BundleEvent.UNINSTALLED) {
+            states.remove(event.getBundle().getBundleId());
+        }
+    }
+
+    public void setBundleContext(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+
+    public void afterPropertiesSet() throws Exception {
+        bundleContext.addBundleListener(this);
+    }
+
+    public void destroy() throws Exception {
+        bundleContext.removeBundleListener(this);
+    }
+}
diff --git a/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/StartBundle.java b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/StartBundle.java
new file mode 100644
index 0000000..6639802
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/StartBundle.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.osgi;
+
+import org.osgi.framework.Bundle;
+
+public class StartBundle extends BundleCommand {
+
+    protected void doExecute(Bundle bundle) throws Exception {
+        bundle.start();
+    }
+
+}
diff --git a/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/StartLevel.java b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/StartLevel.java
new file mode 100644
index 0000000..a04a688
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/StartLevel.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.osgi;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.apache.servicemix.kernel.gshell.core.OsgiCommandSupport;
+import org.osgi.framework.ServiceReference;
+
+public class StartLevel extends OsgiCommandSupport {
+
+    @Argument(required = false, index = 0)
+    Integer level;
+
+    protected Object doExecute() throws Exception {
+        // Get package admin service.
+        ServiceReference ref = getBundleContext().getServiceReference(org.osgi.service.startlevel.StartLevel.class.getName());
+        if (ref == null) {
+            io.out.println("StartLevel service is unavailable.");
+            return null;
+        }
+        try {
+            org.osgi.service.startlevel.StartLevel sl = (org.osgi.service.startlevel.StartLevel) getBundleContext().getService(ref);
+            if (sl == null) {
+                io.out.println("StartLevel service is unavailable.");
+                return null;
+            }
+
+            if (level == null) {
+                io.out.println("Level " + sl.getStartLevel());
+            }
+            else {
+                sl.setStartLevel(level);
+            }
+        }
+        finally {
+            getBundleContext().ungetService(ref);
+        }
+        return Result.SUCCESS;
+    }
+
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/StopBundle.java b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/StopBundle.java
new file mode 100644
index 0000000..867a0a0
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/StopBundle.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.osgi;
+
+import org.osgi.framework.Bundle;
+
+public class StopBundle extends BundleCommand {
+
+    protected void doExecute(Bundle bundle) throws Exception {
+        bundle.stop();
+    }
+
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/UninstallBundle.java b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/UninstallBundle.java
new file mode 100644
index 0000000..f92cc9b
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/UninstallBundle.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.osgi;
+
+import org.osgi.framework.Bundle;
+
+public class UninstallBundle extends BundleCommand {
+
+    protected void doExecute(Bundle bundle) throws Exception {
+        bundle.uninstall();
+    }
+
+}
diff --git a/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/UpdateBundle.java b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/UpdateBundle.java
new file mode 100644
index 0000000..1e02e6f
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/UpdateBundle.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.osgi;
+
+import java.io.InputStream;
+import java.net.URL;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.osgi.framework.Bundle;
+
+public class UpdateBundle extends BundleCommand {
+
+	@Argument(required = false, description = "Bundle location", index=1)
+	String location;
+
+	protected void doExecute(Bundle bundle) throws Exception {
+		if (location != null) {
+			InputStream is = new URL(location).openStream();
+			bundle.update(is);
+		} else {
+			bundle.update();
+		}
+	}
+
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/Util.java b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/Util.java
new file mode 100644
index 0000000..c8481d6
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/java/org/apache/servicemix/kernel/gshell/osgi/Util.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.servicemix.kernel.gshell.osgi;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+
+public class Util
+{
+    public static String getBundleName(Bundle bundle)
+    {
+        if (bundle != null)
+        {
+            String name = (String) bundle.getHeaders().get(Constants.BUNDLE_NAME);
+            return (name == null)
+                ? "Bundle " + Long.toString(bundle.getBundleId())
+                : name + " (" + Long.toString(bundle.getBundleId()) + ")";
+        }
+        return "[STALE BUNDLE]";
+    }
+
+    private static StringBuffer m_sb = new StringBuffer();
+
+    public static String getUnderlineString(String s)
+    {
+        synchronized (m_sb)
+        {
+            m_sb.delete(0, m_sb.length());
+            for (int i = 0; i < s.length(); i++)
+            {
+                m_sb.append('-');
+            }
+            return m_sb.toString();
+        }
+    }
+
+    public static String getValueString(Object obj)
+    {
+        synchronized (m_sb)
+        {
+            if (obj instanceof String)
+            {
+                return (String) obj;
+            }
+            else if (obj instanceof String[])
+            {
+                String[] array = (String[]) obj;
+                m_sb.delete(0, m_sb.length());
+                for (int i = 0; i < array.length; i++)
+                {
+                    if (i != 0)
+                    {
+                        m_sb.append(", ");
+                    }
+                    m_sb.append(array[i].toString());
+                }
+                return m_sb.toString();
+            }
+            else if (obj instanceof Boolean)
+            {
+                return ((Boolean) obj).toString();
+            }
+            else if (obj instanceof Long)
+            {
+                return ((Long) obj).toString();
+            }
+            else if (obj instanceof Integer)
+            {
+                return ((Integer) obj).toString();
+            }
+            else if (obj instanceof Short)
+            {
+                return ((Short) obj).toString();
+            }
+            else if (obj instanceof Double)
+            {
+                return ((Double) obj).toString();
+            }
+            else if (obj instanceof Float)
+            {
+                return ((Float) obj).toString();
+            }
+            else if (obj == null)
+            {
+                return "null";
+            }
+            else
+            {
+                return obj.toString();
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-osgi/src/main/resources/META-INF/spring/gshell-osgi.xml b/karaf/gshell/gshell-osgi/src/main/resources/META-INF/spring/gshell-osgi.xml
new file mode 100644
index 0000000..7f06ebf
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/resources/META-INF/spring/gshell-osgi.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<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"
+       xmlns:gshell="http://servicemix.apache.org/schema/servicemix-gshell"
+       xsi:schemaLocation="
+  http://www.springframework.org/schema/beans
+  http://www.springframework.org/schema/beans/spring-beans.xsd
+  http://www.springframework.org/schema/util
+  http://www.springframework.org/schema/util/spring-util.xsd
+  http://www.springframework.org/schema/osgi
+  http://www.springframework.org/schema/osgi/spring-osgi.xsd
+  http://servicemix.apache.org/schema/servicemix-gshell
+  http://servicemix.apache.org/schema/servicemix-gshell/servicemix-gshell.xsd">
+
+    <import resource="classpath:org/apache/servicemix/kernel/gshell/core/commands.xml" />
+
+    <gshell:command-bundle>
+        <gshell:command name="osgi/bundle-level">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.osgi.BundleLevel" />
+        </gshell:command>
+        <gshell:command name="osgi/headers">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.osgi.Headers" />
+        </gshell:command>
+        <gshell:command name="osgi/install">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.osgi.InstallBundle" />
+        </gshell:command>
+        <gshell:command name="osgi/list">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.osgi.ListBundles">
+                <property name="springApplicationListener" ref="springApplicationListener" />
+            </gshell:action>
+        </gshell:command>
+        <gshell:command name="osgi/ls">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.osgi.ListServices" />
+        </gshell:command>
+        <gshell:command name="osgi/refresh">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.osgi.RefreshBundle" />
+        </gshell:command>
+        <gshell:command name="osgi/update">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.osgi.UpdateBundle" />
+        </gshell:command>
+        <gshell:command name="osgi/resolve">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.osgi.ResolveBundle" />
+        </gshell:command>
+        <gshell:command name="osgi/restart">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.osgi.RestartBundle" />
+        </gshell:command>
+        <gshell:command name="osgi/shutdown">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.osgi.Shutdown" />
+        </gshell:command>
+        <gshell:command name="osgi/start">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.osgi.StartBundle" />
+        </gshell:command>
+        <gshell:command name="osgi/start-level">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.osgi.StartLevel" />
+        </gshell:command>
+        <gshell:command name="osgi/stop">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.osgi.StopBundle" />
+        </gshell:command>
+        <gshell:command name="osgi/uninstall">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.osgi.UninstallBundle" />
+        </gshell:command>
+    </gshell:command-bundle>
+
+    <bean id="springApplicationListener" class="org.apache.servicemix.kernel.gshell.osgi.SpringApplicationListener" />
+
+    <osgi:service ref="springApplicationListener" interface="org.springframework.osgi.context.event.OsgiBundleApplicationContextListener" />
+
+</beans>
\ No newline at end of file
diff --git a/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/BundleLevel.properties b/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/BundleLevel.properties
new file mode 100644
index 0000000..9a9bee9
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/BundleLevel.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Get or set the start level of a given bundle
+
+command.manual=\
+  TODO: about manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/Headers.properties b/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/Headers.properties
new file mode 100644
index 0000000..7d53e5f
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/Headers.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Display OSGi headers
+
+command.manual=\
+  TODO: about manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/InstallBundle.properties b/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/InstallBundle.properties
new file mode 100644
index 0000000..85858db
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/InstallBundle.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Install bundle
+
+command.manual=\
+  TODO: about manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/ListBundles.properties b/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/ListBundles.properties
new file mode 100644
index 0000000..204792a
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/ListBundles.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=List bundles
+
+command.manual=\
+  TODO: about manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/ListServices.properties b/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/ListServices.properties
new file mode 100644
index 0000000..1f8ccf9
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/ListServices.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=List services
+
+command.manual=\
+  TODO: about manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/RefreshBundle.properties b/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/RefreshBundle.properties
new file mode 100644
index 0000000..db60c15
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/RefreshBundle.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Refresh bundle
+
+command.manual=\
+  TODO: about manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/ResolveBundle.properties b/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/ResolveBundle.properties
new file mode 100644
index 0000000..9f5de69
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/ResolveBundle.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Resolve bundle
+
+command.manual=\
+  TODO: about manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/RestartBundle.properties b/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/RestartBundle.properties
new file mode 100644
index 0000000..762aa40
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/RestartBundle.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Restart bundle
+
+command.manual=\
+  TODO: about manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/Shutdown.properties b/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/Shutdown.properties
new file mode 100644
index 0000000..940f5f6
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/Shutdown.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Shutdown OSGi
+
+command.manual=\
+  TODO: about manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/StartBundle.properties b/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/StartBundle.properties
new file mode 100644
index 0000000..7a6e7ae
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/StartBundle.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Start bundle
+
+command.manual=\
+  TODO: about manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/StartLevel.properties b/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/StartLevel.properties
new file mode 100644
index 0000000..1b9761f
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/StartLevel.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Get or set the start level
+
+command.manual=\
+  TODO: about manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/StopBundle.properties b/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/StopBundle.properties
new file mode 100644
index 0000000..40fc360
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/StopBundle.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Stop bundle
+
+command.manual=\
+  TODO: about manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/UninstallBundle.properties b/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/UninstallBundle.properties
new file mode 100644
index 0000000..36351ae
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/UninstallBundle.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Uninstall bundle
+
+command.manual=\
+  TODO: about manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/UpdateBundle.properties b/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/UpdateBundle.properties
new file mode 100644
index 0000000..9b07581
--- /dev/null
+++ b/karaf/gshell/gshell-osgi/src/main/resources/org/apache/servicemix/kernel/gshell/osgi/UpdateBundle.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Update bundle
+
+command.manual=\
+  TODO: about manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-packages/pom.xml b/karaf/gshell/gshell-packages/pom.xml
new file mode 100644
index 0000000..e127f98
--- /dev/null
+++ b/karaf/gshell/gshell-packages/pom.xml
@@ -0,0 +1,88 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <!--
+
+        Licensed to the Apache Software Foundation (ASF) under one or more
+        contributor license agreements.  See the NOTICE file distributed with
+        this work for additional information regarding copyright ownership.
+        The ASF licenses this file to You under the Apache License, Version 2.0
+        (the "License"); you may not use this file except in compliance with
+        the License.  You may obtain a copy of the License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software
+        distributed under the License is distributed on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        See the License for the specific language governing permissions and
+        limitations under the License.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.servicemix.kernel.gshell</groupId>
+        <artifactId>gshell</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.servicemix.kernel.gshell</groupId>
+    <artifactId>org.apache.servicemix.kernel.gshell.packages</artifactId>
+    <packaging>bundle</packaging>
+    <version>1.2.0-SNAPSHOT</version>
+    <name>Apache ServiceMix Kernel :: GShell PackageAdmin Commands</name>
+
+    <description>
+        Provides the PackageAdmin GShell commands
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel.gshell</groupId>
+            <artifactId>org.apache.servicemix.kernel.gshell.core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.osgi</groupId>
+            <artifactId>spring-osgi-core</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>${artifactId}</Bundle-SymbolicName>
+                        <Export-Package>
+                            org.apache.servicemix.kernel.gshell.packages*;version=${project.version};-split-package:=merge-first
+                        </Export-Package>
+                        <Import-Package>
+                            org.apache.geronimo.gshell.wisdom.command,
+                            org.apache.geronimo.gshell.wisdom.registry,
+                            org.apache.servicemix.kernel.gshell.core,
+                            *
+                        </Import-Package>
+                        <Private-Package>!*</Private-Package>
+                        <Spring-Context>*;publish-context:=false;create-asynchronously:=false</Spring-Context>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/karaf/gshell/gshell-packages/src/main/java/org/apache/servicemix/kernel/gshell/packages/ExportsCommand.java b/karaf/gshell/gshell-packages/src/main/java/org/apache/servicemix/kernel/gshell/packages/ExportsCommand.java
new file mode 100644
index 0000000..7bb15f1
--- /dev/null
+++ b/karaf/gshell/gshell-packages/src/main/java/org/apache/servicemix/kernel/gshell/packages/ExportsCommand.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.packages;
+
+import java.io.PrintWriter;
+import java.util.List;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.apache.geronimo.gshell.clp.Option;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.service.packageadmin.ExportedPackage;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+public class ExportsCommand extends PackageCommandSupport {
+
+    @Option(name = "-i", aliases = { "--imports"}, description = "List bundles importing the packages")
+    boolean imports;
+
+    @Argument(required = false, multiValued = true, description = "bundle ids")
+    List<Long> ids;
+
+    protected void doExecute(PackageAdmin admin) throws Exception {
+        if (ids != null && !ids.isEmpty()) {
+            for (long id : ids) {
+                Bundle bundle = getBundleContext().getBundle(id);
+                if (bundle != null) {
+                    printExports(io.out, bundle, admin.getExportedPackages(bundle));
+                } else {
+                    io.err.println("Bundle ID " + id + " is invalid.");
+                }
+            }
+        }
+        else {
+            printExports(io.out, null, admin.getExportedPackages((Bundle) null));
+        }
+    }
+
+    protected void printExports(PrintWriter out, Bundle target, ExportedPackage[] exports) {
+        if ((exports != null) && (exports.length > 0)) {
+            for (int i = 0; i < exports.length; i++) {
+                Bundle bundle = exports[i].getExportingBundle();
+                out.print(getBundleName(bundle));
+                out.println(": " + exports[i]);
+                if (imports) {
+                    Bundle[] bs = exports[i].getImportingBundles();
+                    if (bs != null) {
+                        for (Bundle b : bs) {
+                            out.println("\t" + getBundleName(b));
+                        }
+                    }
+                }
+            }
+        } else {
+            out.println(getBundleName(target) + ": No active exported packages.");
+        }
+    }
+
+    public static String getBundleName(Bundle bundle) {
+        if (bundle != null) {
+            String name = (String) bundle.getHeaders().get(Constants.BUNDLE_NAME);
+            return (name == null)
+                ? "Bundle " + Long.toString(bundle.getBundleId())
+                : name + " (" + Long.toString(bundle.getBundleId()) + ")";
+        }
+        return "[STALE BUNDLE]";
+    }
+
+}
diff --git a/karaf/gshell/gshell-packages/src/main/java/org/apache/servicemix/kernel/gshell/packages/ImportsCommand.java b/karaf/gshell/gshell-packages/src/main/java/org/apache/servicemix/kernel/gshell/packages/ImportsCommand.java
new file mode 100644
index 0000000..7d109cb
--- /dev/null
+++ b/karaf/gshell/gshell-packages/src/main/java/org/apache/servicemix/kernel/gshell/packages/ImportsCommand.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.packages;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.service.packageadmin.ExportedPackage;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+public class ImportsCommand extends PackageCommandSupport {
+
+    @Argument(required = false, multiValued = true, description = "bundle ids")
+    List<Long> ids;
+
+    protected void doExecute(PackageAdmin admin) throws Exception {
+        Map<Long, List<ExportedPackage>> packages = new HashMap<Long, List<ExportedPackage>>();
+        ExportedPackage[] exported = admin.getExportedPackages((Bundle) null);
+        for (ExportedPackage pkg : exported) {
+            Bundle[] bundles = pkg.getImportingBundles();
+            if (bundles != null) {
+                for (Bundle b : bundles) {
+                    List<ExportedPackage> p = packages.get(b.getBundleId());
+                    if (p == null) {
+                        p = new ArrayList<ExportedPackage>();
+                        packages.put(b.getBundleId(), p);
+                    }
+                    p.add(pkg);
+                }
+            }
+        }
+        if (ids != null && !ids.isEmpty()) {
+            for (long id : ids) {
+                Bundle bundle = getBundleContext().getBundle(id);
+                if (bundle != null) {
+                    printImports(io.out, bundle, packages.get(bundle.getBundleId()));
+                } else {
+                    io.err.println("Bundle ID " + id + " is invalid.");
+                }
+            }
+        }
+        else {
+            List<ExportedPackage> pkgs = new ArrayList<ExportedPackage>();
+            for (List<ExportedPackage> l : packages.values()) {
+                pkgs.addAll(l);
+            }
+            printImports(io.out, null, pkgs);
+        }
+    }
+
+    protected void printImports(PrintWriter out, Bundle target, List<ExportedPackage> imports) {
+        if ((imports != null) && (imports.size() > 0)) {
+            for (ExportedPackage p : imports) {
+                Bundle bundle = p.getExportingBundle();
+                out.print(getBundleName(bundle));
+                out.println(": " + p);
+            }
+        } else {
+            out.println(getBundleName(target) + ": No active imported packages.");
+        }
+    }
+
+    public static String getBundleName(Bundle bundle) {
+        if (bundle != null) {
+            String name = (String) bundle.getHeaders().get(Constants.BUNDLE_NAME);
+            return (name == null)
+                ? "Bundle " + Long.toString(bundle.getBundleId())
+                : name + " (" + Long.toString(bundle.getBundleId()) + ")";
+        }
+        return "[STALE BUNDLE]";
+    }
+
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-packages/src/main/java/org/apache/servicemix/kernel/gshell/packages/PackageCommandSupport.java b/karaf/gshell/gshell-packages/src/main/java/org/apache/servicemix/kernel/gshell/packages/PackageCommandSupport.java
new file mode 100644
index 0000000..ef99b94
--- /dev/null
+++ b/karaf/gshell/gshell-packages/src/main/java/org/apache/servicemix/kernel/gshell/packages/PackageCommandSupport.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.packages;
+
+import org.apache.servicemix.kernel.gshell.core.OsgiCommandSupport;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+/**
+ * Abstract class from which all commands related to the PackageAdmin
+ * service should derive.
+ * This command retrieves a reference to the PackageAdmin service before
+ * calling another method to actually process the command.
+ */
+public abstract class PackageCommandSupport extends OsgiCommandSupport {
+
+    protected Object doExecute() throws Exception {
+        // Get package admin service.
+        ServiceReference ref = getBundleContext().getServiceReference(PackageAdmin.class.getName());
+        if (ref == null) {
+            io.out.println("PackageAdmin service is unavailable.");
+            return null;
+        }
+        try {
+            PackageAdmin admin = (PackageAdmin) getBundleContext().getService(ref);
+            if (admin == null) {
+                io.out.println("PackageAdmin service is unavailable.");
+                return null;
+            }
+
+            doExecute(admin);
+        }
+        finally {
+            getBundleContext().ungetService(ref);
+        }
+        return null;
+    }
+
+    protected abstract void doExecute(PackageAdmin admin) throws Exception;
+
+}
diff --git a/karaf/gshell/gshell-packages/src/main/resources/META-INF/spring/gshell-packages.xml b/karaf/gshell/gshell-packages/src/main/resources/META-INF/spring/gshell-packages.xml
new file mode 100644
index 0000000..9e3060d
--- /dev/null
+++ b/karaf/gshell/gshell-packages/src/main/resources/META-INF/spring/gshell-packages.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<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"
+       xmlns:gshell="http://servicemix.apache.org/schema/servicemix-gshell"
+       xsi:schemaLocation="
+  http://www.springframework.org/schema/beans
+  http://www.springframework.org/schema/beans/spring-beans.xsd
+  http://www.springframework.org/schema/util
+  http://www.springframework.org/schema/util/spring-util.xsd
+  http://www.springframework.org/schema/osgi
+  http://www.springframework.org/schema/osgi/spring-osgi.xsd
+  http://servicemix.apache.org/schema/servicemix-gshell
+  http://servicemix.apache.org/schema/servicemix-gshell/servicemix-gshell.xsd">
+
+    <import resource="classpath:org/apache/servicemix/kernel/gshell/core/commands.xml" />
+
+    <gshell:command-bundle>
+        <gshell:command name="packages/exports">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.packages.ExportsCommand" />
+        </gshell:command>
+        <gshell:command name="packages/imports">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.packages.ImportsCommand" />
+        </gshell:command>
+    </gshell:command-bundle>
+
+</beans>
diff --git a/karaf/gshell/gshell-packages/src/main/resources/org/apache/servicemix/kernel/gshell/packages/ExportsCommand.properties b/karaf/gshell/gshell-packages/src/main/resources/org/apache/servicemix/kernel/gshell/packages/ExportsCommand.properties
new file mode 100644
index 0000000..9487118
--- /dev/null
+++ b/karaf/gshell/gshell-packages/src/main/resources/org/apache/servicemix/kernel/gshell/packages/ExportsCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Print exported packages.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-packages/src/main/resources/org/apache/servicemix/kernel/gshell/packages/ImportsCommand.properties b/karaf/gshell/gshell-packages/src/main/resources/org/apache/servicemix/kernel/gshell/packages/ImportsCommand.properties
new file mode 100644
index 0000000..917d860
--- /dev/null
+++ b/karaf/gshell/gshell-packages/src/main/resources/org/apache/servicemix/kernel/gshell/packages/ImportsCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Print imported packages.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-wrapper/pom.xml b/karaf/gshell/gshell-wrapper/pom.xml
new file mode 100644
index 0000000..341e837
--- /dev/null
+++ b/karaf/gshell/gshell-wrapper/pom.xml
@@ -0,0 +1,115 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <!--
+
+        Licensed to the Apache Software Foundation (ASF) under one or more
+        contributor license agreements.  See the NOTICE file distributed with
+        this work for additional information regarding copyright ownership.
+        The ASF licenses this file to You under the Apache License, Version 2.0
+        (the "License"); you may not use this file except in compliance with
+        the License.  You may obtain a copy of the License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software
+        distributed under the License is distributed on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        See the License for the specific language governing permissions and
+        limitations under the License.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.servicemix.kernel.gshell</groupId>
+        <artifactId>gshell</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.servicemix.kernel.gshell</groupId>
+    <artifactId>org.apache.servicemix.kernel.gshell.wrapper</artifactId>
+    <packaging>bundle</packaging>
+    <version>1.2.0-SNAPSHOT</version>
+    <name>Apache ServiceMix Kernel :: GShell Service Wrapper</name>
+
+    <description>
+        Provides the Service Wrapper GShell integration
+    </description>
+
+    <properties>
+        <gshell.osgi.import>
+            org.apache.servicemix.kernel.main.spi.*;resolution:=optional,
+            org.apache.geronimo.gshell*,
+        </gshell.osgi.import>
+        <gshell.osgi.export>
+        </gshell.osgi.export>
+        <gshell.osgi.private>
+            org.apache.servicemix.kernel.gshell.wrapper.*,
+        </gshell.osgi.private>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel.gshell</groupId>
+            <artifactId>org.apache.servicemix.kernel.gshell.core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.osgi</groupId>
+            <artifactId>spring-osgi-core</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <resources>
+            <resource>
+                <directory>${pom.basedir}/src/main/resources</directory>
+                <includes>
+                    <include>**/*</include>
+                </includes>
+            </resource>
+            <resource>
+                <directory>${pom.basedir}/src/main/filtered-resources</directory>
+                <filtering>true</filtering>
+                <includes>
+                    <include>**/*</include>
+                </includes>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>exec-maven-plugin</artifactId>
+                <configuration>
+                    <mainClass>Main</mainClass>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>${artifactId}</Bundle-SymbolicName>
+                        <Export-Package>org.apache.servicemix.kernel.gshell.wrapper.*;version=${project.version}
+                        </Export-Package>
+                        <Import-Package>
+                            org.apache.geronimo.gshell.wisdom.command,
+                            org.apache.geronimo.gshell.wisdom.registry,
+                            org.apache.servicemix.kernel.gshell.core,
+                            *
+                        </Import-Package>
+                        <Private-Package>!*</Private-Package>
+                        <Spring-Context>*;publish-context:=false;create-asynchronously:=false</Spring-Context>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/karaf/gshell/gshell-wrapper/src/main/java/org/apache/servicemix/kernel/gshell/wrapper/InstallCommand.java b/karaf/gshell/gshell-wrapper/src/main/java/org/apache/servicemix/kernel/gshell/wrapper/InstallCommand.java
new file mode 100644
index 0000000..f58c3cc
--- /dev/null
+++ b/karaf/gshell/gshell-wrapper/src/main/java/org/apache/servicemix/kernel/gshell/wrapper/InstallCommand.java
@@ -0,0 +1,360 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.wrapper;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Scanner;
+
+import org.apache.geronimo.gshell.clp.Option;
+import org.apache.geronimo.gshell.io.PumpStreamHandler;
+import org.apache.servicemix.kernel.gshell.core.OsgiCommandSupport;
+
+/**
+ * Installs this ServiceMix instance as a service in your operating systems. 
+ *
+ * @version $Rev: 603634 $ $Date: 2007-12-12 16:07:16 +0100 (Wed, 12 Dec 2007) $
+ */
+public class InstallCommand extends OsgiCommandSupport
+{
+	
+    @Option(name="-n", aliases={"--name"}, description="The service name that will be used when installing the service.")
+    private String name="servicemix";
+    @Option(name="-d", aliases={"--display"}, description="The display name of the service.")
+    private String displayName;
+    @Option(name="-D", aliases={"--description"}, description="The description of the service.")
+    private String description="";
+    @Option(name="-s", aliases={"--start-type"}, description="Mode in which the service is installed.  AUTO_START or DEMAND_START")
+    private String startType="AUTO_START";
+
+    protected Object doExecute() throws Exception {
+    	
+    	try {
+    		String name = getName();    		
+    		File base = new File(System.getProperty("servicemix.base"));
+    		File bin = new File(base, "bin");
+    		File etc = new File(base, "etc");
+    		File lib = new File(base, "lib");
+    		
+			HashMap<String, String> props = new HashMap<String, String>();
+			props.put("${servicemix.home}", System.getProperty("servicemix.home"));
+			props.put("${servicemix.base}", base.getPath());
+			props.put("${name}", name);
+			props.put("${displayName}", getDisplayName());
+			props.put("${description}", getDescription());
+			props.put("${startType}", getStartType());
+			
+			String os = System.getProperty("os.name", "Unknown");
+			File serviceFile=null;
+			if( os.startsWith("Win") ) {
+				mkdir(bin);
+				copyResourceTo(new File(bin, name+"-wrapper.exe"), "windows/servicemix-wrapper.exe", false);
+				serviceFile = new File(bin,name+"-service.bat");
+				copyFilteredResourceTo(serviceFile, "windows/servicemix-service.bat", props);
+				mkdir(lib);
+				copyResourceTo(new File(bin, "wrapper.dll"), "windows/wrapper.dll", false);								
+			} else if( os.startsWith("Mac OS X") ) {
+				mkdir(bin);
+				
+				File file = new File(bin, name+"-wrapper");
+				copyResourceTo(file, "macosx/servicemix-wrapper", false);
+				chmod(file, "a+x");
+				
+				serviceFile = new File(bin,name+"-service");
+				copyFilteredResourceTo(serviceFile, "unix/servicemix-service", props);
+				chmod(serviceFile, "a+x");
+				
+				mkdir(lib);
+				copyResourceTo(new File(lib, "libwrapper.jnilib"), "macosx/libwrapper.jnilib", false);
+				
+				// TODO: figure out how to hook in the service that it starts up
+				// when the machine boots up.
+			} else if( os.startsWith("Linux") ) {
+				mkdir(bin);
+				
+				File file = new File(bin, name+"-wrapper");
+				copyResourceTo(file, "linux/servicemix-wrapper", false);
+				chmod(file, "a+x");
+
+				serviceFile = new File(bin,name+"-service");
+				copyFilteredResourceTo(serviceFile, "unix/servicemix-service", props);
+				chmod(serviceFile, "a+x");
+				
+				mkdir(lib);
+				copyResourceTo(new File(lib, "libwrapper.so"), "linux/libwrapper.so", false);
+				
+				// TODO: figure out how to hook in the service that it starts up
+				// when the machine boots up.
+			} else {
+		        io.out.println("Your operating system '"+os+"' is not currently supported.");
+		        return 1;
+			}
+
+    		// Install the wrapper jar to the lib directory..
+			mkdir(lib);
+			copyResourceTo(new File(lib, "servicemix-wrapper.jar"), "all/servicemix-wrapper.jar", false);
+			mkdir(etc);
+			File wrapperConf = new File(etc,name+"-wrapper.conf");
+			copyFilteredResourceTo(wrapperConf, "all/servicemix-wrapper.conf", props);
+
+			io.out.println("");
+			io.out.println("Setup complete.  You may want to tweak the JVM properties in the wrapper configuration file: "+wrapperConf.getPath());
+			io.out.println("before installing and starting the service.");
+			io.out.println("");
+			if( os.startsWith("Win") ) {
+				io.out.println("");
+				io.out.println("To install the service, run: ");
+				io.out.println("  C:> "+serviceFile.getPath()+" install");
+				io.out.println("");
+				io.out.println("Once installed, to start the service run: ");
+				io.out.println("  C:> net start \""+name+"\"");
+				io.out.println("");
+				io.out.println("Once running, to stop the service run: ");
+				io.out.println("  C:> net stop \""+name+"\"");
+				io.out.println("");
+				io.out.println("Once stopped, to remove the installed the service run: ");
+				io.out.println("  C:> "+serviceFile.getPath()+" remove");
+				io.out.println("");
+			} else if( os.startsWith("Mac OS X") ) {
+				io.out.println("");
+				io.out.println("At this time it is not known how to get this service to start when the machine is rebooted.");
+				io.out.println("If you know how to install the following service script so that it gets started");
+				io.out.println("when OS X starts, please email dev@servicemix.apache.org and let us know how so");
+				io.out.println("we can update this message.");
+				io.out.println(" ");
+				io.out.println("  To start the service:");
+				io.out.println("    $ "+serviceFile.getPath()+" start");
+				io.out.println("");
+				io.out.println("  To stop the service:");
+				io.out.println("    $ "+serviceFile.getPath()+" stop");
+				io.out.println("");
+			} else if( os.startsWith("Linux") ) {
+				io.out.println("The way the service is installed depends upon your flavor of Linux.");
+				
+				// TODO: figure out if we can detect the Linux flavor
+				
+				io.out.println("");
+				io.out.println("@|cyan On Redhat/Fedora/CentOS Systems:|");
+				io.out.println("  To install the service:");
+				io.out.println("    $ ln -s "+serviceFile.getPath()+" /etc/init.d/");
+				io.out.println("    $ chkconfig "+serviceFile.getName()+" --add");
+				io.out.println("");
+				io.out.println("  To start the service when the machine is rebooted:");
+				io.out.println("    $ chkconfig "+serviceFile.getName()+" on");
+				io.out.println("");
+				io.out.println("  To disable starting the service when the machine is rebooted:");
+				io.out.println("    $ chkconfig "+serviceFile.getName()+" off");
+				io.out.println("");
+				io.out.println("  To start the service:");
+				io.out.println("    $ service "+serviceFile.getName()+" start");
+				io.out.println("");
+				io.out.println("  To stop the service:");
+				io.out.println("    $ service "+serviceFile.getName()+" stop");
+				io.out.println("");
+				io.out.println("  To uninstall the service :");
+				io.out.println("    $ chkconfig "+serviceFile.getName()+" --del");
+				io.out.println("    $ rm /etc/init.d/"+serviceFile.getName());
+				
+				io.out.println("");
+				io.out.println("@|cyan On Ubuntu/Debian Systems:|");
+				io.out.println("  To install the service:");
+				io.out.println("    $ ln -s "+serviceFile.getPath()+" /etc/init.d/");
+				io.out.println("");
+				io.out.println("  To start the service when the machine is rebooted:");
+				io.out.println("    $ update-rc.d "+serviceFile.getName()+" defaults");
+				io.out.println("");
+				io.out.println("  To disable starting the service when the machine is rebooted:");
+				io.out.println("    $ update-rc.d -f "+serviceFile.getName()+" remove");
+				io.out.println("");
+				io.out.println("  To start the service:");
+				io.out.println("    $ /etc/init.d/"+serviceFile.getName()+" start");
+				io.out.println("");
+				io.out.println("  To stop the service:");
+				io.out.println("    $ /etc/init.d/"+serviceFile.getName()+" stop");
+				io.out.println("");
+				io.out.println("  To uninstall the service :");
+				io.out.println("    $ rm /etc/init.d/"+serviceFile.getName());
+				
+			}
+
+			
+		} catch (Exception e) {
+			e.printStackTrace();
+			throw e;
+		}
+
+        return 0;
+    }
+
+	private int chmod(File serviceFile, String mode) throws Exception {
+		ProcessBuilder builder = new ProcessBuilder();
+		builder.command("chmod", mode, serviceFile.getCanonicalPath());
+        Process p = builder.start();
+
+        PumpStreamHandler handler = new PumpStreamHandler(io.inputStream, io.outputStream, io.errorStream);
+        handler.attach(p);
+        handler.start();
+        int status = p.waitFor();
+        handler.stop();
+        return status;
+	}
+
+	private void copyResourceTo(File outFile, String resource, boolean text) throws Exception {
+		if( !outFile.exists() ) {
+	        io.out.println("Creating file: @|green "+outFile.getPath()+"|");
+			InputStream is = InstallCommand.class.getResourceAsStream(resource);
+			try {
+				if( text ) {
+					// Read it line at a time so that we can use the platform line ending when we write it out.
+					PrintStream out = new PrintStream(new FileOutputStream(outFile));
+					try { 
+						Scanner scanner = new Scanner(is);
+						while (scanner.hasNextLine() ) {
+							String line = scanner.nextLine();
+							io.out.println("writing: "+line);
+							out.println(line);
+						}
+					} finally {
+						safeClose(out);
+					}
+				} else {
+					// Binary so just write it out the way it came in.
+					FileOutputStream out = new FileOutputStream(outFile);
+					try {
+						int c=0;
+						while((c=is.read())>=0) {
+							out.write(c);
+						}
+					} finally {
+						safeClose(out);
+					}
+				}
+			} finally {
+				safeClose(is);
+			}
+		} else {
+	        io.out.println("@|red File allready exists|. Move it out of the way if you want it re-created: "+outFile.getPath()+"");
+		}
+	}
+	
+	private void copyFilteredResourceTo(File outFile, String resource, HashMap<String, String> props) throws Exception {
+		if( !outFile.exists() ) {
+	        io.out.println("Creating file: @|green "+outFile.getPath()+"|");
+			InputStream is = InstallCommand.class.getResourceAsStream(resource);
+			try {
+				// Read it line at a time so that we can use the platform line ending when we write it out.
+				PrintStream out = new PrintStream(new FileOutputStream(outFile));
+				try { 
+					Scanner scanner = new Scanner(is);
+					while (scanner.hasNextLine() ) {
+						String line = scanner.nextLine();
+						line = filter(line, props);
+						out.println(line);
+					}
+				} finally {
+					safeClose(out);
+				}
+			} finally {
+				safeClose(is);
+			}
+		} else {
+	        io.out.println("@|red File allready exists|. Move it out of the way if you want it re-created: "+outFile.getPath()+"");
+		}
+	}
+
+	private void safeClose(InputStream is) throws IOException {
+		if( is==null)
+			return;
+		try {
+			is.close();
+		} catch (Throwable ignore) {
+		}
+	}
+	
+	private void safeClose(OutputStream is) throws IOException {
+		if( is==null)
+			return;
+		try {
+			is.close();
+		} catch (Throwable ignore) {
+		}
+	}
+
+	private String filter(String line, HashMap<String, String> props) {
+		for (Map.Entry<String, String> i : props.entrySet()) {
+			int p1 = line.indexOf(i.getKey());
+			if( p1 >= 0 ) {
+				String l1 = line.substring(0, p1);
+				String l2 = line.substring(p1+i.getKey().length());
+				line = l1+i.getValue()+l2;
+			}
+		}
+		return line;
+	}
+
+	private void mkdir(File file) {
+		if( !file.exists() ) {
+	        io.out.println("Creating missing directory: @|green "+file.getPath()+"|");
+			file.mkdirs();
+		}
+	}
+
+	public String getName() {
+		if( name ==  null ) {
+    		File base = new File(System.getProperty("servicemix.base"));
+    		name = base.getName();
+		}
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getDisplayName() {
+		if( displayName == null ) {
+			displayName = getName();
+		}
+		return displayName;
+	}
+
+	public void setDisplayName(String displayName) {
+		this.displayName = displayName;
+	}
+
+	public String getDescription() {
+		return description;
+	}
+
+	public void setDescription(String description) {
+		this.description = description;
+	}
+
+	public String getStartType() {
+		return startType;
+	}
+
+	public void setStartType(String startType) {
+		this.startType = startType;
+	}
+}
diff --git a/karaf/gshell/gshell-wrapper/src/main/resources/META-INF/spring/gshell-wrapper.xml b/karaf/gshell/gshell-wrapper/src/main/resources/META-INF/spring/gshell-wrapper.xml
new file mode 100644
index 0000000..3eb5a60
--- /dev/null
+++ b/karaf/gshell/gshell-wrapper/src/main/resources/META-INF/spring/gshell-wrapper.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<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"
+       xmlns:gshell="http://servicemix.apache.org/schema/servicemix-gshell"
+       xsi:schemaLocation="
+  http://www.springframework.org/schema/beans
+  http://www.springframework.org/schema/beans/spring-beans.xsd
+  http://www.springframework.org/schema/util
+  http://www.springframework.org/schema/util/spring-util.xsd
+  http://www.springframework.org/schema/osgi
+  http://www.springframework.org/schema/osgi/spring-osgi.xsd
+  http://servicemix.apache.org/schema/servicemix-gshell
+  http://servicemix.apache.org/schema/servicemix-gshell/servicemix-gshell.xsd">
+
+    <import resource="classpath:org/apache/servicemix/kernel/gshell/core/commands.xml" />
+
+    <gshell:command-bundle>
+        <gshell:command name="wrapper/install">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.wrapper.InstallCommand" />
+        </gshell:command>
+    </gshell:command-bundle>
+
+</beans>
diff --git a/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/InstallCommand.properties b/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/InstallCommand.properties
new file mode 100644
index 0000000..e5a5cb8
--- /dev/null
+++ b/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/InstallCommand.properties
@@ -0,0 +1,27 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##  http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied.  See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Install ServiceMix Kernel as a system service in the OS.
+
+command.manual=\
+  TODO: install manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/all/servicemix-wrapper.conf b/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/all/servicemix-wrapper.conf
new file mode 100644
index 0000000..021872d
--- /dev/null
+++ b/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/all/servicemix-wrapper.conf
@@ -0,0 +1,124 @@
+# ------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ------------------------------------------------------------------------
+
+#********************************************************************
+# Wrapper Properties
+#********************************************************************
+set.default.SERVICEMIX_HOME=${servicemix.home}
+set.default.SERVICEMIX_BASE=${servicemix.base}
+
+# Java Application
+wrapper.working.dir=%SERVICEMIX_BASE%
+wrapper.java.command=java
+wrapper.java.mainclass=org.tanukisoftware.wrapper.WrapperSimpleApp
+wrapper.java.classpath.1=%SERVICEMIX_BASE%/lib/servicemix-wrapper.jar
+wrapper.java.classpath.2=%SERVICEMIX_HOME%/lib/servicemix.jar
+wrapper.java.classpath.3=%SERVICEMIX_HOME%/lib/servicemix-jaas-boot.jar
+wrapper.java.library.path.1=%SERVICEMIX_BASE%/lib/
+
+# Application Parameters.  Add parameters as needed starting from 1
+wrapper.app.parameter.1=org.apache.servicemix.kernel.main.Main
+
+# JVM Parameters
+# note that n is the parameter number starting from 1.
+wrapper.java.additional.1=-Dservicemix.home=%SERVICEMIX_HOME%
+wrapper.java.additional.2=-Dservicemix.base=%SERVICEMIX_BASE%
+wrapper.java.additional.3=-Dcom.sun.management.jmxremote
+wrapper.java.additional.4=-Dservicemix.startLocalConsole=false
+wrapper.java.additional.5=-Dservicemix.startRemoteShell=true
+
+# Uncomment to enable jmx
+#wrapper.java.additional.n=-Dcom.sun.management.jmxremote.port=1616
+#wrapper.java.additional.n=-Dcom.sun.management.jmxremote.authenticate=false
+#wrapper.java.additional.n=-Dcom.sun.management.jmxremote.ssl=false
+
+# Uncomment to enable YourKit profiling
+#wrapper.java.additional.n=-Xrunyjpagent
+
+# Uncomment to enable remote debugging
+#wrapper.java.additional.n=-Xdebug -Xnoagent -Djava.compiler=NONE
+#wrapper.java.additional.n=-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005
+
+# Initial Java Heap Size (in MB)
+#wrapper.java.initmemory=3
+
+# Maximum Java Heap Size (in MB)
+wrapper.java.maxmemory=512
+
+
+#********************************************************************
+# Wrapper Logging Properties
+#********************************************************************
+# Format of output for the console.  (See docs for formats)
+wrapper.console.format=PM
+
+# Log Level for console output.  (See docs for log levels)
+wrapper.console.loglevel=INFO
+
+# Log file to use for wrapper output logging.
+wrapper.logfile=%SERVICEMIX_BASE%/data/log/wrapper.log
+
+# Format of output for the log file.  (See docs for formats)
+wrapper.logfile.format=LPTM
+
+# Log Level for log file output.  (See docs for log levels)
+wrapper.logfile.loglevel=INFO
+
+# Maximum size that the log file will be allowed to grow to before
+#  the log is rolled. Size is specified in bytes.  The default value
+#  of 0, disables log rolling.  May abbreviate with the 'k' (kb) or
+#  'm' (mb) suffix.  For example: 10m = 10 megabytes.
+wrapper.logfile.maxsize=10m
+
+# Maximum number of rolled log files which will be allowed before old
+#  files are deleted.  The default value of 0 implies no limit.
+wrapper.logfile.maxfiles=5
+
+# Log Level for sys/event log output.  (See docs for log levels)
+wrapper.syslog.loglevel=NONE
+
+#********************************************************************
+# Wrapper Windows Properties
+#********************************************************************
+# Title to use when running as a console
+wrapper.console.title=${name}
+
+#********************************************************************
+# Wrapper Windows NT/2000/XP Service Properties
+#********************************************************************
+# WARNING - Do not modify any of these properties when an application
+#  using this configuration file has been installed as a service.
+#  Please uninstall the service before modifying this section.  The
+#  service can then be reinstalled.
+
+# Name of the service
+wrapper.ntservice.name=${name}
+
+# Display name of the service
+wrapper.ntservice.displayname=${displayName}
+
+# Description of the service
+wrapper.ntservice.description=${description}
+
+# Service dependencies.  Add dependencies as needed starting from 1
+wrapper.ntservice.dependency.1=
+
+# Mode in which the service is installed.  AUTO_START or DEMAND_START
+wrapper.ntservice.starttype=${startType}
+
+# Allow the service to interact with the desktop.
+wrapper.ntservice.interactive=false
diff --git a/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/all/servicemix-wrapper.jar b/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/all/servicemix-wrapper.jar
new file mode 100755
index 0000000..c766405
--- /dev/null
+++ b/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/all/servicemix-wrapper.jar
Binary files differ
diff --git a/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/linux/libwrapper.so b/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/linux/libwrapper.so
new file mode 100644
index 0000000..df25ec6
--- /dev/null
+++ b/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/linux/libwrapper.so
Binary files differ
diff --git a/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/linux/servicemix-wrapper b/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/linux/servicemix-wrapper
new file mode 100644
index 0000000..c58d4f7
--- /dev/null
+++ b/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/linux/servicemix-wrapper
Binary files differ
diff --git a/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/macosx/libwrapper.jnilib b/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/macosx/libwrapper.jnilib
new file mode 100644
index 0000000..ae5a14e
--- /dev/null
+++ b/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/macosx/libwrapper.jnilib
Binary files differ
diff --git a/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/macosx/servicemix-wrapper b/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/macosx/servicemix-wrapper
new file mode 100644
index 0000000..8c281b9
--- /dev/null
+++ b/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/macosx/servicemix-wrapper
Binary files differ
diff --git a/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/unix/servicemix-service b/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/unix/servicemix-service
new file mode 100755
index 0000000..d80c13b
--- /dev/null
+++ b/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/unix/servicemix-service
@@ -0,0 +1,543 @@
+#! /bin/sh
+
+# ------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ------------------------------------------------------------------------
+
+# Application
+APP_NAME="${name}"
+APP_LONG_NAME="${displayName}"
+
+# Wrapper
+WRAPPER_CMD="${servicemix.base}/bin/${APP_NAME}-wrapper"
+WRAPPER_CONF="${servicemix.base}/etc/${APP_NAME}-wrapper.conf"
+
+# Priority at which to run the wrapper.  See "man nice" for valid priorities.
+#  nice is only used if a priority is specified.
+PRIORITY=
+
+# Location of the pid file.
+PIDDIR="${servicemix.base}/data"
+
+# If uncommented, causes the Wrapper to be shutdown using an anchor file.
+#  When launched with the 'start' command, it will also ignore all INT and
+#  TERM signals.
+#IGNORE_SIGNALS=true
+
+# If specified, the Wrapper will be run as the specified user.
+# IMPORTANT - Make sure that the user has the required privileges to write
+#  the PID file and wrapper.log files.  Failure to be able to write the log
+#  file will cause the Wrapper to exit without any way to write out an error
+#  message.
+# NOTE - This will set the user which is used to run the Wrapper as well as
+#  the JVM and is not useful in situations where a privileged resource or
+#  port needs to be allocated prior to the user being changed.
+#RUN_AS_USER=
+
+# The following two lines are used by the chkconfig command. Change as is
+#  appropriate for your application.  They should remain commented.
+# chkconfig: 2345 20 80
+# description: ${displayName}
+
+# Do not modify anything beyond this point
+#-----------------------------------------------------------------------------
+
+# Get the fully qualified path to the script
+case $0 in
+    /*)
+        SCRIPT="$0"
+        ;;
+    *)
+        PWD=`pwd`
+        SCRIPT="$PWD/$0"
+        ;;
+esac
+
+# Resolve the true real path without any sym links.
+CHANGED=true
+while [ "X$CHANGED" != "X" ]
+do
+    # Change spaces to ":" so the tokens can be parsed.
+    SCRIPT=`echo $SCRIPT | sed -e 's; ;:;g'`
+    # Get the real path to this script, resolving any symbolic links
+    TOKENS=`echo $SCRIPT | sed -e 's;/; ;g'`
+    REALPATH=
+    for C in $TOKENS; do
+        REALPATH="$REALPATH/$C"
+        while [ -h "$REALPATH" ] ; do
+            LS="`ls -ld "$REALPATH"`"
+            LINK="`expr "$LS" : '.*-> \(.*\)$'`"
+            if expr "$LINK" : '/.*' > /dev/null; then
+                REALPATH="$LINK"
+            else
+                REALPATH="`dirname "$REALPATH"`""/$LINK"
+            fi
+        done
+    done
+    # Change ":" chars back to spaces.
+    REALPATH=`echo $REALPATH | sed -e 's;:; ;g'`
+
+    if [ "$REALPATH" = "$SCRIPT" ]
+    then
+        CHANGED=""
+    else
+        SCRIPT="$REALPATH"
+    fi
+done
+
+# Change the current directory to the location of the script
+cd "`dirname "$REALPATH"`"
+REALDIR=`pwd`
+
+# If the PIDDIR is relative, set its value relative to the full REALPATH to avoid problems if
+#  the working directory is later changed.
+FIRST_CHAR=`echo $PIDDIR | cut -c1,1`
+if [ "$FIRST_CHAR" != "/" ]
+then
+    PIDDIR=$REALDIR/$PIDDIR
+fi
+# Same test for WRAPPER_CMD
+FIRST_CHAR=`echo $WRAPPER_CMD | cut -c1,1`
+if [ "$FIRST_CHAR" != "/" ]
+then
+    WRAPPER_CMD=$REALDIR/$WRAPPER_CMD
+fi
+# Same test for WRAPPER_CONF
+FIRST_CHAR=`echo $WRAPPER_CONF | cut -c1,1`
+if [ "$FIRST_CHAR" != "/" ]
+then
+    WRAPPER_CONF=$REALDIR/$WRAPPER_CONF
+fi
+
+# Process ID
+ANCHORFILE="$PIDDIR/$APP_NAME.anchor"
+PIDFILE="$PIDDIR/$APP_NAME.pid"
+LOCKDIR="/var/lock/subsys"
+LOCKFILE="$LOCKDIR/$APP_NAME"
+pid=""
+
+# Resolve the location of the 'ps' command
+PSEXE="/usr/bin/ps"
+if [ ! -x $PSEXE ]
+then
+    PSEXE="/bin/ps"
+    if [ ! -x $PSEXE ]
+    then
+        echo "Unable to locate 'ps'."
+        echo "Please report this message along with the location of the command on your system."
+        exit 1
+    fi
+fi
+
+# Resolve the os
+DIST_OS=`uname -s | tr [:upper:] [:lower:] | tr -d [:blank:]`
+case "$DIST_OS" in
+    'sunos')
+        DIST_OS="solaris"
+        ;;
+    'hp-ux' | 'hp-ux64')
+        DIST_OS="hpux"
+        ;;
+    'darwin')
+        DIST_OS="macosx"
+        ;;
+    'unix_sv')
+        DIST_OS="unixware"
+        ;;
+esac
+
+# Resolve the architecture
+DIST_ARCH=`uname -p | tr [:upper:] [:lower:] | tr -d [:blank:]`
+if [ "$DIST_ARCH" = "unknown" ]
+then
+    DIST_ARCH=`uname -m | tr [:upper:] [:lower:] | tr -d [:blank:]`
+fi
+case "$DIST_ARCH" in
+    'amd64' | 'ia32' | 'ia64' | 'i386' | 'i486' | 'i586' | 'i686' | 'x86_64')
+        DIST_ARCH="x86"
+        ;;
+    'ip27')
+        DIST_ARCH="mips"
+        ;;
+    'power' | 'powerpc' | 'power_pc' | 'ppc64')
+        DIST_ARCH="ppc"
+        ;;
+    'pa_risc' | 'pa-risc')
+        DIST_ARCH="parisc"
+        ;;
+    'sun4u' | 'sparcv9')
+        DIST_ARCH="sparc"
+        ;;
+    '9000/800')
+        DIST_ARCH="parisc"
+        ;;
+esac
+
+# Decide on the wrapper binary to use.
+# If a 32-bit wrapper binary exists then it will work on 32 or 64 bit
+#  platforms, if the 64-bit binary exists then the distribution most
+#  likely wants to use long names.  Otherwise, look for the default.
+# For macosx, we also want to look for universal binaries.
+WRAPPER_TEST_CMD="$WRAPPER_CMD-$DIST_OS-$DIST_ARCH-32"
+if [ -x $WRAPPER_TEST_CMD ]
+then
+    WRAPPER_CMD="$WRAPPER_TEST_CMD"
+else
+    if [ "$DIST_OS" = "macosx" ]
+    then
+        WRAPPER_TEST_CMD="$WRAPPER_CMD-$DIST_OS-universal-32"
+        if [ -x $WRAPPER_TEST_CMD ]
+        then
+            WRAPPER_CMD="$WRAPPER_TEST_CMD"
+        else
+            WRAPPER_TEST_CMD="$WRAPPER_CMD-$DIST_OS-$DIST_ARCH-64"
+            if [ -x $WRAPPER_TEST_CMD ]
+            then
+                WRAPPER_CMD="$WRAPPER_TEST_CMD"
+            else
+                WRAPPER_TEST_CMD="$WRAPPER_CMD-$DIST_OS-universal-64"
+                if [ -x $WRAPPER_TEST_CMD ]
+                then
+                    WRAPPER_CMD="$WRAPPER_TEST_CMD"
+                else
+                    if [ ! -x $WRAPPER_CMD ]
+                    then
+                        echo "Unable to locate any of the following binaries:"
+                        echo "  $WRAPPER_CMD-$DIST_OS-$DIST_ARCH-32"
+                        echo "  $WRAPPER_CMD-$DIST_OS-universal-32"
+                        echo "  $WRAPPER_CMD-$DIST_OS-$DIST_ARCH-64"
+                        echo "  $WRAPPER_CMD-$DIST_OS-universal-64"
+                        echo "  $WRAPPER_CMD"
+                        exit 1
+                    fi
+                fi
+            fi
+        fi
+    else
+        WRAPPER_TEST_CMD="$WRAPPER_CMD-$DIST_OS-$DIST_ARCH-64"
+        if [ -x $WRAPPER_TEST_CMD ]
+        then
+            WRAPPER_CMD="$WRAPPER_TEST_CMD"
+        else
+            if [ ! -x $WRAPPER_CMD ]
+            then
+                echo "Unable to locate any of the following binaries:"
+                echo "  $WRAPPER_CMD-$DIST_OS-$DIST_ARCH-32"
+                echo "  $WRAPPER_CMD-$DIST_OS-$DIST_ARCH-64"
+                echo "  $WRAPPER_CMD"
+                exit 1
+            fi
+        fi
+    fi
+fi
+
+# Build the nice clause
+if [ "X$PRIORITY" = "X" ]
+then
+    CMDNICE=""
+else
+    CMDNICE="nice -$PRIORITY"
+fi
+
+# Build the anchor file clause.
+if [ "X$IGNORE_SIGNALS" = "X" ]
+then
+   ANCHORPROP=
+   IGNOREPROP=
+else
+   ANCHORPROP=wrapper.anchorfile=$ANCHORFILE
+   IGNOREPROP=wrapper.ignore_signals=TRUE
+fi
+
+# Build the lock file clause.  Only create a lock file if the lock directory exists on this platform.
+if [ -d $LOCKDIR ]
+then
+    LOCKPROP=wrapper.lockfile=$LOCKFILE
+else
+    LOCKPROP=
+fi
+
+checkUser() {
+    # Check the configured user.  If necessary rerun this script as the desired user.
+    if [ "X$RUN_AS_USER" != "X" ]
+    then
+        # Resolve the location of the 'id' command
+        IDEXE="/usr/xpg4/bin/id"
+        if [ ! -x $IDEXE ]
+        then
+            IDEXE="/usr/bin/id"
+            if [ ! -x $IDEXE ]
+            then
+                echo "Unable to locate 'id'."
+                echo "Please report this message along with the location of the command on your system."
+                exit 1
+            fi
+        fi
+
+        if [ "`$IDEXE -u -n`" = "$RUN_AS_USER" ]
+        then
+            # Already running as the configured user.  Avoid password prompts by not calling su.
+            RUN_AS_USER=""
+        fi
+    fi
+    if [ "X$RUN_AS_USER" != "X" ]
+    then
+        # If LOCKPROP and $RUN_AS_USER are defined then the new user will most likely not be
+        # able to create the lock file.  The Wrapper will be able to update this file once it
+        # is created but will not be able to delete it on shutdown.  If $2 is defined then
+        # the lock file should be created for the current command
+        if [ "X$LOCKPROP" != "X" ]
+        then
+            if [ "X$2" != "X" ]
+            then
+                # Resolve the primary group
+                RUN_AS_GROUP=`groups $RUN_AS_USER | awk '{print $3}' | tail -1`
+                if [ "X$RUN_AS_GROUP" = "X" ]
+                then
+                    RUN_AS_GROUP=RUN_AS_USER
+                fi
+                touch $LOCKFILE
+                chown $RUN_AS_USER:$RUN_AS_GROUP $LOCKFILE
+            fi
+        fi
+
+        # Still want to change users, recurse.  This means that the user will only be
+        #  prompted for a password once.
+        su -m $RUN_AS_USER -c "$REALPATH $1"
+
+        # Now that we are the original user again, we may need to clean up the lock file.
+        if [ "X$LOCKPROP" != "X" ]
+        then
+            getpid
+            if [ "X$pid" = "X" ]
+            then
+                # Wrapper is not running so make sure the lock file is deleted.
+                if [ -f $LOCKFILE ]
+                then
+                    rm $LOCKFILE
+                fi
+            fi
+        fi
+
+        exit 0
+    fi
+}
+
+getpid() {
+    if [ -f $PIDFILE ]
+    then
+        if [ -r $PIDFILE ]
+        then
+            pid=`cat $PIDFILE`
+            if [ "X$pid" != "X" ]
+            then
+                # It is possible that 'a' process with the pid exists but that it is not the
+                #  correct process.  This can happen in a number of cases, but the most
+                #  common is during system startup after an unclean shutdown.
+                # The ps statement below looks for the specific wrapper command running as
+                #  the pid.  If it is not found then the pid file is considered to be stale.
+                pidtest=`$PSEXE -p $pid -o command | grep $WRAPPER_CMD | tail -1`
+                if [ "X$pidtest" = "X" ]
+                then
+                    # This is a stale pid file.
+                    rm -f $PIDFILE
+                    echo "Removed stale pid file: $PIDFILE"
+                    pid=""
+                fi
+            fi
+        else
+            echo "Cannot read $PIDFILE."
+            exit 1
+        fi
+    fi
+}
+
+testpid() {
+    pid=`$PSEXE -p $pid | grep $pid | grep -v grep | awk '{print $1}' | tail -1`
+    if [ "X$pid" = "X" ]
+    then
+        # Process is gone so remove the pid file.
+        rm -f $PIDFILE
+        pid=""
+    fi
+}
+
+console() {
+    echo "Running $APP_LONG_NAME..."
+    getpid
+    if [ "X$pid" = "X" ]
+    then
+        COMMAND_LINE="$CMDNICE $WRAPPER_CMD $WRAPPER_CONF wrapper.syslog.ident=$APP_NAME wrapper.pidfile=$PIDFILE $ANCHORPROP $LOCKPROP"
+        exec $COMMAND_LINE
+    else
+        echo "$APP_LONG_NAME is already running."
+        exit 1
+    fi
+}
+
+start() {
+    echo "Starting $APP_LONG_NAME..."
+    getpid
+    if [ "X$pid" = "X" ]
+    then
+        if [ ! -d ../../data ]; then
+            mkdir ../../data
+        fi
+        if [ ! -d ../../data/log ]; then
+            mkdir ../../data/log
+        fi
+        COMMAND_LINE="$CMDNICE $WRAPPER_CMD $WRAPPER_CONF wrapper.syslog.ident=$APP_NAME wrapper.pidfile=$PIDFILE wrapper.daemonize=TRUE $ANCHORPROP $IGNOREPROP $LOCKPROP"
+        exec $COMMAND_LINE
+    else
+        echo "$APP_LONG_NAME is already running."
+        exit 1
+    fi
+}
+
+stopit() {
+    echo "Stopping $APP_LONG_NAME..."
+    getpid
+    if [ "X$pid" = "X" ]
+    then
+        echo "$APP_LONG_NAME was not running."
+    else
+        if [ "X$IGNORE_SIGNALS" = "X" ]
+        then
+            # Running so try to stop it.
+            kill $pid
+            if [ $? -ne 0 ]
+            then
+                # An explanation for the failure should have been given
+                echo "Unable to stop $APP_LONG_NAME."
+                exit 1
+            fi
+        else
+            rm -f $ANCHORFILE
+            if [ -f $ANCHORFILE ]
+            then
+                # An explanation for the failure should have been given
+                echo "Unable to stop $APP_LONG_NAME."
+                exit 1
+            fi
+        fi
+
+        # We can not predict how long it will take for the wrapper to
+        #  actually stop as it depends on settings in wrapper.conf.
+        #  Loop until it does.
+        savepid=$pid
+        CNT=0
+        TOTCNT=0
+        while [ "X$pid" != "X" ]
+        do
+            # Show a waiting message every 5 seconds.
+            if [ "$CNT" -lt "5" ]
+            then
+                CNT=`expr $CNT + 1`
+            else
+                echo "Waiting for $APP_LONG_NAME to exit..."
+                CNT=0
+            fi
+            TOTCNT=`expr $TOTCNT + 1`
+
+            sleep 1
+
+            testpid
+        done
+
+        pid=$savepid
+        testpid
+        if [ "X$pid" != "X" ]
+        then
+            echo "Failed to stop $APP_LONG_NAME."
+            exit 1
+        else
+            echo "Stopped $APP_LONG_NAME."
+        fi
+    fi
+}
+
+status() {
+    getpid
+    if [ "X$pid" = "X" ]
+    then
+        echo "$APP_LONG_NAME is not running."
+        exit 1
+    else
+        echo "$APP_LONG_NAME is running ($pid)."
+        exit 0
+    fi
+}
+
+dump() {
+    echo "Dumping $APP_LONG_NAME..."
+    getpid
+    if [ "X$pid" = "X" ]
+    then
+        echo "$APP_LONG_NAME was not running."
+
+    else
+        kill -3 $pid
+
+        if [ $? -ne 0 ]
+        then
+            echo "Failed to dump $APP_LONG_NAME."
+            exit 1
+        else
+            echo "Dumped $APP_LONG_NAME."
+        fi
+    fi
+}
+
+case "$1" in
+
+    'console')
+        checkUser $1 touchlock
+        console
+        ;;
+
+    'start')
+        checkUser $1 touchlock
+        start
+        ;;
+
+    'stop')
+        checkUser $1
+        stopit
+        ;;
+
+    'restart')
+        checkUser $1 touchlock
+        stopit
+        start
+        ;;
+
+    'status')
+        checkUser $1
+        status
+        ;;
+
+    'dump')
+        checkUser $1
+        dump
+        ;;
+
+    *)
+        echo "Usage: $0 { console | start | stop | restart | status | dump }"
+        exit 1
+        ;;
+esac
+
+exit 0
diff --git a/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/windows/servicemix-service.bat b/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/windows/servicemix-service.bat
new file mode 100644
index 0000000..df0160e
--- /dev/null
+++ b/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/windows/servicemix-service.bat
@@ -0,0 +1,50 @@
+@echo off
+
+REM ------------------------------------------------------------------------
+REM Licensed to the Apache Software Foundation (ASF) under one or more
+REM contributor license agreements.  See the NOTICE file distributed with
+REM this work for additional information regarding copyright ownership.
+REM The ASF licenses this file to You under the Apache License, Version 2.0
+REM (the "License"); you may not use this file except in compliance with
+REM the License.  You may obtain a copy of the License at
+REM
+REM http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM Unless required by applicable law or agreed to in writing, software
+REM distributed under the License is distributed on an "AS IS" BASIS,
+REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+REM See the License for the specific language governing permissions and
+REM limitations under the License.
+REM ------------------------------------------------------------------------
+
+setlocal
+
+set APP_NAME=${name}
+set APP_LONG_NAME=${displayName}
+set APP_BASE=${servicemix.base}
+
+if ""%1"" == ""run"" goto doRun
+if ""%1"" == ""install"" goto doInstall
+if ""%1"" == ""remove"" goto doRemove
+
+echo Usage:  servicemix-service ( commands ... )
+echo commands:
+echo   run               Start %APP_NAME% in the current console
+echo   install           Install %APP_NAME% as a Windows service
+echo   remove            Remove the %APP_NAME% Windows service
+goto end
+
+:doRun
+"%APP_BASE%\bin\%APP_NAME%-wrapper.exe" -c "%APP_BASE%\etc\%APP_NAME%-wrapper.conf"
+goto end
+
+:doInstall
+"%APP_BASE%\bin\%APP_NAME%-wrapper.exe" -i "%APP_BASE%\etc\%APP_NAME%-wrapper.conf"
+goto end
+
+:doRemove
+"%APP_BASE%\bin\%APP_NAME%-wrapper.exe" -r "%APP_BASE%\etc\%APP_NAME%-wrapper.conf"
+goto end
+
+:end
+if not "%PAUSE%" == "" pause
diff --git a/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/windows/servicemix-wrapper.exe b/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/windows/servicemix-wrapper.exe
new file mode 100644
index 0000000..a46a2ac
--- /dev/null
+++ b/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/windows/servicemix-wrapper.exe
Binary files differ
diff --git a/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/windows/wrapper.dll b/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/windows/wrapper.dll
new file mode 100644
index 0000000..37c4f33
--- /dev/null
+++ b/karaf/gshell/gshell-wrapper/src/main/resources/org/apache/servicemix/kernel/gshell/wrapper/windows/wrapper.dll
Binary files differ
diff --git a/karaf/gshell/itests/pom.xml b/karaf/gshell/itests/pom.xml
new file mode 100644
index 0000000..c684ceb
--- /dev/null
+++ b/karaf/gshell/itests/pom.xml
@@ -0,0 +1,153 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <!--
+
+        Licensed to the Apache Software Foundation (ASF) under one or more
+        contributor license agreements.  See the NOTICE file distributed with
+        this work for additional information regarding copyright ownership.
+        The ASF licenses this file to You under the Apache License, Version 2.0
+        (the "License"); you may not use this file except in compliance with
+        the License.  You may obtain a copy of the License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software
+        distributed under the License is distributed on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        See the License for the specific language governing permissions and
+        limitations under the License.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.servicemix.kernel.gshell</groupId>
+        <artifactId>gshell</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.servicemix.kernel.gshell</groupId>
+    <artifactId>org.apache.servicemix.kernel.gshell.itests</artifactId>
+    <packaging>jar</packaging>
+    <version>1.2.0-SNAPSHOT</version>
+    <name>Apache ServiceMix Kernel :: GShell ITests</name>
+
+    <description>
+        Provides the OSGi GShell commands
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel.gshell</groupId>
+            <artifactId>org.apache.servicemix.kernel.gshell.core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel.gshell</groupId>
+            <artifactId>org.apache.servicemix.kernel.gshell.log</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel.gshell</groupId>
+            <artifactId>org.apache.servicemix.kernel.gshell.osgi</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel.jaas</groupId>
+            <artifactId>org.apache.servicemix.kernel.jaas.boot</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel.testing</groupId>
+            <artifactId>org.apache.servicemix.kernel.testing.support</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+        <artifactId>maven-resources-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>copy-resources</id>
+            <phase>validate</phase>
+            <goals>
+              <goal>copy-resources</goal>
+            </goals>
+            <configuration>
+              <outputDirectory>${pom.basedir}/target/test-classes/</outputDirectory>
+              <resources>          
+                <resource>
+                  <directory>${pom.basedir}/src/test/filtered-resources</directory>
+                  <filtering>true</filtering>
+                </resource>
+              </resources>              
+            </configuration>            
+          </execution>
+        </executions>
+      </plugin>
+            <!-- generate dependencies versions -->
+            <plugin>
+                <groupId>org.apache.servicemix.tooling</groupId>
+                <artifactId>depends-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>generate-depends-file</id>
+                        <goals>
+                            <goal>generate-depends-file</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <profiles>
+        <profile>
+            <id>ci-build-profile</id>
+            <activation>
+                <property>
+                   <name>maven.repo.local</name>
+                </property>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <configuration>
+                           <!-- when the local repo location has been specified, we need to pass on this information to PAX mvn url -->
+                           <argLine>-Dorg.ops4j.pax.url.mvn.localRepository=${maven.repo.local}</argLine>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <activation>
+                <os>
+                    <family>Windows</family>
+                </os>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <configuration>
+                            <skip>true</skip>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+
+</project>
diff --git a/karaf/gshell/itests/src/test/filtered-resources/features.xml b/karaf/gshell/itests/src/test/filtered-resources/features.xml
new file mode 100644
index 0000000..8316b3f
--- /dev/null
+++ b/karaf/gshell/itests/src/test/filtered-resources/features.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+      Licensed to the Apache Software Foundation (ASF) under one or more
+      contributor license agreements.  See the NOTICE file distributed with
+      this work for additional information regarding copyright ownership.
+      The ASF licenses this file to You under the Apache License, Version 2.0
+      (the "License"); you may not use this file except in compliance with
+      the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+      Unless required by applicable law or agreed to in writing, software
+      distributed under the License is distributed on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+      See the License for the specific language governing permissions and
+      limitations under the License.
+-->
+<features>
+    <feature name="wrapper" version="${version}">
+        <bundle>mvn:org.apache.servicemix.kernel.gshell/org.apache.servicemix.kernel.gshell.wrapper/${version}</bundle>
+    </feature>
+    <feature name="obr" version="${version}">
+        <bundle>mvn:org.apache.felix/org.apache.felix.bundlerepository/${felix.bundlerepository.version}</bundle>
+        <bundle>mvn:org.apache.servicemix.kernel.gshell/org.apache.servicemix.kernel.gshell.obr/${version}</bundle>
+    </feature>
+</features>
diff --git a/karaf/gshell/itests/src/test/java/org/apache/servicemix/kernel/gshell/itests/CoreTest.java b/karaf/gshell/itests/src/test/java/org/apache/servicemix/kernel/gshell/itests/CoreTest.java
new file mode 100644
index 0000000..6f90dc2
--- /dev/null
+++ b/karaf/gshell/itests/src/test/java/org/apache/servicemix/kernel/gshell/itests/CoreTest.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.gshell.itests;
+
+import org.apache.geronimo.gshell.commandline.CommandLineExecutionFailed;
+import org.apache.geronimo.gshell.registry.NoSuchCommandException;
+import org.apache.geronimo.gshell.shell.Shell;
+import org.apache.servicemix.kernel.testing.support.AbstractIntegrationTest;
+import org.osgi.framework.Bundle;
+
+public class CoreTest extends AbstractIntegrationTest {
+
+    static {
+        System.setProperty("servicemix.startLocalConsole", "false");
+        System.setProperty("servicemix.startRemoteShell", "false");
+    }
+
+    @Override
+    protected String getManifestLocation() {
+        return "classpath:org/apache/servicemix/kernel/gshell/itests/MANIFEST.MF";
+    }
+
+    @Override
+    protected String[] getTestBundlesNames() {
+        return new String[] {
+            getBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.jline"),
+            getBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.commons-httpclient"),
+            getBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.commons-jexl"),
+            getBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.commons-vfs"),
+            getBundle("org.apache.mina", "mina-core"),
+            getBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.oro"),
+            getBundle("org.apache.servicemix.kernel.jaas", "org.apache.servicemix.kernel.jaas.config"),
+            getBundle("org.apache.sshd", "sshd-core"),
+            getBundle("org.apache.servicemix.kernel.gshell", "org.apache.servicemix.kernel.gshell.core"),
+            getBundle("org.apache.servicemix.kernel.gshell", "org.apache.servicemix.kernel.gshell.osgi")
+        };
+    }
+
+    public void testHelp() throws Exception {
+        Shell shell = getOsgiService(Shell.class);
+        shell.execute("help");
+    }
+
+    public void testInstallCommand() throws Exception {
+        Shell shell = getOsgiService(Shell.class);
+
+        try {
+            shell.execute("log/display");
+            fail("command should not exist");
+        } catch (CommandLineExecutionFailed e) {
+            assertNotNull(e.getCause());
+            assertTrue(e.getCause() instanceof NoSuchCommandException);
+        }
+
+        Bundle b = installBundle("org.apache.servicemix.kernel.gshell", "org.apache.servicemix.kernel.gshell.log", null, "jar");
+
+        shell.execute("log/display");
+
+        b.uninstall();
+
+        try {
+            shell.execute("log/display");
+            fail("command should not exist");
+        } catch (CommandLineExecutionFailed e) {
+            assertNotNull(e.getCause());
+            assertTrue(e.getCause() instanceof NoSuchCommandException);
+        }
+    }
+
+    public void testCommandGroup() throws Exception {
+        Shell shell = getOsgiService(Shell.class);
+        shell.execute("osgi");
+        shell.execute("help");
+        shell.execute("..");
+    }
+    
+    public void testInstallFeature() throws Exception {
+        Shell shell = getOsgiService(Shell.class);
+
+        try {
+            shell.execute("obr");
+            fail("command should not exist");
+        } catch (CommandLineExecutionFailed e) {
+            assertNotNull(e.getCause());
+            assertTrue(e.getCause() instanceof NoSuchCommandException);
+        }
+        try {
+            shell.execute("wrapper");
+            fail("command should not exist");
+        } catch (CommandLineExecutionFailed e) {
+            assertNotNull(e.getCause());
+            assertTrue(e.getCause() instanceof NoSuchCommandException);
+        }
+        String url = getClass().getClassLoader().getResource("features.xml").toString();
+        addFeatureRepo(url);
+        installFeature("obr");
+        installFeature("wrapper");
+        shell.execute("obr");
+        shell.execute("wrapper");
+    }
+
+    /**
+     * TODO: This test seems to fail, there must be a timing issue somewhere
+     *
+    public void testCommandGroupAfterInstall() throws Exception {
+        Bundle b = installBundle("org.apache.servicemix.kernel.gshell", "org.apache.servicemix.kernel.gshell.log", null, "jar");
+        Shell shell = getOsgiService(Shell.class);
+        shell.execute("log");
+        shell.execute("help");
+        shell.execute("..");
+    }
+     */
+
+
+}
diff --git a/karaf/gshell/itests/src/test/resources/log4j.properties b/karaf/gshell/itests/src/test/resources/log4j.properties
new file mode 100644
index 0000000..8cc85f8
--- /dev/null
+++ b/karaf/gshell/itests/src/test/resources/log4j.properties
@@ -0,0 +1,33 @@
+################################################################################
+#
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+################################################################################
+
+# Root logger
+log4j.rootLogger=INFO, stdout
+
+# CONSOLE appender not used by default
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} | %-5.5p | %-16.16t | %-32.32c{1} | %-32.32C %4L | %m%n
+
+# File appender
+log4j.appender.out=org.apache.log4j.FileAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.out.layout.ConversionPattern=%d{ABSOLUTE} | %-5.5p | %-16.16t | %-32.32c{1} | %-32.32C %4L | %m%n
+log4j.appender.out.file=${servicemix.base}/data/log/servicemix.log
+log4j.appender.out.append=true
diff --git a/karaf/gshell/itests/src/test/resources/org/apache/servicemix/kernel/gshell/itests/MANIFEST.MF b/karaf/gshell/itests/src/test/resources/org/apache/servicemix/kernel/gshell/itests/MANIFEST.MF
new file mode 100644
index 0000000..df8a1a7
--- /dev/null
+++ b/karaf/gshell/itests/src/test/resources/org/apache/servicemix/kernel/gshell/itests/MANIFEST.MF
@@ -0,0 +1,30 @@
+Manifest-Version: 1.0
+License-00: .
+License-01: Licensed to the Apache Software Foundation (ASF) under one or more
+License-02: contributor license agreements.  See the NOTICE file distributed with
+License-03: this work for additional information regarding copyright ownership.
+License-04: The ASF licenses this file to You under the Apache License, Version 2.0
+License-05: (the "License"); you may not use this file except in compliance with
+License-06: the License.  You may obtain a copy of the License at
+License-07: .
+License-08:      http://www.apache.org/licenses/LICENSE-2.0
+License-09: .
+License-10: Unless required by applicable law or agreed to in writing, software
+License-11: distributed under the License is distributed on an "AS IS" BASIS,
+License-12: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+License-13: See the License for the specific language governing permissions and
+License-14: limitations under the License.
+License-15: .
+Bundle-Name: org.apache.servicemix.testing.itests
+Bundle-SymbolicName: org.apache.servicemix.testing.itests
+Bundle-Vendor: Spring Framework
+Bundle-Activator: org.springframework.osgi.test.JUnitTestActivator
+Import-Package: junit.framework,
+ org.osgi.framework;specification-version="1.3.0",
+ org.apache.commons.logging,
+ org.springframework.core.io,
+ org.springframework.osgi.test,
+ org.apache.servicemix.kernel.testing.support,
+ org.apache.geronimo.gshell.commandline,
+ org.apache.geronimo.gshell.registry,
+ org.apache.geronimo.gshell.shell
diff --git a/karaf/gshell/pom.xml b/karaf/gshell/pom.xml
new file mode 100644
index 0000000..3c2d24f
--- /dev/null
+++ b/karaf/gshell/pom.xml
@@ -0,0 +1,49 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <!--
+
+        Licensed to the Apache Software Foundation (ASF) under one or more
+        contributor license agreements.  See the NOTICE file distributed with
+        this work for additional information regarding copyright ownership.
+        The ASF licenses this file to You under the Apache License, Version 2.0
+        (the "License"); you may not use this file except in compliance with
+        the License.  You may obtain a copy of the License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software
+        distributed under the License is distributed on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        See the License for the specific language governing permissions and
+        limitations under the License.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.servicemix.kernel</groupId>
+        <artifactId>kernel</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.servicemix.kernel.gshell</groupId>
+    <artifactId>gshell</artifactId>
+    <packaging>pom</packaging>
+    <version>1.2.0-SNAPSHOT</version>
+    <name>Apache ServiceMix Kernel :: GShell</name>
+
+    <modules>
+        <module>gshell-core</module>
+        <module>gshell-osgi</module>
+        <module>gshell-admin</module>
+        <module>gshell-features</module>
+        <module>gshell-obr</module>
+        <module>gshell-wrapper</module>
+        <module>gshell-log</module>
+        <module>gshell-config</module>
+        <module>gshell-packages</module>
+        <module>itests</module>
+    </modules>
+
+</project>
\ No newline at end of file
diff --git a/karaf/gshell/src/test/configs/services/org.apache.servicemix.shell.properties b/karaf/gshell/src/test/configs/services/org.apache.servicemix.shell.properties
new file mode 100644
index 0000000..7779a61
--- /dev/null
+++ b/karaf/gshell/src/test/configs/services/org.apache.servicemix.shell.properties
@@ -0,0 +1,20 @@
+# 
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed  under the  License is distributed on an "AS IS" BASIS,
+# WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+# implied.
+#  
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+startLocalConsole=false
diff --git a/karaf/gshell/src/test/configs/services/org.ops4j.pax.logging.properties b/karaf/gshell/src/test/configs/services/org.ops4j.pax.logging.properties
new file mode 100644
index 0000000..23075bf
--- /dev/null
+++ b/karaf/gshell/src/test/configs/services/org.ops4j.pax.logging.properties
@@ -0,0 +1,34 @@
+# 
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed  under the  License is distributed on an "AS IS" BASIS,
+# WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+# implied.
+#  
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+log4j.rootLogger=DEBUG, out
+
+log4j.logger.org.springframework=DEBUG
+
+# CONSOLE appender not used by default
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} | %-5.5p | %-16.16t | %-32.32c{1} | %-32.32C %4L | %m%n
+
+# File appender
+log4j.appender.out=org.apache.log4j.FileAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.out.layout.ConversionPattern=%d{ABSOLUTE} | %-5.5p | %-16.16t | %-32.32c{1} | %-32.32C %4L | %m%n
+log4j.appender.out.file=target/gshell.log
+log4j.appender.out.append=true
diff --git a/karaf/jaas/jaas-boot/pom.xml b/karaf/jaas/jaas-boot/pom.xml
new file mode 100644
index 0000000..4cf046e
--- /dev/null
+++ b/karaf/jaas/jaas-boot/pom.xml
@@ -0,0 +1,65 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <!--
+
+        Licensed to the Apache Software Foundation (ASF) under one or more
+        contributor license agreements.  See the NOTICE file distributed with
+        this work for additional information regarding copyright ownership.
+        The ASF licenses this file to You under the Apache License, Version 2.0
+        (the "License"); you may not use this file except in compliance with
+        the License.  You may obtain a copy of the License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software
+        distributed under the License is distributed on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        See the License for the specific language governing permissions and
+        limitations under the License.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.servicemix.kernel.jaas</groupId>
+        <artifactId>jaas</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.servicemix.kernel.jaas</groupId>
+    <artifactId>org.apache.servicemix.kernel.jaas.boot</artifactId>
+    <packaging>bundle</packaging>
+    <version>1.2.0-SNAPSHOT</version>
+    <name>Apache ServiceMix Kernel :: JAAS Boot</name>
+
+    <description>
+        Provides the JAAS Boot classes
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>${artifactId}</Bundle-SymbolicName>
+                        <Export-Package>org.apache.servicemix*;version=${project.version};-split-package:=merge-first
+                        </Export-Package>
+                        <Import-Package>*</Import-Package>
+                        <Private-Package>!*</Private-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/karaf/jaas/jaas-boot/src/main/java/org/apache/servicemix/kernel/jaas/boot/ProxyLoginModule.java b/karaf/jaas/jaas-boot/src/main/java/org/apache/servicemix/kernel/jaas/boot/ProxyLoginModule.java
new file mode 100644
index 0000000..3b3aed0
--- /dev/null
+++ b/karaf/jaas/jaas-boot/src/main/java/org/apache/servicemix/kernel/jaas/boot/ProxyLoginModule.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.jaas.boot;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+/**
+ * An OSGi proxy login module that should be used instead of a plain reference to
+ * a given login module.  Two properties must be set, the name of the login module
+ * class and the bundle to be used to load it.
+ * This class must be available from all modules, so it has to be either in a fragment
+ * bundle attached to the system bundle or be made available through the boot delegation
+ * class path.
+ */
+public class ProxyLoginModule implements LoginModule {
+
+    public static final String PROPERTY_MODULE = "org.apache.servicemix.kernel.jaas.module";
+    public static final String PROPERTY_BUNDLE = "org.apache.servicemix.kernel.jaas.bundle";
+
+    private static BundleContext bundleContext = null;
+    
+    private LoginModule target = null;
+
+    public static void init(BundleContext context) {
+        bundleContext = context;
+    }
+
+    /* (non-Javadoc)
+     * @see javax.security.auth.spi.LoginModule#initialize(javax.security.auth.Subject, javax.security.auth.callback.CallbackHandler, java.util.Map, java.util.Map)
+     */
+    public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options) {
+        if (bundleContext == null) {
+            throw new IllegalStateException("ProxyLoginModule not initialized. Init must be called prior any invocation.");
+        }
+        Map<String,?> newOptions = new HashMap<String,Object>(options);
+        String module = (String) newOptions.remove(PROPERTY_MODULE);
+        if (module == null) {
+            throw new IllegalStateException("Option " + PROPERTY_MODULE + " must be set to the name of the factory service");
+        }
+        String bundleId = (String) newOptions.remove(PROPERTY_BUNDLE);
+        if (bundleId == null) {
+            throw new IllegalStateException("Option " + PROPERTY_BUNDLE + " must be set to the name of the factory service");
+        }
+        Bundle bundle = bundleContext.getBundle(Long.parseLong(bundleId));
+        if (bundle == null) {
+            throw new IllegalStateException("No bundle found for id " + bundleId);
+        }
+        try {
+            target = (LoginModule) bundle.loadClass(module).newInstance();
+        } catch (Exception e) {
+            throw new IllegalStateException("Can not load or create login module " + module + " for bundle " + bundleId, e);
+        }
+        target.initialize(subject, callbackHandler, sharedState, options);
+    }
+
+    /* (non-Javadoc)
+     * @see javax.security.auth.spi.LoginModule#login()
+     */
+    public boolean login() throws LoginException {
+        return target.login();
+    }
+
+    /* (non-Javadoc)
+     * @see javax.security.auth.spi.LoginModule#commit()
+     */
+    public boolean commit() throws LoginException {
+        return target.commit();
+    }
+
+    /* (non-Javadoc)
+     * @see javax.security.auth.spi.LoginModule#abort()
+     */
+    public boolean abort() throws LoginException {
+        return target.abort();
+    }
+
+    /* (non-Javadoc)
+     * @see javax.security.auth.spi.LoginModule#logout()
+     */
+    public boolean logout() throws LoginException {
+        return target.logout();
+    }
+
+}
diff --git a/karaf/jaas/jaas-config/pom.xml b/karaf/jaas/jaas-config/pom.xml
new file mode 100644
index 0000000..bc47433
--- /dev/null
+++ b/karaf/jaas/jaas-config/pom.xml
@@ -0,0 +1,95 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <!--
+
+        Licensed to the Apache Software Foundation (ASF) under one or more
+        contributor license agreements.  See the NOTICE file distributed with
+        this work for additional information regarding copyright ownership.
+        The ASF licenses this file to You under the Apache License, Version 2.0
+        (the "License"); you may not use this file except in compliance with
+        the License.  You may obtain a copy of the License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software
+        distributed under the License is distributed on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        See the License for the specific language governing permissions and
+        limitations under the License.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.servicemix.kernel.jaas</groupId>
+        <artifactId>jaas</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.servicemix.kernel.jaas</groupId>
+    <artifactId>org.apache.servicemix.kernel.jaas.config</artifactId>
+    <packaging>bundle</packaging>
+    <version>1.2.0-SNAPSHOT</version>
+    <name>Apache ServiceMix Kernel :: JAAS Config</name>
+
+    <description>
+        Provides the JAAS Config
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel.jaas</groupId>
+            <artifactId>org.apache.servicemix.kernel.jaas.boot</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.osgi</groupId>
+            <artifactId>spring-osgi-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-logging</groupId>
+            <artifactId>commons-logging</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.aopalliance</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymock</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>${artifactId}</Bundle-SymbolicName>
+                        <Export-Package>
+                            ${artifactId};version=${project.version};-split-package:=merge-first
+                        </Export-Package>
+                        <Import-Package>*</Import-Package>
+                        <Private-Package>${artifactId}.impl</Private-Package>
+                        <Spring-Context>*;publish-context:=false;create-asynchronously:=false</Spring-Context>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/JaasRealm.java b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/JaasRealm.java
new file mode 100644
index 0000000..b5237d1
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/JaasRealm.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.jaas.config;
+
+import javax.security.auth.login.AppConfigurationEntry;
+
+public interface JaasRealm {
+
+    public String getName();
+
+    public int getRank();
+
+    public AppConfigurationEntry[] getEntries();
+}
diff --git a/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/KeyIsLocked.java b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/KeyIsLocked.java
new file mode 100644
index 0000000..5ff4736
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/KeyIsLocked.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.jaas.config;
+
+import java.security.GeneralSecurityException;
+
+public class KeyIsLocked extends GeneralSecurityException {
+
+    public KeyIsLocked() {
+        super();
+    }
+
+    public KeyIsLocked(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public KeyIsLocked(String msg) {
+        super(msg);
+    }
+
+    public KeyIsLocked(Throwable cause) {
+        super(cause);
+    }
+
+}
diff --git a/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/KeystoreInstance.java b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/KeystoreInstance.java
new file mode 100644
index 0000000..022d95b
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/KeystoreInstance.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.jaas.config;
+
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.TrustManager;
+
+/**
+ * Based on http://svn.apache.org/repos/asf/geronimo/trunk/modules/management/
+ *              src/java/org/apache/geronimo/management/geronimo/KeystoreInstance.java
+ *
+ * @version $Rev: $ $Date: $
+ */
+public interface KeystoreInstance {
+
+    String getName();
+
+    int getRank();
+
+    String[] listPrivateKeys();
+
+    String[] listTrustCertificates();
+
+    Certificate getCertificate(String alias);
+
+    String getCertificateAlias(Certificate cert);
+
+    Certificate[] getCertificateChain(String alias);
+
+    PrivateKey getPrivateKey(String alias);
+
+    boolean isKeystoreLocked();
+
+    boolean isKeyLocked(String keyAlias);
+
+    KeyManager[] getKeyManager(String algorithm, String keyAlias) throws NoSuchAlgorithmException,
+                                UnrecoverableKeyException, KeyStoreException, KeystoreIsLocked;
+
+    TrustManager[] getTrustManager(String algorithm) throws KeyStoreException, NoSuchAlgorithmException, KeystoreIsLocked;
+
+}
diff --git a/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/KeystoreIsLocked.java b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/KeystoreIsLocked.java
new file mode 100644
index 0000000..34c9a2b
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/KeystoreIsLocked.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.jaas.config;
+
+import java.security.GeneralSecurityException;
+
+public class KeystoreIsLocked extends GeneralSecurityException {
+
+    public KeystoreIsLocked() {
+        super();
+    }
+
+    public KeystoreIsLocked(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public KeystoreIsLocked(String msg) {
+        super(msg);
+    }
+
+    public KeystoreIsLocked(Throwable cause) {
+        super(cause);
+    }
+
+}
diff --git a/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/KeystoreManager.java b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/KeystoreManager.java
new file mode 100644
index 0000000..74fa466
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/KeystoreManager.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.jaas.config;
+
+import java.security.GeneralSecurityException;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocketFactory;
+
+/**
+ * Based on http://svn.apache.org/repos/asf/geronimo/trunk/modules/management/
+ *                      src/java/org/apache/geronimo/management/geronimo/KeystoreManager.java
+ *
+ */
+public interface KeystoreManager {
+
+    KeystoreInstance getKeystore(String name);
+
+    /**
+     * Gets a SSLContext using one Keystore to access the private key
+     * and another to provide the list of trusted certificate authorities.
+     * @param provider
+     * @param protocol The SSL protocol to use
+     * @param algorithm The SSL algorithm to use
+     * @param keyStore The key keystore name as provided by listKeystores.  The
+     *                 KeystoreInstance for this keystore must be unlocked.
+     * @param keyAlias The name of the private key in the keystore.  The
+     *                 KeystoreInstance for this keystore must have unlocked
+     *                 this key.
+     * @param trustStore The trust keystore name as provided by listKeystores.
+     *                   The KeystoreInstance for this keystore must have
+     *                   unlocked this key.
+     *
+     * @throws KeystoreIsLocked Occurs when the requested key keystore cannot
+     *                          be used because it has not been unlocked.
+     * @throws KeyIsLocked Occurs when the requested private key in the key
+     *                     keystore cannot be used because it has not been
+     *                     unlocked.
+     */
+    SSLContext createSSLContext(String provider, String protocol,
+                                String algorithm, String keyStore,
+                                String keyAlias, String trustStore) throws GeneralSecurityException;
+
+    /**
+     * Gets a ServerSocketFactory using one Keystore to access the private key
+     * and another to provide the list of trusted certificate authorities.
+     * @param provider
+     * @param protocol The SSL protocol to use
+     * @param algorithm The SSL algorithm to use
+     * @param keyStore The key keystore name as provided by listKeystores.  The
+     *                 KeystoreInstance for this keystore must be unlocked.
+     * @param keyAlias The name of the private key in the keystore.  The
+     *                 KeystoreInstance for this keystore must have unlocked
+     *                 this key.
+     * @param trustStore The trust keystore name as provided by listKeystores.
+     *                   The KeystoreInstance for this keystore must have
+     *                   unlocked this key.
+     *
+     * @throws KeystoreIsLocked Occurs when the requested key keystore cannot
+     *                          be used because it has not been unlocked.
+     * @throws KeyIsLocked Occurs when the requested private key in the key
+     *                     keystore cannot be used because it has not been
+     *                     unlocked.
+     */
+    SSLServerSocketFactory createSSLServerFactory(String provider, String protocol,
+                                                  String algorithm, String keyStore,
+                                                  String keyAlias, String trustStore) throws GeneralSecurityException;
+
+    /**
+     * Gets a SocketFactory using one Keystore to access the private key
+     * and another to provide the list of trusted certificate authorities.
+     * @param provider The SSL provider to use, or null for the default
+     * @param protocol The SSL protocol to use
+     * @param algorithm The SSL algorithm to use
+     * @param keyStore The key keystore name as provided by listKeystores.  The
+     *                 KeystoreInstance for this keystore must be unlocked.
+     * @param keyAlias The name of the private key in the keystore.  The
+     *                 KeystoreInstance for this keystore must have unlocked
+     *                 this key.
+     * @param trustStore The trust keystore name as provided by listKeystores.
+     *                   The KeystoreInstance for this keystore must have
+     *                   unlocked this key.
+     *
+     * @throws KeystoreIsLocked Occurs when the requested key keystore cannot
+     *                          be used because it has not been unlocked.
+     * @throws KeyIsLocked Occurs when the requested private key in the key
+     *                     keystore cannot be used because it has not been
+     *                     unlocked.
+     * @throws GeneralSecurityException
+     */
+    SSLSocketFactory createSSLFactory(String provider, String protocol,
+                                      String algorithm, String keyStore,
+                                      String keyAlias, String trustStore) throws GeneralSecurityException;
+
+}
diff --git a/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/Config.java b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/Config.java
new file mode 100644
index 0000000..7ad0b04
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/Config.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.jaas.config.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.security.auth.login.AppConfigurationEntry;
+
+import org.apache.servicemix.kernel.jaas.boot.ProxyLoginModule;
+import org.apache.servicemix.kernel.jaas.config.JaasRealm;
+import org.osgi.framework.BundleContext;
+import org.springframework.osgi.context.BundleContextAware;
+
+/**
+ * An implementation of JaasRealm which is created
+ * by the spring namespace handler.
+ */
+public class Config implements JaasRealm, BundleContextAware {
+
+    private String name;
+    private int rank;
+    private Module[] modules;
+    private BundleContext bundleContext;
+    private transient AppConfigurationEntry[] entries;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public int getRank() {
+        return rank;
+    }
+
+    public void setRank(int rank) {
+        this.rank = rank;
+    }
+
+    public Module[] getModules() {
+        return modules;
+    }
+
+    public void setModules(Module[] modules) {
+        this.modules = modules;
+        this.entries = null;
+    }
+
+    public BundleContext getBundleContext() {
+        return bundleContext;
+    }
+
+    public void setBundleContext(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+
+    public AppConfigurationEntry[] getEntries() {
+        if (this.entries == null && this.modules != null) {
+            Module[] modules = this.modules;
+            AppConfigurationEntry[] entries = new AppConfigurationEntry[modules.length];
+            for (int i = 0; i < modules.length; i++) {
+                Map<String,String> options = new HashMap<String,String>();
+                if (modules[i].getOptions() != null) {
+                    options.putAll(modules[i].getOptions());
+                }
+                options.put(ProxyLoginModule.PROPERTY_MODULE, modules[i].getClassName());
+                options.put(ProxyLoginModule.PROPERTY_BUNDLE, Long.toString(bundleContext.getBundle().getBundleId()));
+                entries[i] = new AppConfigurationEntry(ProxyLoginModule.class.getName(),
+                                                       getControlFlag(modules[i].getFlags()),
+                                                       options);
+            }
+            this.entries = entries;
+        }
+        return this.entries;
+    }
+
+    private AppConfigurationEntry.LoginModuleControlFlag getControlFlag(String flags) {
+        if ("required".equalsIgnoreCase(flags)) {
+            return AppConfigurationEntry.LoginModuleControlFlag.REQUIRED;
+        }
+        if ("optional".equalsIgnoreCase(flags)) {
+            return AppConfigurationEntry.LoginModuleControlFlag.OPTIONAL;
+        }
+        if ("requisite".equalsIgnoreCase(flags)) {
+            return AppConfigurationEntry.LoginModuleControlFlag.REQUISITE;
+        }
+        if ("sufficient".equalsIgnoreCase(flags)) {
+            return AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT;
+        }
+        return null;
+    }
+}
diff --git a/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/ConfigParser.java b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/ConfigParser.java
new file mode 100644
index 0000000..5f8e16a
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/ConfigParser.java
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.jaas.config.impl;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.w3c.dom.Element;
+
+import org.apache.servicemix.kernel.jaas.boot.ProxyLoginModule;
+import org.apache.servicemix.kernel.jaas.config.JaasRealm;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.BeanDefinitionHolder;
+import org.springframework.beans.factory.parsing.BeanComponentDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.ManagedList;
+import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.osgi.service.exporter.support.OsgiServiceFactoryBean;
+import org.springframework.util.xml.DomUtils;
+
+public class ConfigParser extends AbstractSingleBeanDefinitionParser {
+
+    protected Class getBeanClass(Element element) {
+        return Config.class;
+    }
+
+    protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
+        String name = element.getAttribute("name");
+        if (name == null || name.length() == 0) {
+            name = element.getAttribute("id");
+        }
+        builder.addPropertyValue("name", name);
+        String rank = element.getAttribute("rank");
+        if (rank != null && rank.length() > 0) {
+            builder.addPropertyValue("rank", Integer.parseInt(rank));
+        }
+        List childElements = DomUtils.getChildElementsByTagName(element, "module");
+        if (childElements != null && childElements.size() > 0) {
+            ManagedList children = new ManagedList(childElements.size());
+            for (int i = 0; i < childElements.size(); ++i) {
+                Element childElement = (Element) childElements.get(i);
+                BeanDefinitionBuilder bd = BeanDefinitionBuilder.genericBeanDefinition(Module.class);
+                bd.addPropertyValue("className", childElement.getAttribute("className"));
+                if (childElement.getAttribute("flags") != null) {
+                    bd.addPropertyValue("flags", childElement.getAttribute("flags"));
+                }
+                String options = DomUtils.getTextValue(childElement);
+                if (options != null && options.length() > 0) {
+                    Properties props = new Properties();
+                    try {
+                        props.load(new ByteArrayInputStream(options.getBytes()));
+                    } catch (IOException e) {
+                        throw new IllegalStateException("Can not load options for JAAS module "
+                                        + childElement.getAttribute("className") + " in config " + name);
+                    }
+                    bd.addPropertyValue("options", props);
+                }
+                children.add(bd.getBeanDefinition());
+            }
+            builder.addPropertyValue("modules", children);
+        }
+        // Publish to OSGi
+        String publish = element.getAttribute("publish");
+        if (Boolean.valueOf(publish)) {
+            // Publish Config
+            BeanDefinitionBuilder bd = BeanDefinitionBuilder.genericBeanDefinition(OsgiServiceFactoryBean.class);
+            bd.addPropertyValue("target", builder.getBeanDefinition());
+            bd.addPropertyValue("interfaces", new Class[] { JaasRealm.class });
+            Map<String,String> props = new HashMap<String,String>();
+            props.put(ProxyLoginModule.PROPERTY_MODULE, name);
+            bd.addPropertyValue("serviceProperties", props);
+            BeanDefinition def = bd.getBeanDefinition();
+            String id = parserContext.getReaderContext().generateBeanName(def);
+            BeanDefinitionHolder holder = new BeanDefinitionHolder(def, id);
+            registerBeanDefinition(holder, parserContext.getRegistry());
+            if (shouldFireEvents()) {
+                BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);
+                postProcessComponentDefinition(componentDefinition);
+                parserContext.registerComponent(componentDefinition);
+            }
+        }
+    }
+}
diff --git a/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/Module.java b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/Module.java
new file mode 100644
index 0000000..488f19a
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/Module.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.jaas.config.impl;
+
+import java.util.Map;
+
+/**
+ * POJO for a login module.
+ * It contains the class name, flags and a map of options.
+ */
+public class Module {
+
+    private String className;
+    private String flags;
+    private Map<String,String> options;
+
+    public String getClassName() {
+        return className;
+    }
+
+    public void setClassName(String className) {
+        this.className = className;
+    }
+
+    public String getFlags() {
+        return flags;
+    }
+
+    public void setFlags(String flags) {
+        this.flags = flags;
+    }
+
+    public Map<String, String> getOptions() {
+        return options;
+    }
+
+    public void setOptions(Map<String, String> options) {
+        this.options = options;
+    }
+
+}
diff --git a/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/NamespaceHandler.java b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/NamespaceHandler.java
new file mode 100644
index 0000000..d1b8192
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/NamespaceHandler.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.jaas.config.impl;
+
+import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
+
+public class NamespaceHandler extends NamespaceHandlerSupport {
+
+    public void init() {
+        registerBeanDefinitionParser("config", new ConfigParser());
+        registerBeanDefinitionParser("keystore", new ResourceKeystoreInstanceParser());
+    }
+
+
+}
diff --git a/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/OsgiConfiguration.java b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/OsgiConfiguration.java
new file mode 100644
index 0000000..a2e6119
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/OsgiConfiguration.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.jaas.config.impl;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+
+import org.apache.servicemix.kernel.jaas.config.JaasRealm;
+
+public class OsgiConfiguration extends Configuration {
+
+    private List<JaasRealm> realms;
+
+    public void init() {
+        realms = new CopyOnWriteArrayList<JaasRealm>();
+        Configuration.setConfiguration(this);
+    }
+
+    public void close() {
+        realms.clear();
+        realms = null;
+        Configuration.setConfiguration(null);
+    }
+
+    public void register(JaasRealm realm, Map<String,?> properties) {
+        realms.add(realm);
+    }
+
+    public void unregister(JaasRealm realm, Map<String,?> properties) {
+        if (realms != null) {
+            realms.remove(realm);
+        }
+    }
+
+    public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
+        JaasRealm realm = null;
+        for (JaasRealm r : realms) {
+            if (r.getName().equals(name)) {
+                if (realm == null || r.getRank() > realm.getRank()) {
+                    realm = r;
+                }
+            }
+        }
+        if (realm != null) {
+            return realm.getEntries();
+        }
+        return null;
+    }
+
+    public void refresh() {
+        // Nothing to do, as we auto-update the configuration
+    }
+}
diff --git a/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/OsgiKeystoreManager.java b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/OsgiKeystoreManager.java
new file mode 100644
index 0000000..41135c2
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/OsgiKeystoreManager.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.jaas.config.impl;
+
+import java.security.GeneralSecurityException;
+import java.security.SecureRandom;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocketFactory;
+
+import org.apache.servicemix.kernel.jaas.config.KeystoreInstance;
+import org.apache.servicemix.kernel.jaas.config.KeystoreIsLocked;
+import org.apache.servicemix.kernel.jaas.config.KeystoreManager;
+
+/**
+ * Implementation of KeystoreManager
+ */
+public class OsgiKeystoreManager implements KeystoreManager {
+
+    private List<KeystoreInstance> keystores = new CopyOnWriteArrayList<KeystoreInstance>();
+
+    public void register(KeystoreInstance keystore, Map<String,?> properties) {
+        keystores.add(keystore);
+    }
+
+    public void unregister(KeystoreInstance keystore, Map<String,?> properties) {
+        keystores.remove(keystore);
+    }
+
+    public KeystoreInstance getKeystore(String name) {
+        KeystoreInstance keystore = null;
+        for (KeystoreInstance ks : keystores) {
+            if (ks.getName().equals(name)) {
+                if (keystore == null || keystore.getRank() < ks.getRank()) {
+                    keystore = ks;
+                }
+            }
+        }
+        return keystore;
+    }
+
+    public SSLContext createSSLContext(String provider, String protocol, String algorithm, String keyStore, String keyAlias, String trustStore) throws GeneralSecurityException {
+        KeystoreInstance keyInstance = getKeystore(keyStore);
+        if (keyInstance != null && keyInstance.isKeystoreLocked()) {
+            throw new KeystoreIsLocked("Keystore '" + keyStore + "' is locked");
+        }
+        if (keyInstance != null && keyInstance.isKeyLocked(keyAlias)) {
+            throw new KeystoreIsLocked("Key '" + keyAlias + "' in keystore '" + keyStore + "' is locked");
+        }
+        KeystoreInstance trustInstance = trustStore == null ? null : getKeystore(trustStore);
+        if (trustInstance != null && trustInstance.isKeystoreLocked()) {
+            throw new KeystoreIsLocked("Keystore '" + trustStore + "' is locked");
+        }
+        SSLContext context;
+        if (provider == null) {
+            context = SSLContext.getInstance(protocol);
+        } else {
+            context = SSLContext.getInstance(protocol, provider);
+        }
+        context.init(keyInstance == null ? null : keyInstance.getKeyManager(algorithm, keyAlias),
+                     trustInstance == null ? null : trustInstance.getTrustManager(algorithm), new SecureRandom());
+        return context;
+    }
+
+    public SSLServerSocketFactory createSSLServerFactory(String provider, String protocol, String algorithm, String keyStore, String keyAlias, String trustStore) throws GeneralSecurityException {
+        SSLContext context = createSSLContext(provider, protocol, algorithm, keyStore, keyAlias, trustStore);
+        return context.getServerSocketFactory();
+    }
+
+    public SSLSocketFactory createSSLFactory(String provider, String protocol, String algorithm, String keyStore, String keyAlias, String trustStore) throws GeneralSecurityException {
+        SSLContext context = createSSLContext(provider, protocol, algorithm, keyStore, keyAlias, trustStore);
+        return context.getSocketFactory();
+    }
+}
diff --git a/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/ProxyLoginModuleInitializer.java b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/ProxyLoginModuleInitializer.java
new file mode 100644
index 0000000..f2b8c32
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/ProxyLoginModuleInitializer.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.jaas.config.impl;
+
+import org.apache.servicemix.kernel.jaas.boot.ProxyLoginModule;
+import org.osgi.framework.BundleContext;
+import org.springframework.osgi.context.BundleContextAware;
+
+public class ProxyLoginModuleInitializer implements BundleContextAware {
+
+    private BundleContext bundleContext;
+
+    public void setBundleContext(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+
+    public void init() {
+        BundleContext context = bundleContext.getBundle(0).getBundleContext();
+        ProxyLoginModule.init(context);
+    }
+}
diff --git a/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/ResourceKeystoreInstance.java b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/ResourceKeystoreInstance.java
new file mode 100644
index 0000000..7974ed6
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/ResourceKeystoreInstance.java
@@ -0,0 +1,289 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.jaas.config.impl;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.servicemix.kernel.jaas.config.KeystoreInstance;
+import org.apache.servicemix.kernel.jaas.config.KeystoreIsLocked;
+import org.springframework.core.io.Resource;
+
+/**
+ *
+ */
+public class ResourceKeystoreInstance implements KeystoreInstance {
+
+    private static final Log LOG = LogFactory.getLog(ResourceKeystoreInstance.class);
+    private static final String JKS = "JKS";
+
+    private String name;
+    private int rank;
+    private Resource path;
+    private String keystorePassword;
+    private Map keyPasswords = new HashMap();
+    private File keystoreFile; // Only valid after startup and if the resource points to a file
+
+    // The following variables are the state of the keystore, which should be chucked if the file on disk changes
+    private List privateKeys = new ArrayList();
+    private List trustCerts = new ArrayList();
+    private KeyStore keystore;
+    private long keystoreReadDate = Long.MIN_VALUE;
+
+    /**
+     * @return the keystoreName
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @param keystoreName the keystoreName to set
+     */
+    public void setName(String keystoreName) {
+        this.name = keystoreName;
+    }
+
+    /**
+     * @return the rank
+     */
+    public int getRank() {
+        return rank;
+    }
+
+    /**
+     * @param rank the rank to set
+     */
+    public void setRank(int rank) {
+        this.rank = rank;
+    }
+
+    /**
+     * @return the keystorePath
+     */
+    public Resource getPath() {
+        return path;
+    }
+
+    /**
+     * @param keystorePath the keystorePath to set
+     */
+    public void setPath(Resource keystorePath) throws IOException {
+        this.path = keystorePath;
+        if (keystorePath.getURL().getProtocol().equals("file")) {
+            this.keystoreFile = keystorePath.getFile();
+        }
+    }
+
+    /**
+     * @param keystorePassword the keystorePassword to set
+     */
+    public void setKeystorePassword(String keystorePassword) {
+        this.keystorePassword = keystorePassword;
+    }
+
+    /**
+     * @param keyPasswords the keyPasswords to set
+     */
+    public void setKeyPasswords(String keyPasswords) {
+        if (keyPasswords != null) {
+            String[] keys = keyPasswords.split("\\]\\!\\[");
+            for (int i = 0; i < keys.length; i++) {
+                String key = keys[i];
+                int pos = key.indexOf('=');
+                this.keyPasswords.put(key.substring(0, pos), key.substring(pos + 1).toCharArray());
+            }
+        }
+    }
+
+    public Certificate getCertificate(String alias) {
+        if (!loadKeystoreData()) {
+            return null;
+        }
+        try {
+            return keystore.getCertificate(alias);
+        } catch (KeyStoreException e) {
+            LOG.error("Unable to read certificate from keystore", e);
+        }
+        return null;
+    }
+
+    public String getCertificateAlias(Certificate cert) {
+        if (!loadKeystoreData()) {
+            return null;
+        }
+        try {
+            return keystore.getCertificateAlias(cert);
+        } catch (KeyStoreException e) {
+            LOG.error("Unable to read retrieve alias for given certificate from keystore", e);
+        }
+        return null;
+    }
+
+    public Certificate[] getCertificateChain(String alias) {
+        if (!loadKeystoreData()) {
+            return null;
+        }
+        try {
+            return keystore.getCertificateChain(alias);
+        } catch (KeyStoreException e) {
+            LOG.error("Unable to read certificate chain from keystore", e);
+        }
+        return null;
+    }
+
+    public KeyManager[] getKeyManager(String algorithm, String keyAlias) throws KeystoreIsLocked,
+                                    NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException {
+        if (isKeystoreLocked()) {
+            throw new KeystoreIsLocked("Keystore '" + name + "' is locked.");
+        }
+        if (!loadKeystoreData()) {
+            return null;
+        }
+        KeyManagerFactory keyFactory = KeyManagerFactory.getInstance(algorithm);
+        keyFactory.init(keystore, (char[]) keyPasswords.get(keyAlias));
+        return keyFactory.getKeyManagers();
+    }
+
+    public PrivateKey getPrivateKey(String alias) {
+        if (!loadKeystoreData()) {
+            return null;
+        }
+        try {
+            if (isKeyLocked(alias)) {
+                return null;
+            }
+            Key key = keystore.getKey(alias, (char[]) keyPasswords.get(alias));
+            if (key instanceof PrivateKey) {
+                return (PrivateKey) key;
+            }
+        } catch (KeyStoreException e) {
+            LOG.error("Unable to read private key from keystore", e);
+        } catch (NoSuchAlgorithmException e) {
+            LOG.error("Unable to read private key from keystore", e);
+        } catch (UnrecoverableKeyException e) {
+            LOG.error("Unable to read private key from keystore", e);
+        }
+        return null;
+    }
+
+    public TrustManager[] getTrustManager(String algorithm) throws KeyStoreException,
+                                            NoSuchAlgorithmException, KeystoreIsLocked {
+        if (isKeystoreLocked()) {
+            throw new KeystoreIsLocked("Keystore '" + name + "' is locked.");
+        }
+        if (!loadKeystoreData()) {
+            return null;
+        }
+        TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(algorithm);
+        trustFactory.init(keystore);
+        return trustFactory.getTrustManagers();
+    }
+
+    public boolean isKeyLocked(String keyAlias) {
+        return keyPasswords.get(keyAlias) == null;
+    }
+
+    public boolean isKeystoreLocked() {
+        return keystorePassword == null;
+    }
+
+    public String[] listPrivateKeys() {
+        if (!loadKeystoreData()) {
+            return null;
+        }
+        return (String[]) privateKeys.toArray(new String[privateKeys.size()]);
+    }
+
+    public String[] listTrustCertificates() {
+        if (!loadKeystoreData()) {
+            return null;
+        }
+        return (String[]) trustCerts.toArray(new String[trustCerts.size()]);
+    }
+
+    // ==================== Internals =====================
+
+    private boolean loadKeystoreData() {
+        // Check to reload the data if needed
+        if (keystoreFile != null && keystoreReadDate >= keystoreFile.lastModified()) {
+            return true;
+        }
+        // If not a file, just not reload the data if it has already been loaded
+        if (keystoreFile == null && keystore != null) {
+            return true;
+        }
+        // Check if the file is invalid
+        if (keystoreFile != null && (!keystoreFile.exists() || !keystoreFile.canRead())) {
+            throw new IllegalArgumentException("Invalid keystore file (" + path + " = " + keystoreFile.getAbsolutePath() + ")");
+        }
+        // Load the keystore data
+        try {
+            keystoreReadDate = System.currentTimeMillis();
+            privateKeys.clear();
+            trustCerts.clear();
+            if (keystore == null) {
+                keystore = KeyStore.getInstance(JKS);
+            }
+            InputStream in = new BufferedInputStream(path.getInputStream());
+            keystore.load(in, keystorePassword == null ? new char[0] : keystorePassword.toCharArray());
+            in.close();
+            Enumeration aliases = keystore.aliases();
+            while (aliases.hasMoreElements()) {
+                String alias = (String) aliases.nextElement();
+                if (keystore.isKeyEntry(alias)) {
+                    privateKeys.add(alias);
+                } else if (keystore.isCertificateEntry(alias)) {
+                    trustCerts.add(alias);
+                }
+            }
+            return true;
+        } catch (KeyStoreException e) {
+            LOG.error("Unable to open keystore with provided password", e);
+        } catch (IOException e) {
+            LOG.error("Unable to open keystore with provided password", e);
+        } catch (NoSuchAlgorithmException e) {
+            LOG.error("Unable to open keystore with provided password", e);
+        } catch (CertificateException e) {
+            LOG.error("Unable to open keystore with provided password", e);
+        }
+        return false;
+    }
+
+}
diff --git a/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/ResourceKeystoreInstanceParser.java b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/ResourceKeystoreInstanceParser.java
new file mode 100644
index 0000000..01f3531
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/java/org/apache/servicemix/kernel/jaas/config/impl/ResourceKeystoreInstanceParser.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.jaas.config.impl;
+
+import org.w3c.dom.Element;
+
+import org.apache.servicemix.kernel.jaas.config.KeystoreInstance;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.BeanDefinitionHolder;
+import org.springframework.beans.factory.parsing.BeanComponentDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.osgi.service.exporter.support.OsgiServiceFactoryBean;
+
+/**
+ * Spring parser for a keystore instance
+ */
+public class ResourceKeystoreInstanceParser extends AbstractSingleBeanDefinitionParser {
+
+    public static final String PUBLISH_ATTRIBUTE = "publish";
+
+    protected Class getBeanClass(Element element) {
+        return ResourceKeystoreInstance.class;
+    }
+
+    protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
+        // Parse name
+        String name = element.getAttribute("name");
+        if (name == null || name.length() == 0) {
+            name = element.getAttribute("id");
+        }
+        if (name != null && name.length() > 0) {
+            builder.addPropertyValue("name", name);
+        }
+        // Parse rank
+        String rank = element.getAttribute("rank");
+        if (rank != null && rank.length() > 0) {
+            builder.addPropertyValue("rank", rank);
+        }
+        // Parse path
+        String path = element.getAttribute("path");
+        if (path != null && path.length() > 0) {
+            builder.addPropertyValue("path", path);
+        }
+        // Parse keystorePassword
+        String keystorePassword = element.getAttribute("keystorePassword");
+        if (keystorePassword != null && keystorePassword.length() > 0) {
+            builder.addPropertyValue("keystorePassword", keystorePassword);
+        }
+        // Parse keyPasswords
+        String keyPasswords = element.getAttribute("keyPasswords");
+        if (keyPasswords != null && keyPasswords.length() > 0) {
+            builder.addPropertyValue("keyPasswords", keyPasswords);
+        }
+        // Parse publish
+        String publish = element.getAttribute("publish");
+        if (Boolean.valueOf(publish)) {
+            // Publish Config
+            BeanDefinitionBuilder bd = BeanDefinitionBuilder.genericBeanDefinition(OsgiServiceFactoryBean.class);
+            bd.addPropertyValue("target", builder.getBeanDefinition());
+            bd.addPropertyValue("interfaces", new Class[] { KeystoreInstance.class });
+            BeanDefinition def = bd.getBeanDefinition();
+            String id = parserContext.getReaderContext().generateBeanName(def);
+            BeanDefinitionHolder holder = new BeanDefinitionHolder(def, id);
+            registerBeanDefinition(holder, parserContext.getRegistry());
+            if (shouldFireEvents()) {
+                BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);
+                postProcessComponentDefinition(componentDefinition);
+                parserContext.registerComponent(componentDefinition);
+            }
+        }
+    }
+
+}
diff --git a/karaf/jaas/jaas-config/src/main/resources/META-INF/spring.handlers b/karaf/jaas/jaas-config/src/main/resources/META-INF/spring.handlers
new file mode 100644
index 0000000..fe59e34
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/resources/META-INF/spring.handlers
@@ -0,0 +1,20 @@
+################################################################################
+#
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+################################################################################
+http\://servicemix.apache.org/jaas = org.apache.servicemix.kernel.jaas.config.impl.NamespaceHandler
+ 
\ No newline at end of file
diff --git a/karaf/jaas/jaas-config/src/main/resources/META-INF/spring.schemas b/karaf/jaas/jaas-config/src/main/resources/META-INF/spring.schemas
new file mode 100644
index 0000000..3001be1
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/resources/META-INF/spring.schemas
@@ -0,0 +1,19 @@
+################################################################################
+#
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+################################################################################
+http\://servicemix.apache.org/schema/servicemix-jaas.xsd = org/apache/servicemix/kernel/jaas/config/servicemix-jaas.xsd
diff --git a/karaf/jaas/jaas-config/src/main/resources/META-INF/spring/servicemix-jaas.xml b/karaf/jaas/jaas-config/src/main/resources/META-INF/spring/servicemix-jaas.xml
new file mode 100644
index 0000000..eca5fbd
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/resources/META-INF/spring/servicemix-jaas.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<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/beans
+  http://www.springframework.org/schema/beans/spring-beans.xsd
+  http://www.springframework.org/schema/util
+  http://www.springframework.org/schema/util/spring-util.xsd
+  http://www.springframework.org/schema/osgi
+  http://www.springframework.org/schema/osgi/spring-osgi.xsd">
+
+    <bean id="config"
+          class="org.apache.servicemix.kernel.jaas.config.impl.OsgiConfiguration"
+          init-method="init"
+          destroy-method="close"/>
+
+    <osgi:list id="realms"
+               interface="org.apache.servicemix.kernel.jaas.config.JaasRealm"
+               cardinality="0..N">
+        <osgi:listener ref="config" bind-method="register" unbind-method="unregister" />
+    </osgi:list>
+
+    <bean id="proxyLoginModuleInitializer"
+          class="org.apache.servicemix.kernel.jaas.config.impl.ProxyLoginModuleInitializer"
+          init-method="init"/>
+
+    <!-- Register the Straight-Through flow -->
+    <bean id="keystoreManager" class="org.apache.servicemix.kernel.jaas.config.impl.OsgiKeystoreManager" />
+    <osgi:service ref="keystoreManager">
+        <osgi:interfaces>
+            <value>org.apache.servicemix.kernel.jaas.config.KeystoreManager</value>
+        </osgi:interfaces>
+    </osgi:service>
+
+    <osgi:list id="keystores"
+               interface="org.apache.servicemix.kernel.jaas.config.KeystoreInstance"
+               cardinality="0..N">
+        <osgi:listener ref="keystoreManager" bind-method="register" unbind-method="unregister" />
+    </osgi:list>
+
+</beans>
diff --git a/karaf/jaas/jaas-config/src/main/resources/org/apache/servicemix/kernel/jaas/config/servicemix-jaas.xsd b/karaf/jaas/jaas-config/src/main/resources/org/apache/servicemix/kernel/jaas/config/servicemix-jaas.xsd
new file mode 100644
index 0000000..320e04d
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/main/resources/org/apache/servicemix/kernel/jaas/config/servicemix-jaas.xsd
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<xs:schema elementFormDefault='qualified'
+           targetNamespace='http://servicemix.apache.org/jaas'
+           xmlns:xs='http://www.w3.org/2001/XMLSchema'
+           xmlns:beans="http://www.springframework.org/schema/beans"
+           xmlns:tns='http://servicemix.apache.org/jaas'>
+
+    <xs:import namespace="http://www.springframework.org/schema/beans"/>
+
+    <xs:element name="config">
+        <xs:complexType>
+            <xs:complexContent>
+                <xs:extension base="beans:identifiedType">
+                    <xs:sequence>
+                        <xs:element name="module" minOccurs="0" maxOccurs="unbounded">
+                            <xs:complexType mixed="true">
+                                <xs:attribute name="className" use="required" type="xs:string" />
+                                <xs:attribute name="flags" default="required">
+                                    <xs:simpleType>
+                                        <xs:restriction base="xs:NMTOKEN">
+                                            <xs:enumeration value="required"/>
+                                            <xs:enumeration value="requisite"/>
+                                            <xs:enumeration value="sufficient"/>
+                                            <xs:enumeration value="optional"/>
+                                        </xs:restriction>
+                                    </xs:simpleType>
+                                </xs:attribute>
+                            </xs:complexType>
+                        </xs:element>
+                    </xs:sequence>
+                    <xs:attribute name="name" use="optional" type="xs:string" />
+                    <xs:attribute name="rank" use="optional" default="0" type="xs:int" />
+                    <xs:attribute name="publish" use="optional" default="true" type="xs:boolean" />
+                </xs:extension>
+            </xs:complexContent>
+        </xs:complexType>
+    </xs:element>
+
+    <xs:element name="keystore">
+        <xs:complexType>
+            <xs:complexContent>
+                <xs:extension base="beans:identifiedType">
+                    <xs:attribute name="name" use="optional" type="xs:string" />
+                    <xs:attribute name="rank" use="optional" default="0" type="xs:int" />
+                    <xs:attribute name="publish" use="optional" default="true" type="xs:boolean" />
+                    <xs:attribute name="path" use="required" type="xs:string" />
+                    <xs:attribute name="keystorePassword" use="optional" type="xs:string" />
+                    <xs:attribute name="keyPasswords" use="optional" type="xs:string" />
+                </xs:extension>
+            </xs:complexContent>
+        </xs:complexType>
+    </xs:element>
+    
+</xs:schema>
diff --git a/karaf/jaas/jaas-config/src/test/java/org/apache/servicemix/kernel/jaas/config/NamespaceHandlerTest.java b/karaf/jaas/jaas-config/src/test/java/org/apache/servicemix/kernel/jaas/config/NamespaceHandlerTest.java
new file mode 100644
index 0000000..fb282e9
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/test/java/org/apache/servicemix/kernel/jaas/config/NamespaceHandlerTest.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.jaas.config;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Map;
+
+import javax.security.auth.login.AppConfigurationEntry;
+
+import junit.framework.TestCase;
+import org.apache.servicemix.kernel.jaas.boot.ProxyLoginModule;
+import org.apache.servicemix.kernel.jaas.config.impl.Config;
+import org.easymock.EasyMock;
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.aryEq;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.context.support.AbstractApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import org.springframework.osgi.context.support.BundleContextAwareProcessor;
+
+public class NamespaceHandlerTest extends TestCase {
+
+    public void testConfig() throws Exception {
+        final Dictionary headers = new Hashtable();
+        headers.put(Constants.BUNDLE_VERSION, "1.0.0.SNAPSHOT");
+
+        final BundleContext bundleContext = EasyMock.createMock(BundleContext.class);
+        final Bundle bundle = EasyMock.createMock(Bundle.class);
+        final ServiceRegistration reg = EasyMock.createMock(ServiceRegistration.class);
+
+        expect(bundleContext.getBundle()).andReturn(bundle).anyTimes();
+        expect(bundle.getSymbolicName()).andReturn("symbolic-name").anyTimes();
+        expect(bundle.getBundleId()).andReturn(Long.valueOf(32)).anyTimes();
+        expect(bundle.getHeaders()).andReturn(headers).anyTimes();
+        expect(bundleContext.registerService(aryEq(new String[] { JaasRealm.class.getName() }),
+                                             anyObject(), EasyMock.<Dictionary>anyObject())).andReturn(reg);
+        expect(bundleContext.registerService(aryEq(new String[] { KeystoreInstance.class.getName() }),
+                                             anyObject(), EasyMock.<Dictionary>anyObject())).andReturn(reg);
+
+        replay(bundleContext, bundle);
+
+        AbstractApplicationContext ctx = new ClassPathXmlApplicationContext(new String[] { "classpath:config.xml" }, false) {
+            protected DefaultListableBeanFactory createBeanFactory() {
+                DefaultListableBeanFactory f = super.createBeanFactory();
+                f.addBeanPostProcessor(new BundleContextAwareProcessor(bundleContext));
+                return f;
+            }
+        };
+        ctx.refresh();
+
+        verify(bundleContext, bundle);
+
+        // Test realm
+        Object obj = ctx.getBean("realm");
+        assertNotNull(obj);
+        assertTrue(obj instanceof Config);
+        Config cfg = (Config) obj;
+        assertNotNull(cfg.getBundleContext());
+        assertEquals("realm", cfg.getName());
+        assertNotNull(cfg.getModules());
+        assertEquals(1, cfg.getModules().length);
+        assertNotNull(cfg.getModules()[0]);
+        assertEquals("org.apache.servicemix.kernel.jaas.config.SimpleLoginModule", cfg.getModules()[0].getClassName());
+        assertEquals("required", cfg.getModules()[0].getFlags());
+        assertNotNull(cfg.getModules()[0].getOptions());
+        assertEquals(1, cfg.getModules()[0].getOptions().size());
+        assertEquals("value", cfg.getModules()[0].getOptions().get("key"));
+        AppConfigurationEntry[] entries = cfg.getEntries();
+        assertNotNull(entries);
+        assertEquals(1, entries.length);
+        assertNotNull(entries[0]);
+        assertEquals(ProxyLoginModule.class.getName(), entries[0].getLoginModuleName());
+        assertEquals(AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, entries[0].getControlFlag());
+        Map<String,?> options = entries[0].getOptions();
+        assertNotNull(options);
+        assertEquals(3, options.size());
+        assertEquals("value", options.get("key"));
+        assertEquals("org.apache.servicemix.kernel.jaas.config.SimpleLoginModule", options.get(ProxyLoginModule.PROPERTY_MODULE));
+        assertEquals("32", options.get(ProxyLoginModule.PROPERTY_BUNDLE));
+
+        // Test keystore
+        obj = ctx.getBean("keystore");
+        assertNotNull(obj);
+        assertTrue(obj instanceof KeystoreInstance);
+        KeystoreInstance ks = (KeystoreInstance) obj;
+        assertEquals("ks", ks.getName());
+        assertEquals(1, ks.getRank());
+        assertNotNull(ks.getPrivateKey("myalias"));
+    }
+}
diff --git a/karaf/jaas/jaas-config/src/test/resources/config.xml b/karaf/jaas/jaas-config/src/test/resources/config.xml
new file mode 100644
index 0000000..868b7c7
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/test/resources/config.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<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"
+       xmlns:jaas="http://servicemix.apache.org/jaas"
+       xsi:schemaLocation="
+  http://www.springframework.org/schema/beans
+  http://www.springframework.org/schema/beans/spring-beans.xsd
+  http://www.springframework.org/schema/util
+  http://www.springframework.org/schema/util/spring-util.xsd
+  http://www.springframework.org/schema/osgi
+  http://www.springframework.org/schema/osgi/spring-osgi.xsd
+  http://servicemix.apache.org/jaas
+  http://servicemix.apache.org/schema/servicemix-jaas.xsd">
+
+    <jaas:config id="realm">
+        <jaas:module className="org.apache.servicemix.kernel.jaas.config.SimpleLoginModule" flags="required">
+            key=value
+        </jaas:module>
+    </jaas:config>
+
+    <jaas:keystore id="keystore"
+                   name="ks"
+                   rank="1"
+                   path="classpath:privatestore.jks"
+                   keystorePassword="keyStorePassword"
+                   keyPasswords="myalias=myAliasPassword" />
+
+</beans>
diff --git a/karaf/jaas/jaas-config/src/test/resources/privatestore.jks b/karaf/jaas/jaas-config/src/test/resources/privatestore.jks
new file mode 100644
index 0000000..26fc0bc
--- /dev/null
+++ b/karaf/jaas/jaas-config/src/test/resources/privatestore.jks
Binary files differ
diff --git a/karaf/jaas/jaas-modules/pom.xml b/karaf/jaas/jaas-modules/pom.xml
new file mode 100644
index 0000000..b3d0300
--- /dev/null
+++ b/karaf/jaas/jaas-modules/pom.xml
@@ -0,0 +1,92 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <!--
+
+        Licensed to the Apache Software Foundation (ASF) under one or more
+        contributor license agreements.  See the NOTICE file distributed with
+        this work for additional information regarding copyright ownership.
+        The ASF licenses this file to You under the Apache License, Version 2.0
+        (the "License"); you may not use this file except in compliance with
+        the License.  You may obtain a copy of the License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software
+        distributed under the License is distributed on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        See the License for the specific language governing permissions and
+        limitations under the License.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.servicemix.kernel.jaas</groupId>
+        <artifactId>jaas</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.servicemix.kernel.jaas</groupId>
+    <artifactId>org.apache.servicemix.kernel.jaas.modules</artifactId>
+    <packaging>bundle</packaging>
+    <version>1.2.0-SNAPSHOT</version>
+    <name>Apache ServiceMix Kernel :: JAAS Modules</name>
+
+    <description>
+        Provides the JAAS Config
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel.jaas</groupId>
+            <artifactId>org.apache.servicemix.kernel.jaas.config</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>commons-logging</groupId>
+            <artifactId>commons-logging</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.osgi</groupId>
+            <artifactId>spring-osgi-core</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>${artifactId}</Bundle-SymbolicName>
+                        <Export-Package>
+                            org.apache.servicemix.kernel.jaas.modules*;version=${project.version};-split-package:=merge-first
+                        </Export-Package>
+                        <Import-Package>
+                            org.apache.servicemix.kernel.jaas.config,
+                            org.springframework.beans.factory.config,
+                            *
+                        </Import-Package>
+                        <Spring-Context>*;publish-context:=false;create-asynchronously:=false</Spring-Context>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
\ No newline at end of file
diff --git a/karaf/jaas/jaas-modules/src/main/java/org/apache/servicemix/kernel/jaas/modules/RolePrincipal.java b/karaf/jaas/jaas-modules/src/main/java/org/apache/servicemix/kernel/jaas/modules/RolePrincipal.java
new file mode 100644
index 0000000..03da146
--- /dev/null
+++ b/karaf/jaas/jaas-modules/src/main/java/org/apache/servicemix/kernel/jaas/modules/RolePrincipal.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.jaas.modules;
+
+import java.security.Principal;
+
+public class RolePrincipal implements Principal {
+
+    private final String name;
+
+    public RolePrincipal(String name) {
+        assert name != null;
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof RolePrincipal)) return false;
+
+        RolePrincipal that = (RolePrincipal) o;
+
+        if (name != null ? !name.equals(that.name) : that.name != null) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return name != null ? name.hashCode() : 0;
+    }
+
+    @Override
+    public String toString() {
+        return "RolePrincipal[" + name + "]";
+    }
+}
diff --git a/karaf/jaas/jaas-modules/src/main/java/org/apache/servicemix/kernel/jaas/modules/UserPrincipal.java b/karaf/jaas/jaas-modules/src/main/java/org/apache/servicemix/kernel/jaas/modules/UserPrincipal.java
new file mode 100644
index 0000000..4978076
--- /dev/null
+++ b/karaf/jaas/jaas-modules/src/main/java/org/apache/servicemix/kernel/jaas/modules/UserPrincipal.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.jaas.modules;
+
+import java.security.Principal;
+
+public class UserPrincipal implements Principal {
+
+    private final String name;
+
+    public UserPrincipal(String name) {
+        assert name != null;
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof UserPrincipal)) return false;
+
+        UserPrincipal that = (UserPrincipal) o;
+
+        if (name != null ? !name.equals(that.name) : that.name != null) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return name != null ? name.hashCode() : 0;
+    }
+
+    @Override
+    public String toString() {
+        return "UserPrincipal[" + name + "]";
+    }
+}
diff --git a/karaf/jaas/jaas-modules/src/main/java/org/apache/servicemix/kernel/jaas/modules/osgi/ConfigAdminHolder.java b/karaf/jaas/jaas-modules/src/main/java/org/apache/servicemix/kernel/jaas/modules/osgi/ConfigAdminHolder.java
new file mode 100644
index 0000000..ec93095
--- /dev/null
+++ b/karaf/jaas/jaas-modules/src/main/java/org/apache/servicemix/kernel/jaas/modules/osgi/ConfigAdminHolder.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.jaas.modules.osgi;
+
+import org.osgi.service.cm.ConfigurationAdmin;
+
+public class ConfigAdminHolder {
+
+    private static ConfigurationAdmin configAdmin;
+
+    public static ConfigurationAdmin getService() {
+        return configAdmin;
+    }
+
+    public void setService(ConfigurationAdmin configAdmin) {
+        ConfigAdminHolder.configAdmin = configAdmin;
+    }
+
+}
diff --git a/karaf/jaas/jaas-modules/src/main/java/org/apache/servicemix/kernel/jaas/modules/osgi/OsgiConfigLoginModule.java b/karaf/jaas/jaas-modules/src/main/java/org/apache/servicemix/kernel/jaas/modules/osgi/OsgiConfigLoginModule.java
new file mode 100644
index 0000000..2b48eb4
--- /dev/null
+++ b/karaf/jaas/jaas-modules/src/main/java/org/apache/servicemix/kernel/jaas/modules/osgi/OsgiConfigLoginModule.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.jaas.modules.osgi;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.FailedLoginException;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+
+import org.apache.servicemix.kernel.jaas.modules.RolePrincipal;
+import org.apache.servicemix.kernel.jaas.modules.UserPrincipal;
+import org.osgi.service.cm.Configuration;
+
+public class OsgiConfigLoginModule implements LoginModule {
+
+    public static final String PID = "pid";
+    public static final String USER_PREFIX = "user.";
+
+    private Subject subject;
+    private CallbackHandler callbackHandler;
+    private Map<String, ?> options;
+
+    private Set<Principal> principals;
+
+    public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options) {
+        this.subject = subject;
+        this.callbackHandler = callbackHandler;
+        this.options = options;
+    }
+
+    public boolean login() throws LoginException {
+        try {
+            String pid = (String) options.get(PID);
+            Configuration config = ConfigAdminHolder.getService().getConfiguration(pid);
+            Dictionary properties = config.getProperties();
+
+            Callback[] callbacks = new Callback[2];
+
+            callbacks[0] = new NameCallback("Username: ");
+            callbacks[1] = new PasswordCallback("Password: ", false);
+            try {
+                callbackHandler.handle(callbacks);
+            } catch (IOException ioe) {
+                throw new LoginException(ioe.getMessage());
+            } catch (UnsupportedCallbackException uce) {
+                throw new LoginException(uce.getMessage() + " not available to obtain information from user");
+            }
+            String user = ((NameCallback) callbacks[0]).getName();
+            char[] tmpPassword = ((PasswordCallback) callbacks[1]).getPassword();
+            if (tmpPassword == null) {
+                tmpPassword = new char[0];
+            }
+
+            String userInfos = (String) properties.get(USER_PREFIX + user);
+            if (userInfos == null) {
+                throw new FailedLoginException("User does not exist");
+            }
+            String[] infos = userInfos.split(",");
+            if (!new String(tmpPassword).equals(infos[0])) {
+                throw new FailedLoginException("Password does not match");
+            }
+
+            principals = new HashSet<Principal>();
+            principals.add(new UserPrincipal(user));
+            for (int i = 1; i < infos.length; i++) {
+                principals.add(new RolePrincipal(infos[i]));
+            }
+
+            return true;
+        } catch (LoginException e) {
+            throw e;
+        } catch (Exception e) {
+            throw (LoginException) new LoginException("Unable to authenticate user").initCause(e);
+        } finally {
+            callbackHandler = null;
+            options = null;
+        }
+    }
+
+    public boolean commit() throws LoginException {
+        subject.getPrincipals().addAll(principals);
+        return true;
+    }
+
+    public boolean abort() throws LoginException {
+        subject = null;
+        principals = null;
+        return true;
+    }
+
+    public boolean logout() throws LoginException {
+        try {
+            subject.getPrincipals().removeAll(principals);
+            principals.clear();
+            return true;
+        } finally {
+            subject = null;
+            principals = null;
+        }
+    }
+
+}
diff --git a/karaf/jaas/jaas-modules/src/main/java/org/apache/servicemix/kernel/jaas/modules/properties/PropertiesLoginModule.java b/karaf/jaas/jaas-modules/src/main/java/org/apache/servicemix/kernel/jaas/modules/properties/PropertiesLoginModule.java
new file mode 100644
index 0000000..5971745
--- /dev/null
+++ b/karaf/jaas/jaas-modules/src/main/java/org/apache/servicemix/kernel/jaas/modules/properties/PropertiesLoginModule.java
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.jaas.modules.properties;
+
+import java.io.File;
+import java.io.IOException;
+import java.security.Principal;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.FailedLoginException;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.servicemix.kernel.jaas.modules.RolePrincipal;
+import org.apache.servicemix.kernel.jaas.modules.UserPrincipal;
+
+/**
+ * JAAS Login module for user / password, based on two properties files.
+ *
+ */
+public class PropertiesLoginModule implements LoginModule {
+
+    private static final String USER_FILE = "users";
+    private static final Log LOG = LogFactory.getLog(PropertiesLoginModule.class);
+
+    private Subject subject;
+    private CallbackHandler callbackHandler;
+    private boolean debug;
+    private String usersFile;
+    private String user;
+    private Set principals = new HashSet();
+
+    public void initialize(Subject sub, CallbackHandler handler, Map sharedState, Map options) {
+        this.subject = sub;
+        this.callbackHandler = handler;
+
+        debug = "true".equalsIgnoreCase((String) options.get("debug"));
+        usersFile = (String) options.get(USER_FILE) + "";
+
+        if (debug) {
+            LOG.debug("Initialized debug=" + debug + " usersFile=" + usersFile);
+        }
+    }
+
+    public boolean login() throws LoginException {
+        Properties users = new Properties();
+        File f = new File(usersFile);
+        try {
+            users.load(new java.io.FileInputStream(f));
+        } catch (IOException ioe) {
+            throw new LoginException("Unable to load user properties file " + f);
+        }
+
+        Callback[] callbacks = new Callback[2];
+
+        callbacks[0] = new NameCallback("Username: ");
+        callbacks[1] = new PasswordCallback("Password: ", false);
+        try {
+            callbackHandler.handle(callbacks);
+        } catch (IOException ioe) {
+            throw new LoginException(ioe.getMessage());
+        } catch (UnsupportedCallbackException uce) {
+            throw new LoginException(uce.getMessage() + " not available to obtain information from user");
+        }
+        user = ((NameCallback) callbacks[0]).getName();
+        char[] tmpPassword = ((PasswordCallback) callbacks[1]).getPassword();
+        if (tmpPassword == null) {
+            tmpPassword = new char[0];
+        }
+
+        String userInfos = (String) users.get(user);
+        if (userInfos == null) {
+            throw new FailedLoginException("User does not exist");
+        }
+        String[] infos = userInfos.split(",");
+        if (!new String(tmpPassword).equals(infos[0])) {
+            throw new FailedLoginException("Password does not match");
+        }
+
+        principals = new HashSet<Principal>();
+        principals.add(new UserPrincipal(user));
+        for (int i = 1; i < infos.length; i++) {
+            principals.add(new RolePrincipal(infos[i]));
+        }
+
+        users.clear();
+
+        if (debug) {
+            LOG.debug("login " + user);
+        }
+        return true;
+    }
+
+    public boolean commit() throws LoginException {
+        subject.getPrincipals().addAll(principals);
+        clear();
+        if (debug) {
+            LOG.debug("commit");
+        }
+        return true;
+    }
+
+    public boolean abort() throws LoginException {
+        clear();
+        if (debug) {
+            LOG.debug("abort");
+        }
+        return true;
+    }
+
+    public boolean logout() throws LoginException {
+        subject.getPrincipals().removeAll(principals);
+        principals.clear();
+        if (debug) {
+            LOG.debug("logout");
+        }
+        return true;
+    }
+
+    private void clear() {
+        user = null;
+    }
+}
diff --git a/karaf/jaas/jaas-modules/src/main/resources/META-INF/spring/servicemix-jaas-module.xml b/karaf/jaas/jaas-modules/src/main/resources/META-INF/spring/servicemix-jaas-module.xml
new file mode 100644
index 0000000..e8acabe
--- /dev/null
+++ b/karaf/jaas/jaas-modules/src/main/resources/META-INF/spring/servicemix-jaas-module.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<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:jaas="http://servicemix.apache.org/jaas"
+       xsi:schemaLocation="
+  http://www.springframework.org/schema/beans
+  http://www.springframework.org/schema/beans/spring-beans.xsd
+  http://www.springframework.org/schema/osgi
+  http://www.springframework.org/schema/osgi/spring-osgi.xsd
+  http://servicemix.apache.org/jaas
+  http://servicemix.apache.org/schema/servicemix-jaas.xsd">
+
+    <!--
+      - The following beans define an alternate realm which uses the OSGi Configuration Admin service
+      - to obtain passwords.  However, this realm is not really secure as there is no access restriction
+      - on this service, which means any bundle could access all the passwords.
+      -->
+    <!--
+    <bean id="configAdminHolder" class="org.apache.servicemix.kernel.jaas.modules.osgi.ConfigAdminHolder">
+        <property name="service" ref="configAdmin" />
+    </bean>
+
+    <osgi:reference id="configAdmin" interface="org.osgi.service.cm.ConfigurationAdmin" />
+
+    <jaas:config id="servicemix">
+        <jaas:module className="org.apache.servicemix.kernel.jaas.modules.osgi.OsgiConfigLoginModule" flags="required">
+            pid = org.apache.servicemix.users
+        </jaas:module>
+    </jaas:config>
+    -->
+
+    <!-- Bean to allow the ${servicemix.home} property to be correctly resolved -->
+    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" />
+
+    <jaas:config id="servicemix">
+        <jaas:module className="org.apache.servicemix.kernel.jaas.modules.properties.PropertiesLoginModule" flags="required">
+            users = ${servicemix.base}/etc/users.properties
+        </jaas:module>
+    </jaas:config>
+
+</beans>
\ No newline at end of file
diff --git a/karaf/jaas/pom.xml b/karaf/jaas/pom.xml
new file mode 100644
index 0000000..5be1cd7
--- /dev/null
+++ b/karaf/jaas/pom.xml
@@ -0,0 +1,42 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <!--
+
+        Licensed to the Apache Software Foundation (ASF) under one or more
+        contributor license agreements.  See the NOTICE file distributed with
+        this work for additional information regarding copyright ownership.
+        The ASF licenses this file to You under the Apache License, Version 2.0
+        (the "License"); you may not use this file except in compliance with
+        the License.  You may obtain a copy of the License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software
+        distributed under the License is distributed on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        See the License for the specific language governing permissions and
+        limitations under the License.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.servicemix.kernel</groupId>
+        <artifactId>kernel</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.servicemix.kernel.jaas</groupId>
+    <artifactId>jaas</artifactId>
+    <packaging>pom</packaging>
+    <version>1.2.0-SNAPSHOT</version>
+    <name>Apache ServiceMix Kernel :: JAAS</name>
+
+    <modules>
+        <module>jaas-boot</module>
+        <module>jaas-config</module>
+        <module>jaas-modules</module>
+    </modules>
+
+</project>
\ No newline at end of file
diff --git a/karaf/main/pom.xml b/karaf/main/pom.xml
new file mode 100644
index 0000000..4166785
--- /dev/null
+++ b/karaf/main/pom.xml
@@ -0,0 +1,202 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <!--
+
+        Licensed to the Apache Software Foundation (ASF) under one or more
+        contributor license agreements.  See the NOTICE file distributed with
+        this work for additional information regarding copyright ownership.
+        The ASF licenses this file to You under the Apache License, Version 2.0
+        (the "License"); you may not use this file except in compliance with
+        the License.  You may obtain a copy of the License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software
+        distributed under the License is distributed on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        See the License for the specific language governing permissions and
+        limitations under the License.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.servicemix.kernel</groupId>
+        <artifactId>kernel</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.servicemix.kernel</groupId>
+    <artifactId>org.apache.servicemix.kernel.main</artifactId>
+    <packaging>bundle</packaging>
+    <version>1.2.0-SNAPSHOT</version>
+    <name>Apache ServiceMix Kernel :: Main</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.framework</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <_donotcopy>(CVS|.svn|config.properties)</_donotcopy>
+                        <Main-Class>org.apache.servicemix.kernel.main.Main</Main-Class>
+                        <Bundle-Name>Apache ServiceMix</Bundle-Name>
+                        <Bundle-Description>OSGi R4 framework.</Bundle-Description>
+                        <Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName>
+                        <Export-Package>org.apache.servicemix.kernel.main.spi.*;version=${pom.version}</Export-Package>
+                        <Private-Package>
+                            org.apache.servicemix.kernel.main;-split-package:=merge-first,
+                            org.apache.felix.moduleloader.*;-split-package:=merge-first,
+                            org.apache.felix.framework.*;-split-package:=merge-first,
+                            org.osgi.framework.launch*,
+                            org.osgi.framework.hooks*,
+                            org.osgi.framework;-split-package:=merge-first,
+                            org.osgi.service.packageadmin;-split-package:=merge-first,
+                            org.osgi.service.startlevel;-split-package:=merge-first,
+                            org.osgi.service.url;-split-package:=merge-first,
+                            org.osgi.util.tracker;-split-package:=merge-first,
+                            META-INF;-split-package:=merge-first
+                        </Private-Package>
+                        <Import-Package>!*</Import-Package>
+                    </instructions>
+                    <unpackBundle>true</unpackBundle>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                        <configuration>
+                            <artifactSet>
+                                <includes>
+                                    <include>org.apache.felix:org.apache.felix.framework</include>
+                                    <include>org.apache.felix:org.osgi.core</include>
+                                    <include>${project.groupId}:${project.artifactId}</include>
+                                </includes>
+                            </artifactSet>
+                            <filters>
+                                <filter>
+                                    <artifact>org.apache.felix:org.apache.felix.framework</artifact>
+                                    <excludes>
+                                        <exclude>org/apache/felix/**</exclude>
+                                        <exclude>org/osgi/**</exclude>
+                                    </excludes>
+                                </filter>
+                                <filter>
+                                    <artifact>org.apache.felix:org.osgi.core</artifact>
+                                    <excludes>
+                                        <exclude>org/osgi/**</exclude>
+                                    </excludes>
+                                </filter>
+                            </filters>
+                            <createSourcesJar>${createSourcesJar}</createSourcesJar>
+                            <promoteTransitiveDependencies>true</promoteTransitiveDependencies>
+                            <createDependencyReducedPom>true</createDependencyReducedPom>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+                <filtering>true</filtering>
+            </resource>
+        </resources>
+    </build>
+
+    <profiles>
+        <profile>
+            <id>deploy</id>
+            <properties>
+                <createSourcesJar>true</createSourcesJar>
+            </properties>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-dependency-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>unpack-sources</id>
+                                <phase>generate-sources</phase>
+                                <goals>
+                                    <goal>unpack</goal>
+                                </goals>
+                                <configuration>
+                                    <artifactItems>
+                                        <artifactItem>
+                                            <groupId>org.apache.felix</groupId>
+                                            <artifactId>org.osgi.core</artifactId>
+                                            <classifier>sources</classifier>
+                                        </artifactItem>
+                                        <artifactItem>
+                                            <groupId>org.apache.felix</groupId>
+                                            <artifactId>org.apache.felix.framework</artifactId>
+                                            <classifier>sources</classifier>
+                                        </artifactItem>
+                                    </artifactItems>
+                                    <outputDirectory>${project.build.directory}/sources</outputDirectory>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-source-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>attach-sources</id>
+                                <phase>process-classes</phase>
+                                <goals>
+                                    <goal>jar</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-javadoc-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>package</id>
+                                <phase>package</phase>
+                                <goals>
+                                    <goal>jar</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                        <configuration>
+                            <minmemory>128m</minmemory>
+                            <maxmemory>512m</maxmemory>
+                            <sourcepath>${project.build.directory}/sources</sourcepath>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+
+</project>
diff --git a/karaf/main/src/main/java/org/apache/servicemix/kernel/main/DefaultJDBCLock.java b/karaf/main/src/main/java/org/apache/servicemix/kernel/main/DefaultJDBCLock.java
new file mode 100644
index 0000000..bf4bfba
--- /dev/null
+++ b/karaf/main/src/main/java/org/apache/servicemix/kernel/main/DefaultJDBCLock.java
@@ -0,0 +1,194 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.servicemix.kernel.main;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.Properties;
+
+/**
+ * Represents an exclusive lock on a database,
+ * used to avoid multiple SMX instances attempting
+ * to become master.
+ * 
+ * @version $Revision: $
+ */
+public class DefaultJDBCLock implements Lock {
+
+    private static final String PROPERTY_LOCK_URL               = "servicemix.lock.jdbc.url";
+    private static final String PROPERTY_LOCK_JDBC_DRIVER       = "servicemix.lock.jdbc.driver";
+    private static final String PROPERTY_LOCK_JDBC_USER         = "servicemix.lock.jdbc.user";
+    private static final String PROPERTY_LOCK_JDBC_PASSWORD     = "servicemix.lock.jdbc.password";
+    private static final String PROPERTY_LOCK_JDBC_TABLE        = "servicemix.lock.jdbc.table";
+    private static final String PROPERTY_LOCK_JDBC_CLUSTERNAME  = "servicemix.lock.jdbc.clustername";
+    private static final String PROPERTY_LOCK_JDBC_TIMEOUT      = "servicemix.lock.jdbc.timeout";
+
+    private final Statements statements;
+    private Connection lockConnection;
+    private String url;
+    private String driver;
+    private String user; 
+    private String password;
+    private String table;
+    private String clusterName;
+    private int timeout;
+
+    public DefaultJDBCLock(Properties props) {
+        this.url = props.getProperty(PROPERTY_LOCK_URL);
+        this.driver = props.getProperty(PROPERTY_LOCK_JDBC_DRIVER);
+        this.user = props.getProperty(PROPERTY_LOCK_JDBC_USER);
+        this.password = props.getProperty(PROPERTY_LOCK_JDBC_PASSWORD);
+        this.table = props.getProperty(PROPERTY_LOCK_JDBC_TABLE);
+        this.clusterName = props.getProperty(PROPERTY_LOCK_JDBC_CLUSTERNAME);
+        String time = props.getProperty(PROPERTY_LOCK_JDBC_TIMEOUT);
+        this.lockConnection = null;
+        if (table == null) { table = "SERVICEMIX_LOCK"; }
+        if ( clusterName == null) { clusterName = "smx4"; }
+        this.statements = new Statements(table, clusterName);
+        if (time != null) { 
+            this.timeout = Integer.parseInt(time) * 1000; 
+        } else {
+            this.timeout = 10000; // 10 seconds
+        }
+        if (user == null) { user = ""; }
+        if (password == null) { password = ""; }
+        try {
+            obtainLock();
+        } catch (Exception e) {
+            System.err.println("Error occured while attempting to obtain connection: " + e.getMessage());
+        }
+    }
+
+    /**
+     * obtainLock - obtain the lock connection.
+     *
+     * @throws Exception
+     */
+    private void obtainLock() throws Exception {
+        PreparedStatement statement = null;
+        while (true) {
+            try {
+                lockConnection = getConnection(driver, url, user, password);
+                lockConnection.setAutoCommit(false);
+                statements.init(lockConnection);
+                String sql = statements.testLockTableStatus();
+                statement = lockConnection.prepareStatement(sql);
+                statement.execute();
+                break;
+            } catch (Exception e) {
+                System.err.println("Could not obtain lock: " + e.getMessage());
+                Thread.sleep(this.timeout);
+            } finally {
+                if (null != statement) {
+                    try {
+                        statement.close();
+                    } catch (SQLException e1) {
+                        System.err.println("Caught while closing statement: " + e1.getMessage());
+                    }
+                    statement = null;
+                }
+            }
+            Thread.sleep(this.timeout);
+        }
+        System.out.println("Connected to data source: " + url);
+    }
+
+    /**
+     * lock - a KeepAlive function to maintain lock. 
+     *
+     * @return true if connection lock retained, false otherwise.
+     */
+    public boolean lock() {
+        PreparedStatement statement = null;
+        boolean result = false;
+        try {
+            if (lockConnection.isClosed()) { obtainLock(); } 
+            long time = System.currentTimeMillis();
+            statement = lockConnection.prepareStatement(statements.getLockUpdateStatement(time));
+            int rows = statement.executeUpdate();
+            if (rows == 1) {
+                result=true;
+            }
+        } catch (Exception e) {
+            System.err.println("Failed to acquire database lock: " + e.getMessage());
+        }finally {
+            if (statement != null) {
+                try {
+                    statement.close();
+                } catch (SQLException e) {
+                    System.err.println("Failed to close statement" + e);
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * release - terminate the lock connection safely.
+     */
+    public void release() throws Exception {
+        if (lockConnection != null && !lockConnection.isClosed()) {
+            lockConnection.rollback();
+            lockConnection.close();
+        }
+    }
+
+    /**
+     * isAlive - test if lock still exists.
+     */
+    public boolean isAlive() throws Exception {
+        if (lockConnection == null) { return false; }
+        PreparedStatement statement = null;
+        try { 
+            lockConnection.setAutoCommit(false);
+            statements.init(lockConnection);
+            String sql = statements.testLockTableStatus();
+            statement = lockConnection.prepareStatement(sql);
+            statement.execute();
+        } catch (Exception ex) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * getConnection - Obtain connection to database via jdbc driver.
+     *
+     * @throws Exception
+     * @param driver, the JDBC driver class.
+     * @param url, url to data source.
+     * @param username, user to access data source.
+     * @param password, password for specified user.
+     * @return connection, null returned if conenction fails.
+     */
+    private Connection getConnection(String driver, String url, 
+                                     String username, String password) throws Exception {
+        Connection conn = null;
+        try {
+            Class.forName(driver);
+            conn = DriverManager.getConnection(url + ";create=true", username, password);
+        } catch (Exception e) {
+            throw e; 
+        }
+        return conn;
+    }
+
+}
diff --git a/karaf/main/src/main/java/org/apache/servicemix/kernel/main/Lock.java b/karaf/main/src/main/java/org/apache/servicemix/kernel/main/Lock.java
new file mode 100644
index 0000000..f4e8ab8
--- /dev/null
+++ b/karaf/main/src/main/java/org/apache/servicemix/kernel/main/Lock.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.servicemix.kernel.main;
+
+public interface Lock {
+
+    boolean lock() throws Exception;
+
+    void release() throws Exception;
+
+    boolean isAlive() throws Exception;
+
+}
diff --git a/karaf/main/src/main/java/org/apache/servicemix/kernel/main/Main.java b/karaf/main/src/main/java/org/apache/servicemix/kernel/main/Main.java
new file mode 100644
index 0000000..d09a033
--- /dev/null
+++ b/karaf/main/src/main/java/org/apache/servicemix/kernel/main/Main.java
@@ -0,0 +1,1150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.servicemix.kernel.main;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.JarURLConnection;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.security.Provider;
+import java.security.Security;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import java.util.concurrent.CountDownLatch;
+
+import org.apache.felix.framework.Felix;
+import org.apache.felix.framework.cache.BundleCache;
+import org.apache.felix.framework.util.FelixConstants;
+import org.apache.felix.framework.util.StringMap;
+import org.apache.servicemix.kernel.main.spi.MainService;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.startlevel.StartLevel;
+
+/**
+ * <p>
+ * This class is the default way to instantiate and execute the framework. It is not
+ * intended to be the only way to instantiate and execute the framework; rather, it is
+ * one example of how to do so. When embedding the framework in a host application,
+ * this class can serve as a simple guide of how to do so. It may even be
+ * worthwhile to reuse some of its property handling capabilities. This class
+ * is completely static and is only intended to start a single instance of
+ * the framework.
+ * </p>
+ */
+public class Main implements MainService, BundleActivator {
+    /**
+     * The default name used for the system properties file.
+     */
+    public static final String SYSTEM_PROPERTIES_FILE_NAME = "system.properties";
+    /**
+     * The default name used for the configuration properties file.
+     */
+    public static final String CONFIG_PROPERTIES_FILE_NAME = "config.properties";
+    /**
+     * The default name used for the startup properties file.
+     */
+    public static final String STARTUP_PROPERTIES_FILE_NAME = "startup.properties";
+    /**
+     * The property name prefix for the launcher's auto-install property.
+     */
+    public static final String PROPERTY_AUTO_INSTALL = "felix.auto.install";
+    /**
+     * The property for auto-discovering the bundles
+     */
+    public static final String PROPERTY_AUTO_START = "felix.auto.start";
+    /**
+     * The system property for specifying the ServiceMix home directory.  The home directory
+     * hold the binary install of ServiceMix.
+     */
+    public static final String PROP_SERVICEMIX_HOME = "servicemix.home";
+    /**
+     * The environment variable for specifying the ServiceMix home directory.  The home directory
+     * hold the binary install of ServiceMix.
+     */
+    public static final String ENV_SERVICEMIX_HOME = "SERVICEMIX_HOME";
+    /**
+     * The system property for specifying the ServiceMix base directory.  The base directory
+     * holds the configuration and data for a ServiceMix instance.
+     */
+    public static final String PROP_SERVICEMIX_BASE = "servicemix.base";
+    /**
+     * The environment variable for specifying the ServiceMix base directory.  The base directory
+     * holds the configuration and data for a ServiceMix instance.
+     */
+    public static final String ENV_SERVICEMIX_BASE = "SERVICEMIX_BASE";
+
+    /**
+     * Config property which identifies directories which contain bundles to be loaded by SMX
+     */
+    public static final String BUNDLE_LOCATIONS = "bundle.locations";
+
+    /**
+     * Config property that indicates we want to convert bundles locations to maven style urls
+     */
+    public static final String PROPERTY_CONVERT_TO_MAVEN_URL = "servicemix.maven.convert";
+
+    /**
+     * If a lock should be used before starting the runtime
+     */
+    public static final String PROPERTY_USE_LOCK = "servicemix.lock";
+
+    /**
+     * The lock implementation
+     */
+    public static final String PROPERTY_LOCK_CLASS = "servicemix.lock.class";
+
+    public static final String PROPERTY_LOCK_DELAY = "servicemix.lock.delay";
+
+    public static final String PROPERTY_LOCK_LEVEL = "servicemix.lock.level";
+
+    public static final String PROPERTY_LOCK_CLASS_DEFAULT = SimpleFileLock.class.getName();
+
+
+    private File servicemixHome;
+    private File servicemixBase;
+    private static Properties m_configProps = null;
+    private static Felix m_felix = null;
+    private final String[] args;
+    private int exitCode;
+    private Lock lock;
+    private CountDownLatch shutdown = new CountDownLatch(1);
+    private int defaultStartLevel = 100;
+    private int lockStartLevel = 0;
+    private int lockDelay = 1000;
+    private boolean exiting = false;
+
+    public Main(String[] args) {
+        this.args = args;
+    }
+
+    public void launch() throws Exception {
+        servicemixHome = getServiceMixHome();
+        servicemixBase = getServiceMixBase(servicemixHome);
+
+        //System.out.println("ServiceMix Home: "+main.servicemixHome.getPath());
+        //System.out.println("ServiceMix Base: "+main.servicemixBase.getPath());
+
+        System.setProperty(PROP_SERVICEMIX_HOME, servicemixHome.getPath());
+        System.setProperty(PROP_SERVICEMIX_BASE, servicemixBase.getPath());
+
+        // Load system properties.
+        loadSystemProperties();
+
+        // Read configuration properties.
+        m_configProps = loadConfigProperties();
+
+        // Copy framework properties from the system properties.
+        Main.copySystemProperties(m_configProps);
+
+        processSecurityProperties(m_configProps);
+
+        m_configProps.setProperty(BundleCache.CACHE_ROOTDIR_PROP, servicemixBase.getPath() + "/data");
+        m_configProps.setProperty(Constants.FRAMEWORK_STORAGE, "cache");
+
+        // Register the Main class so that other bundles can inspect the command line args.
+        BundleActivator activator = new BundleActivator() {
+            private ServiceRegistration registration;
+
+            public void start(BundleContext context) {
+                registration = context.registerService(MainService.class.getName(), Main.this, null);
+            }
+
+            public void stop(BundleContext context) {
+                registration.unregister();
+                shutdown.countDown();
+            }
+        };
+        List<BundleActivator> activations = new ArrayList<BundleActivator>();
+        activations.add(this);
+        activations.add(activator);
+
+        m_configProps.put(FelixConstants.SYSTEMBUNDLE_ACTIVATORS_PROP, activations);
+
+        try {
+            defaultStartLevel = Integer.parseInt(m_configProps.getProperty(Constants.FRAMEWORK_BEGINNING_STARTLEVEL));
+            lockStartLevel = Integer.parseInt(m_configProps.getProperty(PROPERTY_LOCK_LEVEL, Integer.toString(lockStartLevel)));
+            lockDelay = Integer.parseInt(m_configProps.getProperty(PROPERTY_LOCK_DELAY, Integer.toString(lockDelay)));
+            m_configProps.setProperty(Constants.FRAMEWORK_BEGINNING_STARTLEVEL, Integer.toString(lockStartLevel));
+            // Start up the OSGI framework
+            m_felix = new Felix(new StringMap(m_configProps, false));
+            m_felix.start();
+            // Start lock monitor
+            new Thread() {
+                public void run() {
+                    lock(m_configProps);
+                }
+            }.start();
+        }
+        catch (Exception ex) {
+            setExitCode(-1);
+            throw new Exception("Could not create framework", ex);
+        }
+    }
+
+    public void destroy(boolean await) throws Exception {
+        try {
+            if (await) {
+                shutdown.await();
+            }
+            exiting = true;
+            if (m_felix.getState() == Bundle.ACTIVE) {
+                m_felix.stop();
+            }
+        } finally {
+            unlock();
+        }
+    }
+
+    /**
+     * Used to instigate auto-install and auto-start configuration
+     * property processing via a custom framework activator during
+     * framework startup.
+     *
+     * @param context The system bundle context.
+     */
+    public void start(BundleContext context) {
+        Main.processAutoProperties(context);
+    }
+
+    /**
+     * Currently does nothing as part of framework shutdown.
+     *
+     * @param context The system bundle context.
+     */
+    public void stop(BundleContext context) {
+        // Do nothing.
+    }
+
+    /**
+     * <p>
+     * This method performs the main task of constructing an framework instance
+     * and starting its execution. The following functions are performed
+     * when invoked:
+     * </p>
+     * <ol>
+     *   <li><i><b>Read the system properties file.<b></i> This is a file
+     *       containing properties to be pushed into <tt>System.setProperty()</tt>
+     *       before starting the framework. This mechanism is mainly shorthand
+     *       for people starting the framework from the command line to avoid having
+     *       to specify a bunch of <tt>-D</tt> system property definitions.
+     *       The only properties defined in this file that will impact the framework's
+     *       behavior are the those concerning setting HTTP proxies, such as
+     *       <tt>http.proxyHost</tt>, <tt>http.proxyPort</tt>, and
+     *       <tt>http.proxyAuth</tt>.
+     *   </li>
+     *   <li><i><b>Perform system property variable substitution on system
+     *       properties.</b></i> Any system properties in the system property
+     *       file whose value adheres to <tt>${&lt;system-prop-name&gt;}</tt>
+     *       syntax will have their value substituted with the appropriate
+     *       system property value.
+     *   </li>
+     *   <li><i><b>Read the framework's configuration property file.</b></i> This is
+     *       a file containing properties used to configure the framework
+     *       instance and to pass configuration information into
+     *       bundles installed into the framework instance. The configuration
+     *       property file is called <tt>config.properties</tt> by default
+     *       and is located in the <tt>conf/</tt> directory of the Felix
+     *       installation directory, which is the parent directory of the
+     *       directory containing the <tt>felix.jar</tt> file. It is possible
+     *       to use a different location for the property file by specifying
+     *       the desired URL using the <tt>felix.config.properties</tt>
+     *       system property; this should be set using the <tt>-D</tt> syntax
+     *       when executing the JVM. Refer to the
+     *       <a href="Felix.html#Felix(java.util.Map, java.util.List)">
+     *       <tt>Felix</tt></a> constructor documentation for more
+     *       information on the framework configuration options.
+     *   </li>
+     *   <li><i><b>Perform system property variable substitution on configuration
+     *       properties.</b></i> Any configuration properties whose value adheres to
+     *       <tt>${&lt;system-prop-name&gt;}</tt> syntax will have their value
+     *       substituted with the appropriate system property value.
+     *   </li>
+     *   <li><i><b>Ensure the default bundle cache has sufficient information to
+     *       initialize.</b></i> The default implementation of the bundle cache
+     *       requires either a profile name or a profile directory in order to
+     *       start. The configuration properties are checked for at least one
+     *       of the <tt>felix.cache.profile</tt> or <tt>felix.cache.profiledir</tt>
+     *       properties. If neither is found, the user is asked to supply a profile
+     *       name that is added to the configuration property set. See the
+     *       <a href="cache/DefaultBundleCache.html"><tt>DefaultBundleCache</tt></a>
+     *       documentation for more details its configuration options.
+     *   </li>
+     *   <li><i><b>Creates and starts a framework instance.</b></i> A
+     *       case insensitive
+     *       <a href="util/StringMap.html"><tt>StringMap</tt></a>
+     *       is created for the configuration property file and is passed
+     *       into the framework.
+     *   </li>
+     * </ol>
+     * <p>
+     * It should be noted that simply starting an instance of the framework is not enough
+     * to create an interactive session with it. It is necessary to install
+     * and start bundles that provide an interactive impl; this is generally
+     * done by specifying an "auto-start" property in the framework configuration
+     * property file. If no interactive impl bundles are installed or if
+     * the configuration property file cannot be found, the framework will appear to
+     * be hung or deadlocked. This is not the case, it is executing correctly,
+     * there is just no way to interact with it. Refer to the
+     * <a href="Felix.html#Felix(java.util.Map, java.util.List)">
+     * <tt>Felix</tt></a> constructor documentation for more information on
+     * framework configuration options.
+     * </p>
+     * @param args An array of arguments, all of which are ignored.
+     * @throws Exception If an error occurs.
+     **/
+    public static void main(String[] args) throws Exception {
+        final Main main = new Main(args);
+        try {
+            main.launch();
+            main.destroy(true);
+        }
+        catch (Exception ex) {
+            System.err.println("Error occured shutting down framework: " + ex);
+            ex.printStackTrace();
+        } finally {
+            System.exit(main.getExitCode());
+        }
+    }
+
+    private static File getServiceMixHome() throws IOException {
+        File rc = null;
+
+        // Use the system property if specified.
+        String path = System.getProperty(PROP_SERVICEMIX_HOME);
+        if (path != null) {
+            rc = validateDirectoryExists(path, "Invalid " + PROP_SERVICEMIX_HOME + " system property");
+        }
+
+        if (rc == null) {
+            path = System.getenv(ENV_SERVICEMIX_HOME);
+            if (path != null) {
+                rc = validateDirectoryExists(path, "Invalid " + ENV_SERVICEMIX_HOME + " environment variable");
+            }
+        }
+
+        // Try to figure it out using the jar file this class was loaded from.
+        if (rc == null) {
+            // guess the home from the location of the jar
+            URL url = Main.class.getClassLoader().getResource(Main.class.getName().replace(".", "/") + ".class");
+            if (url != null) {
+                try {
+                    JarURLConnection jarConnection = (JarURLConnection) url.openConnection();
+                    url = jarConnection.getJarFileURL();
+                    rc = new File(new URI(url.toString())).getCanonicalFile().getParentFile().getParentFile();
+                } catch (Exception ignored) {
+                }
+            }
+        }
+
+        if (rc == null) {
+            // Dig into the classpath to guess the location of the jar
+            String classpath = System.getProperty("java.class.path");
+            int index = classpath.toLowerCase().indexOf("servicemix.jar");
+            int start = classpath.lastIndexOf(File.pathSeparator, index) + 1;
+            if (index >= start) {
+                String jarLocation = classpath.substring(start, index);
+                rc = new File(jarLocation).getCanonicalFile().getParentFile();
+            }
+        }
+        if (rc == null) {
+            throw new IOException("The ServiceMix install directory could not be determined.  Please set the " + PROP_SERVICEMIX_HOME + " system property or the " + ENV_SERVICEMIX_HOME + " environment variable.");
+        }
+
+        return rc;
+    }
+
+    private static File validateDirectoryExists(String path, String errPrefix) {
+        File rc;
+        try {
+            rc = new File(path).getCanonicalFile();
+        } catch (IOException e) {
+            throw new IllegalArgumentException(errPrefix + " '" + path + "' : " + e.getMessage());
+        }
+        if (!rc.exists()) {
+            throw new IllegalArgumentException(errPrefix + " '" + path + "' : does not exist");
+        }
+        if (!rc.isDirectory()) {
+            throw new IllegalArgumentException(errPrefix + " '" + path + "' : is not a directory");
+        }
+        return rc;
+    }
+
+    private static File getServiceMixBase(File defaultValue) {
+        File rc = null;
+
+        String path = System.getProperty(PROP_SERVICEMIX_BASE);
+        if (path != null) {
+            rc = validateDirectoryExists(path, "Invalid " + PROP_SERVICEMIX_BASE + " system property");
+        }
+
+        if (rc == null) {
+            path = System.getenv(ENV_SERVICEMIX_BASE);
+            if (path != null) {
+                rc = validateDirectoryExists(path, "Invalid " + ENV_SERVICEMIX_BASE + " environment variable");
+            }
+        }
+
+        if (rc == null) {
+            rc = defaultValue;
+        }
+        return rc;
+    }
+
+    private static void processSecurityProperties(Properties m_configProps) {
+        String prop = m_configProps.getProperty("org.apache.servicemix.security.providers");
+        if (prop != null) {
+            String[] providers = prop.split(",");
+            for (String provider : providers) {
+                try {
+                    Security.addProvider((Provider) Class.forName(provider).newInstance());
+                } catch (Throwable t) {
+                    System.err.println("Unable to register security provider: " + t);
+                }
+            }
+        }
+    }
+
+    /**
+     * <p/>
+     * Processes the auto-install and auto-start properties from the
+     * specified configuration properties.
+     */
+    private static void processAutoProperties(BundleContext context) {
+        // Check if we want to convert URLs to maven style
+        boolean convertToMavenUrls = Boolean.parseBoolean(m_configProps.getProperty(PROPERTY_CONVERT_TO_MAVEN_URL, "true"));
+
+        // Retrieve the Start Level service, since it will be needed
+        // to set the start level of the installed bundles.
+        StartLevel sl = (StartLevel) context.getService(
+                context.getServiceReference(org.osgi.service.startlevel.StartLevel.class.getName()));
+
+        // The auto-install property specifies a space-delimited list of
+        // bundle URLs to be automatically installed into each new profile;
+        // the start level to which the bundles are assigned is specified by
+        // appending a ".n" to the auto-install property name, where "n" is
+        // the desired start level for the list of bundles.
+        for (Iterator i = m_configProps.keySet().iterator(); i.hasNext();) {
+            String key = (String) i.next();
+
+            // Ignore all keys that are not the auto-install property.
+            if (!key.startsWith(PROPERTY_AUTO_INSTALL)) {
+                continue;
+            }
+
+            // If the auto-install property does not have a start level,
+            // then assume it is the default bundle start level, otherwise
+            // parse the specified start level.
+            int startLevel = sl.getInitialBundleStartLevel();
+            if (!key.equals(PROPERTY_AUTO_INSTALL)) {
+                try {
+                    startLevel = Integer.parseInt(key.substring(key.lastIndexOf('.') + 1));
+                }
+                catch (NumberFormatException ex) {
+                    System.err.println("Invalid property: " + key);
+                }
+            }
+
+            StringTokenizer st = new StringTokenizer(m_configProps.getProperty(key), "\" ", true);
+            if (st.countTokens() > 0) {
+                String location = null;
+                do {
+                    location = nextLocation(st);
+                    if (location != null) {
+                        try {
+                            String[] parts = convertToMavenUrlsIfNeeded(location, convertToMavenUrls);
+                            Bundle b = context.installBundle(parts[0], new URL(parts[1]).openStream());
+                            sl.setBundleStartLevel(b, startLevel);
+                        }
+                        catch (Exception ex) {
+                            System.err.println("Auto-properties install: " + ex);
+                        }
+                    }
+                }
+                while (location != null);
+            }
+        }
+
+        // The auto-start property specifies a space-delimited list of
+        // bundle URLs to be automatically installed and started into each
+        // new profile; the start level to which the bundles are assigned
+        // is specified by appending a ".n" to the auto-start property name,
+        // where "n" is the desired start level for the list of bundles.
+        // The following code starts bundles in two passes, first it installs
+        // them, then it starts them.
+        for (Iterator i = m_configProps.keySet().iterator(); i.hasNext();) {
+            String key = (String) i.next();
+
+            // Ignore all keys that are not the auto-start property.
+            if (!key.startsWith(PROPERTY_AUTO_START)) {
+                continue;
+            }
+
+            // If the auto-start property does not have a start level,
+            // then assume it is the default bundle start level, otherwise
+            // parse the specified start level.
+            int startLevel = sl.getInitialBundleStartLevel();
+            if (!key.equals(PROPERTY_AUTO_START)) {
+                try {
+                    startLevel = Integer.parseInt(key.substring(key.lastIndexOf('.') + 1));
+                }
+                catch (NumberFormatException ex) {
+                    System.err.println("Invalid property: " + key);
+                }
+            }
+
+            StringTokenizer st = new StringTokenizer(m_configProps.getProperty(key), "\" ", true);
+            if (st.countTokens() > 0) {
+                String location = null;
+                do {
+                    location = nextLocation(st);
+                    if (location != null) {
+                        try {
+                            String[] parts = convertToMavenUrlsIfNeeded(location, convertToMavenUrls);
+                            Bundle b = context.installBundle(parts[0], new URL(parts[1]).openStream());
+                            sl.setBundleStartLevel(b, startLevel);
+                        }
+                        catch (Exception ex) {
+                            System.err.println("Auto-properties install:" + ex);
+                        }
+                    }
+                }
+                while (location != null);
+            }
+        }
+
+        // Now loop through and start the installed bundles.
+        for (Iterator i = m_configProps.keySet().iterator(); i.hasNext();) {
+            String key = (String) i.next();
+            if (key.startsWith(PROPERTY_AUTO_START)) {
+                StringTokenizer st = new StringTokenizer(m_configProps.getProperty(key), "\" ", true);
+                if (st.countTokens() > 0) {
+                    String location = null;
+                    do {
+                        location = nextLocation(st);
+                        if (location != null) {
+                            // Installing twice just returns the same bundle.
+                            try {
+                                String[] parts = convertToMavenUrlsIfNeeded(location, convertToMavenUrls);
+                                Bundle b = context.installBundle(parts[0], new URL(parts[1]).openStream());
+                                if (b != null) {
+                                    b.start();
+                                }
+                            }
+                            catch (Exception ex) {
+                                System.err.println("Auto-properties start: " + ex);
+                            }
+                        }
+                    }
+                    while (location != null);
+                }
+            }
+        }
+    }
+
+    private static String[] convertToMavenUrlsIfNeeded(String location, boolean convertToMavenUrls) {
+        String[] parts = location.split("\\|");
+        if (convertToMavenUrls) {
+            String[] p = parts[1].split("/");
+            if (p.length >= 4 && p[p.length-1].startsWith(p[p.length-3] + "-" + p[p.length-2])) {
+                String groupId = null;
+                String artifactId = p[p.length-3];
+                String version = p[p.length-2];
+                String classifier;
+                String type;
+                String artifactIdVersion = artifactId + "-" + version;
+                StringBuffer sb = new StringBuffer();
+                if (p[p.length-1].charAt(artifactIdVersion.length()) == '-') {
+                    classifier = p[p.length-1].substring(artifactIdVersion.length() + 1, p[p.length-1].lastIndexOf('.'));
+                } else {
+                    classifier = null;
+                }
+                type = p[p.length-1].substring(p[p.length-1].lastIndexOf('.') + 1);
+                sb.append("mvn:");
+                for (int j = 0; j < p.length - 3; j++) {
+                    if (j > 0) {
+                        sb.append('.');
+                    }
+                    sb.append(p[j]);
+                }
+                sb.append('/').append(artifactId).append('/').append(version);
+                if (!"jar".equals(type) || classifier != null) {
+                    sb.append('/');
+                    if (!"jar".equals(type)) {
+                        sb.append(type);
+                    }
+                    if (classifier != null) {
+                        sb.append('/').append(classifier);
+                    }
+                }
+                parts[1] = parts[0];
+                parts[0] = sb.toString();
+            } else {
+                parts[1] = parts[0];
+            }
+        } else {
+            parts[1] = parts[0];
+        }
+        return parts;
+    }
+
+    private static String nextLocation(StringTokenizer st) {
+        String retVal = null;
+
+        if (st.countTokens() > 0) {
+            String tokenList = "\" ";
+            StringBuffer tokBuf = new StringBuffer(10);
+            String tok = null;
+            boolean inQuote = false;
+            boolean tokStarted = false;
+            boolean exit = false;
+            while ((st.hasMoreTokens()) && (!exit)) {
+                tok = st.nextToken(tokenList);
+                if (tok.equals("\"")) {
+                    inQuote = !inQuote;
+                    if (inQuote) {
+                        tokenList = "\"";
+                    } else {
+                        tokenList = "\" ";
+                    }
+
+                } else if (tok.equals(" ")) {
+                    if (tokStarted) {
+                        retVal = tokBuf.toString();
+                        tokStarted = false;
+                        tokBuf = new StringBuffer(10);
+                        exit = true;
+                    }
+                } else {
+                    tokStarted = true;
+                    tokBuf.append(tok.trim());
+                }
+            }
+
+            // Handle case where end of token stream and
+            // still got data
+            if ((!exit) && (tokStarted)) {
+                retVal = tokBuf.toString();
+            }
+        }
+
+        return retVal;
+    }
+
+    /**
+     * <p>
+     * Loads the properties in the system property file associated with the
+     * framework installation into <tt>System.setProperty()</tt>. These properties
+     * are not directly used by the framework in anyway. By default, the system
+     * property file is located in the <tt>conf/</tt> directory of the Felix
+     * installation directory and is called "<tt>system.properties</tt>". The
+     * installation directory of Felix is assumed to be the parent directory of
+     * the <tt>felix.jar</tt> file as found on the system class path property.
+     * The precise file from which to load system properties can be set by
+     * initializing the "<tt>felix.system.properties</tt>" system property to an
+     * arbitrary URL.
+     * </p>
+     */
+    private void loadSystemProperties() {
+        // The system properties file is either specified by a system
+        // property or it is in the same directory as the Felix JAR file.
+        // Try to load it from one of these places.
+
+        // See if the property URL was specified as a property.
+        URL propURL = null;
+        try {
+            File file = new File(new File(servicemixBase, "etc"), SYSTEM_PROPERTIES_FILE_NAME);
+            propURL = file.toURL();
+        }
+        catch (MalformedURLException ex) {
+            System.err.print("Main: " + ex);
+            return;
+        }
+
+        // Read the properties file.
+        Properties props = new Properties();
+        InputStream is = null;
+        try {
+            is = propURL.openConnection().getInputStream();
+            props.load(is);
+            is.close();
+        }
+        catch (FileNotFoundException ex) {
+            // Ignore file not found.
+        }
+        catch (Exception ex) {
+            System.err.println(
+                    "Main: Error loading system properties from " + propURL);
+            System.err.println("Main: " + ex);
+            try {
+                if (is != null) is.close();
+            }
+            catch (IOException ex2) {
+                // Nothing we can do.
+            }
+            return;
+        }
+
+        // Perform variable substitution on specified properties.
+        for (Enumeration e = props.propertyNames(); e.hasMoreElements();) {
+            String name = (String) e.nextElement();
+            System.setProperty(name,
+                    substVars(props.getProperty(name), name, null, null));
+        }
+    }
+
+    /**
+     * <p>
+     * Loads the configuration properties in the configuration property file
+     * associated with the framework installation; these properties
+     * are accessible to the framework and to bundles and are intended
+     * for configuration purposes. By default, the configuration property
+     * file is located in the <tt>conf/</tt> directory of the Felix
+     * installation directory and is called "<tt>config.properties</tt>".
+     * The installation directory of Felix is assumed to be the parent
+     * directory of the <tt>felix.jar</tt> file as found on the system class
+     * path property. The precise file from which to load configuration
+     * properties can be set by initializing the "<tt>felix.config.properties</tt>"
+     * system property to an arbitrary URL.
+     * </p>
+     *
+     * @return A <tt>Properties</tt> instance or <tt>null</tt> if there was an error.
+     * @throws Exception 
+     */
+    private Properties loadConfigProperties() throws Exception {
+        // The config properties file is either specified by a system
+        // property or it is in the conf/ directory of the Felix
+        // installation directory.  Try to load it from one of these
+        // places.
+
+            ArrayList<File> bundleDirs = new ArrayList<File>();
+
+        // See if the property URL was specified as a property.
+        URL configPropURL = null;
+        URL startupPropURL = null;
+
+        try {
+            File file = new File(new File(servicemixBase, "etc"), CONFIG_PROPERTIES_FILE_NAME);
+            configPropURL = file.toURL();
+
+            file = new File(new File(servicemixBase, "etc"), STARTUP_PROPERTIES_FILE_NAME);
+            startupPropURL = file.toURL();
+
+            if (servicemixBase.equals(servicemixHome)) {
+                bundleDirs.add(new File(servicemixHome, "system"));
+            } else {
+                bundleDirs.add(new File(servicemixBase, "system"));
+                bundleDirs.add(new File(servicemixHome, "system"));
+            }
+
+        }
+        catch (MalformedURLException ex) {
+            System.err.print("Main: " + ex);
+            return null;
+        }
+
+
+        Properties configProps = loadPropertiesFile(configPropURL);
+        Properties startupProps = loadPropertiesFile(startupPropURL);
+
+        String locations = configProps.getProperty(BUNDLE_LOCATIONS);
+
+        if (locations != null) {
+            StringTokenizer st = new StringTokenizer(locations, "\" ", true);
+            if (st.countTokens() > 0) {
+                String location = null;
+                do {
+                    location = nextLocation(st);
+                    if (location != null) {
+                        File f = new File(location);
+                        if (f.exists() && f.isDirectory()) {
+                            bundleDirs.add(f);
+                        } else {
+                            System.err.println("Bundle location " + location
+                                    + " does not exist or is not a directory.");
+                        }
+                    }
+                }
+
+                while (location != null);
+            }
+        }
+
+        // Perform variable substitution for system properties.
+        for (Enumeration e = configProps.propertyNames(); e.hasMoreElements();) {
+            String name = (String) e.nextElement();
+            configProps.setProperty(name,
+                    substVars(configProps.getProperty(name), name, null, configProps));
+        }
+
+        // Mutate properties
+        Main.processConfigurationProperties(configProps, startupProps, bundleDirs);
+
+        return configProps;
+    }
+
+    private static Properties loadPropertiesFile(URL configPropURL) throws Exception {
+        // Read the properties file.
+        Properties configProps = new Properties();
+        InputStream is = null;
+        try {
+            is = configPropURL.openConnection().getInputStream();
+            configProps.load(is);
+            is.close();
+        }
+        catch (FileNotFoundException ex) {
+        	if (configPropURL.getFile().lastIndexOf(STARTUP_PROPERTIES_FILE_NAME) != -1) {
+        		throw ex;
+        	}
+        }
+        catch (Exception ex) {
+            System.err.println(
+                    "Error loading config properties from " + configPropURL);
+            System.err.println("Main: " + ex);
+            try {
+                if (is != null) is.close();
+            }
+            catch (IOException ex2) {
+                // Nothing we can do.
+            }
+            return null;
+        }
+        return configProps;
+    }
+
+    private static void copySystemProperties(Properties configProps) {
+        for (Enumeration e = System.getProperties().propertyNames();
+             e.hasMoreElements();) {
+            String key = (String) e.nextElement();
+            if (key.startsWith("felix.") ||
+                    key.startsWith("servicemix.") ||
+                    key.equals("org.osgi.framework.system.packages") ||
+                    key.equals("org.osgi.framework.bootdelegation")) {
+                configProps.setProperty(key, System.getProperty(key));
+            }
+        }
+    }
+
+    /**
+     * Process properties to customize default felix behavior
+     *
+     * @param startupProps
+     */
+    private static void processConfigurationProperties(Properties props, Properties startupProps, ArrayList<File> bundleDirs) {
+        if (bundleDirs == null) {
+            return;
+        }
+        if ("all".equals(props.getProperty(PROPERTY_AUTO_START, "").trim())) {
+            props.remove(PROPERTY_AUTO_START);
+            ArrayList<File> jars = new ArrayList<File>();
+
+            // We should start all the bundles in the system dir.
+            for (File bundleDir : bundleDirs) {
+                findJars(bundleDir, jars);
+            }
+
+            StringBuffer sb = new StringBuffer();
+
+            for (File jar : jars) {
+                try {
+                    sb.append("\"").append(jar.toURL().toString()).append("\" ");
+                } catch (MalformedURLException e) {
+                    System.err.print("Ignoring " + jar.toString() + " (" + e + ")");
+                }
+            }
+
+            props.setProperty(PROPERTY_AUTO_START, sb.toString());
+
+        } else if (STARTUP_PROPERTIES_FILE_NAME.equals(props.getProperty(PROPERTY_AUTO_START, "").trim())) {
+            props.remove(PROPERTY_AUTO_START);
+            // We should start the bundles in the startup.properties file.
+            HashMap<Integer, StringBuffer> levels = new HashMap<Integer, StringBuffer>();
+            for (Iterator iterator = startupProps.keySet().iterator(); iterator.hasNext();) {
+                String name = (String) iterator.next();
+                File file = findFile(bundleDirs, name);
+
+                if (file != null) {
+                    Integer level;
+                    try {
+                        level = new Integer(startupProps.getProperty(name).trim());
+                    } catch (NumberFormatException e1) {
+                        System.err.print("Ignoring " + file.toString() + " (run level must be an integer)");
+                        continue;
+                    }
+                    StringBuffer sb = levels.get(level);
+                    if (sb == null) {
+                        sb = new StringBuffer(256);
+                        levels.put(level, sb);
+                    }
+                    try {
+                        sb.append("\"").append(file.toURL().toString()).append("|").append(name).append("\" ");
+                    } catch (MalformedURLException e) {
+                        System.err.print("Ignoring " + file.toString() + " (" + e + ")");
+                    }
+                } else {
+                    System.err.println("Bundle listed in " + STARTUP_PROPERTIES_FILE_NAME + " configuration not found: " + name);
+                }
+            }
+
+            for (Map.Entry<Integer, StringBuffer> entry : levels.entrySet()) {
+                props.setProperty(PROPERTY_AUTO_START + "." + entry.getKey(), entry.getValue().toString());
+            }
+        }
+
+    }
+
+    private static File findFile(ArrayList<File> bundleDirs, String name) {
+        for (File bundleDir : bundleDirs) {
+            File file = findFile(bundleDir, name);
+            if (file != null) {
+                return file;
+            }
+        }
+        return null;
+    }
+
+    private static File findFile(File dir, String name) {
+        File theFile = new File(dir, name);
+
+        if (theFile.exists() && !theFile.isDirectory()) {
+            return theFile;
+        }
+
+        for (File file : dir.listFiles()) {
+            if (file.isDirectory()) {
+                return findFile(file, name);
+            }
+        }
+
+        return null;
+    }
+
+    private static void findJars(File dir, ArrayList<File> jars) {
+        for (File file : dir.listFiles()) {
+            if (file.isDirectory()) {
+                findJars(file, jars);
+            } else {
+                if (file.toString().endsWith(".jar")) {
+                    jars.add(file);
+                }
+            }
+        }
+    }
+
+    private static final String DELIM_START = "${";
+    private static final String DELIM_STOP = "}";
+
+    /**
+     * <p>
+     * This method performs property variable substitution on the
+     * specified value. If the specified value contains the syntax
+     * <tt>${&lt;prop-name&gt;}</tt>, where <tt>&lt;prop-name&gt;</tt>
+     * refers to either a configuration property or a system property,
+     * then the corresponding property value is substituted for the variable
+     * placeholder. Multiple variable placeholders may exist in the
+     * specified value as well as nested variable placeholders, which
+     * are substituted from inner most to outer most. Configuration
+     * properties override system properties.
+     * </p>
+     *
+     * @param val         The string on which to perform property substitution.
+     * @param currentKey  The key of the property being evaluated used to
+     *                    detect cycles.
+     * @param cycleMap    Map of variable references used to detect nested cycles.
+     * @param configProps Set of configuration properties.
+     * @return The value of the specified string after system property substitution.
+     * @throws IllegalArgumentException If there was a syntax error in the
+     *                                  property placeholder syntax or a recursive variable reference.
+     */
+    public static String substVars(String val, String currentKey,
+                                    Map<String, String> cycleMap, Properties configProps)
+            throws IllegalArgumentException {
+        // If there is currently no cycle map, then create
+        // one for detecting cycles for this invocation.
+        if (cycleMap == null) {
+            cycleMap = new HashMap<String, String>();
+        }
+
+        // Put the current key in the cycle map.
+        cycleMap.put(currentKey, currentKey);
+
+        // Assume we have a value that is something like:
+        // "leading ${foo.${bar}} middle ${baz} trailing"
+
+        // Find the first ending '}' variable delimiter, which
+        // will correspond to the first deepest nested variable
+        // placeholder.
+        int stopDelim = val.indexOf(DELIM_STOP);
+
+        // Find the matching starting "${" variable delimiter
+        // by looping until we find a start delimiter that is
+        // greater than the stop delimiter we have found.
+        int startDelim = val.indexOf(DELIM_START);
+        while (stopDelim >= 0) {
+            int idx = val.indexOf(DELIM_START, startDelim + DELIM_START.length());
+            if ((idx < 0) || (idx > stopDelim)) {
+                break;
+            } else if (idx < stopDelim) {
+                startDelim = idx;
+            }
+        }
+
+        // If we do not have a start or stop delimiter, then just
+        // return the existing value.
+        if ((startDelim < 0) && (stopDelim < 0)) {
+            return val;
+        }
+        // At this point, we found a stop delimiter without a start,
+        // so throw an exception.
+        else if (((startDelim < 0) || (startDelim > stopDelim))
+                && (stopDelim >= 0)) {
+            throw new IllegalArgumentException(
+                    "stop delimiter with no start delimiter: "
+                            + val);
+        }
+
+        // At this point, we have found a variable placeholder so
+        // we must perform a variable substitution on it.
+        // Using the start and stop delimiter indices, extract
+        // the first, deepest nested variable placeholder.
+        String variable =
+                val.substring(startDelim + DELIM_START.length(), stopDelim);
+
+        // Verify that this is not a recursive variable reference.
+        if (cycleMap.get(variable) != null) {
+            throw new IllegalArgumentException(
+                    "recursive variable reference: " + variable);
+        }
+
+        // Get the value of the deepest nested variable placeholder.
+        // Try to configuration properties first.
+        String substValue = (configProps != null)
+                ? configProps.getProperty(variable, null)
+                : null;
+        if (substValue == null) {
+            // Ignore unknown property values.
+            substValue = System.getProperty(variable, "");
+        }
+
+        // Remove the found variable from the cycle map, since
+        // it may appear more than once in the value and we don't
+        // want such situations to appear as a recursive reference.
+        cycleMap.remove(variable);
+
+        // Append the leading characters, the substituted value of
+        // the variable, and the trailing characters to get the new
+        // value.
+        val = val.substring(0, startDelim)
+                + substValue
+                + val.substring(stopDelim + DELIM_STOP.length(), val.length());
+
+        // Now perform substitution again, since there could still
+        // be substitutions to make.
+        val = substVars(val, currentKey, cycleMap, configProps);
+
+        // Return the value.
+        return val;
+    }
+
+    /* (non-Javadoc)
+      * @see org.apache.servicemix.main.MainService#getArgs()
+      */
+    public String[] getArgs() {
+        return args;
+    }
+
+    public int getExitCode() {
+        return exitCode;
+    }
+
+    public void setExitCode(int exitCode) {
+        this.exitCode = exitCode;
+    }
+
+    public File getServicemixHome() {
+        return servicemixHome;
+    }
+
+    public File getServicemixBase() {
+        return servicemixBase;
+    }
+
+    public void lock(Properties props) {
+        try {
+            if (Boolean.parseBoolean(props.getProperty(PROPERTY_USE_LOCK, "true"))) {
+                String clz = props.getProperty(PROPERTY_LOCK_CLASS, PROPERTY_LOCK_CLASS_DEFAULT);
+                lock = (Lock) Class.forName(clz).getConstructor(Properties.class).newInstance(props);
+                boolean lockLogged = false;
+                for (;;) {
+                    if (lock.lock()) {
+                        if (lockLogged) {
+                            System.out.println("Lock acquired.");
+                        }
+                        setStartLevel(defaultStartLevel);
+                        for (;;) {
+                            if (!lock.isAlive()) {
+                                break;
+                            }
+                            Thread.sleep(lockDelay);
+                        }
+                        if (m_felix.getState() == Bundle.ACTIVE && !exiting) {
+                            System.out.println("Lost the lock, stopping this instance ...");
+                            setStartLevel(lockStartLevel);
+                        }
+                        break;
+                    } else if (!lockLogged) {
+                        System.out.println("Waiting for the lock ...");
+                        lockLogged = true;
+                    }
+                    Thread.sleep(lockDelay);
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public void unlock() throws Exception {
+        if (lock != null) {
+            lock.release();
+        }
+    }
+
+    protected void setStartLevel(int level) throws Exception {
+        BundleContext ctx = m_felix.getBundleContext();
+        ServiceReference[] refs = ctx.getServiceReferences(StartLevel.class.getName(), null);
+        StartLevel sl = (StartLevel) ctx.getService(refs[0]);
+        sl.setStartLevel(level);
+    }
+
+}
diff --git a/karaf/main/src/main/java/org/apache/servicemix/kernel/main/SimpleFileLock.java b/karaf/main/src/main/java/org/apache/servicemix/kernel/main/SimpleFileLock.java
new file mode 100644
index 0000000..c9791fd
--- /dev/null
+++ b/karaf/main/src/main/java/org/apache/servicemix/kernel/main/SimpleFileLock.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.servicemix.kernel.main;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.channels.FileLock;
+import java.util.Properties;
+
+public class SimpleFileLock implements Lock {
+
+    private static final String PROPERTY_LOCK_DIR = "servicemix.lock.dir";
+    private static final String PROP_SERVICEMIX_BASE = "servicemix.base";
+    private RandomAccessFile lockFile;
+    private FileLock lock;
+
+    public SimpleFileLock(Properties props) {
+        try {
+            String lock = props.getProperty(PROPERTY_LOCK_DIR);
+
+            if (lock != null) {
+                File servicemixLock = getServiceMixLock(new File(lock), props);
+                props.setProperty(PROPERTY_LOCK_DIR, servicemixLock.getPath());
+            } else {
+                props.setProperty(PROPERTY_LOCK_DIR, System.getProperty(PROP_SERVICEMIX_BASE));
+            }
+
+            File base = new File(props.getProperty(PROPERTY_LOCK_DIR));
+            lockFile = new RandomAccessFile(new File(base, "lock"), "rw");
+        } catch (IOException e) {
+            throw new RuntimeException("Could not create file lock", e);
+        }
+    }
+
+    public boolean lock() throws Exception {
+        if (lock == null) {
+            lock = lockFile.getChannel().tryLock();
+        }
+        return lock != null;
+    }
+
+    public void release() throws Exception {
+        if (lock != null && lock.isValid()) {
+            lock.release();
+            lock.channel().close();
+        }
+        lock = null;
+    }
+ 
+    public boolean isAlive() throws Exception {
+        return lock != null;
+    }
+
+    private static File getServiceMixLock(File lock,Properties props) {
+        File rc = null;
+
+        String path = lock.getPath();
+        if (path != null) {
+            rc = validateDirectoryExists(path, "Invalid " + PROPERTY_LOCK_DIR + " system property");
+        }
+
+        if (rc == null) {
+            path = props.getProperty(PROP_SERVICEMIX_BASE);
+            if (path != null) {
+                rc = validateDirectoryExists(path, "Invalid " + PROP_SERVICEMIX_BASE + " property");
+            }
+        }
+
+        if (rc == null) {
+            rc = lock;
+        }
+        return rc;
+    }
+
+    private static File validateDirectoryExists(String path, String errPrefix) {
+        File rc;
+        try {
+            rc = new File(path).getCanonicalFile();
+        } catch (IOException e) {
+            throw new IllegalArgumentException(errPrefix + " '" + path + "' : " + e.getMessage());
+        }
+        if (!rc.exists()) {
+            throw new IllegalArgumentException(errPrefix + " '" + path + "' : does not exist");
+        }
+        if (!rc.isDirectory()) {
+            throw new IllegalArgumentException(errPrefix + " '" + path + "' : is not a directory");
+        }
+        return rc;
+    }
+
+}
diff --git a/karaf/main/src/main/java/org/apache/servicemix/kernel/main/Statements.java b/karaf/main/src/main/java/org/apache/servicemix/kernel/main/Statements.java
new file mode 100644
index 0000000..0681792
--- /dev/null
+++ b/karaf/main/src/main/java/org/apache/servicemix/kernel/main/Statements.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.servicemix.kernel.main;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+public class Statements {
+
+    private String lockTableName = "SERVICEMIX_LOCK";
+    private String clusterName = "smx4";
+    private String lockCreateStatement;
+    private String lockPopulateStatement;
+    private String lockUpdateStatement;
+
+    public Statements(String tableName, String clusterName) {
+        this.lockTableName = tableName; 
+        this.clusterName = clusterName;
+        this.lockCreateStatement="create table " + lockTableName + " (TIME bigint, CLUSTER varchar(20))";
+        this.lockPopulateStatement="insert into " + lockTableName + " (TIME, CLUSTER) values (1, '" + clusterName + "')";
+    }
+
+    public String testLockTableStatus() {
+        String test = "SELECT * FROM " + lockTableName + " FOR UPDATE";
+        return test;
+    }
+
+    public String getLockUpdateStatement(long timeStamp) {
+        lockUpdateStatement = "UPDATE " + lockTableName + 
+                              " SET TIME=" + timeStamp + 
+                              " WHERE CLUSTER = '" + clusterName + "'";
+        return lockUpdateStatement;
+    }
+
+    /**
+     * init - initialize db
+     */
+    public void init (Connection lockConnection) {
+        Statement s = null;
+        try {
+            // Check to see if the table already exists. If it does, then don't
+            // log warnings during startup.
+            // Need to run the scripts anyways since they may contain ALTER
+            // statements that upgrade a previous version
+            // of the table
+            boolean alreadyExists = false;
+            ResultSet rs = null;
+            try {
+                rs = lockConnection.getMetaData().getTables(null, null, lockTableName, new String[] {"TABLE"});
+                alreadyExists = rs.next();
+            } catch (Throwable ignore) {
+                System.err.println(ignore);
+            } finally {
+                close(rs);
+            }
+            if (alreadyExists) {
+                return;
+            }
+            s = lockConnection.createStatement();
+            String[] createStatments = {lockCreateStatement, lockPopulateStatement};
+            for (int i = 0; i < createStatments.length; i++) {
+                // This will fail usually since the tables will be
+                // created already.
+                try {
+                    s.execute(createStatments[i]);
+                } catch (SQLException e) {
+                    System.err.println("Could not create JDBC tables; they could already exist."
+                                 + " Failure was: " + createStatments[i] + " Message: " + e.getMessage()
+                                 + " SQLState: " + e.getSQLState() + " Vendor code: " + e.getErrorCode());
+                }
+            }
+            lockConnection.commit();
+        } catch (Exception ignore) {
+            System.err.println(ignore);
+        } finally {
+            try {
+                s.close();
+            } catch (Throwable e) {
+                // ignore
+            }
+        }
+    }
+
+    private static void close(ResultSet rs) {
+        try {
+            rs.close();
+        } catch (Throwable e) {
+            // ignore
+        }
+    }
+
+}
diff --git a/karaf/main/src/main/java/org/apache/servicemix/kernel/main/spi/MainService.java b/karaf/main/src/main/java/org/apache/servicemix/kernel/main/spi/MainService.java
new file mode 100644
index 0000000..ab6a24b
--- /dev/null
+++ b/karaf/main/src/main/java/org/apache/servicemix/kernel/main/spi/MainService.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.servicemix.kernel.main.spi;
+
+public interface MainService {
+
+	public abstract String[] getArgs();
+	public int getExitCode();
+	public void setExitCode(int exitCode);
+
+}
\ No newline at end of file
diff --git a/karaf/main/src/main/resources/config.properties b/karaf/main/src/main/resources/config.properties
new file mode 100644
index 0000000..100d484
--- /dev/null
+++ b/karaf/main/src/main/resources/config.properties
@@ -0,0 +1,528 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+#
+# Framework config properties.
+#
+org.osgi.framework.system.packages=org.osgi.framework; version=1.4.0, \
+ org.osgi.service.packageadmin; version=1.2.0, \
+ org.osgi.service.startlevel; version=1.1.0, \
+ org.osgi.service.url; version=1.0.0, \
+ org.osgi.util.tracker; version=1.3.2 \
+ ${jre-${java.specification.version}}
+
+#org.osgi.framework.bootdelegation=sun.*,com.sun.*
+#felix.cache.profile=foo
+felix.auto.start.1= \
+ file:bundle/org.apache.felix.shell-1.0.0.jar \
+ file:bundle/org.apache.felix.shell.tui-1.0.0.jar \
+ file:bundle/org.apache.felix.bundlerepository-1.0.0.jar 
+felix.log.level=4
+felix.startlevel.framework=1
+felix.startlevel.bundle=1
+#framework.service.urlhandlers=false
+
+#
+# Bundle config properties.
+#
+org.osgi.service.http.port=8080
+osgi.shell.telnet=on
+#obr.repository.url=http://bundles.osgi.org/obr/browse?_xml=1&cmd=repository
+
+#list of directories containing bundles to be loaded by SMX
+#bundle.locations=
+
+#
+# Java platform package export properties.
+#
+jre-1.3=, \
+ javax.accessibility; \
+ javax.accessibility.resources; \
+ javax.naming; \
+ javax.naming.directory; \
+ javax.naming.event; \
+ javax.naming.ldap; \
+ javax.naming.spi; \
+ javax.rmi; \
+ javax.rmi.CORBA; \
+ javax.sound.midi; \
+ javax.sound.midi.spi; \
+ javax.sound.sampled; \
+ javax.sound.sampled.spi; \
+ javax.swing; \
+ javax.swing.border; \
+ javax.swing.colorchooser; \
+ javax.swing.event; \
+ javax.swing.filechooser; \
+ javax.swing.plaf; \
+ javax.swing.plaf.basic; \
+ javax.swing.plaf.basic.resources; \
+ javax.swing.plaf.metal; \
+ javax.swing.plaf.metal.resources; \
+ javax.swing.plaf.multi; \
+ javax.swing.table; \
+ javax.swing.text; \
+ javax.swing.text.html; \
+ javax.swing.text.html.parser; \
+ javax.swing.text.rtf; \
+ javax.swing.tree; \
+ javax.swing.undo; \
+ javax.transaction; \
+ org.omg.CORBA; \
+ org.omg.CORBA_2_3; \
+ org.omg.CORBA_2_3.portable; \
+ org.omg.CORBA.DynAnyPackage; \
+ org.omg.CORBA.ORBPackage; \
+ org.omg.CORBA.portable; \
+ org.omg.CORBA.TypeCodePackage; \
+ org.omg.CosNaming; \
+ org.omg.CosNaming.NamingContextPackage; \
+ org.omg.SendingContext; \
+ org.omg.stub.java.rmi; \
+ version="1.3.0"
+
+jre-1.4=, \
+ javax.accessibility; \
+ javax.imageio; \
+ javax.imageio.event; \
+ javax.imageio.metadata; \
+ javax.imageio.plugins.jpeg; \
+ javax.imageio.spi; \
+ javax.imageio.stream; \
+ javax.naming; \
+ javax.naming.directory; \
+ javax.naming.event; \
+ javax.naming.ldap; \
+ javax.naming.spi; \
+ javax.net; \
+ javax.net.ssl; \
+ javax.print; \
+ javax.print.attribute; \
+ javax.print.attribute.standard; \
+ javax.print.event; \
+ javax.rmi; \
+ javax.rmi.CORBA; \
+ javax.security.auth; \
+ javax.security.auth.callback; \
+ javax.security.auth.kerberos; \
+ javax.security.auth.login; \
+ javax.security.auth.spi; \
+ javax.security.auth.x500; \
+ javax.sound.midi; \
+ javax.sound.midi.spi; \
+ javax.sound.sampled; \
+ javax.sound.sampled.spi; \
+ javax.sql; \
+ javax.swing; \
+ javax.swing.border; \
+ javax.swing.colorchooser; \
+ javax.swing.event; \
+ javax.swing.filechooser; \
+ javax.swing.plaf; \
+ javax.swing.plaf.basic; \
+ javax.swing.plaf.metal; \
+ javax.swing.plaf.multi; \
+ javax.swing.table; \
+ javax.swing.text; \
+ javax.swing.text.html; \
+ javax.swing.text.html.parser; \
+ javax.swing.text.rtf; \
+ javax.swing.tree; \
+ javax.swing.undo; \
+ javax.transaction; \
+ javax.transaction.xa; \
+ javax.xml.parsers; \
+ javax.xml.transform; \
+ javax.xml.transform.dom; \
+ javax.xml.transform.sax; \
+ javax.xml.transform.stream; \
+ org.ietf.jgss; \
+ org.omg.CORBA; \
+ org.omg.CORBA_2_3; \
+ org.omg.CORBA_2_3.portable; \
+ org.omg.CORBA.DynAnyPackage; \
+ org.omg.CORBA.ORBPackage; \
+ org.omg.CORBA.portable; \
+ org.omg.CORBA.TypeCodePackage; \
+ org.omg.CosNaming; \
+ org.omg.CosNaming.NamingContextExtPackage; \
+ org.omg.CosNaming.NamingContextPackage; \
+ org.omg.Dynamic; \
+ org.omg.DynamicAny; \
+ org.omg.DynamicAny.DynAnyFactoryPackage; \
+ org.omg.DynamicAny.DynAnyPackage; \
+ org.omg.IOP; \
+ org.omg.IOP.CodecFactoryPackage; \
+ org.omg.IOP.CodecPackage; \
+ org.omg.Messaging; \
+ org.omg.PortableInterceptor; \
+ org.omg.PortableInterceptor.ORBInitInfoPackage; \
+ org.omg.PortableServer; \
+ org.omg.PortableServer.CurrentPackage; \
+ org.omg.PortableServer.POAManagerPackage; \
+ org.omg.PortableServer.POAPackage; \
+ org.omg.PortableServer.portable; \
+ org.omg.PortableServer.ServantLocatorPackage; \
+ org.omg.SendingContext; \
+ org.omg.stub.java.rmi; \
+ org.w3c.dom; \
+ org.w3c.dom.css; \
+ org.w3c.dom.events; \
+ org.w3c.dom.html; \
+ org.w3c.dom.stylesheets; \
+ org.w3c.dom.traversal; \
+ org.w3c.dom.views; \
+ org.xml.sax; \
+ org.xml.sax.ext; \
+ org.xml.sax.helpers; \
+ version="1.4.0"
+
+jre-1.5=, \
+ javax.accessibility; \
+ javax.activity; \
+ javax.imageio; \
+ javax.imageio.event; \
+ javax.imageio.metadata; \
+ javax.imageio.plugins.bmp; \
+ javax.imageio.plugins.jpeg; \
+ javax.imageio.spi; \
+ javax.imageio.stream; \
+ javax.management; \
+ javax.management.loading; \
+ javax.management.modelmbean; \
+ javax.management.monitor; \
+ javax.management.openmbean; \
+ javax.management.relation; \
+ javax.management.remote; \
+ javax.management.remote.rmi; \
+ javax.management.timer; \
+ javax.naming; \
+ javax.naming.directory; \
+ javax.naming.event; \
+ javax.naming.ldap; \
+ javax.naming.spi; \
+ javax.net; \
+ javax.net.ssl; \
+ javax.print; \
+ javax.print.attribute; \
+ javax.print.attribute.standard; \
+ javax.print.event; \
+ javax.rmi; \
+ javax.rmi.CORBA; \
+ javax.rmi.ssl; \
+ javax.security.auth; \
+ javax.security.auth.callback; \
+ javax.security.auth.kerberos; \
+ javax.security.auth.login; \
+ javax.security.auth.spi; \
+ javax.security.auth.x500; \
+ javax.security.sasl; \
+ javax.sound.midi; \
+ javax.sound.midi.spi; \
+ javax.sound.sampled; \
+ javax.sound.sampled.spi; \
+ javax.sql; \
+ javax.sql.rowset; \
+ javax.sql.rowset.serial; \
+ javax.sql.rowset.spi; \
+ javax.swing; \
+ javax.swing.border; \
+ javax.swing.colorchooser; \
+ javax.swing.event; \
+ javax.swing.filechooser; \
+ javax.swing.plaf; \
+ javax.swing.plaf.basic; \
+ javax.swing.plaf.metal; \
+ javax.swing.plaf.multi; \
+ javax.swing.plaf.synth; \
+ javax.swing.table; \
+ javax.swing.text; \
+ javax.swing.text.html; \
+ javax.swing.text.html.parser; \
+ javax.swing.text.rtf; \
+ javax.swing.tree; \
+ javax.swing.undo; \
+ javax.transaction; \
+ javax.transaction.xa; \
+ javax.xml; \
+ javax.xml.datatype; \
+ javax.xml.namespace; \
+ javax.xml.parsers; \
+ javax.xml.transform; \
+ javax.xml.transform.dom; \
+ javax.xml.transform.sax; \
+ javax.xml.transform.stream; \
+ javax.xml.validation; \
+ javax.xml.xpath; \
+ org.ietf.jgss; \
+ org.omg.CORBA; \
+ org.omg.CORBA_2_3; \
+ org.omg.CORBA_2_3.portable; \
+ org.omg.CORBA.DynAnyPackage; \
+ org.omg.CORBA.ORBPackage; \
+ org.omg.CORBA.portable; \
+ org.omg.CORBA.TypeCodePackage; \
+ org.omg.CosNaming; \
+ org.omg.CosNaming.NamingContextExtPackage; \
+ org.omg.CosNaming.NamingContextPackage; \
+ org.omg.Dynamic; \
+ org.omg.DynamicAny; \
+ org.omg.DynamicAny.DynAnyFactoryPackage; \
+ org.omg.DynamicAny.DynAnyPackage; \
+ org.omg.IOP; \
+ org.omg.IOP.CodecFactoryPackage; \
+ org.omg.IOP.CodecPackage; \
+ org.omg.Messaging; \
+ org.omg.PortableInterceptor; \
+ org.omg.PortableInterceptor.ORBInitInfoPackage; \
+ org.omg.PortableServer; \
+ org.omg.PortableServer.CurrentPackage; \
+ org.omg.PortableServer.POAManagerPackage; \
+ org.omg.PortableServer.POAPackage; \
+ org.omg.PortableServer.portable; \
+ org.omg.PortableServer.ServantLocatorPackage; \
+ org.omg.SendingContext; \
+ org.omg.stub.java.rmi; \
+ org.omg.stub.javax.management.remote.rmi; \
+ org.w3c.dom; \
+ org.w3c.dom.bootstrap; \
+ org.w3c.dom.css; \
+ org.w3c.dom.events; \
+ org.w3c.dom.html; \
+ org.w3c.dom.ls; \
+ org.w3c.dom.ranges; \
+ org.w3c.dom.stylesheets; \
+ org.w3c.dom.traversal; \
+ org.w3c.dom.views; \
+ org.xml.sax; \
+ org.xml.sax.ext; \
+ org.xml.sax.helpers; \
+ version="1.5.0"
+
+jre-1.6=, \
+ java.applet; \
+ java.awt; \
+ java.awt.color; \
+ java.awt.datatransfer; \
+ java.awt.dnd; \
+ java.awt.dnd.peer; \
+ java.awt.event; \
+ java.awt.font; \
+ java.awt.geom; \
+ java.awt.im; \
+ java.awt.image; \
+ java.awt.image.renderable; \
+ java.awt.im.spi; \
+ java.awt.peer; \
+ java.awt.print; \
+ java.beans; \
+ java.beans.beancontext; \
+ java.io; \
+ java.lang; \
+ java.lang.annotation; \
+ java.lang.instrument; \
+ java.lang.management; \
+ java.lang.ref; \
+ java.lang.reflect; \
+ java.math; \
+ java.net; \
+ java.nio; \
+ java.nio.channels; \
+ java.nio.channels.spi; \
+ java.nio.charset; \
+ java.nio.charset.spi; \
+ java.rmi; \
+ java.rmi.activation; \
+ java.rmi.dgc; \
+ java.rmi.registry; \
+ java.rmi.server; \
+ java.security; \
+ java.security.acl; \
+ java.security.cert; \
+ java.security.interfaces; \
+ java.security.spec; \
+ java.sql; \
+ java.text; \
+ java.text.spi; \
+ java.util; \
+ java.util.concurrent; \
+ java.util.concurrent.atomic; \
+ java.util.concurrent.locks; \
+ java.util.jar; \
+ java.util.logging; \
+ java.util.prefs; \
+ java.util.regex; \
+ java.util.spi; \
+ java.util.zip; \
+ javax.accessibility; \
+ javax.activation; \
+ javax.activity; \
+ javax.annotation; \
+ javax.annotation.processing; \
+ javax.imageio; \
+ javax.imageio.event; \
+ javax.imageio.metadata; \
+ javax.imageio.plugins.bmp; \
+ javax.imageio.plugins.jpeg; \
+ javax.imageio.spi; \
+ javax.imageio.stream; \
+ javax.jws; \
+ javax.jws.soap; \
+ javax.lang.model; \
+ javax.lang.model.element; \
+ javax.lang.model.type; \
+ javax.lang.model.util; \
+ javax.management; \
+ javax.management.loading; \
+ javax.management.modelmbean; \
+ javax.management.monitor; \
+ javax.management.openmbean; \
+ javax.management.relation; \
+ javax.management.remote; \
+ javax.management.remote.rmi; \
+ javax.management.timer; \
+ javax.naming; \
+ javax.naming.directory; \
+ javax.naming.event; \
+ javax.naming.ldap; \
+ javax.naming.spi; \
+ javax.net; \
+ javax.net.ssl; \
+ javax.print; \
+ javax.print.attribute; \
+ javax.print.attribute.standard; \
+ javax.print.event; \
+ javax.rmi; \
+ javax.rmi.CORBA; \
+ javax.rmi.ssl; \
+ javax.script; \
+ javax.security.auth; \
+ javax.security.auth.callback; \
+ javax.security.auth.kerberos; \
+ javax.security.auth.login; \
+ javax.security.auth.spi; \
+ javax.security.auth.x500; \
+ javax.security.sasl; \
+ javax.smartcardio; \
+ javax.sound.midi; \
+ javax.sound.midi.spi; \
+ javax.sound.sampled; \
+ javax.sound.sampled.spi; \
+ javax.sql; \
+ javax.sql.rowset; \
+ javax.sql.rowset.serial; \
+ javax.sql.rowset.spi; \
+ javax.swing; \
+ javax.swing.border; \
+ javax.swing.colorchooser; \
+ javax.swing.event; \
+ javax.swing.filechooser; \
+ javax.swing.plaf; \
+ javax.swing.plaf.basic; \
+ javax.swing.plaf.metal; \
+ javax.swing.plaf.multi; \
+ javax.swing.plaf.synth; \
+ javax.swing.table; \
+ javax.swing.text; \
+ javax.swing.text.html; \
+ javax.swing.text.html.parser; \
+ javax.swing.text.rtf; \
+ javax.swing.tree; \
+ javax.swing.undo; \
+ javax.tools; \
+ javax.transaction; \
+ javax.transaction.xa; \
+ javax.xml; \
+ javax.xml.bind; \
+ javax.xml.bind.annotation; \
+ javax.xml.bind.annotation.adapters; \
+ javax.xml.bind.attachment; \
+ javax.xml.bind.helpers; \
+ javax.xml.bind.util; \
+ javax.xml.crypto; \
+ javax.xml.crypto.dom; \
+ javax.xml.crypto.dsig; \
+ javax.xml.crypto.dsig.dom; \
+ javax.xml.crypto.dsig.keyinfo; \
+ javax.xml.crypto.dsig.spec; \
+ javax.xml.datatype; \
+ javax.xml.namespace; \
+ javax.xml.parsers; \
+ javax.xml.soap; \
+ javax.xml.stream; \
+ javax.xml.stream.events; \
+ javax.xml.stream.util; \
+ javax.xml.transform; \
+ javax.xml.transform.dom; \
+ javax.xml.transform.sax; \
+ javax.xml.transform.stax; \
+ javax.xml.transform.stream; \
+ javax.xml.validation; \
+ javax.xml.ws; \
+ javax.xml.ws.handler; \
+ javax.xml.ws.handler.soap; \
+ javax.xml.ws.http; \
+ javax.xml.ws.soap; \
+ javax.xml.ws.spi; \
+ javax.xml.xpath; \
+ org.ietf.jgss; \
+ org.jcp.xml.dsig.internal; \
+ org.jcp.xml.dsig.internal.dom; \
+ org.omg.CORBA; \
+ org.omg.CORBA_2_3; \
+ org.omg.CORBA_2_3.portable; \
+ org.omg.CORBA.DynAnyPackage; \
+ org.omg.CORBA.ORBPackage; \
+ org.omg.CORBA.portable; \
+ org.omg.CORBA.TypeCodePackage; \
+ org.omg.CosNaming; \
+ org.omg.CosNaming.NamingContextExtPackage; \
+ org.omg.CosNaming.NamingContextPackage; \
+ org.omg.Dynamic; \
+ org.omg.DynamicAny; \
+ org.omg.DynamicAny.DynAnyFactoryPackage; \
+ org.omg.DynamicAny.DynAnyPackage; \
+ org.omg.IOP; \
+ org.omg.IOP.CodecFactoryPackage; \
+ org.omg.IOP.CodecPackage; \
+ org.omg.Messaging; \
+ org.omg.PortableInterceptor; \
+ org.omg.PortableInterceptor.ORBInitInfoPackage; \
+ org.omg.PortableServer; \
+ org.omg.PortableServer.CurrentPackage; \
+ org.omg.PortableServer.POAManagerPackage; \
+ org.omg.PortableServer.POAPackage; \
+ org.omg.PortableServer.portable; \
+ org.omg.PortableServer.ServantLocatorPackage; \
+ org.omg.SendingContext; \
+ org.omg.stub.java.rmi; \
+ org.omg.stub.javax.management.remote.rmi; \
+ org.w3c.dom; \
+ org.w3c.dom.bootstrap; \
+ org.w3c.dom.css; \
+ org.w3c.dom.events; \
+ org.w3c.dom.html; \
+ org.w3c.dom.ls; \
+ org.w3c.dom.ranges; \
+ org.w3c.dom.stylesheets; \
+ org.w3c.dom.traversal; \
+ org.w3c.dom.views; \
+ org.w3c.dom.xpath; \
+ org.xml.sax; \
+ org.xml.sax.ext; \
+ org.xml.sax.helpers; \
+ version=\"1.6.0\"
diff --git a/karaf/management/pom.xml b/karaf/management/pom.xml
new file mode 100644
index 0000000..ed0112b
--- /dev/null
+++ b/karaf/management/pom.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <!--
+
+        Licensed to the Apache Software Foundation (ASF) under one or more
+        contributor license agreements.  See the NOTICE file distributed with
+        this work for additional information regarding copyright ownership.
+        The ASF licenses this file to You under the Apache License, Version 2.0
+        (the "License"); you may not use this file except in compliance with
+        the License.  You may obtain a copy of the License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software
+        distributed under the License is distributed on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        See the License for the specific language governing permissions and
+        limitations under the License.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.servicemix.kernel</groupId>
+        <artifactId>kernel</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.servicemix.kernel</groupId>
+    <artifactId>org.apache.servicemix.kernel.management</artifactId>
+    <packaging>bundle</packaging>
+    <version>1.2.0-SNAPSHOT</version>
+    <name>Apache ServiceMix Kernel :: Management</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.osgi</groupId>
+            <artifactId>spring-osgi-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>commons-logging</groupId>
+            <artifactId>commons-logging</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName>
+                        <Import-Package>
+                            javax.management,
+                            org.springframework.jmx.support,
+                            *
+                        </Import-Package>
+                        <Export-Package>org.apache.servicemix.management*</Export-Package>
+                        <Spring-Context>*;publish-context:=false</Spring-Context>
+                    </instructions>
+                </configuration>
+            </plugin>
+       </plugins>
+    </build>
+
+
+</project>
diff --git a/karaf/management/src/main/java/org/apache/servicemix/management/JaasAuthenticator.java b/karaf/management/src/main/java/org/apache/servicemix/management/JaasAuthenticator.java
new file mode 100644
index 0000000..1353d3f
--- /dev/null
+++ b/karaf/management/src/main/java/org/apache/servicemix/management/JaasAuthenticator.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.management;
+
+import java.io.IOException;
+
+import javax.management.remote.JMXAuthenticator;
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
+public class JaasAuthenticator implements JMXAuthenticator {
+
+    private String realm;
+
+    public String getRealm() {
+        return realm;
+    }
+
+    public void setRealm(String realm) {
+        this.realm = realm;
+    }
+
+    public Subject authenticate(Object credentials) throws SecurityException {
+        if (!(credentials instanceof String[])) {
+            throw new IllegalArgumentException("Expected String[2], got "
+                            + (credentials != null ? credentials.getClass().getName() : null));
+        }
+        final String[] params = (String[]) credentials;
+        if (params.length != 2) {
+            throw new IllegalArgumentException("Expected String[2] but length was " + params.length);
+        }
+        try {
+            LoginContext loginContext = new LoginContext(realm, new CallbackHandler() {
+                public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+                    for (int i = 0; i < callbacks.length; i++) {
+                        if (callbacks[i] instanceof NameCallback) {
+                            ((NameCallback) callbacks[i]).setName(params[0]);
+                        } else if (callbacks[i] instanceof PasswordCallback) {
+                            ((PasswordCallback) callbacks[i]).setPassword((params[1].toCharArray()));
+                        } else {
+                            throw new UnsupportedCallbackException(callbacks[i]);
+                        }
+                    }
+                }
+            });
+            loginContext.login();
+            return loginContext.getSubject();
+        } catch (LoginException e) {
+            throw new SecurityException("Authentication failed", e);
+        }
+    }
+}
diff --git a/karaf/management/src/main/java/org/apache/servicemix/management/RmiRegistryFactoryBean.java b/karaf/management/src/main/java/org/apache/servicemix/management/RmiRegistryFactoryBean.java
new file mode 100644
index 0000000..1a5a995
--- /dev/null
+++ b/karaf/management/src/main/java/org/apache/servicemix/management/RmiRegistryFactoryBean.java
@@ -0,0 +1,118 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one or more

+ * contributor license agreements.  See the NOTICE file distributed with

+ * this work for additional information regarding copyright ownership.

+ * The ASF licenses this file to You under the Apache License, Version 2.0

+ * (the "License"); you may not use this file except in compliance with

+ * the License.  You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+package org.apache.servicemix.management;

+

+import java.rmi.RemoteException;

+import java.rmi.registry.LocateRegistry;

+import java.rmi.registry.Registry;

+import java.rmi.server.UnicastRemoteObject;

+

+import org.springframework.beans.factory.DisposableBean;

+import org.springframework.beans.factory.FactoryBean;

+import org.springframework.beans.factory.InitializingBean;

+

+/**

+ * 

+ * @author gnodet

+ */

+public class RmiRegistryFactoryBean implements FactoryBean, InitializingBean, DisposableBean {

+

+    private int port = Registry.REGISTRY_PORT;

+    private Registry registry;

+    private boolean locate;

+    private boolean create = true;

+    private boolean locallyCreated;

+    

+    /**

+     * @return the create

+     */

+    public boolean isCreate() {

+        return create;

+    }

+

+    /**

+     * @param create the create to set

+     */

+    public void setCreate(boolean create) {

+        this.create = create;

+    }

+

+    /**

+     * @return the locate

+     */

+    public boolean isLocate() {

+        return locate;

+    }

+

+    /**

+     * @param locate the locate to set

+     */

+    public void setLocate(boolean locate) {

+        this.locate = locate;

+    }

+

+    /**

+     * @return the port

+     */

+    public int getPort() {

+        return port;

+    }

+

+    /**

+     * @param port the port to set

+     */

+    public void setPort(int port) {

+        this.port = port;

+    }

+

+    public Object getObject() throws Exception {

+        return registry;

+    }

+

+    public Class getObjectType() {

+        return Registry.class;

+    }

+

+    public boolean isSingleton() {

+        return true;

+    }

+

+    public void afterPropertiesSet() throws RemoteException {

+        if (registry == null && locate) {

+            try {

+                Registry reg = LocateRegistry.getRegistry(getPort());

+                reg.list();

+                registry = reg;

+            } catch (RemoteException e) {

+                // ignore

+            }

+        }

+        if (registry == null && create) {

+            registry = LocateRegistry.createRegistry(getPort());

+            locallyCreated = true;

+        }

+    }

+

+    public void destroy() throws RemoteException {

+        if (registry != null && locallyCreated) {

+            Registry reg = registry;

+            registry = null;

+            UnicastRemoteObject.unexportObject(reg, true);

+        }

+    }

+

+}

diff --git a/karaf/management/src/main/resources/META-INF/spring/servicemix-management.xml b/karaf/management/src/main/resources/META-INF/spring/servicemix-management.xml
new file mode 100644
index 0000000..6a9bcc3
--- /dev/null
+++ b/karaf/management/src/main/resources/META-INF/spring/servicemix-management.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!--

+

+    Licensed to the Apache Software Foundation (ASF) under one or more

+    contributor license agreements.  See the NOTICE file distributed with

+    this work for additional information regarding copyright ownership.

+    The ASF licenses this file to You under the Apache License, Version 2.0

+    (the "License"); you may not use this file except in compliance with

+    the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+    Unless required by applicable law or agreed to in writing, software

+    distributed under the License is distributed on an "AS IS" BASIS,

+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+    See the License for the specific language governing permissions and

+    limitations under the License.

+

+-->

+<beans xmlns="http://www.springframework.org/schema/beans"

+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

+       xmlns:ctx="http://www.springframework.org/schema/context"

+       xmlns:osgi="http://www.springframework.org/schema/osgi"

+       xmlns:osgix="http://www.springframework.org/schema/osgi-compendium"

+       xmlns:util="http://www.springframework.org/schema/util"

+       xsi:schemaLocation="

+  http://www.springframework.org/schema/beans

+  http://www.springframework.org/schema/beans/spring-beans.xsd

+  http://www.springframework.org/schema/context

+  http://www.springframework.org/schema/context/spring-context.xsd

+  http://www.springframework.org/schema/util

+  http://www.springframework.org/schema/util/spring-util.xsd

+  http://www.springframework.org/schema/osgi

+  http://www.springframework.org/schema/osgi/spring-osgi.xsd

+  http://www.springframework.org/schema/osgi-compendium

+  http://www.springframework.org/schema/osgi-compendium/spring-osgi-compendium.xsd">

+

+    <!-- MBeanServer bean -->

+    <bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean">

+        <property name="locateExistingServerIfPossible" value="true"/>

+    </bean>

+

+    <!-- Export the MBeanServer as an OSGi service -->

+    <osgi:service ref="mbeanServer">

+        <osgi:interfaces>

+            <value>javax.management.MBeanServer</value>

+        </osgi:interfaces>

+    </osgi:service>

+

+    <!-- Create a RMI registry -->

+    <bean id="rmiRegistry" class="org.apache.servicemix.management.RmiRegistryFactoryBean">

+        <property name="create" value="true" />

+        <property name="locate" value="true" />

+        <property name="port" value="${rmiRegistryPort}" />

+    </bean>

+

+    <!-- Create a JMX connector ServiceFactory -->

+    <bean id="jmxConnectorService" class="org.springframework.jmx.support.ConnectorServerFactoryBean">

+        <property name="server" ref="mbeanServer" />

+        <property name="serviceUrl" value="${serviceUrl}" />

+        <property name="daemon" value="${daemon}" />

+        <property name="threaded" value="${threaded}" />

+        <property name="objectName" value="${objectName}" />

+        <property name="environment" ref="jmxConnectorEnvironment" />

+    </bean>

+

+    <!-- Environment map for connectors -->

+    <util:map id="jmxConnectorEnvironment">

+        <entry key="jmx.remote.authenticator" value-ref="jaasAuthenticator" />

+    </util:map>

+

+    <!-- JAAS authenticator -->

+    <bean id="jaasAuthenticator" class="org.apache.servicemix.management.JaasAuthenticator">

+        <property name="realm" value="${jmxRealm}" />

+    </bean>

+

+    <!-- Property place holder -->

+    <osgix:cm-properties id="cmProps" persistent-id="org.apache.servicemix.management">

+        <prop key="rmiRegistryPort">1099</prop>

+        <prop key="jmxRealm">servicemix</prop>

+        <prop key="serviceUrl">service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi</prop>

+        <prop key="daemon">true</prop>

+        <prop key="threaded">true</prop>

+        <prop key="objectName">connector:name=rmi</prop>

+    </osgix:cm-properties>

+

+    <ctx:property-placeholder properties-ref="cmProps" />

+

+</beans>

+

diff --git a/karaf/management/src/test/configs/factories/management.properties b/karaf/management/src/test/configs/factories/management.properties
new file mode 100644
index 0000000..10c22db
--- /dev/null
+++ b/karaf/management/src/test/configs/factories/management.properties
@@ -0,0 +1,26 @@
+################################################################################
+#
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+################################################################################
+
+service.pid=org.apache.servicemix.management.JmxConnectorServiceFactory
+instances=1
+keys=objectName,serviceUrl,threaded,daemon,
+objectName.1=connector:name=rmi
+serviceUrl.1=service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi
+threaded.1=true
+daemon.1=true
diff --git a/karaf/management/src/test/configs/services/org.ops4j.pax.logging.properties b/karaf/management/src/test/configs/services/org.ops4j.pax.logging.properties
new file mode 100644
index 0000000..23075bf
--- /dev/null
+++ b/karaf/management/src/test/configs/services/org.ops4j.pax.logging.properties
@@ -0,0 +1,34 @@
+# 
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed  under the  License is distributed on an "AS IS" BASIS,
+# WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+# implied.
+#  
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+log4j.rootLogger=DEBUG, out
+
+log4j.logger.org.springframework=DEBUG
+
+# CONSOLE appender not used by default
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} | %-5.5p | %-16.16t | %-32.32c{1} | %-32.32C %4L | %m%n
+
+# File appender
+log4j.appender.out=org.apache.log4j.FileAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.out.layout.ConversionPattern=%d{ABSOLUTE} | %-5.5p | %-16.16t | %-32.32c{1} | %-32.32C %4L | %m%n
+log4j.appender.out.file=target/gshell.log
+log4j.appender.out.append=true
diff --git a/karaf/pom.xml b/karaf/pom.xml
new file mode 100644
index 0000000..31f8796
--- /dev/null
+++ b/karaf/pom.xml
@@ -0,0 +1,1098 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <!--
+
+        Licensed to the Apache Software Foundation (ASF) under one or more
+        contributor license agreements.  See the NOTICE file distributed with
+        this work for additional information regarding copyright ownership.
+        The ASF licenses this file to You under the Apache License, Version 2.0
+        (the "License"); you may not use this file except in compliance with
+        the License.  You may obtain a copy of the License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software
+        distributed under the License is distributed on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        See the License for the specific language governing permissions and
+        limitations under the License.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.servicemix</groupId>
+        <artifactId>servicemix-pom</artifactId>
+        <version>2</version>
+    </parent>
+
+    <groupId>org.apache.servicemix.kernel</groupId>
+    <artifactId>kernel</artifactId>
+    <packaging>pom</packaging>
+    <version>1.2.0-SNAPSHOT</version>
+    <name>Apache ServiceMix Kernel</name>
+    <inceptionYear>2007</inceptionYear>
+
+    <modules>
+        <module>main</module>
+        <module>filemonitor</module>
+        <module>gshell</module>
+        <module>spring</module>
+        <module>testing</module>
+        <module>jaas</module>
+        <module>client</module>
+        <module>management</module>
+        <module>assembly</module>
+        <module>demos</module>
+    </modules>
+
+    <scm>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/servicemix/smx4/kernel/trunk</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/servicemix/smx4/kernel/trunk</developerConnection>
+        <url>http://svn.apache.org/viewvc/servicemix/smx4/kernel/trunk/</url>
+    </scm>
+
+    <issueManagement>
+        <system>jira</system>
+        <url>http://issues.apache.org/activemq/browse/SMX4KNL</url>
+    </issueManagement>
+
+    <prerequisites>
+        <maven>2.0.7</maven>
+    </prerequisites>
+
+    <properties>
+        <config.location>etc</config.location>
+        <ant.version>1.7.0_1</ant.version>
+        <aopalliance.version>1.0_1</aopalliance.version>
+        <asm.version>2.2.3_1</asm.version>
+        <cglib.version>2.1_3_2-SNAPSHOT</cglib.version>
+        <commons.codec.version>1.2_1</commons.codec.version>
+        <commons.httpclient.version>3.1_1</commons.httpclient.version>
+        <commons.io.version>1.3.2_1</commons.io.version>
+        <commons.jexl.version>1.1_1</commons.jexl.version>
+        <commons.logging.version>1.1.1</commons.logging.version>
+        <commons.vfs.version>1.0_1</commons.vfs.version>
+        <depends.maven.plugin.version>1.0</depends.maven.plugin.version>
+        <easymock.version>2.4</easymock.version>
+        <felix.configadmin.version>1.0.4</felix.configadmin.version>
+        <felix.plugin.version>1.4.3</felix.plugin.version>
+        <felix.framework.version>1.5.0-r752991</felix.framework.version>
+        <felix.osgi.version>1.2.0</felix.osgi.version>
+        <felix.compendium.version>1.2.0</felix.compendium.version>
+        <felix.bundlerepository.version>1.2.1</felix.bundlerepository.version>
+        <felix.prefs.version>1.0.2</felix.prefs.version>
+        <geronimo.annotation.version>1.1.1</geronimo.annotation.version>
+        <geronimo.servlet.version>1.1.2</geronimo.servlet.version>
+        <gshell.version>1.0-alpha-2</gshell.version>
+        <jaxp.ri.version>1.4.2_1</jaxp.ri.version>
+        <junit.version>3.8.2_1</junit.version>
+        <jline.version>0.9.94_1</jline.version>
+        <log4j.version>1.2.14</log4j.version>
+        <mina.version>2.0.0-M5</mina.version>
+        <oro.version>2.0.8_1</oro.version>
+        <pax.logging.version>1.3.0</pax.logging.version>
+        <pax.url.version>0.3.3</pax.url.version>
+        <servicemix.legal.version>1.0</servicemix.legal.version>
+        <servicemix.specs.version>1.4-SNAPSHOT</servicemix.specs.version>
+        <spring.osgi.version>1.2.0-rc1</spring.osgi.version>
+        <spring.version>2.5.6</spring.version>
+        <sshd.version>1.0-SNAPSHOT</sshd.version>
+        <woodstox.version>3.2.7_1</woodstox.version>
+        <osgi.jmx.version>1.0-r6125-patched</osgi.jmx.version>
+
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <repositories>
+        <!-- Default repository -->
+        <repository>
+            <id>central</id>
+            <name>Default maven repo</name>
+            <url>http://repo1.maven.org/maven2</url>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+        </repository>
+        <!-- Apache snapshots -->
+        <repository>
+            <id>apache-snapshots</id>
+            <name>Apache Snapshots Repository</name>
+            <url>http://repository.apache.org/content/groups/snapshots-group</url>
+            <releases>
+                <enabled>false</enabled>
+            </releases>
+            <snapshots>
+                <enabled>true</enabled>
+            </snapshots>
+        </repository>
+        <!-- ServiceMix repo -->
+        <repository>
+            <id>servicemix</id>
+            <name>Apache ServiceMix Repository</name>
+            <url>http://svn.apache.org/repos/asf/servicemix/m2-repo</url>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+        </repository>
+        <!-- OPS4J repo -->
+        <repository>
+            <id>ops4j</id>
+            <name>OPS4j Repository</name>
+            <url>http://repository.ops4j.org/maven2</url>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+        </repository>
+        <!-- Spring milestones repository -->
+        <!-- TODO: remove this repo when spring-dm 1.2.0 is out -->
+        <repository>
+            <id>spring-milestone</id>
+            <name>Spring Portfolio Milestone Repository</name>
+            <url>http://s3.amazonaws.com/maven.springframework.org/milestone</url>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+        </repository>
+    </repositories>
+
+    <pluginRepositories>
+        <!-- ServiceMix repo -->
+        <pluginRepository>
+            <id>servicemix</id>
+            <name>Apache ServiceMix Repository</name>
+            <url>http://svn.apache.org/repos/asf/servicemix/m2-repo</url>
+        </pluginRepository>
+    </pluginRepositories>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.apache.servicemix.kernel</groupId>
+                <artifactId>org.apache.servicemix.kernel.main</artifactId>
+                <version>${pom.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.kernel</groupId>
+                <artifactId>org.apache.servicemix.kernel.client</artifactId>
+                <version>${pom.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.kernel</groupId>
+                <artifactId>org.apache.servicemix.kernel.filemonitor</artifactId>
+                <version>${pom.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.kernel</groupId>
+                <artifactId>org.apache.servicemix.kernel.spring</artifactId>
+                <version>${pom.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.kernel</groupId>
+                <artifactId>org.apache.servicemix.kernel.management</artifactId>
+                <version>${pom.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.kernel</groupId>
+                <artifactId>org.apache.servicemix.kernel.demos</artifactId>
+                <version>${pom.version}</version>
+            </dependency> 
+            <dependency>
+                <groupId>org.apache.servicemix.kernel.gshell</groupId>
+                <artifactId>org.apache.servicemix.kernel.gshell.core</artifactId>
+                <version>${pom.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.kernel.gshell</groupId>
+                <artifactId>org.apache.servicemix.kernel.gshell.admin</artifactId>
+                <version>${pom.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.kernel.gshell</groupId>
+                <artifactId>org.apache.servicemix.kernel.gshell.obr</artifactId>
+                <version>${pom.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.kernel.gshell</groupId>
+                <artifactId>org.apache.servicemix.kernel.gshell.osgi</artifactId>
+                <version>${pom.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.kernel.gshell</groupId>
+                <artifactId>org.apache.servicemix.kernel.gshell.log</artifactId>
+                <version>${pom.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.kernel.gshell</groupId>
+                <artifactId>org.apache.servicemix.kernel.gshell.features</artifactId>
+                <version>${pom.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.kernel.gshell</groupId>
+                <artifactId>org.apache.servicemix.kernel.gshell.config</artifactId>
+                <version>${pom.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.kernel.gshell</groupId>
+                <artifactId>org.apache.servicemix.kernel.gshell.packages</artifactId>
+                <version>${pom.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.kernel.jaas</groupId>
+                <artifactId>org.apache.servicemix.kernel.jaas.boot</artifactId>
+                <version>${pom.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.kernel.jaas</groupId>
+                <artifactId>org.apache.servicemix.kernel.jaas.config</artifactId>
+                <version>${pom.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.kernel.jaas</groupId>
+                <artifactId>org.apache.servicemix.kernel.jaas.modules</artifactId>
+                <version>${pom.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.kernel.testing</groupId>
+                <artifactId>org.apache.servicemix.kernel.testing.support</artifactId>
+                <version>${pom.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.kernel.testing</groupId>
+                <artifactId>org.apache.servicemix.kernel.testing.itests</artifactId>
+                <version>${pom.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.kernel.demos</groupId>
+                <artifactId>smx4web</artifactId>
+                <version>${pom.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.kernel</groupId>
+                <artifactId>apache-servicemix-kernel</artifactId>
+                <version>${pom.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.kernel</groupId>
+                <artifactId>apache-servicemix-kernel</artifactId>
+                <type>zip</type>
+                <version>${pom.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>org.apache.felix.framework</artifactId>
+                <version>${felix.framework.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>org.apache.felix</groupId>
+                        <artifactId>org.osgi.compendium</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>org.osgi.compendium</artifactId>
+                <version>${felix.compendium.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>org.apache.felix</groupId>
+                        <artifactId>org.osgi.foundation</artifactId>
+                    </exclusion>
+                    <exclusion>
+                        <groupId>org.apache.felix</groupId>
+                        <artifactId>javax.servlet</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>org.osgi.core</artifactId>
+                <version>${felix.osgi.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>org.apache.felix.configadmin</artifactId>
+                <version>${felix.configadmin.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>org.apache.felix.prefs</artifactId>
+                <version>${felix.prefs.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>org.apache.felix.bundlerepository</artifactId>
+                <version>${felix.bundlerepository.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>org.apache.felix</groupId>
+                        <artifactId>org.osgi.service.obr</artifactId>
+                    </exclusion>
+                    <exclusion>
+                        <groupId>org.apache.felix</groupId>
+                        <artifactId>org.apache.felix.shell</artifactId>
+                    </exclusion>
+                    <exclusion>
+                        <groupId>net.sf.kxml</groupId>
+                        <artifactId>kxml2</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <dependency>
+                <groupId>org.springframework</groupId>
+                <artifactId>spring-aop</artifactId>
+                <version>${spring.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.springframework</groupId>
+                <artifactId>spring-beans</artifactId>
+                <version>${spring.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.springframework</groupId>
+                <artifactId>spring-core</artifactId>
+                <version>${spring.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.springframework</groupId>
+                <artifactId>spring-context</artifactId>
+                <version>${spring.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.springframework</groupId>
+                <artifactId>spring-test</artifactId>
+                <version>${spring.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.springframework.osgi</groupId>
+                <artifactId>spring-osgi-core</artifactId>
+                <version>${spring.osgi.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.springframework.osgi</groupId>
+                <artifactId>spring-osgi-io</artifactId>
+                <version>${spring.osgi.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.springframework.osgi</groupId>
+                <artifactId>spring-osgi-extender</artifactId>
+                <version>${spring.osgi.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.springframework.osgi</groupId>
+                <artifactId>spring-osgi-test</artifactId>
+                <version>${spring.osgi.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>org.springframework.osgi</groupId>
+                        <artifactId>asm.osgi</artifactId>
+                    </exclusion>
+                    <exclusion>
+                        <groupId>org.junit</groupId>
+                        <artifactId>com.springsource.junit</artifactId>
+                    </exclusion>
+                    <exclusion>
+                        <groupId>org.objectweb.asm</groupId>
+                        <artifactId>com.springsource.org.objectweb.asm</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <dependency>
+                <groupId>org.springframework.osgi</groupId>
+                <artifactId>spring-osgi-extender</artifactId>
+                <version>${spring.osgi.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.springframework.osgi</groupId>
+                <artifactId>spring-osgi-annotation</artifactId>
+                <version>${spring.osgi.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.mina</groupId>
+                <artifactId>mina-core</artifactId>
+                <version>${mina.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.bundles</groupId>
+                <artifactId>org.apache.servicemix.bundles.oro</artifactId>
+                <version>${oro.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.bundles</groupId>
+                <artifactId>org.apache.servicemix.bundles.aopalliance</artifactId>
+                <version>${aopalliance.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.bundles</groupId>
+                <artifactId>org.apache.servicemix.bundles.asm</artifactId>
+                <version>${asm.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.bundles</groupId>
+                <artifactId>org.apache.servicemix.bundles.junit</artifactId>
+                <version>${junit.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.bundles</groupId>
+                <artifactId>org.apache.servicemix.bundles.cglib</artifactId>
+                <version>${cglib.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.bundles</groupId>
+                <artifactId>org.apache.servicemix.bundles.commons-jexl</artifactId>
+                <version>${commons.jexl.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>junit</groupId>
+                        <artifactId>junit</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.bundles</groupId>
+                <artifactId>org.apache.servicemix.bundles.commons-vfs</artifactId>
+                <version>${commons.vfs.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.bundles</groupId>
+                <artifactId>org.apache.servicemix.bundles.commons-codec</artifactId>
+                <version>${commons.codec.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.bundles</groupId>
+                <artifactId>org.apache.servicemix.bundles.commons-httpclient</artifactId>
+                <version>${commons.httpclient.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>log4j</groupId>
+                <artifactId>log4j</artifactId>
+                <version>${log4j.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.bundles</groupId>
+                <artifactId>org.apache.servicemix.bundles.jline</artifactId>
+                <version>${jline.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>junit</groupId>
+                        <artifactId>junit</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <dependency>
+                <groupId>commons-logging</groupId>
+                <artifactId>commons-logging</artifactId>
+                <version>${commons.logging.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.maven.artifact</groupId>
+                <artifactId>maven-artifact</artifactId>
+                <version>3.0-alpha-1</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.bundles</groupId>
+                <artifactId>org.apache.servicemix.bundles.commons-io</artifactId>
+                <version>${commons.io.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.mina</groupId>
+                <artifactId>mina-core</artifactId>
+                <version>${mina.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>net.gleamynode</groupId>
+                        <artifactId>netty2</artifactId>
+                    </exclusion>
+                    <exclusion>
+                        <groupId>com.jcraft</groupId>
+                        <artifactId>jzlib</artifactId>
+                    </exclusion>
+                    <exclusion>
+                        <groupId>log4j</groupId>
+                        <artifactId>log4j</artifactId>
+                    </exclusion>
+                    <exclusion>
+                        <groupId>logkit</groupId>
+                        <artifactId>logkit</artifactId>
+                    </exclusion>
+                    <exclusion>
+                        <groupId>avalon-framework</groupId>
+                        <artifactId>avalon-framework</artifactId>
+                    </exclusion>
+                    <exclusion>
+                        <groupId>javax.servlet</groupId>
+                        <artifactId>servlet-api</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.geronimo.gshell.support</groupId>
+                <artifactId>gshell-terminal</artifactId>
+                <version>${gshell.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>jline</groupId>
+                        <artifactId>jline</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.geronimo.gshell.support</groupId>
+                <artifactId>gshell-spring</artifactId>
+                <version>${gshell.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>org.slf4j</groupId>
+                        <artifactId>jcl-over-slf4j</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.geronimo.gshell.support</groupId>
+                <artifactId>gshell-interpolation</artifactId>
+                <version>${gshell.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>org.slf4j</groupId>
+                        <artifactId>jcl-over-slf4j</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.geronimo.gshell.commands</groupId>
+                <artifactId>gshell-builtin</artifactId>
+                <version>${gshell.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>oro</groupId>
+                        <artifactId>oro</artifactId>
+                    </exclusion>
+                    <exclusion>
+                        <groupId>commons-vfs</groupId>
+                        <artifactId>commons-vfs</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.geronimo.gshell.commands</groupId>
+                <artifactId>gshell-file</artifactId>
+                <version>${gshell.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.geronimo.gshell.commands</groupId>
+                <artifactId>gshell-network</artifactId>
+                <version>${gshell.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.geronimo.gshell.commands</groupId>
+                <artifactId>gshell-shell</artifactId>
+                <version>${gshell.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.geronimo.gshell.commands</groupId>
+                <artifactId>gshell-ssh</artifactId>
+                <version>${gshell.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>org.apache.geronimo.gshell.support</groupId>
+                        <artifactId>gshell-security</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.geronimo.gshell.commands</groupId>
+                <artifactId>gshell-text</artifactId>
+                <version>${gshell.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.geronimo.gshell.wisdom</groupId>
+                <artifactId>gshell-wisdom-core</artifactId>
+                <version>${gshell.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>org.apache.geronimo.gshell.support</groupId>
+                        <artifactId>gshell-ivy</artifactId>
+                    </exclusion>
+                    <exclusion>
+                        <groupId>org.apache.geronimo.gshell.support</groupId>
+                        <artifactId>gshell-xstore</artifactId>
+                    </exclusion>
+                    <exclusion>
+                        <groupId>commons-jexl</groupId>
+                        <artifactId>commons-jexl</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <dependency>
+                <groupId>org.codehaus.plexus</groupId>
+                <artifactId>plexus-component-api</artifactId>
+                <version>1.0-alpha-32</version>
+            </dependency>
+            <dependency>
+                <groupId>org.codehaus.plexus</groupId>
+                <artifactId>plexus-utils</artifactId>
+                <version>1.5.5</version>
+            </dependency>
+            <dependency>
+                <groupId>org.slf4j</groupId>
+                <artifactId>slf4j-api</artifactId>
+                <version>1.4.3</version>
+            </dependency>
+            <dependency>
+                <groupId>org.slf4j</groupId>
+                <artifactId>slf4j-jdk14</artifactId>
+                <version>1.4.3</version>
+            </dependency>
+            <dependency>
+                <groupId>org.slf4j</groupId>
+                <artifactId>slf4j-nop</artifactId>
+                <version>1.4.3</version>
+            </dependency>
+            <dependency>
+                <groupId>com.thoughtworks.xstream</groupId>
+                <artifactId>xstream</artifactId>
+                <version>1.3</version>
+                <exclusions>
+                    <exclusion>
+                    <!-- xom is an optional dependency of xstream. Its also 
+                         LGPL, so its really not ASF compatible. -->
+                        <groupId>xom</groupId>
+                        <artifactId>xom</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <dependency>
+                <groupId>org.ops4j.pax.logging</groupId>
+                <artifactId>pax-logging-api</artifactId>
+                <version>${pax.logging.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.ops4j.pax.logging</groupId>
+                <artifactId>pax-logging-service</artifactId>
+                <version>${pax.logging.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>log4j</groupId>
+                        <artifactId>log4j</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <dependency>
+                <groupId>org.ops4j.pax.url</groupId>
+                <artifactId>pax-url-mvn</artifactId>
+                <version>${pax.url.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.ops4j.pax.url</groupId>
+                <artifactId>pax-url-wrap</artifactId>
+                <version>${pax.url.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.geronimo.specs</groupId>
+                <artifactId>geronimo-servlet_2.5_spec</artifactId>
+                <version>${geronimo.servlet.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.geronimo.specs</groupId>
+                <artifactId>geronimo-annotation_1.0_spec</artifactId>
+                <version>${geronimo.annotation.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.specs</groupId>
+                <artifactId>org.apache.servicemix.specs.jaxp-api-1.4</artifactId>
+                <version>${servicemix.specs.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.bundles</groupId>
+                <artifactId>org.apache.servicemix.bundles.jaxp-ri</artifactId>
+                <version>${jaxp.ri.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.servicemix.bundles</groupId>
+                <artifactId>org.apache.servicemix.bundles.woodstox</artifactId>
+                <version>${woodstox.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.easymock</groupId>
+                <artifactId>easymock</artifactId>
+                <version>${easymock.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.sshd</groupId>
+                <artifactId>sshd-core</artifactId>
+                <version>${sshd.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>org.apache.mina</groupId>
+                        <artifactId>mina-core</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <dependency>
+                <groupId>org.osgi</groupId>
+                <artifactId>jmx</artifactId>
+                <version>${osgi.jmx.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>org.osgi</groupId>
+                        <artifactId>osgi_R4_core</artifactId>
+                    </exclusion>
+                    <exclusion>
+                        <groupId>org.osgi</groupId>
+                        <artifactId>osgi_R4_compendium</artifactId>
+                    </exclusion>
+                    <exclusion>
+                        <groupId>org.slf4j</groupId>
+                        <artifactId>jcl104-over-slf4j</artifactId>
+                    </exclusion>
+                    <exclusion>
+                        <groupId>org.easymock</groupId>
+                        <artifactId>easymock</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <dependency>
+                <groupId>com.oracle.osgi</groupId>
+                <artifactId>jmx-impl</artifactId>
+                <version>${osgi.jmx.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>org.osgi</groupId>
+                        <artifactId>osgi_R4_core</artifactId>
+                    </exclusion>
+                    <exclusion>
+                        <groupId>org.osgi</groupId>
+                        <artifactId>osgi_R4_compendium</artifactId>
+                    </exclusion>
+                    <exclusion>
+                        <groupId>org.slf4j</groupId>
+                        <artifactId>jcl104-over-slf4j</artifactId>
+                    </exclusion>
+                    <exclusion>
+                        <groupId>org.easymock</groupId>
+                        <artifactId>easymock</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <build>
+        <defaultGoal>install</defaultGoal>
+
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-eclipse-plugin</artifactId>
+                    <version>2.4</version>
+                    <configuration>
+                        <outputDirectory>${basedir}/eclipse-classes</outputDirectory>
+                        <downloadSources>true</downloadSources>
+                        <downloadJavadocs>true</downloadJavadocs>
+                    </configuration>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-release-plugin</artifactId>
+                    <version>2.0-beta-7</version>
+                    <configuration>
+                        <useReleaseProfile>false</useReleaseProfile>
+                        <preparationGoals>clean verify install</preparationGoals>
+                        <goals>deploy</goals>
+                        <arguments>-Prelease,deploy</arguments>
+                        <autoVersionSubmodules>true</autoVersionSubmodules>
+                    </configuration>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.felix</groupId>
+                    <artifactId>maven-bundle-plugin</artifactId>
+                    <version>${felix.plugin.version}</version>
+                    <extensions>true</extensions>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-compiler-plugin</artifactId>
+                    <version>2.0.2</version>
+                    <configuration>
+                        <source>1.5</source>
+                        <target>1.5</target>
+                        <maxmem>256M</maxmem>
+                        <fork>${compiler.fork}</fork>
+                    </configuration>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-idea-plugin</artifactId>
+                    <version>2.1</version>
+                    <configuration>
+                        <downloadSources>true</downloadSources>
+                        <downloadJavadocs>true</downloadJavadocs>
+                    </configuration>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-surefire-plugin</artifactId>
+                    <version>2.3.1</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-shade-plugin</artifactId>
+                    <version>1.2</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-resources-plugin</artifactId>
+                    <version>2.3</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.servicemix.tooling</groupId>
+                    <artifactId>depends-maven-plugin</artifactId>
+                    <version>${depends.maven.plugin.version}</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-source-plugin</artifactId>
+                    <version>2.0.4</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-assembly-plugin</artifactId>
+                    <version>2.2-beta-3</version>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <version>2.0</version>
+                <executions>
+                    <execution>
+                        <id>copy-legal</id>
+                        <phase>generate-resources</phase>
+                        <goals>
+                            <goal>copy</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>org.apache.servicemix.legal</groupId>
+                                    <artifactId>legal</artifactId>
+                                    <version>${servicemix.legal.version}</version>
+                                    <type>xml</type>
+                                    <outputDirectory>target/legal/</outputDirectory>
+                                </artifactItem>
+                            </artifactItems>
+                            <stripVersion>true</stripVersion>
+                        </configuration>
+                    </execution>
+                </executions>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.apache.servicemix.legal</groupId>
+                        <artifactId>legal</artifactId>
+                        <version>${servicemix.legal.version}</version>
+                        <type>xml</type>
+                    </dependency>
+                </dependencies>
+            </plugin>
+            <plugin>
+                <artifactId>maven-remote-resources-plugin</artifactId>
+                <version>1.0</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>process</goal>
+                        </goals>
+                        <configuration>
+                            <resourceBundles>
+                                <resourceBundle>org.apache:apache-jar-resource-bundle:1.4</resourceBundle>
+                            </resourceBundles>
+                            <supplementalModels>
+                                <supplementalModel>target/legal/legal.xml</supplementalModel>
+                            </supplementalModels>
+                            <properties>
+                                <addLicense>true</addLicense>
+                                <addArtifact>true</addArtifact>
+                                <projectName>Apache ServiceMix</projectName>
+                            </properties>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <reporting>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-javadoc-plugin</artifactId>
+                <version>2.3</version>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jxr-plugin</artifactId>
+                <version>2.0</version>
+            </plugin>
+        </plugins>
+    </reporting>
+
+    <profiles>
+        <profile>
+            <id>fastinstall</id>
+            <properties>
+                <maven.test.skip>true</maven.test.skip>
+            </properties>
+        </profile>
+        <profile>
+            <id>rat</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>rat-maven-plugin</artifactId>
+                        <version>1.0-alpha-3</version>
+                        <executions>
+                            <execution>
+                                <phase>verify</phase>
+                                <goals>
+                                    <goal>check</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                        <configuration>
+                            <reportFile>${project.build.directory}/${project.build.finalName}.rat</reportFile>
+                            <excludes>
+                                <exclude>**/target/**/*</exclude>
+                                <!-- IDEA files -->
+                                <exclude>**/*.iml</exclude>
+                                <exclude>**/*.ipr</exclude>
+                                <exclude>**/*.iws</exclude>
+                                <!-- Eclipse files -->
+                                <exclude>**/.*</exclude>
+                                <exclude>**/eclipse-classes/**/*</exclude>
+                                <exclude>**/dependency-reduced-pom.xml</exclude>
+                            </excludes>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>release</id>
+            <build>
+                <plugins>
+                    <!-- We want to deploy the artifact to a staging location for perusal -->
+                    <plugin>
+                        <inherited>true</inherited>
+                        <artifactId>maven-deploy-plugin</artifactId>
+                        <version>2.3</version>
+                        <configuration>
+                            <altDeploymentRepository>${deploy.altRepository}</altDeploymentRepository>
+                            <updateReleaseInfo>true</updateReleaseInfo>
+                        </configuration>
+                    </plugin>
+                    <!-- We want to sign the artifact, the POM, and all attached artifacts -->
+                    <plugin>
+                        <artifactId>maven-gpg-plugin</artifactId>
+                        <version>1.0-alpha-4</version>
+                        <executions>
+                            <execution>
+                                <goals>
+                                    <goal>sign</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>setup.eclipse</id>
+            <modules>
+                <module>assembly</module>
+            </modules>
+            <properties>
+                <eclipse.workspace.dir>${basedir}/../workspace</eclipse.workspace.dir>
+            </properties>
+            <build>
+                <defaultGoal>eclipse:eclipse</defaultGoal>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-eclipse-plugin</artifactId>
+                        <inherited>false</inherited>
+                        <executions>
+                            <execution>
+                                <id>setup.eclipse.workspace</id>
+                                <phase>process-test-sources</phase>
+                                <goals>
+                                    <goal>add-maven-repo</goal>
+                                </goals>
+                                <configuration>
+                                    <workspace>${eclipse.workspace.dir}</workspace>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>deploy</id>
+            <properties>
+                <createSourcesJar>true</createSourcesJar>
+            </properties>
+            <build>
+                <defaultGoal>deploy</defaultGoal>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-source-plugin</artifactId>
+                        <version>2.0.4</version>
+                        <executions>
+                            <execution>
+                                <id>attach-sources</id>
+                                <goals>
+                                    <goal>jar</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-javadoc-plugin</artifactId>
+                        <version>2.4</version>
+                        <configuration>
+                            <source>1.5</source>
+                        </configuration>
+                        <executions>
+                            <execution>
+                                <id>attach-javadocs</id>
+                                <goals>
+                                    <goal>jar</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+
+</project>
diff --git a/karaf/spring/pom.xml b/karaf/spring/pom.xml
new file mode 100644
index 0000000..6eb7b2b
--- /dev/null
+++ b/karaf/spring/pom.xml
@@ -0,0 +1,74 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <!--
+
+        Licensed to the Apache Software Foundation (ASF) under one or more
+        contributor license agreements.  See the NOTICE file distributed with
+        this work for additional information regarding copyright ownership.
+        The ASF licenses this file to You under the Apache License, Version 2.0
+        (the "License"); you may not use this file except in compliance with
+        the License.  You may obtain a copy of the License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software
+        distributed under the License is distributed on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        See the License for the specific language governing permissions and
+        limitations under the License.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.servicemix.kernel</groupId>
+        <artifactId>kernel</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.servicemix.kernel</groupId>
+    <artifactId>org.apache.servicemix.kernel.spring</artifactId>
+    <packaging>bundle</packaging>
+    <version>1.2.0-SNAPSHOT</version>
+    <name>Apache ServiceMix Kernel :: Spring Deployer</name>
+
+    <description>This deployer transforms a plain spring xml file to a deployable bundle</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.osgi</groupId>
+            <artifactId>spring-osgi-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel</groupId>
+            <artifactId>org.apache.servicemix.kernel.filemonitor</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.junit</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName>
+                        <Private-Package>org.apache.servicemix.kernel.spring</Private-Package>
+                        <Spring-Context>*;publish-context:=false;create-asynchronously:=false</Spring-Context>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
\ No newline at end of file
diff --git a/karaf/spring/src/main/java/org/apache/servicemix/kernel/spring/SpringDeploymentListener.java b/karaf/spring/src/main/java/org/apache/servicemix/kernel/spring/SpringDeploymentListener.java
new file mode 100644
index 0000000..ce0c1e0
--- /dev/null
+++ b/karaf/spring/src/main/java/org/apache/servicemix/kernel/spring/SpringDeploymentListener.java
@@ -0,0 +1,81 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.spring;
+
+import java.io.File;
+import java.io.FileOutputStream;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.w3c.dom.Document;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.servicemix.kernel.filemonitor.DeploymentListener;
+
+/**
+ * A deployment listener that listens for spring xml applications
+ * and creates bundles for these.
+ */
+public class SpringDeploymentListener implements DeploymentListener {
+
+
+    private static final Log LOGGER = LogFactory.getLog(SpringDeploymentListener.class);
+
+    private DocumentBuilderFactory dbf;
+
+    public boolean canHandle(File artifact) {
+        try {
+            if (artifact.isFile() && artifact.getName().endsWith(".xml")) {
+                Document doc = parse(artifact);
+                String name = doc.getDocumentElement().getLocalName();
+                String uri  = doc.getDocumentElement().getNamespaceURI();
+                if ("beans".equals(name) && "http://www.springframework.org/schema/beans".equals(uri)) {
+                    return true;
+                }
+            }
+        } catch (Exception e) {
+            LOGGER.error("Unable to parse deployed file " + artifact.getAbsolutePath(), e);
+        }
+        return false;
+    }
+
+    public File handle(File artifact, File tmpDir) {
+        try {
+            File destFile = new File(tmpDir, artifact.getName() + ".jar");
+            FileOutputStream os = new FileOutputStream(destFile);
+            SpringTransformer.transform(artifact.toURL(), os);
+            os.close();
+            return destFile;
+        } catch (Exception e) {
+            LOGGER.error("Unable to build spring application bundle", e);
+            return null;
+        }
+    }
+
+    protected Document parse(File artifact) throws Exception {
+        if (dbf == null) {
+            dbf = DocumentBuilderFactory.newInstance();
+            dbf.setNamespaceAware(true);
+        }
+        DocumentBuilder db = dbf.newDocumentBuilder();
+        return db.parse(artifact);
+    }
+
+}
diff --git a/karaf/spring/src/main/java/org/apache/servicemix/kernel/spring/SpringTransformer.java b/karaf/spring/src/main/java/org/apache/servicemix/kernel/spring/SpringTransformer.java
new file mode 100644
index 0000000..982fbc9
--- /dev/null
+++ b/karaf/spring/src/main/java/org/apache/servicemix/kernel/spring/SpringTransformer.java
@@ -0,0 +1,249 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.spring;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.zip.ZipEntry;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import org.osgi.framework.Constants;
+
+public class SpringTransformer {
+
+    static Transformer transformer;
+    static DocumentBuilderFactory dbf;
+    static TransformerFactory tf;
+
+
+    public static void transform(URL url, OutputStream os) throws Exception {
+        // Build dom document
+        Document doc = parse(url);
+        // Heuristicly retrieve name and version
+        String name = url.getPath();
+        int idx = name.lastIndexOf('/');
+        if (idx >= 0) {
+            name = name.substring(idx + 1);
+        }
+        String[] str = extractNameVersionType(name);
+        // Create manifest
+        Manifest m = new Manifest();
+        m.getMainAttributes().putValue("Manifest-Version", "2");
+        m.getMainAttributes().putValue(Constants.BUNDLE_MANIFESTVERSION, "2");
+        m.getMainAttributes().putValue(Constants.BUNDLE_SYMBOLICNAME, str[0]);
+        m.getMainAttributes().putValue(Constants.BUNDLE_VERSION, str[1]);
+        m.getMainAttributes().putValue("Spring-Context", "*;publish-context:=false;create-asynchronously:=true");
+        String importPkgs = getImportPackages(analyze(new DOMSource(doc)));
+        if (importPkgs != null && importPkgs.length() > 0) {
+            m.getMainAttributes().putValue(Constants.IMPORT_PACKAGE, importPkgs);
+        }
+        m.getMainAttributes().putValue(Constants.DYNAMICIMPORT_PACKAGE, "*");
+        // Extract manifest entries from the DOM
+        NodeList l = doc.getElementsByTagName("manifest");
+        if (l != null) {
+            for (int i = 0; i < l.getLength(); i++) {
+                Element e = (Element) l.item(i);
+                String text = e.getTextContent();
+                Properties props = new Properties();
+                props.load(new ByteArrayInputStream(text.trim().getBytes()));
+                Enumeration en = props.propertyNames();
+                while (en.hasMoreElements()) {
+                    String k = (String) en.nextElement();
+                    String v = props.getProperty(k);
+                    m.getMainAttributes().putValue(k, v);
+                }
+                e.getParentNode().removeChild(e);
+            }
+        }
+
+        JarOutputStream out = new JarOutputStream(os);
+        ZipEntry e = new ZipEntry(JarFile.MANIFEST_NAME);
+        out.putNextEntry(e);
+        m.write(out);
+        out.closeEntry();
+        e = new ZipEntry("META-INF/");
+        out.putNextEntry(e);
+        e = new ZipEntry("META-INF/spring/");
+        out.putNextEntry(e);
+        out.closeEntry();
+        e = new ZipEntry("META-INF/spring/" + name);
+        out.putNextEntry(e);
+        // Copy the new DOM
+        if (tf == null) {
+            tf = TransformerFactory.newInstance();
+        }
+        tf.newTransformer().transform(new DOMSource(doc), new StreamResult(out));
+        out.closeEntry();
+        out.close();
+    }
+
+    private static final String DEFAULT_VERSION = "0.0.0";
+
+    private static final Pattern ARTIFACT_MATCHER = Pattern.compile("(.+)(?:-(\\d+)(?:\\.(\\d+)(?:\\.(\\d+))?)?(?:[^a-zA-Z0-9](.*))?)(?:\\.([^\\.]+))", Pattern.DOTALL);
+    private static final Pattern FUZZY_MODIFIDER = Pattern.compile("(?:\\d+[.-])*(.*)", Pattern.DOTALL);
+
+    public static String[] extractNameVersionType(String url) {
+        Matcher m = ARTIFACT_MATCHER.matcher(url);
+        if (!m.matches()) {
+            return new String[] { url, DEFAULT_VERSION };
+        }
+        else {
+            //System.err.println(m.groupCount());
+            //for (int i = 1; i <= m.groupCount(); i++) {
+            //    System.err.println("Group " + i + ": " + m.group(i));
+            //}
+
+            StringBuffer v = new StringBuffer();
+            String d1 = m.group(1);
+            String d2 = m.group(2);
+            String d3 = m.group(3);
+            String d4 = m.group(4);
+            String d5 = m.group(5);
+            String d6 = m.group(6);
+            if (d2 != null) {
+                v.append(d2);
+                if (d3 != null) {
+                    v.append('.');
+                    v.append(d3);
+                    if (d4 != null) {
+                        v.append('.');
+                        v.append(d4);
+                        if (d5 != null) {
+                            v.append(".");
+                            cleanupModifier(v, d5);
+                        }
+                    } else if (d5 != null) {
+                        v.append(".0.");
+                        cleanupModifier(v, d5);
+                    }
+                } else if (d5 != null) {
+                    v.append(".0.0.");
+                    cleanupModifier(v, d5);
+                }
+            }
+            return new String[] { d1, v.toString(), d6 };
+        }
+    }
+
+    private static void cleanupModifier(StringBuffer result, String modifier) {
+        Matcher m = FUZZY_MODIFIDER.matcher(modifier);
+        if (m.matches()) {
+            modifier = m.group(1);
+        }
+        for (int i = 0; i < modifier.length(); i++) {
+            char c = modifier.charAt(i);
+            if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c == '-') {
+                result.append(c);
+            }
+        }
+    }
+
+    public static Set<String> analyze(Source source) throws Exception {
+        if (transformer == null) {
+            if (tf == null) {
+                tf = TransformerFactory.newInstance();
+            }
+            Source s = new StreamSource(SpringTransformer.class.getResourceAsStream("extract.xsl"));
+            transformer = tf.newTransformer(s);
+        }
+
+        Set<String> refers = new TreeSet<String>();
+
+        ByteArrayOutputStream bout = new ByteArrayOutputStream();
+        Result r = new StreamResult(bout);
+        transformer.transform(source, r);
+
+        ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
+        bout.close();
+
+        BufferedReader br = new BufferedReader(new InputStreamReader(bin));
+
+        String line = br.readLine();
+        while (line != null) {
+            line = line.trim();
+            if (line.length() > 0) {
+                String parts[] = line.split("\\s*,\\s*");
+                for (int i = 0; i < parts.length; i++) {
+                    int n = parts[i].lastIndexOf('.');
+                    if (n > 0) {
+                        refers.add(parts[i].substring(0, n));
+                    }
+                }
+            }
+            line = br.readLine();
+        }
+        br.close();
+        return refers;
+    }
+
+    protected static String getImportPackages(Set<String> packages) {
+        StringBuilder sb = new StringBuilder();
+        for (String pkg : packages) {
+            if (sb.length() > 0) {
+                sb.append(",");
+            }
+            sb.append(pkg);
+        }
+        return sb.toString();
+    }
+
+    protected static Document parse(URL url) throws Exception {
+        if (dbf == null) {
+            dbf = DocumentBuilderFactory.newInstance();
+            dbf.setNamespaceAware(true);
+        }
+        DocumentBuilder db = dbf.newDocumentBuilder();
+        return db.parse(url.toString());
+    }
+
+    protected static void copyInputStream(InputStream in, OutputStream out) throws Exception {
+        byte[] buffer = new byte[4096];
+        int len = in.read(buffer);
+        while (len >= 0) {
+            out.write(buffer, 0, len);
+            len = in.read(buffer);
+        }
+    }
+}
diff --git a/karaf/spring/src/main/java/org/apache/servicemix/kernel/spring/SpringURLHandler.java b/karaf/spring/src/main/java/org/apache/servicemix/kernel/spring/SpringURLHandler.java
new file mode 100644
index 0000000..e9fedaf
--- /dev/null
+++ b/karaf/spring/src/main/java/org/apache/servicemix/kernel/spring/SpringURLHandler.java
@@ -0,0 +1,97 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.spring;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.osgi.service.url.AbstractURLStreamHandlerService;
+
+/**
+ * A URL handler that will transform a JBI artifact to an OSGi bundle
+ * on the fly.  Needs to be registered in the OSGi registry.
+ */
+public class SpringURLHandler extends AbstractURLStreamHandlerService {
+
+	private static Log logger = LogFactory.getLog(SpringURLHandler.class);
+
+	private static String SYNTAX = "spring: spring-xml-uri";
+
+	private URL springXmlURL;
+
+    /**
+     * Open the connection for the given URL.
+     *
+     * @param url the url from which to open a connection.
+     * @return a connection on the specified URL.
+     * @throws IOException if an error occurs or if the URL is malformed.
+     */
+    @Override
+	public URLConnection openConnection(URL url) throws IOException {
+		if (url.getPath() == null || url.getPath().trim().length() == 0) {
+			throw new MalformedURLException ("Path can not be null or empty. Syntax: " + SYNTAX );
+		}
+		springXmlURL = new URL(url.getPath());
+
+		logger.debug("Spring xml URL is: [" + springXmlURL + "]");
+		return new Connection(url);
+	}
+	
+	public URL getSpringXmlURL() {
+		return springXmlURL;
+	}
+
+    public class Connection extends URLConnection {
+
+        public Connection(URL url) {
+            super(url);
+        }
+
+        @Override
+        public void connect() throws IOException {
+        }
+
+        @Override
+        public InputStream getInputStream() throws IOException {
+            try {
+                final File f = File.createTempFile("smx", "xml");
+                FileOutputStream os = new FileOutputStream(f);
+                SpringTransformer.transform(springXmlURL, os);
+                os.close();
+                return new FileInputStream(f) {
+                    public void close() throws IOException {
+                        super.close();
+                        f.delete();
+                    }
+                };
+            } catch (Exception e) {
+                logger.error("Error opening spring xml url", e);
+                throw (IOException) new IOException("Error opening spring xml url").initCause(e);
+            }
+        }
+    }
+
+}
diff --git a/karaf/spring/src/main/resources/META-INF/spring/spring-deployer.xml b/karaf/spring/src/main/resources/META-INF/spring/spring-deployer.xml
new file mode 100644
index 0000000..779c2af
--- /dev/null
+++ b/karaf/spring/src/main/resources/META-INF/spring/spring-deployer.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<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/beans
+  http://www.springframework.org/schema/beans/spring-beans.xsd
+  http://www.springframework.org/schema/util
+  http://www.springframework.org/schema/util/spring-util.xsd
+  http://www.springframework.org/schema/osgi
+  http://www.springframework.org/schema/osgi/spring-osgi.xsd">
+
+    <bean id="springDeploymentListener" class="org.apache.servicemix.kernel.spring.SpringDeploymentListener">
+
+    </bean>
+
+    <osgi:service ref="springDeploymentListener">
+        <osgi:interfaces>
+            <value>org.apache.servicemix.kernel.filemonitor.DeploymentListener</value>
+        </osgi:interfaces>
+    </osgi:service>
+
+    <bean id="springHandler" class="org.apache.servicemix.kernel.spring.SpringURLHandler" />
+
+    <osgi:service ref="springHandler" interface="org.osgi.service.url.URLStreamHandlerService">
+    	<osgi:service-properties>
+            <entry key="url.handler.protocol" value="spring"/>
+        </osgi:service-properties>
+    </osgi:service>
+
+</beans>
\ No newline at end of file
diff --git a/karaf/spring/src/main/resources/org/apache/servicemix/kernel/spring/extract.xsl b/karaf/spring/src/main/resources/org/apache/servicemix/kernel/spring/extract.xsl
new file mode 100644
index 0000000..4b06b69
--- /dev/null
+++ b/karaf/spring/src/main/resources/org/apache/servicemix/kernel/spring/extract.xsl
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<xsl:stylesheet version="1.0"
+                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:beans="http://www.springframework.org/schema/beans"
+                xmlns:aop="http://www.springframework.org/schema/aop"
+                xmlns:context="http://www.springframework.org/schema/context"
+                xmlns:jee="http://www.springframework.org/schema/jee"
+                xmlns:jms="http://www.springframework.org/schema/jms"
+                xmlns:lang="http://www.springframework.org/schema/lang"
+                xmlns:osgi-compendium="http://www.springframework.org/schema/osgi-compendium"
+                xmlns:osgi="http://www.springframework.org/schema/osgi"
+                xmlns:tool="http://www.springframework.org/schema/tool"
+                xmlns:tx="http://www.springframework.org/schema/tx"
+                xmlns:util="http://www.springframework.org/schema/util"
+                xmlns:webflow-config="http://www.springframework.org/schema/webflow-config">
+    
+    <xsl:output method="text" />
+
+	<xsl:template match="/">
+
+		<!-- Match all attributes that holds a class or a comma delimited
+		     list of classes and print them -->
+
+		<xsl:for-each select="
+				//beans:bean/@class
+			|	//beans:*/@value-type
+ 			|	//aop:*/@implement-interface
+			|	//aop:*/@default-impl
+			|	//context:load-time-weaver/@weaver-class
+			|	//jee:jndi-lookup/@expected-type
+			|	//jee:jndi-lookup/@proxy-interface
+			| 	//jee:remote-slsb/@ejbType
+			|	//jee:*/@business-interface
+			|	//lang:*/@script-interfaces
+			|	//osgi:*/@interface
+			|	//util:list/@list-class
+			|	//util:set/@set-class
+			|	//util:map/@map-class
+			|	//webflow-config:*/@class
+		">
+			<xsl:value-of select="." />
+			<xsl:text>
+			</xsl:text>
+		</xsl:for-each>
+
+		<!-- This seems some magic to get extra imports? -->
+
+		<xsl:for-each select="//beans:bean[@class='org.springframework.osgi.service.exporter.support.OsgiServiceFactoryBean'
+				or @class='org.springframework.osgi.service.importer.support.OsgiServiceProxyFactoryBean']">
+			<xsl:for-each select="beans:property[@name='interfaces']">
+				<xsl:value-of select="@value" />
+				<xsl:text>
+				</xsl:text>
+			</xsl:for-each>
+		</xsl:for-each>
+
+	</xsl:template>
+
+
+</xsl:stylesheet>
+
diff --git a/karaf/spring/src/test/java/org/apache/servicemix/kernel/spring/SpringDeploymentListenerTest.java b/karaf/spring/src/test/java/org/apache/servicemix/kernel/spring/SpringDeploymentListenerTest.java
new file mode 100644
index 0000000..38a37bb
--- /dev/null
+++ b/karaf/spring/src/test/java/org/apache/servicemix/kernel/spring/SpringDeploymentListenerTest.java
@@ -0,0 +1,84 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.spring;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.jar.JarInputStream;
+
+import javax.xml.transform.dom.DOMSource;
+
+import junit.framework.TestCase;
+
+public class SpringDeploymentListenerTest extends TestCase {
+
+    public void testPackagesExtraction() throws Exception {
+        SpringDeploymentListener l = new SpringDeploymentListener();
+        File f = new File(getClass().getClassLoader().getResource("META-INF/spring/spring-deployer.xml").toURI());
+        Set<String> pkgs = SpringTransformer.analyze(new DOMSource(SpringTransformer.parse(f.toURL())));
+        assertNotNull(pkgs);
+        assertEquals(2, pkgs.size());
+        Iterator<String> it = pkgs.iterator();
+        assertEquals("org.apache.servicemix.kernel.spring", it.next());
+        assertEquals("org.osgi.service.url", it.next());
+    }
+
+    public void testCustomManifest() throws Exception {
+        File f = File.createTempFile("smx", ".jar");
+        try {
+            OutputStream os = new FileOutputStream(f);
+            SpringTransformer.transform(getClass().getClassLoader().getResource("test.xml"), os);
+            os.close();
+            InputStream is = new FileInputStream(f);
+            JarInputStream jar = new JarInputStream(is);
+            jar.getManifest().write(System.err);
+            is.close();
+        } finally {
+            f.delete();
+        }
+    }
+
+    public void testVersions() {
+        assertVersion("org.apache.servicemix.bundles.ant-1.7.0-1.0-m3-SNAPSHOT.jar",
+                      "org.apache.servicemix.bundles.ant-1.7.0", "1.0.0.m3-SNAPSHOT", "jar");
+        assertVersion("org.apache.activemq.core-1.0-SNAPSHOT.xml",
+                      "org.apache.activemq.core", "1.0.0.SNAPSHOT", "xml");
+        assertVersion("org.apache.activemq.core-1.0.0-SNAPSHOT.xml",
+                      "org.apache.activemq.core", "1.0.0.SNAPSHOT", "xml");
+        assertVersion("org.apache.activemq.core-1.0.0.xml",
+                      "org.apache.activemq.core", "1.0.0", "xml");
+        assertVersion("geronimo-servlet_2.5_spec-1.1.2.jar",
+                      "geronimo-servlet_2.5_spec", "1.1.2", "jar");
+        assertVersion("spring-aop-2.5.1.jar",
+                      "spring-aop", "2.5.1", "jar");
+    }
+
+    private void assertVersion(String s, String... expectedParts) {
+        String[] parts = SpringTransformer.extractNameVersionType(s);
+        assertEquals(expectedParts.length, parts.length);
+        for (int i = 0; i < expectedParts.length; i++) {
+            assertEquals(expectedParts[i], parts[i]);
+        }
+    }
+
+}
diff --git a/karaf/spring/src/test/resources/test.xml b/karaf/spring/src/test/resources/test.xml
new file mode 100644
index 0000000..7976cbb
--- /dev/null
+++ b/karaf/spring/src/test/resources/test.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<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/beans
+  http://www.springframework.org/schema/beans/spring-beans.xsd
+  http://www.springframework.org/schema/util
+  http://www.springframework.org/schema/util/spring-util.xsd
+  http://www.springframework.org/schema/osgi
+  http://www.springframework.org/schema/osgi/spring-osgi.xsd">
+
+    <manifest>
+        RequireBundle=org.osgi
+        Header=value
+    </manifest>
+
+    <bean id="springDeploymentListener" class="org.apache.servicemix.kernel.spring.SpringDeploymentListener">
+
+    </bean>
+
+    <osgi:service ref="springDeploymentListener">
+        <osgi:interfaces>
+            <value>org.apache.servicemix.kernel.filemonitor.DeploymentListener</value>
+        </osgi:interfaces>
+    </osgi:service>
+
+    <bean id="springHandler" class="org.apache.servicemix.kernel.spring.SpringURLHandler" />
+
+    <osgi:service ref="springHandler" interface="org.osgi.service.url.URLStreamHandlerService">
+    	<osgi:service-properties>
+            <entry key="url.handler.protocol" value="spring"/>
+        </osgi:service-properties>
+    </osgi:service>
+
+</beans>
\ No newline at end of file
diff --git a/karaf/testing/itests/pom.xml b/karaf/testing/itests/pom.xml
new file mode 100644
index 0000000..8442902
--- /dev/null
+++ b/karaf/testing/itests/pom.xml
@@ -0,0 +1,77 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <!--
+
+        Licensed to the Apache Software Foundation (ASF) under one or more
+        contributor license agreements.  See the NOTICE file distributed with
+        this work for additional information regarding copyright ownership.
+        The ASF licenses this file to You under the Apache License, Version 2.0
+        (the "License"); you may not use this file except in compliance with
+        the License.  You may obtain a copy of the License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software
+        distributed under the License is distributed on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        See the License for the specific language governing permissions and
+        limitations under the License.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.servicemix.kernel.testing</groupId>
+        <artifactId>testing</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.servicemix.kernel.testing</groupId>
+    <artifactId>org.apache.servicemix.kernel.testing.itests</artifactId>
+    <packaging>jar</packaging>
+    <version>1.2.0-SNAPSHOT</version>
+    <name>Apache ServiceMix Kernel :: Testing - ITests</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel.testing</groupId>
+            <artifactId>org.apache.servicemix.kernel.testing.support</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.specs</groupId>
+            <artifactId>org.apache.servicemix.specs.jaxp-api-1.4</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.woodstox</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.jaxp-ri</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <!-- generate dependencies versions -->
+            <plugin>
+                <groupId>org.apache.servicemix.tooling</groupId>
+                <artifactId>depends-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>generate-depends-file</id>
+                        <goals>
+                            <goal>generate-depends-file</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
\ No newline at end of file
diff --git a/karaf/testing/itests/src/test/java/org/apache/servicemix/kernel/testing/itests/SimpleTest.java b/karaf/testing/itests/src/test/java/org/apache/servicemix/kernel/testing/itests/SimpleTest.java
new file mode 100644
index 0000000..dec38ae
--- /dev/null
+++ b/karaf/testing/itests/src/test/java/org/apache/servicemix/kernel/testing/itests/SimpleTest.java
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.testing.itests;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.validation.SchemaFactory;
+
+import org.apache.servicemix.kernel.testing.support.AbstractIntegrationTest;
+import org.osgi.framework.Bundle;
+
+public class SimpleTest extends AbstractIntegrationTest {
+
+    static {
+        System.setProperty("jaxp.debug", "true");
+        System.setProperty("org.apache.servicemix.specs.debug", "true");
+    }
+
+    /**
+	 * The manifest to use for the "virtual bundle" created
+	 * out of the test classes and resources in this project
+	 *
+	 * This is actually the boilerplate manifest with one additional
+	 * import-package added. We should provide a simpler customization
+	 * point for such use cases that doesn't require duplication
+	 * of the entire manifest...
+	 */
+	protected String getManifestLocation() {                            
+		return "classpath:org/apache/servicemix/MANIFEST.MF";
+	}
+
+	/**
+	 * The location of the packaged OSGi bundles to be installed
+	 * for this test. Values are Spring resource paths. The bundles
+	 * we want to use are part of the same multi-project maven
+	 * build as this project is. Hence we use the localMavenArtifact
+	 * helper method to find the bundles produced by the package
+	 * phase of the maven build (these tests will run after the
+	 * packaging phase, in the integration-test phase).
+	 *
+	 * JUnit, commons-logging, spring-core and the spring OSGi
+	 * test bundle are automatically included so do not need
+	 * to be specified here.
+	 */
+	protected String[] getTestBundlesNames() {
+        return new String[0];
+	}
+
+    /**
+     * Do not include the jaxp-ri bundle by default, as we want to test it
+     * @return
+     */
+    @Override
+    protected String[] getTestFrameworkBundlesNames() {
+        return new String[] {
+            getBundle("org.apache.geronimo.specs", "geronimo-servlet_2.5_spec"),
+            getBundle("org.apache.servicemix.specs", "org.apache.servicemix.specs.jaxp-api-1.4"),
+            getBundle("org.apache.felix", "org.osgi.compendium"),
+            getBundle("org.apache.felix", "org.apache.felix.configadmin"),
+            getBundle("org.ops4j.pax.logging", "pax-logging-api"),
+            getBundle("org.ops4j.pax.logging", "pax-logging-service"),
+            getBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.aopalliance"),
+            getBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.asm"),
+            getBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.junit"),
+            getBundle("org.springframework", "spring-beans"),
+            getBundle("org.springframework", "spring-core"),
+            getBundle("org.springframework", "spring-context"),
+            getBundle("org.springframework", "spring-aop"),
+            getBundle("org.springframework", "spring-test"),
+            getBundle("org.springframework.osgi", "spring-osgi-core"),
+            getBundle("org.springframework.osgi", "spring-osgi-io"),
+            getBundle("org.springframework.osgi", "spring-osgi-extender"),
+            getBundle("org.springframework.osgi", "spring-osgi-test"),
+            getBundle("org.springframework.osgi", "spring-osgi-annotation"),
+            getBundle("org.apache.servicemix.kernel.testing", "org.apache.servicemix.kernel.testing.support"),
+		};
+    }
+
+    public void testDocumentBuilderFactory() throws Exception {
+        try {
+            DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
+            fail("Implementation should not have been found");
+        } catch (Throwable t) {
+        }
+        Bundle b = installBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.jaxp-ri", null, "jar");
+        try {
+		    assertNotNull(DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument());
+        } finally {
+            b.uninstall();
+        }
+    }
+
+    public void testTransformerFactory() throws Exception {
+        try {
+            TransformerFactory.newInstance().newTransformer();
+            fail("Implementation should not have been found");
+        } catch (Throwable t) {
+        }
+        Bundle b = installBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.jaxp-ri", null, "jar");
+        try {
+            assertNotNull(TransformerFactory.newInstance().newTransformer());
+        } finally {
+            b.uninstall();
+        }
+    }
+
+    public void testSchemaFactory() throws Exception {
+        try {
+            SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema").newSchema();
+            fail("Implementation should not have been found");
+        } catch (Throwable t) {
+        }
+        Bundle b = installBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.jaxp-ri", null, "jar");
+        try {
+            assertNotNull(SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema").newSchema());
+        } finally {
+            b.uninstall();
+        }
+    }
+
+    public void testStax() throws Exception {
+        try {
+            XMLInputFactory.newInstance();
+            fail("Implementation should not have been found");
+        } catch (Throwable t) {
+        }
+        Bundle b = installBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.jaxp-ri", null, "jar");
+        try {
+            assertNotNull(XMLInputFactory.newInstance());
+        } finally {
+            b.uninstall();
+        }
+    }
+
+}
diff --git a/karaf/testing/itests/src/test/resources/log4j.properties b/karaf/testing/itests/src/test/resources/log4j.properties
new file mode 100644
index 0000000..7944dfb
--- /dev/null
+++ b/karaf/testing/itests/src/test/resources/log4j.properties
@@ -0,0 +1,43 @@
+# 
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed  under the  License is distributed on an "AS IS" BASIS,
+# WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+# implied.
+#  
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+
+#
+# The logging properties used during tests..
+#
+log4j.rootLogger=DEBUG, stdout
+
+log4j.logger.org.springframework=INFO
+log4j.logger.org.apache.activemq=INFO
+log4j.logger.org.apache.activemq.spring=WARN
+
+
+#log4j.logger.org.apache.servicemix=DEBUG
+
+# CONSOLE appender 
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+
+# File appender
+log4j.appender.out=org.apache.log4j.FileAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+log4j.appender.out.file=target/servicemix-test.log
+log4j.appender.out.append=true
diff --git a/karaf/testing/itests/src/test/resources/org/apache/servicemix/MANIFEST.MF b/karaf/testing/itests/src/test/resources/org/apache/servicemix/MANIFEST.MF
new file mode 100644
index 0000000..f26d98a
--- /dev/null
+++ b/karaf/testing/itests/src/test/resources/org/apache/servicemix/MANIFEST.MF
@@ -0,0 +1,32 @@
+Manifest-Version: 1.0
+License-00: .
+License-01: Licensed to the Apache Software Foundation (ASF) under one or more
+License-02: contributor license agreements.  See the NOTICE file distributed with
+License-03: this work for additional information regarding copyright ownership.
+License-04: The ASF licenses this file to You under the Apache License, Version 2.0
+License-05: (the "License"); you may not use this file except in compliance with
+License-06: the License.  You may obtain a copy of the License at
+License-07: .
+License-08:      http://www.apache.org/licenses/LICENSE-2.0
+License-09: .
+License-10: Unless required by applicable law or agreed to in writing, software
+License-11: distributed under the License is distributed on an "AS IS" BASIS,
+License-12: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+License-13: See the License for the specific language governing permissions and
+License-14: limitations under the License.
+License-15: .
+Bundle-Name: org.apache.servicemix.testing.itests
+Bundle-SymbolicName: org.apache.servicemix.testing.itests
+Bundle-Vendor: Spring Framework
+Bundle-Activator: org.springframework.osgi.test.JUnitTestActivator
+Import-Package: junit.framework,
+ org.osgi.framework;specification-version="1.3.0",
+ org.apache.commons.logging,
+ org.springframework.core.io,
+ org.springframework.osgi.test,
+ org.apache.servicemix.kernel.testing.support,
+ org.springframework.osgi.util,
+ javax.xml.stream,
+ javax.xml.transform,
+ javax.xml.validation,
+ javax.xml.parsers
diff --git a/karaf/testing/pom.xml b/karaf/testing/pom.xml
new file mode 100644
index 0000000..9a62891
--- /dev/null
+++ b/karaf/testing/pom.xml
@@ -0,0 +1,41 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <!--
+
+        Licensed to the Apache Software Foundation (ASF) under one or more
+        contributor license agreements.  See the NOTICE file distributed with
+        this work for additional information regarding copyright ownership.
+        The ASF licenses this file to You under the Apache License, Version 2.0
+        (the "License"); you may not use this file except in compliance with
+        the License.  You may obtain a copy of the License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software
+        distributed under the License is distributed on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        See the License for the specific language governing permissions and
+        limitations under the License.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.servicemix.kernel</groupId>
+        <artifactId>kernel</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.servicemix.kernel.testing</groupId>
+    <artifactId>testing</artifactId>
+    <packaging>pom</packaging>
+    <version>1.2.0-SNAPSHOT</version>
+    <name>Apache ServiceMix Kernel :: Testing</name>
+
+    <modules>
+        <module>support</module>
+        <module>itests</module>
+    </modules>
+
+</project>
diff --git a/karaf/testing/support/pom.xml b/karaf/testing/support/pom.xml
new file mode 100644
index 0000000..7eb620a
--- /dev/null
+++ b/karaf/testing/support/pom.xml
@@ -0,0 +1,149 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <!--
+
+        Licensed to the Apache Software Foundation (ASF) under one or more
+        contributor license agreements.  See the NOTICE file distributed with
+        this work for additional information regarding copyright ownership.
+        The ASF licenses this file to You under the Apache License, Version 2.0
+        (the "License"); you may not use this file except in compliance with
+        the License.  You may obtain a copy of the License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software
+        distributed under the License is distributed on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        See the License for the specific language governing permissions and
+        limitations under the License.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.servicemix.kernel.testing</groupId>
+        <artifactId>testing</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.servicemix.kernel.testing</groupId>
+    <artifactId>org.apache.servicemix.kernel.testing.support</artifactId>
+    <packaging>bundle</packaging>
+    <version>1.2.0-SNAPSHOT</version>
+    <name>Apache ServiceMix Kernel :: Testing - Support</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.servicemix.kernel</groupId>
+            <artifactId>org.apache.servicemix.kernel.main</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.configadmin</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.logging</groupId>
+            <artifactId>pax-logging-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.logging</groupId>
+            <artifactId>pax-logging-service</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.osgi</groupId>
+            <artifactId>spring-osgi-test</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.osgi</groupId>
+            <artifactId>spring-osgi-extender</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.osgi</groupId>
+            <artifactId>spring-osgi-annotation</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.geronimo.specs</groupId>
+            <artifactId>geronimo-servlet_2.5_spec</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.specs</groupId>
+            <artifactId>org.apache.servicemix.specs.jaxp-api-1.4</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.aopalliance</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.asm</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.junit</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.woodstox</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.jaxp-ri</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.url</groupId>
+            <artifactId>pax-url-mvn</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-resources-plugin</artifactId>
+                <executions>
+                    <execution>
+                    <id>copy-resources</id>
+                    <!-- here the phase you need -->
+                    <phase>compile</phase>
+                    <goals>
+                        <goal>copy-resources</goal>
+                    </goals>
+                    <configuration>
+                            <outputDirectory>${basedir}/target/classes/org/apache/servicemix/kernel/testing/support/</outputDirectory>
+                            <resources>          
+                                <resource>
+                                    <directory>../../${config.location}</directory>
+                                        <includes>
+                                            <include>config.properties</include>
+                                        </includes>
+                                </resource>
+                            </resources>              
+                        </configuration>            
+                    </execution>
+                </executions>
+            </plugin>            
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName>
+                        <Import-Package>
+                            org.apache.felix*;resolution:=optional,
+                            org.apache.servicemix.kernel.main;resolution:=optional,
+                            org.apache.servicemix.kernel.main.spi;resolution:=optional;version="1.0.0",
+                            *
+                        </Import-Package>
+                        <Export-Package>${pom.artifactId}</Export-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/AbstractIntegrationTest.java b/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/AbstractIntegrationTest.java
new file mode 100644
index 0000000..14cc73a
--- /dev/null
+++ b/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/AbstractIntegrationTest.java
@@ -0,0 +1,268 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.testing.support;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.log4j.PropertyConfigurator;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.springframework.core.io.FileSystemResource;
+import org.springframework.core.io.Resource;
+import org.springframework.osgi.test.AbstractConfigurableBundleCreatorTests;
+import org.springframework.osgi.test.provisioning.ArtifactLocator;
+import org.springframework.osgi.util.OsgiFilterUtils;
+import org.springframework.osgi.util.OsgiListenerUtils;
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+
+
+public class AbstractIntegrationTest extends AbstractConfigurableBundleCreatorTests {
+
+    static {
+        try {
+            File f = new File("target/smx4");
+            f.mkdirs();
+            System.setProperty("servicemix.name", "root");
+            System.setProperty("servicemix.home", f.getAbsolutePath());
+            System.setProperty("servicemix.base", f.getAbsolutePath());
+            System.setProperty("org.apache.servicemix.filemonitor.configDir", new File(f, "etc").getAbsolutePath());
+            System.setProperty("org.apache.servicemix.filemonitor.monitorDir", new File(f, "deploy").getAbsolutePath());
+            System.setProperty("org.apache.servicemix.filemonitor.generatedJarDir", new File(f, "data/generate-bundles").getAbsolutePath());
+            System.setProperty("bundles.configuration.location", new File("src/test/conf").getAbsolutePath());
+            System.setProperty("org.osgi.vendor.framework", "org.apache.servicemix.kernel.testing.support");
+            PropertyConfigurator.configure("target/test-classes/log4j.properties");
+        } catch (Throwable t) {}
+    }
+
+    private Properties dependencies;
+    private FeatureInstaller featureInstaller;
+
+    @Override
+    protected String getPlatformName() {
+        String systemProperty = System.getProperty(OSGI_FRAMEWORK_SELECTOR);
+        if (logger.isTraceEnabled())
+            logger.trace("system property [" + OSGI_FRAMEWORK_SELECTOR + "] has value=" + systemProperty);
+
+        return (systemProperty == null ? SmxKernelPlatform.class.getName() : systemProperty);
+    }
+
+    protected String getBundle(String groupId, String artifactId) {
+        return groupId + "," + artifactId + "," + getBundleVersion(groupId, artifactId);
+    }
+
+    protected String getBundleVersion(String groupId, String artifactId) {
+        if (dependencies == null) {
+            try {
+                File f = new File(System.getProperty("basedir"), "target/classes/META-INF/maven/dependencies.properties");
+                Properties prop = new Properties();
+                prop.load(new FileInputStream(f));
+                dependencies = prop;
+            } catch (IOException e) {
+                throw new IllegalStateException("Unable to load dependencies informations", e);
+            }
+        }
+        String version = dependencies.getProperty(groupId + "/" + artifactId + "/version");
+        if (version == null) {
+            throw new IllegalStateException("Unable to find dependency information for: " + groupId + "/" + artifactId + "/version");
+        }
+        return version;
+    }
+
+    protected String[] getTestFrameworkBundlesNames() {
+        return new String[] {
+            getBundle("org.apache.geronimo.specs", "geronimo-servlet_2.5_spec"),
+            getBundle("org.apache.servicemix.specs", "org.apache.servicemix.specs.jaxp-api-1.4"),
+            getBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.jaxp-ri"),
+            getBundle("org.apache.felix", "org.osgi.compendium"),
+            getBundle("org.apache.felix", "org.apache.felix.configadmin"),
+            getBundle("org.ops4j.pax.logging", "pax-logging-api"),
+            getBundle("org.ops4j.pax.logging", "pax-logging-service"),
+            getBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.aopalliance"),
+            getBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.asm"),
+            getBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.junit"),
+            getBundle("org.springframework", "spring-beans"),
+            getBundle("org.springframework", "spring-core"),
+            getBundle("org.springframework", "spring-context"),
+            getBundle("org.springframework", "spring-aop"),
+            getBundle("org.springframework", "spring-test"),
+            getBundle("org.springframework.osgi", "spring-osgi-core"),
+            getBundle("org.springframework.osgi", "spring-osgi-io"),
+            getBundle("org.springframework.osgi", "spring-osgi-extender"),
+            getBundle("org.springframework.osgi", "spring-osgi-test"),
+            getBundle("org.springframework.osgi", "spring-osgi-annotation"),
+            getBundle("org.ops4j.pax.url", "pax-url-mvn"),
+            getBundle("org.apache.servicemix.kernel.testing", "org.apache.servicemix.kernel.testing.support"),
+        };
+    }
+
+    protected Bundle installBundle(String groupId, String artifactId, String classifier, String type) throws Exception {
+        String version = getBundleVersion(groupId, artifactId);
+        File loc = localMavenBundle(groupId, artifactId, version, classifier, type);
+        Bundle bundle = bundleContext.installBundle(loc.toURI().toString());
+        bundle.start();
+        return bundle;
+    }
+    
+    protected void addFeatureRepo(String url) throws Exception {
+        if (featureInstaller == null) {
+            featureInstaller = new FeatureInstaller();
+            featureInstaller.setBundleContext(bundleContext);
+        }
+        featureInstaller.addRepository(new URI(url));
+    }
+    
+    protected void installFeature(String name) throws Exception {
+        installFeature(name, FeatureImpl.DEFAULT_VERSION);
+    }
+
+    protected void installFeature(String name, String version) throws Exception {
+        if (featureInstaller == null) {
+            featureInstaller = new FeatureInstaller();
+            featureInstaller.setBundleContext(bundleContext);
+            
+        }
+        featureInstaller.installFeature(name, version);
+    }
+    
+    protected Resource locateBundle(String bundleId) {
+        Assert.hasText(bundleId, "bundleId should not be empty");
+
+        // parse the String
+        String[] artifactId = StringUtils.commaDelimitedListToStringArray(bundleId);
+
+        Assert.isTrue(artifactId.length >= 3, "the CSV string " + bundleId + " contains too few values");
+        // TODO: add a smarter mechanism which can handle 1 or 2 values CSVs
+        for (int i = 0; i < artifactId.length; i++) {
+            artifactId[i] = StringUtils.trimWhitespace(artifactId[i]);
+        }
+
+        File f;
+        if (artifactId.length == 3) {
+            f = localMavenBundle(artifactId[0], artifactId[1], artifactId[2], null, ArtifactLocator.DEFAULT_ARTIFACT_TYPE);
+        } else {
+            f = localMavenBundle(artifactId[0], artifactId[1], artifactId[2], null, artifactId[3]);
+        }
+        return new FileSystemResource(f);
+    }
+
+
+    protected File localMavenBundle(String groupId, String artifact, String version, String classifier, String type) {
+        String defaultHome = new File(new File(System.getProperty("user.home")), ".m2/repository").getAbsolutePath();
+        File repositoryHome = new File(System.getProperty("localRepository", defaultHome));
+
+        StringBuffer location = new StringBuffer(groupId.replace('.', '/'));
+        location.append('/');
+        location.append(artifact);
+        location.append('/');
+        location.append(getSnapshot(version));
+        location.append('/');
+        location.append(artifact);
+        location.append('-');
+        location.append(version);
+        if (classifier != null) {
+            location.append('-');
+            location.append(classifier);
+        }
+        location.append(".");
+        location.append(type);
+
+        return new File(repositoryHome, location.toString());
+    }
+
+    protected static String getSnapshot(String version) {
+        if (isTimestamped(version)) {
+            return version.substring(0, version.lastIndexOf('-', version.lastIndexOf('-') - 1)) + "-SNAPSHOT";
+        }
+        return version;
+    }
+
+    protected static boolean isTimestamped(String version) {
+        return version.matches(".+-\\d\\d\\d\\d\\d\\d\\d\\d\\.\\d\\d\\d\\d\\d\\d-\\d+");
+    }
+
+    protected static boolean isSnapshot(String version) {
+        return version.matches(".+-SNAPSHOT");
+    }
+
+    public <T> T getOsgiService(Class<T> type) {
+        return getOsgiService(type, DEFAULT_WAIT_TIME);
+    }
+
+    public <T> T getOsgiService(Class<T> type, long timeout) {
+        // translate from seconds to miliseconds
+        long time = timeout * 1000;
+
+        // use the counter to make sure the threads block
+        final Counter counter = new Counter("waitForOsgiService on bnd=" + type.getName());
+
+        counter.increment();
+
+        final List<T> services = new ArrayList<T>();
+
+        ServiceListener listener = new ServiceListener() {
+            public void serviceChanged(ServiceEvent event) {
+                if (event.getType() == ServiceEvent.REGISTERED) {
+                    services.add((T) bundleContext.getService(event.getServiceReference()));
+                    counter.decrement();
+                }
+            }
+        };
+
+        String filter = OsgiFilterUtils.unifyFilter(type.getName(), null);
+        OsgiListenerUtils.addServiceListener(bundleContext, listener, filter);
+
+        if (logger.isDebugEnabled())
+            logger.debug("start waiting for OSGi service=" + type.getName());
+
+        try {
+            if (counter.waitForZero(time)) {
+                logger.warn("waiting for OSGi service=" + type.getName() + " timed out");
+                throw new RuntimeException("Gave up waiting for OSGi service '" + type.getName() + "' to be created");
+            }
+            else if (logger.isDebugEnabled()) {
+                logger.debug("found OSGi service=" + type.getName());
+            }
+            return services.get(0);
+        }
+        finally {
+            // inform waiting thread
+            bundleContext.removeServiceListener(listener);
+        }
+    }
+
+    protected void checkBundleStarted(String name) {
+        assertNotNull(bundleContext);
+        for (int i = 0; i < bundleContext.getBundles().length; i++) {
+            Bundle b = bundleContext.getBundles()[i];
+            if (b.getSymbolicName().equals(name)) {
+                assertEquals("Bundle '" + name + "' is not active", Bundle.ACTIVE, b.getState());
+                return;
+            }
+        }
+        fail("Bundle '" + name + "' not found");
+    }
+
+
+}
\ No newline at end of file
diff --git a/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/Counter.java b/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/Counter.java
new file mode 100644
index 0000000..95a3a44
--- /dev/null
+++ b/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/Counter.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2002-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.testing.support;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Simple counting class which can be incremented or decremented in a
+ * synchronized manner. This class can be used as a synchronization mechanism
+ * between threads mainly though {@link #waitForZero(long)} method.
+ *
+ * The main usage of the class is to allow a master thread, to know when other
+ * threads (slaves) have passed a certain point in execution.
+ *
+ * <p/> As opposed to a Barrier or a Semaphore, this class should be used only
+ * with 1 waiting thread (a master) and any number of slave threads.
+ *
+ * <pre style="code">
+ * Thread 1:
+ *  synchronized(counter) {
+ *    counter.increment();
+ *    thread2.start();
+ *    counter.increment();
+ *    thread3.start();
+ *
+ *    // wait 1 second for other threads to complete
+ *    counter.waitForZero(1000);
+ * }
+ *
+ * Thread 2:
+ *  // do some work
+ *  counter.decrement();
+ *
+ * Thread 3:
+ *  // do some work
+ *  counter.decrement();
+ *
+ * </pre>
+ *
+ * <p/> Mainly for usage inside the framework. All methods are thread-safe
+ * however for the master/slave pattern, synchronized blocks are recommended as
+ * multiple operations have to be executed at once.
+ *
+ * @author Costin Leau
+ *
+ */
+public class Counter {
+
+	private int counter = 0;
+
+	private static final Log log = LogFactory.getLog(Counter.class);
+
+	private final String name;
+
+	/**
+	 * Create counter with a given name.
+	 * @param name counter name
+	 */
+	public Counter(String name) {
+		this.name = name;
+	}
+
+	/**
+	 * Increment the counter value.
+	 */
+	public synchronized void increment() {
+		counter++;
+		if (log.isTraceEnabled())
+			log.trace("counter [" + name + "] incremented to " + counter);
+	}
+
+	/**
+	 * Decrement the counter value.
+	 */
+	public synchronized void decrement() {
+		counter--;
+		if (log.isTraceEnabled())
+			log.trace("counter [" + name + "] decremented to " + counter);
+		notifyAll();
+	}
+
+	public synchronized boolean decrementAndWait(long timeToWait) {
+		decrement();
+		if (counter > 0)
+			return waitForZero(timeToWait);
+		return true;
+	}
+
+	/**
+	 * Check if the counter value is zero.
+	 * @return true if value is equal or below zero, false otherwise.
+	 */
+	public synchronized boolean isZero() {
+		return is(0);
+	}
+
+	public synchronized boolean is(int value) {
+		return counter == value;
+	}
+
+	/**
+	 * Return the counter value.
+	 *
+	 * @return the counter value.
+	 */
+	public synchronized int getValue() {
+		return counter;
+	}
+
+	public synchronized String toString() {
+		return "" + counter;
+	}
+
+	/**
+	 * Specialized method which waits for 0. Identical to waitFor(0, waitTime).
+	 *
+	 * @see #waitFor(int, long)
+	 * @param waitTime
+	 * @return true if the waiting timed out, false otherwise
+	 */
+	public synchronized boolean waitForZero(long waitTime) {
+		return waitFor(0, waitTime);
+	}
+
+	/**
+	 * Wait maximum the givem amount of time, for the counter to reach the given
+	 * value.. This mechanism relies on {@link Object#wait(long)} and
+	 * {@link Object#notify()} mechanism to work appropriately. Please see the
+	 * class javadoc for more info.
+	 *
+	 * <p/> This method will stop waiting and return true if the thread
+	 * is interrupted.
+	 *
+	 * @param value the value to wait for
+	 * @param waitTime the time (in miliseconds) to wait for zero value
+	 * @return true if the waiting timed out, false otherwise
+	 */
+	public synchronized boolean waitFor(int value, long waitTime) {
+		boolean timedout = false;
+		long remainingTime = waitTime;
+		long startTime = System.currentTimeMillis();
+
+		while (counter > value && !timedout) {
+			// start waiting
+			try {
+				this.wait(remainingTime);
+				// compute the remaining time
+				remainingTime = waitTime - (System.currentTimeMillis() - startTime);
+				timedout = remainingTime <= 0;
+			}
+			catch (InterruptedException ex) {
+				timedout = true;
+			}
+		}
+
+		return timedout;
+	}
+}
diff --git a/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/Feature.java b/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/Feature.java
new file mode 100644
index 0000000..56006cf
--- /dev/null
+++ b/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/Feature.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.testing.support;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A feature is a list of bundles associated identified by its name.
+ */
+public interface Feature {
+
+    String getId();
+
+    String getName();
+
+    String getVersion();
+
+    List<Feature> getDependencies();
+
+    List<String> getBundles();
+
+    Map<String, Map<String, String>> getConfigurations();
+    
+    void addDependency(Feature dependency);
+    
+    void addBundle(String bundle);
+    
+    void addConfig(String name, Map<String,String> properties);
+
+}
diff --git a/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/FeatureImpl.java b/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/FeatureImpl.java
new file mode 100644
index 0000000..9c8c9a2
--- /dev/null
+++ b/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/FeatureImpl.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.testing.support;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+public class FeatureImpl implements Feature {
+
+    private String id;
+    private String name;
+    private String version;
+    private List<Feature> dependencies = new ArrayList<Feature>();
+    private List<String> bundles = new ArrayList<String>();
+    private Map<String, Map<String,String>> configs = new HashMap<String, Map<String,String>>();
+    public static String SPLIT_FOR_NAME_AND_VERSION = "_split_for_name_and_version_";
+    public static String DEFAULT_VERSION = "0.0.0";
+    
+    public FeatureImpl(String name) {
+        this(name, DEFAULT_VERSION);
+    }
+    
+    public FeatureImpl(String name, String version) {
+        this.name = name;
+        this.version = version;
+        this.id = name + "-" + version;
+    }
+
+    
+    public String getId() {
+        return id;
+    }
+
+    
+    public String getName() {
+        return name;
+    }
+
+    
+    public String getVersion() {
+        return version;
+    }
+    
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    
+    public List<Feature> getDependencies() {
+        return dependencies;
+    }
+
+    public List<String> getBundles() {
+        return bundles;
+    }
+
+    public Map<String, Map<String, String>> getConfigurations() {
+        return configs;
+    }
+
+    public void addDependency(Feature dependency) {
+        dependencies.add(dependency);
+    }
+
+    public void addBundle(String bundle) {
+        bundles.add(bundle);
+    }
+
+    public void addConfig(String name, Map<String,String> properties) {
+        configs.put(name, properties);
+    }
+
+    public String toString() {
+        String ret = getName() + SPLIT_FOR_NAME_AND_VERSION + getVersion();
+        return ret;
+    }
+    
+    public static Feature valueOf(String str) {
+        if (str.indexOf(SPLIT_FOR_NAME_AND_VERSION) >= 0) {
+            String strName = str.substring(0, str.indexOf(SPLIT_FOR_NAME_AND_VERSION));
+            String strVersion = str.substring(str.indexOf(SPLIT_FOR_NAME_AND_VERSION) 
+                    + SPLIT_FOR_NAME_AND_VERSION.length(), str.length());
+            return new FeatureImpl(strName, strVersion);
+        } else {
+            return new FeatureImpl(str);
+        }
+                
+        
+    }
+
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        FeatureImpl feature = (FeatureImpl) o;
+
+        if (!name.equals(feature.name)) return false;
+        if (!version.equals(feature.version)) return false;
+
+        return true;
+    }
+
+    public int hashCode() {
+        int result = name.hashCode();
+        result = 31 * result + version.hashCode();
+        return result;
+    }
+}
diff --git a/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/FeatureInstaller.java b/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/FeatureInstaller.java
new file mode 100644
index 0000000..d200e40
--- /dev/null
+++ b/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/FeatureInstaller.java
@@ -0,0 +1,246 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicemix.kernel.testing.support;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URL;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.jar.JarInputStream;
+import java.util.jar.Manifest;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+
+
+public class FeatureInstaller {
+
+    private Map<URI, FeatureRepositoryImpl> repositories = new HashMap<URI, FeatureRepositoryImpl>();
+    private Map<String, Map<String, Feature>> features;
+    private BundleContext bundleContext;
+    
+    public void addRepository(URI uri) throws Exception {
+        if (!repositories.values().contains(uri)) {
+            internalAddRepository(uri);
+        }
+    }
+    
+    protected FeatureRepositoryImpl internalAddRepository(URI uri) throws Exception {
+        FeatureRepositoryImpl repo = new FeatureRepositoryImpl(uri);
+        repositories.put(uri, repo);
+        features = null;
+        return repo;
+    }
+    
+    public void setBundleContext(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+    
+    
+    public void installFeature(String name, String version) throws Exception {
+        Feature f = getFeature(name, version);
+        if (f == null) {
+            throw new Exception("No feature named '" + name 
+                    + "' with version '" + version + "' available");
+        }
+        for (Feature dependency : f.getDependencies()) {
+            installFeature(dependency.getName(), dependency.getVersion());
+        }
+       
+        Set<Long> bundles = new HashSet<Long>();
+        for (String bundleLocation : f.getBundles()) {
+            Bundle b = installBundleIfNeeded(bundleLocation);
+            bundles.add(b.getBundleId());
+        }
+        for (long id : bundles) {
+            bundleContext.getBundle(id).start();
+        }
+
+        
+    }
+    
+    protected Feature getFeature(String name, String version) throws Exception {
+        Map<String, Feature> versions = getFeatures().get(name);
+        if (versions == null || versions.isEmpty()) {
+            return null;
+        } else {
+            Feature feature = versions.get(version);
+            if (feature == null && FeatureImpl.DEFAULT_VERSION.equals(version)) {
+                Version latest = new Version(cleanupVersion(version));
+                for (String available : versions.keySet()) {
+                    Version availableVersion = new Version(cleanupVersion(available));
+                    if (availableVersion.compareTo(latest) > 0) {
+                        feature = versions.get(available);
+                        latest = availableVersion;
+                    }
+                }
+            }
+            return feature;
+        }
+    }
+    
+    protected Map<String, Map<String, Feature>> getFeatures() throws Exception {
+        if (features == null) {
+            //the outer map's key is feature name, the inner map's key is feature version       
+            Map<String, Map<String, Feature>> map = new HashMap<String, Map<String, Feature>>();
+            // Two phase load:
+            // * first load dependent repositories
+            for (;;) {
+                boolean newRepo = false;
+                for (FeatureRepositoryImpl repo : listRepositories()) {
+                    for (URI uri : repo.getRepositories()) {
+                        if (!repositories.keySet().contains(uri)) {
+                            internalAddRepository(uri);
+                            newRepo = true;
+                        }
+                    }
+                }
+                if (!newRepo) {
+                    break;
+                }
+            }
+            // * then load all features
+            for (FeatureRepositoryImpl repo : repositories.values()) {
+                for (Feature f : repo.getFeatures()) {
+                    if (map.get(f.getName()) == null) {
+                        Map<String, Feature> versionMap = new HashMap<String, Feature>();
+                        versionMap.put(f.getVersion(), f);
+                        map.put(f.getName(), versionMap);
+                    } else {
+                        map.get(f.getName()).put(f.getVersion(), f);
+                    }
+                }
+            }
+            features = map;
+        }
+        return features;
+    }
+    
+    public FeatureRepositoryImpl[] listRepositories() {
+        Collection<FeatureRepositoryImpl> repos = repositories.values();
+        return repos.toArray(new FeatureRepositoryImpl[repos.size()]);
+    }
+    
+    protected Bundle installBundleIfNeeded(String bundleLocation) throws IOException, BundleException {
+        InputStream is = new BufferedInputStream(new URL(bundleLocation).openStream());
+        try {
+            is.mark(256 * 1024);
+            JarInputStream jar = new JarInputStream(is);
+            Manifest m = jar.getManifest();
+            String sn = m.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME);
+            String vStr = m.getMainAttributes().getValue(Constants.BUNDLE_VERSION);
+            Version v = vStr == null ? Version.emptyVersion : Version.parseVersion(vStr);
+            for (Bundle b : bundleContext.getBundles()) {
+                if (b.getSymbolicName() != null && b.getSymbolicName().equals(sn)) {
+                    vStr = (String) b.getHeaders().get(Constants.BUNDLE_VERSION);
+                    Version bv = vStr == null ? Version.emptyVersion : Version.parseVersion(vStr);
+                    if (v.equals(bv)) {
+                        return b;
+                    }
+                }
+            }
+            try {
+                is.reset();
+            } catch (IOException e) {
+                is.close();
+                is = new BufferedInputStream(new URL(bundleLocation).openStream());
+            }
+            return getBundleContext().installBundle(bundleLocation, is);
+        } finally {
+            is.close();
+        }
+    }
+    
+    private BundleContext getBundleContext() {
+        return this.bundleContext;
+    }
+
+    /**
+     * Clean up version parameters. Other builders use more fuzzy definitions of
+     * the version syntax. This method cleans up such a version to match an OSGi
+     * version.
+     *
+     * @param version
+     * @return
+     */
+    static Pattern fuzzyVersion  = Pattern.compile("(\\d+)(\\.(\\d+)(\\.(\\d+))?)?([^a-zA-Z0-9](.*))?",
+                                                   Pattern.DOTALL);
+    static Pattern fuzzyModifier = Pattern.compile("(\\d+[.-])*(.*)",
+                                                   Pattern.DOTALL);
+    static public String cleanupVersion(String version) {
+        Matcher m = fuzzyVersion.matcher(version);
+        if (m.matches()) {
+            StringBuffer result = new StringBuffer();
+            String d1 = m.group(1);
+            String d2 = m.group(3);
+            String d3 = m.group(5);
+            String qualifier = m.group(7);
+
+            if (d1 != null) {
+                result.append(d1);
+                if (d2 != null) {
+                    result.append(".");
+                    result.append(d2);
+                    if (d3 != null) {
+                        result.append(".");
+                        result.append(d3);
+                        if (qualifier != null) {
+                            result.append(".");
+                            cleanupModifier(result, qualifier);
+                        }
+                    } else if (qualifier != null) {
+                        result.append(".0.");
+                        cleanupModifier(result, qualifier);
+                    }
+                } else if (qualifier != null) {
+                    result.append(".0.0.");
+                    cleanupModifier(result, qualifier);
+                }
+                return result.toString();
+            }
+        }
+        return version;
+    }
+
+    static void cleanupModifier(StringBuffer result, String modifier) {
+        Matcher m = fuzzyModifier.matcher(modifier);
+        if (m.matches())
+            modifier = m.group(2);
+
+        for (int i = 0; i < modifier.length(); i++) {
+            char c = modifier.charAt(i);
+            if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z')
+                    || (c >= 'A' && c <= 'Z') || c == '_' || c == '-')
+                result.append(c);
+        }
+    }
+
+}
diff --git a/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/FeatureRepositoryImpl.java b/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/FeatureRepositoryImpl.java
new file mode 100644
index 0000000..fb296bb
--- /dev/null
+++ b/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/FeatureRepositoryImpl.java
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.testing.support;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+
+
+/**
+ * The repository implementation.
+ */
+
+public class FeatureRepositoryImpl {
+
+    private URI uri;
+    private List<Feature> features;
+    private List<URI> repositories;
+
+    public FeatureRepositoryImpl(URI uri) {
+        this.uri = uri;
+    }
+
+    
+    public URI getURI() {
+        return uri;
+    }
+
+    public URI[] getRepositories() throws Exception {
+        if (repositories == null) {
+            load();
+        }
+        return repositories.toArray(new URI[repositories.size()]);
+    }
+
+    public Feature[] getFeatures() throws Exception {
+        if (features == null) {
+            load();
+        }
+        return features.toArray(new Feature[features.size()]);
+    }
+
+    public void load() throws IOException {
+        try {
+            repositories = new ArrayList<URI>();
+            features = new ArrayList<Feature>();
+            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+            Document doc = factory.newDocumentBuilder().parse(uri.toURL().openStream());
+            NodeList nodes = doc.getDocumentElement().getChildNodes();
+            for (int i = 0; i < nodes.getLength(); i++) {
+                Node node = nodes.item(i);
+                if (!(node instanceof Element)) {
+                    continue;
+                }
+                if ("repository".equals(node.getNodeName())) {
+                    Element e = (Element) nodes.item(i);
+                    repositories.add(new URI(e.getTextContent()));
+                } else if ("feature".equals(node.getNodeName())) {
+                    Element e = (Element) nodes.item(i);
+                    String name = e.getAttribute("name");
+                    String version = e.getAttribute("version");
+                    Feature f;
+                    if (version != null && version.length() > 0) {
+                        f = new FeatureImpl(name, version);
+                    } else {
+                        f = new FeatureImpl(name);
+                    }
+
+                    NodeList featureNodes = e.getElementsByTagName("feature");
+                    for (int j = 0; j < featureNodes.getLength(); j++) {
+                        Element b = (Element) featureNodes.item(j);
+                        String dependencyFeatureVersion = b.getAttribute("version");
+                        if (dependencyFeatureVersion != null && dependencyFeatureVersion.length() > 0) {
+                            f.addDependency(new FeatureImpl(b.getTextContent(), dependencyFeatureVersion));
+                        } else {
+                            f.addDependency(new FeatureImpl(b.getTextContent()));
+                        }
+                    }
+                    NodeList configNodes = e.getElementsByTagName("config");
+                    for (int j = 0; j < configNodes.getLength(); j++) {
+                        Element c = (Element) configNodes.item(j);
+                        String cfgName = c.getAttribute("name");
+                        String data = c.getTextContent();
+                        Properties properties = new Properties();
+                        properties.load(new ByteArrayInputStream(data.getBytes()));
+                        Map<String, String> hashtable = new Hashtable<String, String>();
+                        for (Object key : properties.keySet()) {
+                            String n = key.toString();
+                            hashtable.put(n, properties.getProperty(n));
+                        }
+                        f.addConfig(cfgName, hashtable);
+                    }
+                    NodeList bundleNodes = e.getElementsByTagName("bundle");
+                    for (int j = 0; j < bundleNodes.getLength(); j++) {
+                        Element b = (Element) bundleNodes.item(j);
+                        f.addBundle(b.getTextContent());
+                    }
+                    features.add(f);
+                }
+            }
+        } catch (SAXException e) {
+            throw (IOException) new IOException().initCause(e);
+        } catch (ParserConfigurationException e) {
+            throw (IOException) new IOException().initCause(e);
+        } catch (URISyntaxException e) {
+            throw (IOException) new IOException().initCause(e);
+        }
+    }
+
+}
diff --git a/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/FrameworkUtil.java b/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/FrameworkUtil.java
new file mode 100644
index 0000000..e3427a9
--- /dev/null
+++ b/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/FrameworkUtil.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.testing.support;
+
+import org.apache.felix.framework.FilterImpl;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+
+/**
+ */
+public class FrameworkUtil {
+
+    public static Filter createFilter(String f) throws InvalidSyntaxException {
+        return new FilterImpl(f);
+    }
+
+}
diff --git a/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/SmxKernelPlatform.java b/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/SmxKernelPlatform.java
new file mode 100644
index 0000000..eed2d5e
--- /dev/null
+++ b/karaf/testing/support/src/main/java/org/apache/servicemix/kernel/testing/support/SmxKernelPlatform.java
@@ -0,0 +1,428 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.testing.support;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.felix.framework.Felix;
+import org.apache.felix.framework.util.CompoundEnumeration;
+import org.apache.felix.framework.util.FelixConstants;
+import org.apache.servicemix.kernel.main.Main;
+import org.apache.servicemix.kernel.main.spi.MainService;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.springframework.osgi.test.platform.FelixPlatform;
+import org.springframework.osgi.test.platform.OsgiPlatform;
+import org.springframework.util.ClassUtils;
+
+public class SmxKernelPlatform implements OsgiPlatform {
+
+    private static final Log log = LogFactory.getLog(FelixPlatform.class);
+
+    private static final String FELIX_CONF_FILE = "config.properties";
+
+    private static final String FELIX_CONFIG_PROPERTY = "config.properties";
+
+    public final static String	FRAMEWORK_STORAGE = "org.osgi.framework.storage";
+
+    private BundleContext context;
+
+    private Object platform;
+
+    private File felixStorageDir;
+
+    private Properties configurationProperties = new Properties();
+
+    protected Properties getPlatformProperties() {
+        // load Felix configuration
+        Properties props = new Properties();
+        props.putAll(getFelixConfiguration());
+        props.putAll(getLocalConfiguration());
+        return props;
+    }
+
+    public Properties getConfigurationProperties() {
+        // local properties
+        configurationProperties.putAll(getPlatformProperties());
+        // system properties
+        configurationProperties.putAll(System.getProperties());
+        return configurationProperties;
+    }
+
+    public BundleContext getBundleContext() {
+        return context;
+    }
+
+    private Set<String> getJars(Class... classes) {
+        Set<String> jars = new HashSet<String>();
+        for (Class cl : classes) {
+            String name = cl.getName().replace('.', '/') + ".class";
+            URL url = (cl.getClassLoader() != null ? cl.getClassLoader() : getClass().getClassLoader()).getResource(name);
+            String path = url.toString();
+            if (path.startsWith("jar:")) {
+                path = path.substring(0, path.indexOf('!'));
+            } else {
+                path = path.substring(0, path.indexOf(name));
+            }
+            jars.add(path);
+        }
+        return jars;
+    }
+
+    public void start() throws Exception {
+        Set<String> jars = getJars(Felix.class);
+        ClassLoader classLoader = new GuardClassLoader(toURLs(jars.toArray(new String[jars.size()])), null);
+
+        BundleActivator activator = new BundleActivator() {
+            private ServiceRegistration registration;
+
+            public void start(BundleContext context) {
+                registration = context.registerService(MainService.class.getName(), new MainService() {
+                    public String[] getArgs() {
+                        return new String[0];
+                    }
+                    public int getExitCode() {
+                        return 0;
+                    }
+                    public void setExitCode(int exitCode) {
+                    }
+                }, null);
+            }
+
+            public void stop(BundleContext context) {
+                registration.unregister();
+            }
+        };
+        List<BundleActivator> activations = new ArrayList<BundleActivator>();
+        activations.add(activator);
+
+        Properties props = getConfigurationProperties();
+        props.put(FelixConstants.SYSTEMBUNDLE_ACTIVATORS_PROP, activations);
+
+        Thread.currentThread().setContextClassLoader(classLoader);
+        Class cl = classLoader.loadClass(Felix.class.getName());
+        Constructor cns = cl.getConstructor(Map.class);
+        platform = cns.newInstance(props);
+        platform.getClass().getMethod("start").invoke(platform);
+
+        Bundle systemBundle = (Bundle) platform;
+
+        // call getBundleContext
+        final Method getContext = systemBundle.getClass().getMethod("getBundleContext", null);
+
+        AccessController.doPrivileged(new PrivilegedAction() {
+
+            public Object run() {
+                getContext.setAccessible(true);
+                return null;
+            }
+        });
+        context = (BundleContext) getContext.invoke(systemBundle, null);
+    }
+
+    public void stop() throws Exception {
+        try {
+            platform.getClass().getMethod("stop").invoke(platform);
+        }
+        finally {
+            // remove cache folder
+            delete(felixStorageDir);
+        }
+    }
+
+    public String toString() {
+        return getClass().getName();
+    }
+
+    File createTempDir(String suffix) {
+        if (suffix == null)
+            suffix = "osgi";
+        File tempFileName;
+
+        try {
+            tempFileName = File.createTempFile("org.sfw.osgi", suffix);
+        }
+        catch (IOException ex) {
+            if (log.isWarnEnabled()) {
+                log.warn("Could not create temporary directory, returning a temp folder inside the current folder", ex);
+            }
+            return new File("./tmp-test");
+        }
+
+        tempFileName.delete(); // we want it to be a directory...
+        File tempFolder = new File(tempFileName.getAbsolutePath());
+        tempFolder.mkdir();
+        return tempFolder;
+    }
+
+    /**
+     * Configuration settings for the OSGi test run.
+     *
+     * @return
+     */
+    private Properties getLocalConfiguration() {
+        Properties props = new Properties();
+        felixStorageDir = createTempDir("felix");
+        props.setProperty(FRAMEWORK_STORAGE, this.felixStorageDir.getAbsolutePath());
+        if (log.isTraceEnabled())
+            log.trace("felix storage dir is " + felixStorageDir.getAbsolutePath());
+
+        return props;
+    }
+
+    /**
+     * Loads Felix config.properties.
+     *
+     * <strong>Note</strong> the current implementation uses Felix's Main class
+     * to resolve placeholders as opposed to loading the properties manually
+     * (through JDK's Properties class or Spring's PropertiesFactoryBean).
+     *
+     * @return
+     */
+    // TODO: this method should be removed once Felix 1.0.2 is released
+    private Properties getFelixConfiguration() {
+        String location = "/".concat(ClassUtils.classPackageAsResourcePath(getClass())).concat("/").concat(FELIX_CONF_FILE);
+        URL url = getClass().getResource(location);
+        if (url == null)
+            throw new RuntimeException("cannot find felix configuration properties file:" + location);
+
+        // used with Main
+        System.getProperties().setProperty(FELIX_CONFIG_PROPERTY, url.toExternalForm());
+
+        // load config.properties (use Felix's Main for resolving placeholders)
+        Properties props = new Properties();
+        InputStream is = null;
+        try {
+            is = url.openConnection().getInputStream();
+            props.load(is);
+            is.close();
+        }
+        catch (FileNotFoundException ex) {
+            // Ignore file not found.
+        }
+        catch (Exception ex) {
+            System.err.println("Main: Error loading system properties from " + url);
+            System.err.println("Main: " + ex);
+            try {
+                if (is != null) is.close();
+            }
+            catch (IOException ex2) {
+                // Nothing we can do.
+            }
+            return null;
+        }
+        // Perform variable substitution for system properties.
+        for (Enumeration e = props.propertyNames(); e.hasMoreElements();) {
+            String name = (String) e.nextElement();
+            props.setProperty(name, Main.substVars(props.getProperty(name), name, null, props));
+        }
+        return props;
+    }
+
+    /**
+     * Delete the given file (can be a simple file or a folder).
+     *
+     * @param file the file to be deleted
+     * @return if the deletion succeded or not
+     */
+    public static boolean delete(File file) {
+
+        // bail out quickly
+        if (file == null)
+            return false;
+
+        // recursively delete children file
+        boolean success = true;
+
+        if (file.isDirectory()) {
+            String[] children = file.list();
+            for (int i = 0; i < children.length; i++) {
+                success &= delete(new File(file, children[i]));
+            }
+        }
+
+        // The directory is now empty so delete it
+        return (success &= file.delete());
+    }
+
+    private static URL[] toURLs(String[] jars) throws MalformedURLException {
+        URL[] urls = new URL[jars.length];
+        for (int i = 0; i < urls.length; i++) {
+            String s = jars[i];
+            if (s.startsWith("jar:")) {
+                s = s.substring("jar:".length());
+            }
+            urls[i] = new URL(s);
+        }
+        return urls;
+    }
+
+    public class GuardClassLoader extends URLClassLoader {
+        private Set<String> bootDelegationPackages = new HashSet<String>();
+        private Set<String> packages = new HashSet<String>();
+        private List<ClassLoader> parents = new ArrayList<ClassLoader>();
+
+        public GuardClassLoader(URL[] urls, List<String> additionalPackages) throws MalformedURLException {
+            super(urls, SmxKernelPlatform.class.getClassLoader());
+            Properties props = getConfigurationProperties();
+            String prop = props.getProperty("org.osgi.framework.system.packages");
+            String[] ps = prop.split(",");
+            for (String p : ps) {
+                String[] spack = p.split(";");
+                for (String sp : spack) {
+                    sp = sp.trim();
+                    if (!sp.startsWith("version")) {
+                        packages.add(sp);
+                    }
+                }
+            }
+            if (additionalPackages != null) {
+                packages.addAll(additionalPackages);
+            }
+            prop = props.getProperty("org.osgi.framework.bootdelegation");
+            ps = prop.split(",");
+            for (String p : ps) {
+                p = p.trim();
+                if (p.endsWith("*")) {
+                    p = p.substring(0, p.length() - 1);
+                }
+                bootDelegationPackages.add(p);
+            }
+            ClassLoader cl = getParent();
+            while (cl != null) {
+                parents.add(0, cl);
+                cl = cl.getParent();
+            }
+            //System.err.println("Boot packages: " + packages);
+        }
+
+        protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+            //System.err.println("Loading class: " + name);
+            Class c = findLoadedClass(name);
+            if (c == null) {
+                String pkg = name.substring(0, name.lastIndexOf('.'));
+                boolean match = name.startsWith("java.") || packages.contains(pkg);
+                if (!match) {
+                    for (String p : bootDelegationPackages) {
+                        if (pkg.startsWith(p)) {
+                            match = true;
+                            break;
+                        }
+                    }
+                }
+                if (match) {
+                    for (ClassLoader cl : parents) {
+                        try {
+                            c = cl.loadClass(name);
+                            //System.err.println("Class loaded from: " + cl.getResource(name.replace('.', '/') + ".class"));
+                            break;
+                        } catch (ClassNotFoundException e) {
+                        }
+                    }
+                    if (c == null) {
+                        throw new ClassNotFoundException(name);
+                    }
+                    //c = getParent().loadClass(name);
+                } else  {
+                    c = findClass(name);
+                }
+            }
+            if (resolve) {
+                resolveClass(c);
+            }
+            return c;
+        }
+
+        public URL getResource(String name) {
+            //System.err.println("GetResource: " + name);
+            URL url = getParent().getResource(name);
+            if (url != null && url.toString().startsWith("file:")) {
+                return url;
+            }
+            url = findResource(name);
+            System.err.println("Resource " + name + " found at " + url);
+            return url;
+            /*
+            URL u = getParent().getResource(name);
+            if (u != null) {
+                String path = u.toString();
+                int idx = path.indexOf('!');
+                if (idx > 0) {
+                    path = path.substring(0, idx);
+                    if (!jars.contains(path)) {
+                        return null;
+                    }
+                } else {
+                    idx = 0;
+                }
+            }
+            return u;
+            */
+        }
+
+        public Enumeration<URL> getResources(final String name) throws IOException {
+            //System.err.println("GetResources: " + name);
+            Enumeration[] tmp = new Enumeration[2];
+            final Enumeration<URL> e = getParent().getResources(name);
+            tmp[0] = new Enumeration<URL>() {
+                URL next = null;
+                public boolean hasMoreElements() {
+                    while (next == null && e.hasMoreElements()) {
+                        next = e.nextElement();
+                        String path = next.toString();
+                        if (!path.startsWith("file:")) {
+                            next = null;
+                        }
+                    }
+                    return next != null;
+                }
+                public URL nextElement() {
+                    return next;
+                }
+            };
+            tmp[1] = findResources(name);
+            return new CompoundEnumeration(tmp) {
+                public Object nextElement() {
+                    Object next = super.nextElement();
+                    System.err.println("Resources " + name + " found at " + next);
+                    return next;
+                }
+            };
+        }
+    }
+}
diff --git a/karaf/testing/support/src/test/java/org/apache/servicemix/kernel/testing/support/AbstractIntegrationTestTest.java b/karaf/testing/support/src/test/java/org/apache/servicemix/kernel/testing/support/AbstractIntegrationTestTest.java
new file mode 100644
index 0000000..9acba05
--- /dev/null
+++ b/karaf/testing/support/src/test/java/org/apache/servicemix/kernel/testing/support/AbstractIntegrationTestTest.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicemix.kernel.testing.support;
+
+import junit.framework.TestCase;
+
+
+public class AbstractIntegrationTestTest extends TestCase {
+
+    public void testSnapshotVersion() {
+        assertTrue(AbstractIntegrationTest.isTimestamped("0.9.0-20070713.230317-1"));
+        assertTrue(AbstractIntegrationTest.isSnapshot("0.9.0-SNAPSHOT"));
+        assertFalse(AbstractIntegrationTest.isSnapshot("0.9.0"));
+        assertEquals("0.9.0-SNAPSHOT", AbstractIntegrationTest.getSnapshot("0.9.0-20070713.230317-1"));
+        assertEquals("0.9.0", "0.9.0");
+    }
+
+}