You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by gn...@apache.org on 2014/04/11 19:20:23 UTC

[01/33] [KARAF-2852] Merge jdbc/core and jdbc/command

Repository: karaf
Updated Branches:
  refs/heads/master 4b6b7afb1 -> fd4b3f677


http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-generic.xml
----------------------------------------------------------------------
diff --git a/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-generic.xml b/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-generic.xml
new file mode 100644
index 0000000..090daee
--- /dev/null
+++ b/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-generic.xml
@@ -0,0 +1,141 @@
+<?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.
+    -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+
+    <bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
+        <property name="driverClassName" value="${driver}"/>
+        <property name="url" value="${url}"/>
+        <property name="user" value="${user}"/>
+        <property name="password" value="${password}"/>
+        <property name="maxIdle" value="1"/>
+    </bean>
+
+    <bean id="connectionFactory" class="org.apache.commons.dbcp.DataSourceConnectionFactory">
+        <argument ref="dataSource" />
+    </bean>
+
+    <bean id="connectionPool" class="org.apache.commons.pool.impl.GenericObjectPool" >
+        <!-- No default factory -->
+        <argument><null/></argument> <!-- factory -->
+        <!--
+            controls the maximum number of objects that can be allocated by the pool (checked out to clients, or
+            idle awaiting checkout) at a given time. When non-positive, there is no limit to the number of objects that can
+            be managed by the pool at one time. When maxActive is reached, the pool is said to be exhausted.
+            The default setting for this parameter is 8.
+         -->
+        <argument value="8" /> <!-- maxActive -->
+        <!--
+            specifies the behavior of the borrowObject() method when the pool is exhausted:
+
+            When whenExhaustedAction is WHEN_EXHAUSTED_FAIL, borrowObject() will throw a NoSuchElementException
+            When whenExhaustedAction is WHEN_EXHAUSTED_GROW, borrowObject() will create a new object and return it
+            (essentially making maxActive meaningless.)
+            When whenExhaustedAction is WHEN_EXHAUSTED_BLOCK, borrowObject() will block (invoke Object.wait()) until
+            a new or idle object is available. If a positive maxWait value is supplied, then borrowObject() will block for at most that many milliseconds, after which a NoSuchElementException will be thrown. If maxWait is non-positive, the borrowObject() method will block indefinitely.
+
+            The default whenExhaustedAction setting is WHEN_EXHAUSTED_BLOCK and the default maxWait setting is -1.
+            By default, therefore, borrowObject will block indefinitely until an idle instance becomes available.
+        -->
+        <argument value="WHEN_EXHAUSTED_BLOCK" /> <!-- whenExhaustedAction -->
+        <!--
+            the maximum amount of time to wait for an idle object when the pool is exhausted and whenExhaustedAction
+            is WHEN_EXHAUSTED_BLOCK (otherwise ignored)
+        -->
+        <argument value="-1" /> <!-- maxWait -->
+        <!--
+            controls the maximum number of objects that can sit idle in the pool at any time.
+            When negative, there is no limit to the number of objects that may be idle at one time.
+            The default setting for this parameter is 8.
+        -->
+        <argument value="8" /> <!-- maxIdle -->
+        <!--
+           sets the minimum number of objects allowed in the pool before the evictor thread (if active) spawns
+           new objects.
+        -->
+        <argument value="0" /> <!-- minIdle -->
+        <!--
+            when true, objects will be validated before being returned by the borrowObject() method.
+        -->
+        <argument value="false" /> <!-- testOnBorrow -->
+        <!--
+            when true, objects will be validated before being returned to the pool within the returnObject(T).
+        -->
+        <argument value="false" /> <!-- testOnReturn -->
+        <!--
+            sets the number of milliseconds to sleep between runs of the idle object evictor thread.
+        -->
+        <argument value="-1" /> <!-- timeBetweenEvictionRunsMillis -->
+        <!--
+            the number of idle objects to examine per run within the idle object eviction thread (if any)
+        -->
+        <argument value="3" /> <!-- numTestsPerEvictionRun -->
+        <!--
+            sets the minimum amount of time an object may sit idle in the pool before it is eligible for eviction by
+            the idle object evictor (if any). When non-positive, no objects will be evicted from the pool due to idle
+            time alone.
+        -->
+        <argument value="1800000" /> <!-- minEvictableIdleTimeMillis -->
+        <!--
+            when true, objects will be validated by the idle object evictor (if any). If an object fails to validate,
+            it will be dropped from the pool.
+        -->
+        <argument value="false" /> <!-- testWhileIdle -->
+        <!--
+            softMinEvictableIdleTimeMillis specifies the minimum amount of time an object may sit idle in the pool before
+            it is eligible for eviction by the idle object evictor (if any), with the extra condition that at least "minIdle"
+            object instances remain in the pool. When non-positive, no objects will be evicted from the pool due to idle time alone.
+            This setting has no effect unless timeBetweenEvictionRunsMillis > 0. and it is superceded by
+            minEvictableIdleTimeMillis (that is, if minEvictableIdleTimeMillis is positive, then
+            softMinEvictableIdleTimeMillis is ignored). The default setting for this parameter is -1 (disabled).
+        -->
+        <argument value="-1" /> <!-- softMinEvictableIdleTimeMillis -->
+        <!--
+            lifo determines whether or not the pool returns idle objects in last-in-first-out order. The default setting for this parameter is true.
+        -->
+        <argument value="true" /> <!-- lifo -->
+    </bean>
+
+    <bean id="pooledConnectionFactory" class="org.apache.commons.dbcp.PoolableConnectionFactory" >
+        <argument ref="connectionFactory" />
+        <argument ref="connectionPool" />
+        <argument><null/></argument>
+        <!--
+            a query to use to validate Connections. Should return at least one row. Using null turns off validation.
+        -->
+        <argument><null/></argument> <!-- validationQuery -->
+        <!--
+            the default "read only" setting for borrowed connections
+        -->
+        <argument value="false" /> <!-- defaultReadOnly -->
+        <!--
+            the default "auto commit" setting for returned connections
+        -->
+        <argument value="true" /> <!-- defaultAutoCommit -->
+    </bean>
+
+    <bean id="pooledDataSource" class="org.apache.commons.dbcp.PoolingDataSource" depends-on="pooledConnectionFactory">
+        <argument ref="connectionPool" />
+    </bean>
+
+    <service ref="pooledDataSource" interface="javax.sql.DataSource">
+        <service-properties>
+            <entry key="osgi.jndi.service.name" value="jdbc/${name}"/>
+        </service-properties>
+    </service>
+
+</blueprint>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-h2.xml
----------------------------------------------------------------------
diff --git a/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-h2.xml b/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-h2.xml
new file mode 100644
index 0000000..19805f4
--- /dev/null
+++ b/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-h2.xml
@@ -0,0 +1,31 @@
+<?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.
+    -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+
+    <bean id="dataSource" class="org.h2.jdbcx.JdbcDataSource">
+        <property name="URL" value="${url}"/>
+        <property name="user" value="${user}"/>
+        <property name="password" value="${password}"/>
+    </bean>
+
+    <service interface="javax.sql.DataSource" ref="dataSource">
+        <service-properties>
+            <entry key="osgi.jndi.service.name" value="jdbc/${name}"/>
+        </service-properties>
+    </service>
+</blueprint>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-hsql.xml
----------------------------------------------------------------------
diff --git a/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-hsql.xml b/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-hsql.xml
new file mode 100644
index 0000000..3ea9ba8
--- /dev/null
+++ b/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-hsql.xml
@@ -0,0 +1,31 @@
+<?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.
+    -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+
+    <bean id="dataSource" class="org.hsqldb.jdbc.JDBCDataSource">
+        <property name="url" value="${url}"/>
+        <property name="user" value="${user}"/>
+        <property name="password" value="${password}"/>
+    </bean>
+
+    <service interface="javax.sql.DataSource" ref="dataSource">
+        <service-properties>
+            <entry key="osgi.jndi.service.name" value="jdbc/${name}"/>
+        </service-properties>
+    </service>
+</blueprint>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-mssql.xml
----------------------------------------------------------------------
diff --git a/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-mssql.xml b/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-mssql.xml
new file mode 100644
index 0000000..35e6ed9
--- /dev/null
+++ b/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-mssql.xml
@@ -0,0 +1,32 @@
+<?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.
+    -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+
+    <bean id="dataSource" class="net.sourceforge.jtds.jdbcx.JtdsDataSource">
+        <property name="serverName" value="${url}"/>
+        <property name="databaseName" value="${name}"/>
+        <property name="user" value="${user}"/>
+        <property name="password" value="${password}"/>
+    </bean>
+
+    <service interface="javax.sql.DataSource" ref="dataSource">
+        <service-properties>
+            <entry key="osgi.jndi.service.name" value="jdbc/${name}"/>
+        </service-properties>
+    </service>
+</blueprint>

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-mysql.xml
----------------------------------------------------------------------
diff --git a/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-mysql.xml b/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-mysql.xml
new file mode 100644
index 0000000..012ecaf
--- /dev/null
+++ b/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-mysql.xml
@@ -0,0 +1,31 @@
+<?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.
+    -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+
+    <bean id="dataSource" class="com.mysql.jdbc.jdbc2.optional.MysqlDataSource">
+        <property name="url" value="${url}"/>
+        <property name="user" value="${user}"/>
+        <property name="password" value="${password}"/>
+    </bean>
+
+    <service interface="javax.sql.DataSource" ref="dataSource">
+        <service-properties>
+            <entry key="osgi.jndi.service.name" value="jdbc/${name}"/>
+        </service-properties>
+    </service>
+</blueprint>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-oracle.xml
----------------------------------------------------------------------
diff --git a/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-oracle.xml b/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-oracle.xml
new file mode 100644
index 0000000..8168b16
--- /dev/null
+++ b/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-oracle.xml
@@ -0,0 +1,31 @@
+<?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.
+    -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+
+    <bean id="dataSource" class="oracle.jdbc.pool.OracleDataSource">
+        <property name="URL" value="${url}"/>
+        <property name="user" value="${user}"/>
+        <property name="password" value="${password}"/>
+    </bean>
+
+    <service interface="javax.sql.DataSource" ref="dataSource">
+        <service-properties>
+            <entry key="osgi.jndi.service.name" value="jdbc/${name}"/>
+        </service-properties>
+    </service>
+</blueprint>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-postgres.xml
----------------------------------------------------------------------
diff --git a/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-postgres.xml b/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-postgres.xml
new file mode 100644
index 0000000..1845c48
--- /dev/null
+++ b/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-postgres.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.
+    -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+
+    <bean id="dataSource" class="org.postgresql.ds.PGPoolingDataSource" destroy-method="close">
+        <property name="serverName" value="${url}"/>
+        <property name="user" value="${user}"/>
+        <property name="password" value="${password}"/>
+        <property name="dataSourceName" value="${name}"/>
+        <property name="initialConnections" value="2"/>
+        <property name="maxConnections" value="4" />
+    </bean>
+
+    <service interface="javax.sql.DataSource" ref="dataSource">
+        <service-properties>
+            <entry key="osgi.jndi.service.name" value="jdbc/${name}"/>
+        </service-properties>
+    </service>
+</blueprint>
\ No newline at end of file


[17/33] Revert "[KARAF-2852] Merge features/core and features/command"

Posted by gn...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/resources/org/apache/karaf/features/karaf-features-1.0.0.xsd
----------------------------------------------------------------------
diff --git a/features/src/main/resources/org/apache/karaf/features/karaf-features-1.0.0.xsd b/features/src/main/resources/org/apache/karaf/features/karaf-features-1.0.0.xsd
deleted file mode 100644
index 9536ba1..0000000
--- a/features/src/main/resources/org/apache/karaf/features/karaf-features-1.0.0.xsd
+++ /dev/null
@@ -1,239 +0,0 @@
-<?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://karaf.apache.org/xmlns/features/v1.0.0"
-    xmlns:tns="http://karaf.apache.org/xmlns/features/v1.0.0"
-    xmlns:xs="http://www.w3.org/2001/XMLSchema">
-
-    <xs:annotation>
-        <xs:documentation><![CDATA[
-Karaf features mechanism. For documentation please visit the
-<a href="http://karaf.apache.org/">Karaf website</a>.
-        ]]></xs:documentation>
-    </xs:annotation>
-
-    <xs:complexType name="features">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Root element of the Feature definition. It contains an optional attribute for
-designating the name of the repository of this feature. The Karaf shell will
-show the repository name when displaying information about the feature.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element name="repository" type="xs:anyURI">
-                <xs:annotation>
-                    <xs:documentation><![CDATA[
-Additional repositories where dependencies are stored.
-                    ]]></xs:documentation>
-                </xs:annotation>
-            </xs:element>
-            <xs:element name="feature" type="tns:feature">
-                <xs:annotation>
-                    <xs:documentation><![CDATA[
-Feature definition.
-                    ]]></xs:documentation>
-                </xs:annotation>
-            </xs:element>
-        </xs:choice>
-        <xs:attribute name="name" type="xs:string" />
-    </xs:complexType>
-
-    <xs:complexType name="feature">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Definition of the Feature.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element name="details" minOccurs="0" type="xs:string">
-                <xs:annotation>
-                    <xs:documentation><![CDATA[
-The help text shown for this feature when using the feature:info console command.
-                    ]]>
-                    </xs:documentation>
-                </xs:annotation>
-            </xs:element>
-            <xs:element name="config" type="tns:config" />
-            <xs:element name="configfile" type="tns:configFile" />
-            <xs:element name="feature" type="tns:dependency" />
-            <xs:element name="bundle" type="tns:bundle" />
-        </xs:choice>
-        <xs:attribute name="name" type="tns:featureName" use="required" />
-        <xs:attribute name="version" type="xs:string" default="0.0.0" />
-        <xs:attribute name="description" type="xs:string" />
-        <xs:attribute name="resolver" type="tns:resolver">
-            <xs:annotation>
-                <xs:documentation><![CDATA[
-Optional alternative resolver to use for determining the list of bundles to install for a given feature.
-                ]]>
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute name="install" type="tns:install">
-            <xs:annotation>
-                <xs:documentation><![CDATA[
-If true, marks that the feature should start automatically when placed in the deploy folder.
-                ]]>
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute name="start-level" type="xs:int">
-             <xs:annotation>
-                <xs:documentation><![CDATA[
-Set this attribute to have an OSGi start level for the bundles in this feature different
-from the default start level defined in Karaf's config.properties.
-                ]]>
-                </xs:documentation>
-             </xs:annotation>
-         </xs:attribute>
-         <xs:attribute name="region" type="xs:string"/>
-    </xs:complexType>
-
-    <xs:complexType name="bundle">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Deployable element to install.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:simpleContent>
-            <xs:extension base="xs:anyURI">
-                <xs:attribute name="start-level" type="xs:int">
-                    <xs:annotation>
-                        <xs:documentation><![CDATA[
-Set this attribute to have an OSGi start level for this bundle different
-from the default start level defined in Karaf's config.properties.
-
-                        ]]>
-                        </xs:documentation>
-                    </xs:annotation>
-                </xs:attribute>
-                <xs:attribute name="start" type="xs:boolean" default="true">
-                    <xs:annotation>
-                        <xs:documentation><![CDATA[
-If false, leaves the bundle in resolved state rather than the default active state.
-                        ]]>
-                        </xs:documentation>
-                    </xs:annotation>
-                </xs:attribute>
-                <xs:attribute name="dependency" type="xs:boolean">
-                    <xs:annotation>
-                        <xs:documentation><![CDATA[
-Mark this bundle as a dependency for the resolver.
-                        ]]>
-                        </xs:documentation>
-                    </xs:annotation>
-                </xs:attribute>
-            </xs:extension>
-        </xs:simpleContent>
-    </xs:complexType>
-
-    <xs:complexType name="dependency">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Dependency of feature.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:simpleContent>
-            <xs:extension base="tns:featureName">
-                <xs:attribute name="version" type="xs:string" default="0.0.0" />
-            </xs:extension>
-        </xs:simpleContent>
-    </xs:complexType>
-
-    <xs:complexType name="config">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Configuration entries which should be created during feature installation. This
-configuration may be used with OSGi Configuration Admin. The element content is
-read in as a properties file.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:simpleContent>
-            <xs:extension base="xs:string">
-                <xs:attribute name="name" type="xs:string" use="required" />
-            </xs:extension>
-        </xs:simpleContent>
-    </xs:complexType>
-
-    <xs:complexType name="configFile">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Additional configuration files which should be created during feature installation.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:simpleContent>
-            <xs:extension base="xs:anyURI">
-                <xs:attribute name="finalname" type="xs:string" use="required">
-                    <xs:annotation>
-                        <xs:documentation><![CDATA[
-The final destination path and name for the configuration file (relative to the KARAF_BASE).
-                        ]]></xs:documentation>
-                    </xs:annotation>
-                </xs:attribute>
-                <xs:attribute name="override" type="xs:boolean">
-                    <xs:annotation>
-                        <xs:documentation><![CDATA[
-If the configFile already exists at the finalname location, whether or not to replace it.
-                        ]]></xs:documentation>
-                    </xs:annotation>
-                </xs:attribute>
-
-            </xs:extension>
-        </xs:simpleContent>
-    </xs:complexType>
-
-    <xs:simpleType name="featureName">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Feature name should be non empty string.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:restriction base="xs:string">
-            <xs:minLength value="1" />
-        </xs:restriction>
-    </xs:simpleType>
-
-    <xs:simpleType name="resolver">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Resolver to use. Karaf will look for OSGi service which has following properties:
-objectClass: org.apache.karaf.features.Resolver
-name: the value
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:restriction base="xs:string">
-            <xs:minLength value="1" />
-        </xs:restriction>
-    </xs:simpleType>
-    <xs:simpleType name="install">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Installation mode. Can be either manual or auto. Specifies whether the feature should be automatically installed when
-dropped inside the deploy folder. Note: This attribute doesn't affect feature descriptors that are installed from the
-command line or as part of the org.apache.karaf.features.cfg.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:restriction base="xs:string">
-            <xs:minLength value="1" />
-        </xs:restriction>
-    </xs:simpleType>
-    <xs:element name="features" type="tns:features" />
-
-</xs:schema>

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/resources/org/apache/karaf/features/karaf-features-1.1.0.xsd
----------------------------------------------------------------------
diff --git a/features/src/main/resources/org/apache/karaf/features/karaf-features-1.1.0.xsd b/features/src/main/resources/org/apache/karaf/features/karaf-features-1.1.0.xsd
deleted file mode 100644
index 7138573..0000000
--- a/features/src/main/resources/org/apache/karaf/features/karaf-features-1.1.0.xsd
+++ /dev/null
@@ -1,237 +0,0 @@
-<?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://karaf.apache.org/xmlns/features/v1.1.0"
-    xmlns:tns="http://karaf.apache.org/xmlns/features/v1.1.0"
-    xmlns:xs="http://www.w3.org/2001/XMLSchema">
-
-    <xs:annotation>
-        <xs:documentation><![CDATA[
-Karaf features mechanism. For documentation please visit the
-<a href="http://karaf.apache.org/">Karaf website</a>.
-        ]]></xs:documentation>
-    </xs:annotation>
-
-    <xs:complexType name="features">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Root element of Feature definition. It contains an required attribute for
-designating from which repository this feature should be loaded. The Karaf
-shell will show the repository name when displaying information about the feature.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element name="repository" type="xs:anyURI">
-                <xs:annotation>
-                    <xs:documentation><![CDATA[
-Additional repositories where dependencies are stored.
-                    ]]></xs:documentation>
-                </xs:annotation>
-            </xs:element>
-            <xs:element name="feature" type="tns:feature">
-                <xs:annotation>
-                    <xs:documentation><![CDATA[
-Feature definition.
-                    ]]></xs:documentation>
-                </xs:annotation>
-            </xs:element>
-        </xs:choice>
-        <xs:attribute name="name" type="xs:string" use="required"/>
-    </xs:complexType>
-
-    <xs:complexType name="feature">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Definition of the Feature.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element name="details" minOccurs="0" type="xs:string">
-                <xs:annotation>
-                    <xs:documentation><![CDATA[
-The help text shown for this feature when using feature:info console command.
-                    ]]>
-                    </xs:documentation>
-                </xs:annotation>
-            </xs:element>
-            <xs:element name="config" type="tns:config" />
-            <xs:element name="configfile" type="tns:configFile" />
-            <xs:element name="feature" type="tns:dependency" />
-            <xs:element name="bundle" type="tns:bundle" />
-        </xs:choice>
-        <xs:attribute name="name" type="tns:featureName" use="required" />
-        <xs:attribute name="version" type="xs:string" default="0.0.0" />
-        <xs:attribute name="description" type="xs:string" />
-        <xs:attribute name="resolver" type="tns:resolver">
-            <xs:annotation>
-                <xs:documentation><![CDATA[
-Optional alternative resolver to use for determining the list of bundles to install for a given feature.
-                ]]>
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute name="install" type="tns:install">
-            <xs:annotation>
-                <xs:documentation><![CDATA[
-Marks if the feaute will be automatically started when thrown to the deploy folder.
-                ]]>
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute name="start-level" type="xs:int">
-             <xs:annotation>
-                <xs:documentation><![CDATA[
-Set this attribute to have an OSGi start level for this feature different
-from the default start level defined in Karaf's config.properties.
-                ]]>
-                </xs:documentation>
-             </xs:annotation>
-         </xs:attribute>
-    </xs:complexType>
-
-    <xs:complexType name="bundle">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Deployable element to install.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:simpleContent>
-            <xs:extension base="xs:anyURI">
-                <xs:attribute name="start-level" type="xs:int">
-                    <xs:annotation>
-                        <xs:documentation><![CDATA[
-Set this attribute to have an OSGi start level for this bundle different
-from the default start level defined in the Karaf's config.properties.
-                        ]]>
-                        </xs:documentation>
-                    </xs:annotation>
-                </xs:attribute>
-                <xs:attribute name="start" type="xs:boolean" default="true">
-                    <xs:annotation>
-                        <xs:documentation><![CDATA[
-If false, leaves bundle in resolved state rather than the default active state.
-                        ]]>
-                        </xs:documentation>
-                    </xs:annotation>
-                </xs:attribute>
-                <xs:attribute name="dependency" type="xs:boolean">
-                    <xs:annotation>
-                        <xs:documentation><![CDATA[
-Mark this bundle as a dependency for the resolver.
-                        ]]>
-                        </xs:documentation>
-                    </xs:annotation>
-                </xs:attribute>
-            </xs:extension>
-        </xs:simpleContent>
-    </xs:complexType>
-
-    <xs:complexType name="dependency">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Dependency of feature.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:simpleContent>
-            <xs:extension base="tns:featureName">
-                <xs:attribute name="version" type="xs:string" default="0.0.0" />
-            </xs:extension>
-        </xs:simpleContent>
-    </xs:complexType>
-
-    <xs:complexType name="config">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Configuration entries which should be created during feature installation. This
-configuration may be used with OSGi Configuration Admin. The element content is
-read in as a properties file.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:simpleContent>
-            <xs:extension base="xs:string">
-                <xs:attribute name="name" type="xs:string" use="required" />
-            </xs:extension>
-        </xs:simpleContent>
-    </xs:complexType>
-
-    <xs:complexType name="configFile">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Additional configuration files which should be created during feature installation.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:simpleContent>
-            <xs:extension base="xs:anyURI">
-                <xs:attribute name="finalname" type="xs:string" use="required">
-                    <xs:annotation>
-                        <xs:documentation><![CDATA[
-The final destination path and name for the configuration file.
-                        ]]></xs:documentation>
-                    </xs:annotation>
-                </xs:attribute>
-                <xs:attribute name="override" type="xs:boolean">
-                    <xs:annotation>
-                        <xs:documentation><![CDATA[
-If the configFile already exists at the finalname location, whether or not to replace it.
-                        ]]></xs:documentation>
-                    </xs:annotation>
-                </xs:attribute>
-
-            </xs:extension>
-        </xs:simpleContent>
-    </xs:complexType>
-
-    <xs:simpleType name="featureName">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Feature name should be non empty string.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:restriction base="xs:string">
-            <xs:minLength value="1" />
-        </xs:restriction>
-    </xs:simpleType>
-
-    <xs:simpleType name="resolver">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Resolver to use. Karaf will look for OSGi service which have following properties:
-objectClass: org.apache.karaf.features.Resolver
-name: the value
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:restriction base="xs:string">
-            <xs:minLength value="1" />
-        </xs:restriction>
-    </xs:simpleType>
-    <xs:simpleType name="install">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Installation mode. Can be either manual or auto. Specifies whether the feature should be automatically installed when
-dropped inside the deploy folder. Note: This attribute doesn't affect feature descriptors that are installed from the
-command line or as part of the org.apache.karaf.features.cfg.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:restriction base="xs:string">
-            <xs:minLength value="1" />
-        </xs:restriction>
-    </xs:simpleType>
-    <xs:element name="features" type="tns:features" />
-
-</xs:schema>

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/resources/org/apache/karaf/features/karaf-features-1.2.0.xsd
----------------------------------------------------------------------
diff --git a/features/src/main/resources/org/apache/karaf/features/karaf-features-1.2.0.xsd b/features/src/main/resources/org/apache/karaf/features/karaf-features-1.2.0.xsd
deleted file mode 100644
index dbc4bfa..0000000
--- a/features/src/main/resources/org/apache/karaf/features/karaf-features-1.2.0.xsd
+++ /dev/null
@@ -1,254 +0,0 @@
-<?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://karaf.apache.org/xmlns/features/v1.2.0"
-    xmlns:tns="http://karaf.apache.org/xmlns/features/v1.2.0"
-    xmlns:xs="http://www.w3.org/2001/XMLSchema">
-
-    <xs:annotation>
-        <xs:documentation><![CDATA[
-Karaf features mechanism. For documentation please visit the
-<a href="http://karaf.apache.org/">Karaf website</a>.
-        ]]></xs:documentation>
-    </xs:annotation>
-
-    <xs:complexType name="features">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Root element of Feature definition. It contains an required attribute for
-designating from which repository this feature should be loaded. The Karaf
-shell will show the repository name when displaying information about the feature.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element name="repository" type="xs:anyURI">
-                <xs:annotation>
-                    <xs:documentation><![CDATA[
-Additional repositories where dependencies are stored.
-                    ]]></xs:documentation>
-                </xs:annotation>
-            </xs:element>
-            <xs:element name="feature" type="tns:feature">
-                <xs:annotation>
-                    <xs:documentation><![CDATA[
-Feature definition.
-                    ]]></xs:documentation>
-                </xs:annotation>
-            </xs:element>
-        </xs:choice>
-        <xs:attribute name="name" type="xs:string" use="required"/>
-    </xs:complexType>
-
-    <xs:complexType name="feature">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Definition of the Feature.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element name="details" minOccurs="0" type="xs:string">
-                <xs:annotation>
-                    <xs:documentation><![CDATA[
-The help text shown for this feature when using feature:info console command.
-                    ]]>
-                    </xs:documentation>
-                </xs:annotation>
-            </xs:element>
-            <xs:element name="config" type="tns:config" />
-            <xs:element name="configfile" type="tns:configFile" />
-            <xs:element name="feature" type="tns:dependency" />
-            <xs:element name="bundle" type="tns:bundle" />
-            <xs:element name="conditional" type="tns:conditional" />
-        </xs:choice>
-        <xs:attribute name="name" type="tns:featureName" use="required" />
-        <xs:attribute name="version" type="xs:string" default="0.0.0" />
-        <xs:attribute name="description" type="xs:string" />
-        <xs:attribute name="resolver" type="tns:resolver">
-            <xs:annotation>
-                <xs:documentation><![CDATA[
-Optional alternative resolver to use for determining the list of bundles to install for a given feature.
-                ]]>
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute name="install" type="tns:install">
-            <xs:annotation>
-                <xs:documentation><![CDATA[
-Marks if the feaute will be automatically started when thrown to the deploy folder.
-                ]]>
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute name="start-level" type="xs:int">
-             <xs:annotation>
-                <xs:documentation><![CDATA[
-Set this attribute to have an OSGi start level for this feature different
-from the default start level defined in Karaf's config.properties.
-                ]]>
-                </xs:documentation>
-             </xs:annotation>
-         </xs:attribute>
-    </xs:complexType>
-
-    <xs:complexType name="conditional">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Definition of the Conditional.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element name="config" type="tns:config" />
-            <xs:element name="configfile" type="tns:configFile" />
-            <xs:element name="feature" type="tns:dependency" />
-            <xs:element name="bundle" type="tns:bundle" />
-            <xs:element name="condition" type="tns:dependency" minOccurs="0" maxOccurs="1" />
-        </xs:choice>
-    </xs:complexType>
-
-
-    <xs:complexType name="bundle">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Deployable element to install.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:simpleContent>
-            <xs:extension base="xs:anyURI">
-                <xs:attribute name="start-level" type="xs:int">
-                    <xs:annotation>
-                        <xs:documentation><![CDATA[
-Set this attribute to have an OSGi start level for this bundle different
-from the default start level defined in the Karaf's config.properties.
-                        ]]>
-                        </xs:documentation>
-                    </xs:annotation>
-                </xs:attribute>
-                <xs:attribute name="start" type="xs:boolean" default="true">
-                    <xs:annotation>
-                        <xs:documentation><![CDATA[
-If false, leaves bundle in resolved state rather than the default active state.
-                        ]]>
-                        </xs:documentation>
-                    </xs:annotation>
-                </xs:attribute>
-                <xs:attribute name="dependency" type="xs:boolean">
-                    <xs:annotation>
-                        <xs:documentation><![CDATA[
-Mark this bundle as a dependency for the resolver.
-                        ]]>
-                        </xs:documentation>
-                    </xs:annotation>
-                </xs:attribute>
-            </xs:extension>
-        </xs:simpleContent>
-    </xs:complexType>
-
-    <xs:complexType name="dependency">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Dependency of feature.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:simpleContent>
-            <xs:extension base="tns:featureName">
-                <xs:attribute name="version" type="xs:string" default="0.0.0" />
-            </xs:extension>
-        </xs:simpleContent>
-    </xs:complexType>
-
-    <xs:complexType name="config">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Configuration entries which should be created during feature installation. This
-configuration may be used with OSGi Configuration Admin. The element content is
-read in as a properties file.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:simpleContent>
-            <xs:extension base="xs:string">
-                <xs:attribute name="name" type="xs:string" use="required" />
-            </xs:extension>
-        </xs:simpleContent>
-    </xs:complexType>
-
-    <xs:complexType name="configFile">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Additional configuration files which should be created during feature installation.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:simpleContent>
-            <xs:extension base="xs:anyURI">
-                <xs:attribute name="finalname" type="xs:string" use="required">
-                    <xs:annotation>
-                        <xs:documentation><![CDATA[
-The final destination path and name for the configuration file.
-                        ]]></xs:documentation>
-                    </xs:annotation>
-                </xs:attribute>
-                <xs:attribute name="override" type="xs:boolean">
-                    <xs:annotation>
-                        <xs:documentation><![CDATA[
-If the configFile already exists at the finalname location, whether or not to replace it.
-                        ]]></xs:documentation>
-                    </xs:annotation>
-                </xs:attribute>
-
-            </xs:extension>
-        </xs:simpleContent>
-    </xs:complexType>
-
-    <xs:simpleType name="featureName">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Feature name should be non empty string.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:restriction base="xs:string">
-            <xs:minLength value="1" />
-        </xs:restriction>
-    </xs:simpleType>
-
-    <xs:simpleType name="resolver">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Resolver to use. Karaf will look for OSGi service which have following properties:
-objectClass: org.apache.karaf.features.Resolver
-name: the value
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:restriction base="xs:string">
-            <xs:minLength value="1" />
-        </xs:restriction>
-    </xs:simpleType>
-    <xs:simpleType name="install">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Installation mode. Can be either manual or auto. Specifies whether the feature should be automatically installed when
-dropped inside the deploy folder. Note: This attribute doesn't affect feature descriptors that are installed from the
-command line or as part of the org.apache.karaf.features.cfg.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:restriction base="xs:string">
-            <xs:minLength value="1" />
-        </xs:restriction>
-    </xs:simpleType>
-    <xs:element name="features" type="tns:features" />
-
-</xs:schema>

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/resources/org/apache/karaf/features/karaf-features-1.3.0.xsd
----------------------------------------------------------------------
diff --git a/features/src/main/resources/org/apache/karaf/features/karaf-features-1.3.0.xsd b/features/src/main/resources/org/apache/karaf/features/karaf-features-1.3.0.xsd
deleted file mode 100644
index 60ec8d2..0000000
--- a/features/src/main/resources/org/apache/karaf/features/karaf-features-1.3.0.xsd
+++ /dev/null
@@ -1,280 +0,0 @@
-<?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://karaf.apache.org/xmlns/features/v1.3.0"
-    xmlns:tns="http://karaf.apache.org/xmlns/features/v1.3.0"
-    xmlns:xs="http://www.w3.org/2001/XMLSchema">
-
-    <xs:annotation>
-        <xs:documentation><![CDATA[
-Karaf features mechanism. For documentation please visit the
-<a href="http://karaf.apache.org/">Karaf website</a>.
-        ]]></xs:documentation>
-    </xs:annotation>
-
-    <xs:complexType name="features">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Root element of Feature definition. It contains an required attribute for
-designating from which repository this feature should be loaded. The Karaf
-shell will show the repository name when displaying information about the feature.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element name="repository" type="xs:anyURI">
-                <xs:annotation>
-                    <xs:documentation><![CDATA[
-Additional repositories where dependencies are stored.
-                    ]]></xs:documentation>
-                </xs:annotation>
-            </xs:element>
-            <xs:element name="feature" type="tns:feature">
-                <xs:annotation>
-                    <xs:documentation><![CDATA[
-Feature definition.
-                    ]]></xs:documentation>
-                </xs:annotation>
-            </xs:element>
-        </xs:choice>
-        <xs:attribute name="name" type="xs:string" use="required"/>
-    </xs:complexType>
-
-    <xs:complexType name="feature">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Definition of the Feature.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element name="details" minOccurs="0" type="xs:string">
-                <xs:annotation>
-                    <xs:documentation><![CDATA[
-The help text shown for this feature when using feature:info console command.
-                    ]]>
-                    </xs:documentation>
-                </xs:annotation>
-            </xs:element>
-            <xs:element name="config" type="tns:config" />
-            <xs:element name="configfile" type="tns:configFile" />
-            <xs:element name="feature" type="tns:dependency" />
-            <xs:element name="bundle" type="tns:bundle" />
-            <xs:element name="conditional" type="tns:conditional" />
-            <xs:element name="requirement" type="tns:requirement" />
-            <xs:element name="capability" type="tns:capability" />
-        </xs:choice>
-        <xs:attribute name="name" type="tns:featureName" use="required" />
-        <xs:attribute name="version" type="xs:string" default="0.0.0" />
-        <xs:attribute name="description" type="xs:string" />
-        <xs:attribute name="resolver" type="tns:resolver">
-            <xs:annotation>
-                <xs:documentation><![CDATA[
-Optional alternative resolver to use for determining the list of bundles to install for a given feature.
-                ]]>
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute name="install" type="tns:install">
-            <xs:annotation>
-                <xs:documentation><![CDATA[
-Marks if the feaute will be automatically started when thrown to the deploy folder.
-                ]]>
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute name="start-level" type="xs:int">
-             <xs:annotation>
-                <xs:documentation><![CDATA[
-Set this attribute to have an OSGi start level for this feature different
-from the default start level defined in Karaf's config.properties.
-                ]]>
-                </xs:documentation>
-             </xs:annotation>
-         </xs:attribute>
-    </xs:complexType>
-
-    <xs:complexType name="conditional">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Definition of the Conditional.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element name="config" type="tns:config" />
-            <xs:element name="configfile" type="tns:configFile" />
-            <xs:element name="feature" type="tns:dependency" />
-            <xs:element name="bundle" type="tns:bundle" />
-            <xs:element name="condition" type="tns:dependency" minOccurs="0" maxOccurs="1" />
-        </xs:choice>
-    </xs:complexType>
-
-
-    <xs:complexType name="bundle">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Deployable element to install.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:simpleContent>
-            <xs:extension base="xs:anyURI">
-                <xs:attribute name="start-level" type="xs:int">
-                    <xs:annotation>
-                        <xs:documentation><![CDATA[
-Set this attribute to have an OSGi start level for this bundle different
-from the default start level defined in the Karaf's config.properties.
-                        ]]>
-                        </xs:documentation>
-                    </xs:annotation>
-                </xs:attribute>
-                <xs:attribute name="start" type="xs:boolean" default="true">
-                    <xs:annotation>
-                        <xs:documentation><![CDATA[
-If false, leaves bundle in resolved state rather than the default active state.
-                        ]]>
-                        </xs:documentation>
-                    </xs:annotation>
-                </xs:attribute>
-                <xs:attribute name="dependency" type="xs:boolean">
-                    <xs:annotation>
-                        <xs:documentation><![CDATA[
-Mark this bundle as a dependency for the resolver.
-                        ]]>
-                        </xs:documentation>
-                    </xs:annotation>
-                </xs:attribute>
-            </xs:extension>
-        </xs:simpleContent>
-    </xs:complexType>
-
-    <xs:complexType name="dependency">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Dependency of feature.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:simpleContent>
-            <xs:extension base="tns:featureName">
-                <xs:attribute name="version" type="xs:string" default="0.0.0" />
-            </xs:extension>
-        </xs:simpleContent>
-    </xs:complexType>
-
-    <xs:complexType name="config">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Configuration entries which should be created during feature installation. This
-configuration may be used with OSGi Configuration Admin. The element content is
-read in as a properties file.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:simpleContent>
-            <xs:extension base="xs:string">
-                <xs:attribute name="name" type="xs:string" use="required" />
-            </xs:extension>
-        </xs:simpleContent>
-    </xs:complexType>
-
-    <xs:complexType name="configFile">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Additional configuration files which should be created during feature installation.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:simpleContent>
-            <xs:extension base="xs:anyURI">
-                <xs:attribute name="finalname" type="xs:string" use="required">
-                    <xs:annotation>
-                        <xs:documentation><![CDATA[
-The final destination path and name for the configuration file.
-                        ]]></xs:documentation>
-                    </xs:annotation>
-                </xs:attribute>
-                <xs:attribute name="override" type="xs:boolean">
-                    <xs:annotation>
-                        <xs:documentation><![CDATA[
-If the configFile already exists at the finalname location, whether or not to replace it.
-                        ]]></xs:documentation>
-                    </xs:annotation>
-                </xs:attribute>
-
-            </xs:extension>
-        </xs:simpleContent>
-    </xs:complexType>
-
-    <xs:complexType name="requirement">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Additional requirements of this feature.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:simpleContent>
-            <xs:extension base="xs:string">
-            </xs:extension>
-        </xs:simpleContent>
-    </xs:complexType>
-
-    <xs:complexType name="capability">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Additional capability of this feature.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:simpleContent>
-            <xs:extension base="xs:string">
-            </xs:extension>
-        </xs:simpleContent>
-    </xs:complexType>
-
-    <xs:simpleType name="featureName">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Feature name should be non empty string.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:restriction base="xs:string">
-            <xs:minLength value="1" />
-        </xs:restriction>
-    </xs:simpleType>
-
-    <xs:simpleType name="resolver">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Resolver to use. Karaf will look for OSGi service which have following properties:
-objectClass: org.apache.karaf.features.Resolver
-name: the value
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:restriction base="xs:string">
-            <xs:minLength value="1" />
-        </xs:restriction>
-    </xs:simpleType>
-    <xs:simpleType name="install">
-        <xs:annotation>
-            <xs:documentation><![CDATA[
-Installation mode. Can be either manual or auto. Specifies whether the feature should be automatically installed when
-dropped inside the deploy folder. Note: This attribute doesn't affect feature descriptors that are installed from the
-command line or as part of the org.apache.karaf.features.cfg.
-            ]]></xs:documentation>
-        </xs:annotation>
-        <xs:restriction base="xs:string">
-            <xs:minLength value="1" />
-        </xs:restriction>
-    </xs:simpleType>
-    <xs:element name="features" type="tns:features" />
-
-</xs:schema>

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/test/java/org/apache/karaf/features/ConditionalTest.java
----------------------------------------------------------------------
diff --git a/features/src/test/java/org/apache/karaf/features/ConditionalTest.java b/features/src/test/java/org/apache/karaf/features/ConditionalTest.java
deleted file mode 100644
index b103683..0000000
--- a/features/src/test/java/org/apache/karaf/features/ConditionalTest.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features;
-
-import junit.framework.TestCase;
-import org.apache.karaf.features.internal.service.RepositoryImpl;
-
-
-public class ConditionalTest extends TestCase {
-
-    public void testLoad() throws Exception {
-        RepositoryImpl r = new RepositoryImpl(getClass().getResource("internal/service/f06.xml").toURI());
-        // Check repo
-        Feature[] features = r.getFeatures();
-        assertNotNull(features);
-        assertEquals(1, features.length);
-        Feature feature = features[0];
-
-        assertNotNull(feature.getConditional());
-        assertEquals(2,feature.getConditional().size());
-
-        Conditional conditional = feature.getConditional().get(0);
-        assertNotNull(conditional.getCondition());
-        assertEquals(1,conditional.getCondition().size());
-        String dependency = conditional.getCondition().get(0);
-        assertNotNull(dependency);
-        assertEquals("http", dependency);
-        assertNotNull(conditional.getBundles());
-        assertEquals(1, feature.getConditional().get(0).getBundles().size());
-
-        conditional = feature.getConditional().get(1);
-        assertNotNull(conditional.getCondition());
-        assertEquals(1,conditional.getCondition().size());
-        dependency = conditional.getCondition().get(0);
-        assertNotNull(dependency);
-        assertEquals("req:osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(!(version>=1.7)))\"", dependency);
-
-        String wrapperName = "my6/1.5.3-beta-3".replaceAll("[^A-Za-z0-9 ]", "_");
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/test/java/org/apache/karaf/features/FeatureTest.java
----------------------------------------------------------------------
diff --git a/features/src/test/java/org/apache/karaf/features/FeatureTest.java b/features/src/test/java/org/apache/karaf/features/FeatureTest.java
deleted file mode 100644
index b7d4c27..0000000
--- a/features/src/test/java/org/apache/karaf/features/FeatureTest.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features;
-
-import junit.framework.TestCase;
-
-public class FeatureTest extends TestCase {
-	
-	public void testValueOf() {
-		Feature feature = org.apache.karaf.features.internal.model.Feature.valueOf("name" + org.apache.karaf.features.internal.model.Feature.SPLIT_FOR_NAME_AND_VERSION + "version");
-		assertEquals(feature.getName(), "name");
-		assertEquals(feature.getVersion(), "version");
-		feature = org.apache.karaf.features.internal.model.Feature.valueOf("name");
-		assertEquals(feature.getName(), "name");
-		assertEquals(feature.getVersion(), org.apache.karaf.features.internal.model.Feature.DEFAULT_VERSION);
-	}
-	
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/test/java/org/apache/karaf/features/FeaturesServiceTest.java
----------------------------------------------------------------------
diff --git a/features/src/test/java/org/apache/karaf/features/FeaturesServiceTest.java b/features/src/test/java/org/apache/karaf/features/FeaturesServiceTest.java
deleted file mode 100644
index a74e3d0..0000000
--- a/features/src/test/java/org/apache/karaf/features/FeaturesServiceTest.java
+++ /dev/null
@@ -1,429 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features;
-
-import static org.easymock.EasyMock.eq;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.reset;
-import static org.easymock.EasyMock.verify;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.List;
-import java.util.concurrent.CopyOnWriteArraySet;
-
-import org.apache.karaf.features.internal.service.FeaturesServiceImpl;
-import org.apache.karaf.features.internal.service.StateStorage;
-import org.easymock.EasyMock;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-
-public class FeaturesServiceTest extends TestBase {
-    private static final String FEATURE_WITH_INVALID_BUNDLE = "<features name='test' xmlns='http://karaf.apache.org/xmlns/features/v1.0.0'>"
-            + "  <feature name='f1'><bundle>%s</bundle><bundle>zfs:unknown</bundle></feature>"
-            + "  <feature name='f2'><bundle>%s</bundle></feature>"
-            + "</features>";
-
-    File dataFile;
-
-    @Before
-    public void setUp() throws IOException {
-        dataFile = File.createTempFile("features", null, null);
-    }
-    
-    private URI createTempRepo(String repoContent, Object ... variables) throws IOException {
-        File tmp = File.createTempFile("karaf", ".feature");
-        PrintWriter pw = new PrintWriter(new FileWriter(tmp));
-        pw.printf(repoContent, variables);
-        pw.close();
-        return tmp.toURI();
-    }
-
-    /*
-       TODO: migrate those tests
-
-    @Test
-    public void testInstallFeature() throws Exception {
-        URI uri = createTempRepo(
-                "<features name='test' xmlns='http://karaf.apache.org/xmlns/features/v1.0.0'>" 
-                + "  <feature name='f1'><bundle start='true'>bundle-f1</bundle></feature>"
-                + "</features>");
-
-        BundleManager bundleManager = EasyMock.createMock(BundleManager.class);
-        Bundle installedBundle = createDummyBundle(12345L, "bundle-f1", headers());
-        FeaturesServiceImpl svc = testAddRepository("bundle-f1", uri, bundleManager, installedBundle);
-        
-        reset(bundleManager);
-        
-        expect(bundleManager.installBundleIfNeeded(eq("bundle-f1"), eq(0), eq((String)null))).andReturn(new BundleInstallerResult(installedBundle, true));
-        expect(bundleManager.getDataFile(EasyMock.anyObject(String.class))).andReturn(dataFile);
-        ignoreRefreshes(bundleManager);
-        replay(bundleManager);
-        svc.installFeature("f1", org.apache.karaf.features.internal.model.Feature.DEFAULT_VERSION, EnumSet.of(FeaturesService.Option.NoAutoRefreshBundles));
-        verify(bundleManager);
-        
-        Feature[] installed = svc.listInstalledFeatures();
-        assertEquals(1, installed.length);
-        assertEquals("f1", installed[0].getName());
-    }
-
-    private FeaturesServiceImpl testAddRepository(String name, URI uri, BundleManager bundleManager,
-            Bundle installedBundle) throws IOException, BundleException, Exception {
-        expect(bundleManager.getDataFile(EasyMock.anyObject(String.class))).andReturn(dataFile);
-        expect(bundleManager.installBundleIfNeeded(eq(name), eq(0), eq((String)null))).andReturn(new BundleInstallerResult(installedBundle, true)).anyTimes();
-
-        replay(bundleManager);
-        FeaturesServiceImpl svc = new FeaturesServiceImpl(bundleManager);
-        svc.addRepository(uri);
-        Repository[] repositories = svc.listRepositories();
-        verify(bundleManager);
-
-        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).getLocation());
-        assertTrue(features[0].getBundles().get(0).isStart());
-        return svc;
-    }
-
-    @SuppressWarnings("unchecked")
-    @Test
-    public void testUninstallFeatureWithTwoVersions() throws Exception {
-        URI uri  = createTempRepo("<features name='test' xmlns='http://karaf.apache.org/xmlns/features/v1.0.0'>"
-                + "  <feature name='f1' version='0.1'><bundle>bundle-0.1</bundle></feature>"
-                + "  <feature name='f1' version='0.2'><bundle>bundle-0.1</bundle></feature>" 
-                + "</features>");
-
-        Bundle bundlef101 = createDummyBundle(12345L, "bundle-0.1", headers());
-
-        BundleManager bundleManager = EasyMock.createMock(BundleManager.class);
-        BundleContext bundleContext = EasyMock.createMock(BundleContext.class);
-        expect(bundleManager.getDataFile(EasyMock.anyObject(String.class))).andReturn(dataFile).anyTimes();
-        expect(bundleManager.installBundleIfNeeded("bundle-0.1", 0, null)).andReturn(new BundleInstallerResult(bundlef101, true));
-        expect(bundleManager.installBundleIfNeeded("bundle-0.1", 0, null)).andReturn(new BundleInstallerResult(bundlef101, false));
-        expect(bundleManager.getBundleContext()).andReturn(bundleContext);
-        ignoreRefreshes(bundleManager);
-        bundleManager.uninstall(Collections.EMPTY_LIST, true);
-        EasyMock.expectLastCall().times(2);
-        
-        
-        replay(bundleManager);
-        FeaturesServiceImpl svc = new FeaturesServiceImpl(bundleManager);
-        svc.addRepository(uri);
-
-        try {
-            svc.uninstallFeature("f1");
-            fail("Uninstall should have failed as feature is not installed");
-        } catch (Exception e) {
-            // ok
-        }
-
-        svc.installFeature("f1", "0.1", EnumSet.of(FeaturesService.Option.NoAutoRefreshBundles));
-        svc.installFeature("f1", "0.2", EnumSet.of(FeaturesService.Option.NoAutoRefreshBundles));
-
-        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");
-        verify(bundleManager);
-    }    
-    
-    @Test
-    public void testAddAndRemoveRepository() throws Exception {
-        URI uri = createTempRepo("<features name='test' xmlns='http://karaf.apache.org/xmlns/features/v1.0.0'>"
-                + "  <feature name='f1' version='0.1'><bundle>bundle-f1-0.1</bundle></feature>"
-                + "</features>");
-
-        BundleManager bundleManager = EasyMock.createMock(BundleManager.class);
-        expect(bundleManager.getDataFile(EasyMock.<String>anyObject())).andReturn(dataFile).anyTimes();
-
-        replay(bundleManager);
-        FeaturesServiceImpl svc = new FeaturesServiceImpl(bundleManager);
-        EasyMock.verify(bundleManager);
-
-        svc.addRepository(uri);                                                     
-        svc.removeRepository(uri);
-        verify(bundleManager);
-    }
-
-    // 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
-    @SuppressWarnings("unchecked")
-    @Test
-    public void testInstallFeatureWithDependantFeatures() throws Exception {
-        URI uri = createTempRepo("<features name='test' xmlns='http://karaf.apache.org/xmlns/features/v1.0.0'>"
-                                 + "  <feature name='f1' version='0.1'><feature version='0.1'>f2</feature><bundle>bundle-f1-0.1</bundle></feature>"
-                                 + "  <feature name='f2' version='0.1'><bundle>bundle-f2-0.1</bundle></feature>"
-                                 + "</features>");
-
-        BundleManager bundleManager = EasyMock.createMock(BundleManager.class);
-        BundleContext bundleContext = EasyMock.createMock(BundleContext.class);
-        Bundle bundlef101 = createDummyBundle(12345L, "bundle-f1-0.1", headers());
-        Bundle bundlef201 = createDummyBundle(54321L, "bundle-f2-0.1", headers());
-        expect(bundleManager.getDataFile(EasyMock.<String> anyObject())).andReturn(dataFile).anyTimes();
-        expect(bundleManager.installBundleIfNeeded("bundle-f1-0.1", 0, null))
-            .andReturn(new BundleInstallerResult(bundlef101, true));
-        expect(bundleManager.installBundleIfNeeded("bundle-f2-0.1", 0, null))
-            .andReturn(new BundleInstallerResult(bundlef201, true));
-        expect(bundleManager.getBundleContext()).andReturn(bundleContext).anyTimes();
-        expect(bundleContext.getBundle(12345)).andReturn(bundlef101).anyTimes();
-        ignoreRefreshes(bundleManager);
-        bundleManager.uninstall(Collections.EMPTY_LIST, true);
-       
-        EasyMock.expectLastCall().anyTimes();
-        replay(bundleManager);
-        
-        FeaturesServiceImpl svc = new FeaturesServiceImpl(bundleManager);
-        svc.addRepository(uri);
-        svc.installFeature("f1", "0.1");
-        svc.uninstallFeature("f1", "0.1");
-        verify(bundleManager);
-
-    }
-
-    @SuppressWarnings("unchecked")
-    private BundleManager prepareBundleManagerForInstallUninstall(String bundleUri, String bundlename) throws Exception {
-        BundleManager bundleManager = EasyMock.createMock(BundleManager.class);
-        BundleContext bundleContext = EasyMock.createMock(BundleContext.class);
-        Bundle installedBundle = createDummyBundle(12345L, bundlename, headers());
-        expect(bundleManager.getDataFile(EasyMock.<String>anyObject())).andReturn(dataFile).anyTimes();
-        expect(bundleManager.installBundleIfNeeded(bundleUri, 0, null)).andReturn(new BundleInstallerResult(installedBundle, true));
-        expect(bundleManager.getBundleContext()).andReturn(bundleContext);
-        ignoreRefreshes(bundleManager);
-        bundleManager.uninstall(Collections.EMPTY_LIST, true);
-        EasyMock.expectLastCall().times(2);
-        return bundleManager;
-    }
-
-    @Test
-    public void testInstallFeatureWithDependantFeaturesAndVersionWithoutPreinstall() throws Exception {
-        URI uri = createTempRepo("<features name='test' xmlns='http://karaf.apache.org/xmlns/features/v1.0.0'>"
-                + "  <feature name='f1' version='0.1'><feature version='0.1'>f2</feature></feature>"
-                + "  <feature name='f2' version='0.1'><bundle>bundle-0.1</bundle></feature>"
-                + "  <feature name='f2' version='0.2'><bundle>bundle-0.2</bundle></feature>"
-                + "</features>");
-
-        BundleManager bundleManager = prepareBundleManagerForInstallUninstall("bundle-0.1", "bundle-0.1");
-
-        replay(bundleManager);
-        FeaturesServiceImpl svc = new FeaturesServiceImpl(bundleManager);
-        svc.addRepository(uri);
-        svc.installFeature("f1", "0.1");
-        svc.uninstallFeature("f1", "0.1");
-        svc.uninstallFeature("f2", "0.1");
-        verify(bundleManager);
-    }
-
-    @Test
-    public void testInstallFeatureWithDependantFeaturesAndNoVersionWithoutPreinstall() throws Exception {
-        URI uri = createTempRepo("<features name='test' xmlns='http://karaf.apache.org/xmlns/features/v1.0.0'>"
-                + "  <feature name='f1' version='0.1'><feature>f2</feature></feature>"
-                + "  <feature name='f2' version='0.1'><bundle>bundle-0.1</bundle></feature>"
-                + "  <feature name='f2' version='0.2'><bundle>bundle-0.2</bundle></feature>"
-                + "</features>");
-
-        BundleManager bundleManager = prepareBundleManagerForInstallUninstall("bundle-0.2", "bundle-0.2");
-
-        replay(bundleManager);
-        FeaturesServiceImpl svc = new FeaturesServiceImpl(bundleManager);
-        svc.addRepository(uri);
-        svc.installFeature("f1", "0.1");
-        svc.uninstallFeature("f1", "0.1");
-        svc.uninstallFeature("f2", "0.2");
-        verify(bundleManager);
-    }
-
-    @SuppressWarnings("unchecked")
-    @Test
-    public void testInstallFeatureWithDependantFeaturesAndRangeWithoutPreinstall() throws Exception {
-        URI uri = createTempRepo("<features name='test' xmlns='http://karaf.apache.org/xmlns/features/v1.0.0'>"
-                + "  <feature name='f1' version='0.1'><feature version='[0.1,0.3)'>f2</feature></feature>"
-                + "  <feature name='f2' version='0.1'><bundle>bundle-0.1</bundle></feature>"
-                + "  <feature name='f2' version='0.2'><bundle>bundle-0.2</bundle></feature>"
-                + "</features>");
-
-        BundleManager bundleManager = EasyMock.createMock(BundleManager.class);
-        BundleContext bundleContext = EasyMock.createMock(BundleContext.class);
-        Bundle bundleVer02 = createDummyBundle(54321L, "bundleVer02", headers());
-        expect(bundleManager.getDataFile(EasyMock.<String>anyObject())).andReturn(dataFile).anyTimes();
-        expect(bundleManager.installBundleIfNeeded("bundle-0.2", 0, null)).andReturn(new BundleInstallerResult(bundleVer02, true));
-        expect(bundleManager.getBundleContext()).andReturn(bundleContext);
-        ignoreRefreshes(bundleManager);
-        bundleManager.uninstall(Collections.EMPTY_LIST, true);
-
-        EasyMock.expectLastCall().times(2);
-
-        replay(bundleManager);
-        FeaturesServiceImpl svc = new FeaturesServiceImpl(bundleManager);
-        svc.addRepository(uri);
-        svc.installFeature("f1", "0.1");
-        svc.uninstallFeature("f1", "0.1");
-        svc.uninstallFeature("f2", "0.2");
-        verify(bundleManager);
-    }
-
-    @SuppressWarnings("unchecked")
-    @Test
-    public void testInstallFeatureWithDependantFeaturesAndRangeWithPreinstall() throws Exception {
-        String bundleVer01Uri = "bundle-0.1";
-        String bundleVer02Uri = "bundle-0.2";
-
-        URI uri = createTempRepo("<features name='test' xmlns='http://karaf.apache.org/xmlns/features/v1.0.0'>"
-                + "<feature name='f1' version='0.1'><feature version='[0.1,0.3)'>f2</feature></feature>"
-                + "  <feature name='f2' version='0.1'><bundle>%s</bundle></feature>"
-                + "  <feature name='f2' version='0.2'><bundle>%s</bundle></feature>"
-                + "</features>", bundleVer01Uri, bundleVer02Uri);
-        
-        BundleContext bundleContext = EasyMock.createMock(BundleContext.class);
-        expect(bundleContext.getBundles()).andReturn(new Bundle[0]);
-        replay(bundleContext);
-
-        FeaturesServiceImpl svc = new FeaturesServiceImpl(null, bundleContext, new Storage(), null, null, null, null);
-        svc.addRepository(uri);
-        svc.installFeature("f2", "0.1");
-        svc.installFeature("f1", "0.1");
-        svc.uninstallFeature("f1", "0.1");
-        svc.uninstallFeature("f2", "0.1");
-
-        verify(bundleContext);
-    }
-    */
-
-    @Test
-    public void testGetFeaturesShouldHandleDifferentVersionPatterns() throws Exception {
-        URI uri = createTempRepo("<features name='test' xmlns='http://karaf.apache.org/xmlns/features/v1.0.0'>"
-                + "  <feature name='f1' version='0.1'><feature version='[0.1,0.3)'>f2</feature></feature>"
-                + "  <feature name='f2' version='0.1'><bundle>bundle1</bundle></feature>"
-                + "  <feature name='f2' version='0.2'><bundle>bundle2</bundle></feature>"
-                + "</features>");
-
-        FeaturesServiceImpl svc = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, null, null, null, null);
-        svc.addRepository(uri);
-
-        assertEquals(feature("f2", "0.2"), svc.getFeature("f2", "[0.1,0.3)"));
-        assertEquals(feature("f2", "0.2"), svc.getFeature("f2", "0.0.0"));
-        assertEquals(feature("f2", "0.2"), svc.getFeature("f2", "0.2"));
-        assertNull(svc.getFeature("f2", "0.3"));
-    }
-
-    @Test
-    public void testInstallBatchFeatureWithFailure() throws Exception {
-        String bundle1Uri = "file:bundle1";
-        String bundle2Uri = "file:bundle2";
-
-        URI uri = createTempRepo(FEATURE_WITH_INVALID_BUNDLE, bundle1Uri, bundle2Uri);
-        
-        BundleContext bundleContext = EasyMock.createMock(BundleContext.class);
-        expect(bundleContext.getBundles()).andReturn(new Bundle[0]);
-        replay(bundleContext);
-
-        FeaturesServiceImpl svc = new FeaturesServiceImpl(null, bundleContext, new Storage(), null, null, null, null, null, null, null);
-        svc.addRepository(uri);
-        try {
-            List<String> features = new ArrayList<String>();
-            for (Feature feature : svc.listFeatures()) {
-                features.add(feature.getId());
-            }
-            Collections.reverse(features);
-            svc.installFeatures(new CopyOnWriteArraySet<String>(features),
-                                EnumSet.noneOf(FeaturesService.Option.class));
-            fail("Call should have thrown an exception");
-        } catch (MalformedURLException e) {
-        }
-        verify(bundleContext);
-    }
-
-    /**
-     * This test checks schema validation of submited uri.
-     */
-    @Test
-    public void testSchemaValidation() throws Exception {
-        URI uri = createTempRepo("<features name='test' xmlns='http://karaf.apache.org/xmlns/features/v1.0.0'>"
-                + "  <featur><bundle>somebundle</bundle></featur></features>");
-
-        FeaturesServiceImpl svc = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, null, null, null, null);
-        try {
-            svc.addRepository(uri);
-            fail("exception expected");
-        } catch (Exception e) {
-            assertTrue(e.getMessage().contains("Unable to validate"));
-        }
-    }
-
-    /**
-     * This test checks feature service behavior with old, non namespaced descriptor.
-     */
-    @Test
-    public void testLoadOldFeatureFile() throws Exception {
-        URI uri = createTempRepo("<features name='test' xmlns='http://karaf.apache.org/xmlns/features/v1.0.0'>"
-                + "  <feature name='f1'><bundle>file:bundle1</bundle><bundle>file:bundle2</bundle></feature>"
-                + "</features>");
-
-        FeaturesServiceImpl svc = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, null, null, null, null);
-        svc.addRepository(uri);
-        Feature feature = svc.getFeature("f1");
-        Assert.assertNotNull("No feature named fi found", feature);        
-        List<BundleInfo> bundles = feature.getBundles();
-        Assert.assertEquals(2, bundles.size());
-    }
-
-    static class Storage extends StateStorage {
-        @Override
-        protected InputStream getInputStream() throws IOException {
-            return null;
-        }
-        @Override
-        protected OutputStream getOutputStream() throws IOException {
-            return null;
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/test/java/org/apache/karaf/features/RepositoryTest.java
----------------------------------------------------------------------
diff --git a/features/src/test/java/org/apache/karaf/features/RepositoryTest.java b/features/src/test/java/org/apache/karaf/features/RepositoryTest.java
deleted file mode 100644
index 164dc79..0000000
--- a/features/src/test/java/org/apache/karaf/features/RepositoryTest.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features;
-
-import java.net.URI;
-
-import junit.framework.TestCase;
-import org.apache.karaf.features.internal.resolver.FeatureResource;
-import org.apache.karaf.features.internal.service.RepositoryImpl;
-import org.osgi.resource.Resource;
-
-
-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(3, 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).getLocation());
-        assertEquals("b2", features[0].getBundles().get(1).getLocation());
-        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" + org.apache.karaf.features.internal.model.Feature.SPLIT_FOR_NAME_AND_VERSION + org.apache.karaf.features.internal.model.Feature.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).getLocation());
-        assertEquals("f3", features[2].getName());
-        assertNotNull(features[2].getConfigurationFiles());
-        assertEquals(1, features[2].getConfigurationFiles().size());
-        assertEquals("cf1", features[2].getConfigurationFiles().get(0).getFinalname());
-        assertEquals(true, features[2].getConfigurationFiles().get(0).isOverride());
-        assertEquals("cfloc", features[2].getConfigurationFiles().get(0).getLocation());
-    }
-
-    public void testLoadFormattedRepo() throws Exception {
-        RepositoryImpl r = new RepositoryImpl(getClass().getResource("repo2.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(3, 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).getLocation());
-        assertEquals("b2", features[0].getBundles().get(1).getLocation());
-        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" + org.apache.karaf.features.internal.model.Feature.SPLIT_FOR_NAME_AND_VERSION + org.apache.karaf.features.internal.model.Feature.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).getLocation());
-        assertEquals("f3", features[2].getName());
-        assertNotNull(features[2].getConfigurationFiles());
-        assertEquals(1, features[2].getConfigurationFiles().size());
-        assertEquals("cf1", features[2].getConfigurationFiles().get(0).getFinalname());
-        assertEquals(true, features[2].getConfigurationFiles().get(0).isOverride());
-        assertEquals("cfloc", features[2].getConfigurationFiles().get(0).getLocation());
-    }
-
-    public void testLoadRepoWithCapabilitiesAndRequirement() throws Exception {
-        RepositoryImpl r = new RepositoryImpl(getClass().getResource("repo3.xml").toURI());
-        // Check features
-        Feature[] features = r.getFeatures();
-        assertNotNull(features);
-        assertEquals(1, features.length);
-        assertNotNull(features[0]);
-        assertEquals("f1", features[0].getName());
-        assertEquals(1, features[0].getCapabilities().size());
-        assertEquals("cap", features[0].getCapabilities().get(0).getValue().trim());
-        assertEquals(1, features[0].getRequirements().size());
-        assertEquals("req", features[0].getRequirements().get(0).getValue().trim());
-
-        Resource res = FeatureResource.build(features[0], null, null);
-        assertEquals(1, res.getCapabilities("cap").size());
-        assertEquals(1, res.getRequirements("req").size());
-    }
-
-    public void testShowWrongUriInException() throws Exception {
-        String uri = "src/test/resources/org/apache/karaf/shell/features/repo1.xml";
-        RepositoryImpl r = new RepositoryImpl(new URI(uri));
-        try {
-            r.load();
-        } catch (Exception e) {
-            assertTrue(e.getMessage().contains(uri));
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/test/java/org/apache/karaf/features/TestBase.java
----------------------------------------------------------------------
diff --git a/features/src/test/java/org/apache/karaf/features/TestBase.java b/features/src/test/java/org/apache/karaf/features/TestBase.java
deleted file mode 100644
index ac8f3d9..0000000
--- a/features/src/test/java/org/apache/karaf/features/TestBase.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features;
-
-import java.util.Arrays;
-import java.util.Dictionary;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Hashtable;
-import java.util.Map;
-import java.util.Set;
-
-import org.easymock.EasyMock;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.startlevel.BundleStartLevel;
-
-import static java.util.Arrays.asList;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-
-public class TestBase {
-    public Bundle createDummyBundle(long id, final String symbolicName, Dictionary<String,String> headers) {
-        Bundle bundle = EasyMock.createNiceMock(Bundle.class);
-        
-        // Be aware that this means all bundles are treated as different
-        expect(bundle.compareTo(EasyMock.<Bundle>anyObject())).andReturn(1).anyTimes();
-
-        expect(bundle.getBundleId()).andReturn(id).anyTimes();
-        expect(bundle.getSymbolicName()).andReturn(symbolicName).anyTimes();
-        expect(bundle.getHeaders()).andReturn(headers).anyTimes();
-        BundleStartLevel sl = EasyMock.createMock(BundleStartLevel.class);
-        expect(sl.isPersistentlyStarted()).andReturn(true).anyTimes();
-        expect(bundle.adapt(BundleStartLevel.class)).andReturn(sl).anyTimes();
-        replay(bundle, sl);
-        return bundle;
-    }
-    
-    public Dictionary<String, String> headers(String ... keyAndHeader) {
-        Hashtable<String, String> headersTable = new Hashtable<String, String>();
-        int c=0;
-        while (c < keyAndHeader.length) {
-            String key = keyAndHeader[c++];
-            String value = keyAndHeader[c++];
-            headersTable.put(key, value);
-        }
-        return headersTable;
-    }
-    
-    public Map<String, Map<String, Feature>> features(Feature ... features) {
-        final Map<String, Map<String, Feature>> featuresMap = new HashMap<String, Map<String,Feature>>();
-        for (Feature feature : features) {
-            Map<String, Feature> featureVersion = getOrCreate(featuresMap, feature);
-            featureVersion.put(feature.getVersion(), feature);
-        }
-        return featuresMap;
-    }
-    
-    private Map<String, Feature> getOrCreate(final Map<String, Map<String, Feature>> featuresMap, Feature feature) {
-        Map<String, Feature> featureVersion = featuresMap.get(feature.getName());
-        if (featureVersion == null) {
-            featureVersion = new HashMap<String, Feature>();
-            featuresMap.put(feature.getName(), featureVersion);
-        }
-        return featureVersion;
-    }
-
-    public Feature feature(String name) {
-        return feature(name, null);
-    }
-
-    public Feature feature(String name, String version) {
-        return new org.apache.karaf.features.internal.model.Feature(name, version);
-    }
-    
-    public Set<Bundle> setOf(Bundle ... elements) {
-        return new HashSet<Bundle>(Arrays.asList(elements));
-    }
-    
-    public Set<Long> setOf(Long ... elements) {
-        return new HashSet<Long>(Arrays.asList(elements));
-    }
-    
-    public Set<String> setOf(String ... elements) {
-        return new HashSet<String>(asList(elements));
-    }
-    
-    public Set<Feature> setOf(Feature ... elements) {
-        return new HashSet<Feature>(Arrays.asList(elements));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/test/java/org/apache/karaf/features/internal/service/BootFeaturesInstallerTest.java
----------------------------------------------------------------------
diff --git a/features/src/test/java/org/apache/karaf/features/internal/service/BootFeaturesInstallerTest.java b/features/src/test/java/org/apache/karaf/features/internal/service/BootFeaturesInstallerTest.java
deleted file mode 100644
index 31f4f29..0000000
--- a/features/src/test/java/org/apache/karaf/features/internal/service/BootFeaturesInstallerTest.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.service;
-
-import static java.util.Arrays.asList;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-import static org.junit.Assert.fail;
-
-import java.net.URI;
-import java.util.EnumSet;
-
-import org.apache.karaf.features.Feature;
-import org.apache.karaf.features.FeaturesService.Option;
-import org.apache.karaf.features.TestBase;
-import org.easymock.EasyMock;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class BootFeaturesInstallerTest extends TestBase {
-
-    @Test
-    @SuppressWarnings("unchecked")
-    public void testParser() {
-        BootFeaturesInstaller installer = new BootFeaturesInstaller(null, null, "", "", false);
-        Assert.assertEquals(asList(setOf("test1", "test2"),setOf("test3")), installer.parseBootFeatures("(test1, test2), test3"));
-        Assert.assertEquals(asList(setOf("test1", "test2", "test3")), installer.parseBootFeatures("test1, test2, test3"));
-    }
-    
-    @Test
-    public void testDefaultBootFeatures() throws Exception  {
-        FeaturesServiceImpl impl = EasyMock.createMock(FeaturesServiceImpl.class);
-
-        impl.installFeatures(setOf("config", "standard", "region"), EnumSet.of(Option.NoFailOnFeatureNotFound));
-        EasyMock.expectLastCall();
-
-        impl.bootDone();
-        EasyMock.expectLastCall();
-
-        replay(impl);
-        BootFeaturesInstaller bootFeatures = new BootFeaturesInstaller(null, impl, "", "config,standard,region", false);
-        bootFeatures.installBootFeatures();
-        EasyMock.verify(impl);        
-    }
-
-    @Test
-    public void testStagedBoot() throws Exception  {
-        FeaturesServiceImpl impl = EasyMock.createStrictMock(FeaturesServiceImpl.class);
-
-        impl.installFeatures(setOf("transaction"), EnumSet.of(Option.NoFailOnFeatureNotFound));
-        EasyMock.expectLastCall();
-        impl.installFeatures(setOf("ssh"), EnumSet.of(Option.NoFailOnFeatureNotFound));
-        EasyMock.expectLastCall();
-
-        impl.bootDone();
-        EasyMock.expectLastCall();
-
-        replay(impl);
-        BootFeaturesInstaller bootFeatures = new BootFeaturesInstaller(null, impl , "", "(transaction), ssh", false);
-        bootFeatures.installBootFeatures();
-        EasyMock.verify(impl);        
-    }
-
-    @Test
-    public void testStartDoesNotFailWithOneInvalidUri() throws Exception {
-        FeaturesServiceImpl impl = EasyMock.createStrictMock(FeaturesServiceImpl.class);
-        impl.addRepository(URI.create("mvn:inexistent/features/1.0/xml/features"));
-        EasyMock.expectLastCall().andThrow(new IllegalArgumentException());
-
-        impl.bootDone();
-        EasyMock.expectLastCall();
-
-        replay(impl);
-        BootFeaturesInstaller bootFeatures = new BootFeaturesInstaller(null, impl, "mvn:inexistent/features/1.0/xml/features", "", false);
-        bootFeatures.installBootFeatures();
-        EasyMock.verify(impl);
-    }
-
-}


[03/33] git commit: [KARAF-2852] Merge jdbc/core and jdbc/command

Posted by gn...@apache.org.
[KARAF-2852] Merge jdbc/core and jdbc/command


Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/a9b763f2
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/a9b763f2
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/a9b763f2

Branch: refs/heads/master
Commit: a9b763f2b759d0d018697cdac0f21f4a09445b5b
Parents: 0f53437
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Fri Apr 11 08:38:47 2014 +0200
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Fri Apr 11 19:20:02 2014 +0200

----------------------------------------------------------------------
 .../enterprise/src/main/feature/feature.xml     |   1 -
 jdbc/NOTICE                                     |  71 ++++++
 jdbc/command/NOTICE                             |  71 ------
 jdbc/command/pom.xml                            |  87 -------
 .../karaf/jdbc/command/CreateCommand.java       |  61 -----
 .../karaf/jdbc/command/DataSourcesCommand.java  |  50 ----
 .../karaf/jdbc/command/DeleteCommand.java       |  39 ----
 .../karaf/jdbc/command/ExecuteCommand.java      |  42 ----
 .../apache/karaf/jdbc/command/InfoCommand.java  |  53 -----
 .../karaf/jdbc/command/JdbcCommandSupport.java  |  36 ---
 .../apache/karaf/jdbc/command/QueryCommand.java |  64 -----
 .../karaf/jdbc/command/TablesCommand.java       |  61 -----
 .../DataSourcesFileNameCompleter.java           |  59 -----
 .../completers/DataSourcesNameCompleter.java    |  59 -----
 .../src/main/resources/OSGI-INF/bundle.info     |  26 ---
 jdbc/core/NOTICE                                |  71 ------
 jdbc/core/pom.xml                               |  87 -------
 .../java/org/apache/karaf/jdbc/JdbcMBean.java   |  96 --------
 .../java/org/apache/karaf/jdbc/JdbcService.java |  95 --------
 .../karaf/jdbc/internal/JdbcConnector.java      | 146 ------------
 .../karaf/jdbc/internal/JdbcMBeanImpl.java      | 168 --------------
 .../karaf/jdbc/internal/JdbcServiceImpl.java    | 231 -------------------
 .../resources/OSGI-INF/blueprint/jdbc-core.xml  |  41 ----
 .../src/main/resources/OSGI-INF/bundle.info     |  18 --
 .../karaf/jdbc/internal/datasource-db2.xml      |  32 ---
 .../karaf/jdbc/internal/datasource-derby.xml    |  39 ----
 .../karaf/jdbc/internal/datasource-generic.xml  | 141 -----------
 .../karaf/jdbc/internal/datasource-h2.xml       |  31 ---
 .../karaf/jdbc/internal/datasource-hsql.xml     |  31 ---
 .../karaf/jdbc/internal/datasource-mssql.xml    |  32 ---
 .../karaf/jdbc/internal/datasource-mysql.xml    |  31 ---
 .../karaf/jdbc/internal/datasource-oracle.xml   |  31 ---
 .../karaf/jdbc/internal/datasource-postgres.xml |  34 ---
 jdbc/pom.xml                                    |  71 +++++-
 .../java/org/apache/karaf/jdbc/JdbcMBean.java   |  96 ++++++++
 .../java/org/apache/karaf/jdbc/JdbcService.java |  95 ++++++++
 .../karaf/jdbc/command/CreateCommand.java       |  61 +++++
 .../karaf/jdbc/command/DataSourcesCommand.java  |  50 ++++
 .../karaf/jdbc/command/DeleteCommand.java       |  39 ++++
 .../karaf/jdbc/command/ExecuteCommand.java      |  42 ++++
 .../apache/karaf/jdbc/command/InfoCommand.java  |  53 +++++
 .../karaf/jdbc/command/JdbcCommandSupport.java  |  36 +++
 .../apache/karaf/jdbc/command/QueryCommand.java |  64 +++++
 .../karaf/jdbc/command/TablesCommand.java       |  61 +++++
 .../DataSourcesFileNameCompleter.java           |  59 +++++
 .../completers/DataSourcesNameCompleter.java    |  59 +++++
 .../karaf/jdbc/internal/JdbcConnector.java      | 146 ++++++++++++
 .../karaf/jdbc/internal/JdbcMBeanImpl.java      | 168 ++++++++++++++
 .../karaf/jdbc/internal/JdbcServiceImpl.java    | 231 +++++++++++++++++++
 .../resources/OSGI-INF/blueprint/jdbc-core.xml  |  41 ++++
 jdbc/src/main/resources/OSGI-INF/bundle.info    |  18 ++
 .../karaf/jdbc/internal/datasource-db2.xml      |  32 +++
 .../karaf/jdbc/internal/datasource-derby.xml    |  39 ++++
 .../karaf/jdbc/internal/datasource-generic.xml  | 141 +++++++++++
 .../karaf/jdbc/internal/datasource-h2.xml       |  31 +++
 .../karaf/jdbc/internal/datasource-hsql.xml     |  31 +++
 .../karaf/jdbc/internal/datasource-mssql.xml    |  32 +++
 .../karaf/jdbc/internal/datasource-mysql.xml    |  31 +++
 .../karaf/jdbc/internal/datasource-oracle.xml   |  31 +++
 .../karaf/jdbc/internal/datasource-postgres.xml |  34 +++
 60 files changed, 1855 insertions(+), 2072 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/assemblies/features/enterprise/src/main/feature/feature.xml
----------------------------------------------------------------------
diff --git a/assemblies/features/enterprise/src/main/feature/feature.xml b/assemblies/features/enterprise/src/main/feature/feature.xml
index c68017f..24c4136 100644
--- a/assemblies/features/enterprise/src/main/feature/feature.xml
+++ b/assemblies/features/enterprise/src/main/feature/feature.xml
@@ -190,7 +190,6 @@
         <bundle>mvn:commons-pool/commons-pool/${commons-pool.version}</bundle>
         <bundle>mvn:commons-dbcp/commons-dbcp/${commons-dbcp.version}</bundle>
         <bundle>mvn:org.apache.karaf.jdbc/org.apache.karaf.jdbc.core/${project.version}</bundle>
-        <bundle>mvn:org.apache.karaf.jdbc/org.apache.karaf.jdbc.command/${project.version}</bundle>
     </feature>
 
     <feature name="jms" description="JMS service and commands" version="${project.version}" resolver="(obr)">

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/NOTICE
----------------------------------------------------------------------
diff --git a/jdbc/NOTICE b/jdbc/NOTICE
new file mode 100644
index 0000000..b70f1f9
--- /dev/null
+++ b/jdbc/NOTICE
@@ -0,0 +1,71 @@
+Apache Karaf
+Copyright 2010-2014 The Apache Software Foundation
+
+
+I. Included Software
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2010).
+Licensed under the Apache License 2.0.
+
+This product includes software developed at
+OW2 (http://www.ow2.org/).
+Licensed under the BSD License.
+
+This product includes software developed at
+OPS4J (http://www.ops4j.org/).
+Licensed under the Apache License 2.0.
+
+This product includes software developed at
+Eclipse Foundation (http://www.eclipse.org/).
+Licensed under the EPL.
+
+This product includes software written by
+Antony Lesuisse.
+Licensed under Public Domain.
+
+
+II. Used Software
+
+This product uses software developed at
+FUSE Source (http://www.fusesource.org/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+AOP Alliance (http://aopalliance.sourceforge.net/).
+Licensed under the Public Domain.
+
+This product uses software developed at
+Tanuki Software (http://www.tanukisoftware.com/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+Jasypt (http://jasypt.sourceforge.net/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+JLine (http://jline.sourceforge.net).
+Licensed under the BSD License.
+
+This product uses software developed at
+SLF4J (http://www.slf4j.org/).
+Licensed under the MIT License.
+
+This product uses software developed at
+SpringSource (http://www.springsource.org/).
+Licensed under the Apache License 2.0.
+
+This product includes software from http://www.json.org.
+Copyright (c) 2002 JSON.org
+
+
+III. License Summary
+- Apache License 2.0
+- BSD License
+- EPL License
+- MIT License

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/command/NOTICE
----------------------------------------------------------------------
diff --git a/jdbc/command/NOTICE b/jdbc/command/NOTICE
deleted file mode 100644
index b70f1f9..0000000
--- a/jdbc/command/NOTICE
+++ /dev/null
@@ -1,71 +0,0 @@
-Apache Karaf
-Copyright 2010-2014 The Apache Software Foundation
-
-
-I. Included Software
-
-This product includes software developed at
-The Apache Software Foundation (http://www.apache.org/).
-Licensed under the Apache License 2.0.
-
-This product uses software developed at
-The OSGi Alliance (http://www.osgi.org/).
-Copyright (c) OSGi Alliance (2000, 2010).
-Licensed under the Apache License 2.0.
-
-This product includes software developed at
-OW2 (http://www.ow2.org/).
-Licensed under the BSD License.
-
-This product includes software developed at
-OPS4J (http://www.ops4j.org/).
-Licensed under the Apache License 2.0.
-
-This product includes software developed at
-Eclipse Foundation (http://www.eclipse.org/).
-Licensed under the EPL.
-
-This product includes software written by
-Antony Lesuisse.
-Licensed under Public Domain.
-
-
-II. Used Software
-
-This product uses software developed at
-FUSE Source (http://www.fusesource.org/).
-Licensed under the Apache License 2.0.
-
-This product uses software developed at
-AOP Alliance (http://aopalliance.sourceforge.net/).
-Licensed under the Public Domain.
-
-This product uses software developed at
-Tanuki Software (http://www.tanukisoftware.com/).
-Licensed under the Apache License 2.0.
-
-This product uses software developed at
-Jasypt (http://jasypt.sourceforge.net/).
-Licensed under the Apache License 2.0.
-
-This product uses software developed at
-JLine (http://jline.sourceforge.net).
-Licensed under the BSD License.
-
-This product uses software developed at
-SLF4J (http://www.slf4j.org/).
-Licensed under the MIT License.
-
-This product uses software developed at
-SpringSource (http://www.springsource.org/).
-Licensed under the Apache License 2.0.
-
-This product includes software from http://www.json.org.
-Copyright (c) 2002 JSON.org
-
-
-III. License Summary
-- Apache License 2.0
-- BSD License
-- EPL License
-- MIT License

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/command/pom.xml
----------------------------------------------------------------------
diff --git a/jdbc/command/pom.xml b/jdbc/command/pom.xml
deleted file mode 100644
index b459a13..0000000
--- a/jdbc/command/pom.xml
+++ /dev/null
@@ -1,87 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-
-    <!--
-
-        Licensed to the Apache Software Foundation (ASF) under one or more
-        contributor license agreements.  See the NOTICE file distributed with
-        this work for additional information regarding copyright ownership.
-        The ASF licenses this file to You under the Apache License, Version 2.0
-        (the "License"); you may not use this file except in compliance with
-        the License.  You may obtain a copy of the License at
-
-            http://www.apache.org/licenses/LICENSE-2.0
-
-        Unless required by applicable law or agreed to in writing, software
-        distributed under the License is distributed on an "AS IS" BASIS,
-        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-        See the License for the specific language governing permissions and
-        limitations under the License.
-    -->
-
-    <modelVersion>4.0.0</modelVersion>
-
-    <parent>
-        <groupId>org.apache.karaf.jdbc</groupId>
-        <artifactId>jdbc</artifactId>
-        <version>4.0.0-SNAPSHOT</version>
-        <relativePath>../pom.xml</relativePath>
-    </parent>
-
-    <artifactId>org.apache.karaf.jdbc.command</artifactId>
-    <packaging>bundle</packaging>
-    <name>Apache Karaf :: JDBC :: Command</name>
-    <description>This bundle provides shell commands to manipulate the JDBC service</description>
-
-    <properties>
-        <appendedResourcesDirectory>${basedir}/../../etc/appended-resources</appendedResourcesDirectory>
-    </properties>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.apache.karaf.jdbc</groupId>
-            <artifactId>org.apache.karaf.jdbc.core</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.core</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.karaf.shell</groupId>
-            <artifactId>org.apache.karaf.shell.core</artifactId>
-        </dependency>
-    </dependencies>
-
-    <build>
-        <resources>
-            <resource>
-                <directory>${project.basedir}/src/main/resources</directory>
-                <includes>
-                    <include>**/*</include>
-                </includes>
-            </resource>
-            <resource>
-                <directory>${project.basedir}/src/main/resources</directory>
-                <filtering>true</filtering>
-                <includes>
-                    <include>**/*.info</include>
-                </includes>
-            </resource>
-        </resources>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-bundle-plugin</artifactId>
-                <configuration>
-                    <instructions>
-                        <Export-Package>!*</Export-Package>
-                        <Karaf-Commands>*</Karaf-Commands>
-                    </instructions>
-                </configuration>
-            </plugin>
-        </plugins>
-    </build>
-
-</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/CreateCommand.java
----------------------------------------------------------------------
diff --git a/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/CreateCommand.java b/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/CreateCommand.java
deleted file mode 100644
index 89ed49c..0000000
--- a/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/CreateCommand.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jdbc.command;
-
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.Completion;
-import org.apache.karaf.shell.api.action.Option;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.karaf.shell.support.completers.StringsCompleter;
-
-@Command(scope = "jdbc", name = "create", description = "Create a JDBC datasource")
-@Service
-public class CreateCommand extends JdbcCommandSupport {
-
-    @Argument(index = 0, name = "name", description = "The JDBC datasource name", required = true, multiValued = false)
-    String name;
-
-    @Option(name = "-t", aliases = { "--type" }, description = "The JDBC datasource type (generic, MySQL, Oracle, Postgres, H2, HSQL, Derby, MSSQL)", required = false, multiValued = false)
-    @Completion(value = StringsCompleter.class, values = { "db2", "derby", "generic", "h2", "hsql", "mysql", "oracle", "postgres", "mssql" })
-    String type;
-
-    @Option(name = "-d", aliases = { "--driver" }, description = "The classname of the JDBC driver to use. NB: this option is used only the type generic", required = false, multiValued = false)
-    String driver;
-
-    @Option(name = "-v", aliases = { "--version" }, description = "The version of the driver to use", required = false, multiValued = false)
-    String version;
-
-    @Option(name = "-url", description = "The JDBC URL to use", required = false, multiValued = false)
-    String url;
-
-    @Option(name = "-u", aliases = { "--username" }, description = "The database username", required = false, multiValued = false)
-    String username;
-
-    @Option(name = "-p", aliases = { "--password" }, description = "The database password", required = false, multiValued = false)
-    String password;
-
-    @Option(name = "-i", aliases = { "--install-bundles" }, description = "Try to install the bundles providing the JDBC driver", required = false, multiValued = false)
-    boolean installBundles = false;
-
-    @Override
-    public Object execute() throws Exception {
-        this.getJdbcService().create(name, type, driver, version, url, username, password, installBundles);
-        return null;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/DataSourcesCommand.java
----------------------------------------------------------------------
diff --git a/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/DataSourcesCommand.java b/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/DataSourcesCommand.java
deleted file mode 100644
index cb3edad..0000000
--- a/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/DataSourcesCommand.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jdbc.command;
-
-import java.util.List;
-import java.util.Map;
-
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.karaf.shell.support.table.ShellTable;
-
-@Command(scope = "jdbc", name = "datasources", description = "List the JDBC datasources")
-@Service
-public class DataSourcesCommand extends JdbcCommandSupport {
-
-    @Override
-    public Object execute() throws Exception {
-        ShellTable table = new ShellTable();
-
-        table.column("Name");
-        table.column("Product");
-        table.column("Version");
-        table.column("URL");
-
-        List<String> datasources = this.getJdbcService().datasources();
-        for (String datasource : datasources) {
-            Map<String, String> info = this.getJdbcService().info(datasource);
-            table.addRow().addContent(datasource, info.get("db.product"), info.get("db.version"), info.get("url"));
-        }
-
-        table.print(System.out);
-
-        return null;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/DeleteCommand.java
----------------------------------------------------------------------
diff --git a/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/DeleteCommand.java b/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/DeleteCommand.java
deleted file mode 100644
index 6bf7236..0000000
--- a/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/DeleteCommand.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jdbc.command;
-
-import org.apache.karaf.jdbc.command.completers.DataSourcesFileNameCompleter;
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.Completion;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-
-@Command(scope = "jdbc", name = "delete", description = "Delete a JDBC datasource")
-@Service
-public class DeleteCommand extends JdbcCommandSupport {
-
-    @Argument(index = 0, name = "name", description = "The JDBC datasource name (the one used at creation time)", required = true, multiValued = false)
-    @Completion(DataSourcesFileNameCompleter.class)
-    String name;
-
-    @Override
-    public Object execute() throws Exception {
-        this.getJdbcService().delete(name);
-        return null;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/ExecuteCommand.java
----------------------------------------------------------------------
diff --git a/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/ExecuteCommand.java b/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/ExecuteCommand.java
deleted file mode 100644
index 480ab51..0000000
--- a/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/ExecuteCommand.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jdbc.command;
-
-import org.apache.karaf.jdbc.command.completers.DataSourcesNameCompleter;
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.Completion;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-
-@Command(scope = "jdbc", name = "execute", description = "Execute a SQL command on a given JDBC datasource")
-@Service
-public class ExecuteCommand extends JdbcCommandSupport {
-
-    @Argument(index = 0, name = "datasource", description = "The JDBC datasource", required = true, multiValued = false)
-    @Completion(DataSourcesNameCompleter.class)
-    String datasource;
-
-    @Argument(index = 1, name = "command", description = "The SQL command to execute", required = true, multiValued = false)
-    String command;
-
-    @Override
-    public Object execute() throws Exception {
-        this.getJdbcService().execute(datasource, command);
-        return null;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/InfoCommand.java
----------------------------------------------------------------------
diff --git a/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/InfoCommand.java b/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/InfoCommand.java
deleted file mode 100644
index e53bbab..0000000
--- a/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/InfoCommand.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jdbc.command;
-
-import org.apache.karaf.jdbc.command.completers.DataSourcesNameCompleter;
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.Completion;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.karaf.shell.support.table.ShellTable;
-
-import java.util.Map;
-
-@Command(scope = "jdbc", name = "info", description = "Display details about a JDBC datasource")
-@Service
-public class InfoCommand extends JdbcCommandSupport {
-
-    @Argument(index = 0, name = "datasource", description = "The JDBC datasource name", required = true, multiValued = false)
-    @Completion(DataSourcesNameCompleter.class)
-    String datasource;
-
-    @Override
-    public Object execute() throws Exception {
-        ShellTable table = new ShellTable();
-
-        table.column("Property");
-        table.column("Value");
-
-        Map<String, String> info = this.getJdbcService().info(datasource);
-        for (String property : info.keySet()) {
-            table.addRow().addContent(property, info.get(property));
-        }
-
-        table.print(System.out);
-
-        return null;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/JdbcCommandSupport.java
----------------------------------------------------------------------
diff --git a/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/JdbcCommandSupport.java b/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/JdbcCommandSupport.java
deleted file mode 100644
index cf1eb58..0000000
--- a/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/JdbcCommandSupport.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jdbc.command;
-
-import org.apache.karaf.jdbc.JdbcService;
-import org.apache.karaf.shell.api.action.Action;
-import org.apache.karaf.shell.api.action.lifecycle.Reference;
-
-public abstract class JdbcCommandSupport implements Action {
-
-    @Reference
-    private JdbcService jdbcService;
-
-    public JdbcService getJdbcService() {
-        return jdbcService;
-    }
-
-    public void setJdbcService(JdbcService jdbcService) {
-        this.jdbcService = jdbcService;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/QueryCommand.java
----------------------------------------------------------------------
diff --git a/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/QueryCommand.java b/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/QueryCommand.java
deleted file mode 100644
index 297288b..0000000
--- a/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/QueryCommand.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jdbc.command;
-
-import java.util.List;
-import java.util.Map;
-
-import org.apache.karaf.jdbc.command.completers.DataSourcesNameCompleter;
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.Completion;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.karaf.shell.support.table.Row;
-import org.apache.karaf.shell.support.table.ShellTable;
-
-@Command(scope = "jdbc", name = "query", description = "Execute a SQL query on a JDBC datasource")
-@Service
-public class QueryCommand extends JdbcCommandSupport {
-
-    @Argument(index = 0, name = "datasource", description = "The JDBC datasource to use", required = true, multiValued = false)
-    @Completion(DataSourcesNameCompleter.class)
-    String datasource;
-
-    @Argument(index = 1, name = "query", description = "The SQL query to execute", required = true, multiValued = false)
-    String query;
-
-    @Override
-    public Object execute() throws Exception {
-        ShellTable table = new ShellTable();
-
-        Map<String, List<String>> map = this.getJdbcService().query(datasource, query);
-        int rowCount = 0;
-        for (String column : map.keySet()) {
-            table.column(column);
-            rowCount = map.get(column).size();
-        }
-
-        for (int i = 0; i < rowCount; i++) {
-            Row row = table.addRow();
-            for (String column : map.keySet()) {
-                row.addContent(map.get(column).get(i));
-            }
-        }
-
-        table.print(System.out);
-
-        return null;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/TablesCommand.java
----------------------------------------------------------------------
diff --git a/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/TablesCommand.java b/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/TablesCommand.java
deleted file mode 100644
index 04baa70..0000000
--- a/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/TablesCommand.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jdbc.command;
-
-import java.util.List;
-import java.util.Map;
-
-import org.apache.karaf.jdbc.command.completers.DataSourcesNameCompleter;
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.Completion;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.karaf.shell.support.table.Row;
-import org.apache.karaf.shell.support.table.ShellTable;
-
-@Command(scope = "jdbc", name = "tables", description = "List the tables on a given JDBC datasource")
-@Service
-public class TablesCommand extends JdbcCommandSupport {
-
-    @Argument(index = 0, name = "datasource", description = "The JDBC datasource to use", required = true, multiValued = false)
-    @Completion(DataSourcesNameCompleter.class)
-    String datasource;
-
-    @Override
-    public Object execute() throws Exception {
-        ShellTable table = new ShellTable();
-
-        Map<String, List<String>> map = this.getJdbcService().tables(datasource);
-        int rowCount = 0;
-        for (String column : map.keySet()) {
-            table.column(column);
-            rowCount = map.get(column).size();
-        }
-
-        for (int i = 0; i < rowCount; i++) {
-            Row row = table.addRow();
-            for (String column : map.keySet()) {
-                row.addContent(map.get(column).get(i));
-            }
-        }
-
-        table.print(System.out);
-
-        return null;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/completers/DataSourcesFileNameCompleter.java
----------------------------------------------------------------------
diff --git a/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/completers/DataSourcesFileNameCompleter.java b/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/completers/DataSourcesFileNameCompleter.java
deleted file mode 100644
index 8ba0fe9..0000000
--- a/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/completers/DataSourcesFileNameCompleter.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jdbc.command.completers;
-
-import org.apache.karaf.jdbc.JdbcService;
-import org.apache.karaf.shell.api.action.lifecycle.Reference;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.karaf.shell.api.console.CommandLine;
-import org.apache.karaf.shell.api.console.Completer;
-import org.apache.karaf.shell.api.console.Session;
-import org.apache.karaf.shell.support.completers.StringsCompleter;
-
-import java.util.List;
-
-/**
- * Completer on the JDBC datasources file name.
- */
-@Service
-public class DataSourcesFileNameCompleter implements Completer {
-
-    @Reference
-    private JdbcService jdbcService;
-
-    @Override
-    public int complete(Session session, CommandLine commandLine, List<String> candidates) {
-        StringsCompleter delegate = new StringsCompleter();
-        try {
-            for (String datasourceFileName : jdbcService.datasourceFileNames()) {
-                delegate.getStrings().add(datasourceFileName.replace("datasource-", "").replace(".xml", ""));
-            }
-        } catch (Exception e) {
-            // nothing to do
-        }
-        return delegate.complete(session, commandLine, candidates);
-    }
-
-    public JdbcService getJdbcService() {
-        return jdbcService;
-    }
-
-    public void setJdbcService(JdbcService jdbcService) {
-        this.jdbcService = jdbcService;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/completers/DataSourcesNameCompleter.java
----------------------------------------------------------------------
diff --git a/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/completers/DataSourcesNameCompleter.java b/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/completers/DataSourcesNameCompleter.java
deleted file mode 100644
index 238910f..0000000
--- a/jdbc/command/src/main/java/org/apache/karaf/jdbc/command/completers/DataSourcesNameCompleter.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jdbc.command.completers;
-
-import org.apache.karaf.jdbc.JdbcService;
-import org.apache.karaf.shell.api.action.lifecycle.Reference;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.karaf.shell.api.console.CommandLine;
-import org.apache.karaf.shell.api.console.Completer;
-import org.apache.karaf.shell.api.console.Session;
-import org.apache.karaf.shell.support.completers.StringsCompleter;
-
-import java.util.List;
-
-/**
- * Completer on the JDBC datasources name (JNDI or OSGi service property).
- */
-@Service
-public class DataSourcesNameCompleter implements Completer {
-
-    @Reference
-    private JdbcService jdbcService;
-
-    @Override
-    public int complete(Session session, CommandLine commandLine, List<String> candidates) {
-        StringsCompleter delegate = new StringsCompleter();
-        try {
-            for (String datasource : jdbcService.datasources()) {
-                delegate.getStrings().add(datasource);
-            }
-        } catch (Exception e) {
-            // nothing to do
-        }
-        return delegate.complete(session, commandLine, candidates);
-    }
-
-    public JdbcService getJdbcService() {
-        return jdbcService;
-    }
-
-    public void setJdbcService(JdbcService jdbcService) {
-        this.jdbcService = jdbcService;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/command/src/main/resources/OSGI-INF/bundle.info
----------------------------------------------------------------------
diff --git a/jdbc/command/src/main/resources/OSGI-INF/bundle.info b/jdbc/command/src/main/resources/OSGI-INF/bundle.info
deleted file mode 100644
index f4d4790..0000000
--- a/jdbc/command/src/main/resources/OSGI-INF/bundle.info
+++ /dev/null
@@ -1,26 +0,0 @@
-h1. Synopsis
-
-${project.name}
-
-${project.description}
-
-Maven URL:
-[mvn:${project.groupId}/${project.artifactId}/${project.version}]
-
-h1. Description
-
-This bundle provides the shell commands to manipulate the JDBC service.
-
-The following commands are available:
-
-* jdbc:create
-* jdbc:delete
-* jdbc:datasources
-* jdbc:command
-* jdbc:query
-* jdbc:tables
-* jdbc:info
-
-h1. See also
-
-JDBC - section of the Karaf User Guide
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/core/NOTICE
----------------------------------------------------------------------
diff --git a/jdbc/core/NOTICE b/jdbc/core/NOTICE
deleted file mode 100644
index b70f1f9..0000000
--- a/jdbc/core/NOTICE
+++ /dev/null
@@ -1,71 +0,0 @@
-Apache Karaf
-Copyright 2010-2014 The Apache Software Foundation
-
-
-I. Included Software
-
-This product includes software developed at
-The Apache Software Foundation (http://www.apache.org/).
-Licensed under the Apache License 2.0.
-
-This product uses software developed at
-The OSGi Alliance (http://www.osgi.org/).
-Copyright (c) OSGi Alliance (2000, 2010).
-Licensed under the Apache License 2.0.
-
-This product includes software developed at
-OW2 (http://www.ow2.org/).
-Licensed under the BSD License.
-
-This product includes software developed at
-OPS4J (http://www.ops4j.org/).
-Licensed under the Apache License 2.0.
-
-This product includes software developed at
-Eclipse Foundation (http://www.eclipse.org/).
-Licensed under the EPL.
-
-This product includes software written by
-Antony Lesuisse.
-Licensed under Public Domain.
-
-
-II. Used Software
-
-This product uses software developed at
-FUSE Source (http://www.fusesource.org/).
-Licensed under the Apache License 2.0.
-
-This product uses software developed at
-AOP Alliance (http://aopalliance.sourceforge.net/).
-Licensed under the Public Domain.
-
-This product uses software developed at
-Tanuki Software (http://www.tanukisoftware.com/).
-Licensed under the Apache License 2.0.
-
-This product uses software developed at
-Jasypt (http://jasypt.sourceforge.net/).
-Licensed under the Apache License 2.0.
-
-This product uses software developed at
-JLine (http://jline.sourceforge.net).
-Licensed under the BSD License.
-
-This product uses software developed at
-SLF4J (http://www.slf4j.org/).
-Licensed under the MIT License.
-
-This product uses software developed at
-SpringSource (http://www.springsource.org/).
-Licensed under the Apache License 2.0.
-
-This product includes software from http://www.json.org.
-Copyright (c) 2002 JSON.org
-
-
-III. License Summary
-- Apache License 2.0
-- BSD License
-- EPL License
-- MIT License

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/core/pom.xml
----------------------------------------------------------------------
diff --git a/jdbc/core/pom.xml b/jdbc/core/pom.xml
deleted file mode 100644
index 03fc7bd..0000000
--- a/jdbc/core/pom.xml
+++ /dev/null
@@ -1,87 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-
-    <!--
-
-        Licensed to the Apache Software Foundation (ASF) under one or more
-        contributor license agreements.  See the NOTICE file distributed with
-        this work for additional information regarding copyright ownership.
-        The ASF licenses this file to You under the Apache License, Version 2.0
-        (the "License"); you may not use this file except in compliance with
-        the License.  You may obtain a copy of the License at
-
-            http://www.apache.org/licenses/LICENSE-2.0
-
-        Unless required by applicable law or agreed to in writing, software
-        distributed under the License is distributed on an "AS IS" BASIS,
-        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-        See the License for the specific language governing permissions and
-        limitations under the License.
-    -->
-
-    <modelVersion>4.0.0</modelVersion>
-
-    <parent>
-        <groupId>org.apache.karaf.jdbc</groupId>
-        <artifactId>jdbc</artifactId>
-        <version>4.0.0-SNAPSHOT</version>
-        <relativePath>../pom.xml</relativePath>
-    </parent>
-
-    <artifactId>org.apache.karaf.jdbc.core</artifactId>
-    <packaging>bundle</packaging>
-    <name>Apache Karaf :: JDBC :: Core</name>
-    <description>This bundle provides core implementation of the JDBC service.</description>
-
-    <properties>
-        <appendedResourcesDirectory>${basedir}/../../etc/appended-resources</appendedResourcesDirectory>
-    </properties>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.core</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.karaf</groupId>
-            <artifactId>org.apache.karaf.util</artifactId>
-        </dependency>
-    </dependencies>
-
-    <build>
-        <resources>
-            <resource>
-                <directory>${project.basedir}/src/main/resources</directory>
-                <includes>
-                    <include>**/*</include>
-                </includes>
-            </resource>
-            <resource>
-                <directory>${project.basedir}/src/main/resources</directory>
-                <filtering>true</filtering>
-                <includes>
-                    <include>**/*.info</include>
-                </includes>
-            </resource>
-        </resources>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-bundle-plugin</artifactId>
-                <configuration>
-                    <instructions>
-                        <Export-Package>
-                            org.apache.karaf.jdbc
-                        </Export-Package>
-                        <Private-Package>
-                            org.apache.karaf.jdbc.internal,
-                            org.apache.karaf.util
-                        </Private-Package>
-                    </instructions>
-                </configuration>
-            </plugin>
-        </plugins>
-    </build>
-
-</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/core/src/main/java/org/apache/karaf/jdbc/JdbcMBean.java
----------------------------------------------------------------------
diff --git a/jdbc/core/src/main/java/org/apache/karaf/jdbc/JdbcMBean.java b/jdbc/core/src/main/java/org/apache/karaf/jdbc/JdbcMBean.java
deleted file mode 100644
index 26165c8..0000000
--- a/jdbc/core/src/main/java/org/apache/karaf/jdbc/JdbcMBean.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jdbc;
-
-import javax.management.MBeanException;
-import javax.management.openmbean.TabularData;
-import java.util.Map;
-
-/**
- * JDBC MBean
- */
-public interface JdbcMBean {
-
-    /**
-     * Get the list of JDBC datasources.
-     *
-     * @return a tabular data containing the list of JDBC datasources.
-     * @throws MBeanException
-     */
-    TabularData getDatasources() throws MBeanException;
-
-    /**
-     * Create a JDBC datasource.
-     *
-     * @param name the JDBC datasource name.
-     * @param type the JDBC datasource type (generic, MySQL, Oracle, Postgres, H2, HSQL, Derby, MSSQL).
-     * @param driver the JDBC datasource driver class name (can be null).
-     * @param version the target JDBC driver version (can be null).
-     * @param url the JDBC URL.
-     * @param user the database username.
-     * @param password the database password.
-     * @param installBundles true to install the bundles providing the JDBC driver, false to not install.
-     * @throws MBeanException
-     */
-    void create(String name, String type, String driver, String version, String url, String user, String password, boolean installBundles) throws MBeanException;
-
-    /**
-     * Delete a JDBC datasource.
-     *
-     * @param name the JDBC datasource name (the one used at creation time).
-     * @throws MBeanException
-     */
-    void delete(String name) throws MBeanException;
-
-    /**
-     * Get details about a JDBC datasource.
-     *
-     * @param datasource the JDBC datasource name.
-     * @return a map (property/value) containing JDBC datasource details.
-     * @throws MBeanException
-     */
-    Map<String, String> info(String datasource) throws MBeanException;
-
-    /**
-     * Get the tables available on a JDBC datasource.
-     *
-     * @param datasource the JDBC datasource name.
-     * @return a tabular data containg datasource tables.
-     * @throws MBeanException
-     */
-    TabularData tables(String datasource) throws MBeanException;
-
-    /**
-     * Execute a SQL command on a JDBC datasource.
-     *
-     * @param datasource the JDBC datasource name.
-     * @param command the SQL command to execute.
-     * @throws MBeanException
-     */
-    void execute(String datasource, String command) throws MBeanException;
-
-    /**
-     * Execute a SQL query on a JDBC datasource.
-     *
-     * @param datasource the JDBC datasource name.
-     * @param query the SQL query to execute.
-     * @return a tabular data with the result of execute (columns/values).
-     * @throws MBeanException
-     */
-    TabularData query(String datasource, String query) throws MBeanException;
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/core/src/main/java/org/apache/karaf/jdbc/JdbcService.java
----------------------------------------------------------------------
diff --git a/jdbc/core/src/main/java/org/apache/karaf/jdbc/JdbcService.java b/jdbc/core/src/main/java/org/apache/karaf/jdbc/JdbcService.java
deleted file mode 100644
index d883a07..0000000
--- a/jdbc/core/src/main/java/org/apache/karaf/jdbc/JdbcService.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jdbc;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * JDBC Service.
- */
-public interface JdbcService {
-
-    /**
-     * Create a JDBC datasource (using a default template).
-     *
-     * @param name the JDBC datasource name.
-     * @param type the backend database type (generic, Oracle, MySQL, ...)
-     * @param driverClassName the JDBC driver classname.
-     * @param version the JDBC driver version to use.
-     * @param url the JDBC URL.
-     * @param user the database user name.
-     * @param password the database password.
-     * @param tryToInstallBundles true to try to automatically install the required bundles (JDBC driver, etc) when possible, false else.
-     */
-    void create(String name, String type, String driverClassName, String version, String url, String user, String password, boolean tryToInstallBundles) throws Exception;
-
-    /**
-     * Delete a JDBC datasource identified by a name.
-     *
-     * @param name the JDBC datasource name.
-     */
-    void delete(String name) throws Exception;
-
-    /**
-     * List the JDBC datasources available.
-     *
-     * @return a list of datasources name.
-     */
-    List<String> datasources() throws Exception;
-
-    /**
-     * List the JDBC datasources configuration file names present in the deploy folder.
-     *
-     * @return a list of the JDBC datasources configuration file names.
-     */
-    List<String> datasourceFileNames() throws Exception;
-
-    /**
-     * Execute a SQL query on a given JDBC datasource.
-     *
-     * @param datasource the JDBC datasource name.
-     * @param query the SQL query to execute.
-     * @return the SQL query result (as a String).
-     */
-    Map<String, List<String>> query(String datasource, String query) throws Exception;
-
-    /**
-     * Execute a SQL command on a given JDBC datasource.
-     *
-     * @param datasource the JDBC datasource name.
-     * @param command the SQL command to execute.
-     */
-    void execute(String datasource, String command) throws Exception;
-
-    /**
-     * List the tables available on a given JDBC datasource.
-     *
-     * @param datasource the JDBC datasource name.
-     * @return the list of table names.
-     */
-    Map<String, List<String>> tables(String datasource) throws Exception;
-
-    /**
-     * Get detailed info about a JDBC datasource.
-     *
-     * @param datasource the JDBC datasource name.
-     * @return a map of info (name/value).
-     */
-    Map<String, String> info(String datasource) throws Exception;
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/core/src/main/java/org/apache/karaf/jdbc/internal/JdbcConnector.java
----------------------------------------------------------------------
diff --git a/jdbc/core/src/main/java/org/apache/karaf/jdbc/internal/JdbcConnector.java b/jdbc/core/src/main/java/org/apache/karaf/jdbc/internal/JdbcConnector.java
deleted file mode 100644
index 11c7ca4..0000000
--- a/jdbc/core/src/main/java/org/apache/karaf/jdbc/internal/JdbcConnector.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jdbc.internal;
-
-import java.io.Closeable;
-import java.io.IOException;
-import java.sql.*;
-import java.util.Deque;
-import java.util.LinkedList;
-
-import javax.sql.DataSource;
-import javax.sql.XAConnection;
-import javax.sql.XADataSource;
-
-import org.apache.karaf.util.StreamUtils;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceReference;
-
-public class JdbcConnector implements Closeable {
-    private BundleContext bundleContext;
-    private String datasourceName;
-    private Connection connection;
-    private Deque<Closeable> resources;
-    private ServiceReference<?> reference;
-
-    public JdbcConnector(BundleContext bundleContext, String datasourceName) {
-        this.bundleContext = bundleContext;
-        this.datasourceName = datasourceName;
-        this.resources = new LinkedList<Closeable>();
-    }
-    
-    public Connection connect() throws SQLException {
-        reference = lookupDataSource(datasourceName);
-        Object datasource = bundleContext.getService(reference);
-        if (datasource instanceof DataSource) {
-            connection = ((DataSource) datasource).getConnection();
-        }
-        if (datasource instanceof XADataSource) {
-            connection = ((XADataSource) datasource).getXAConnection().getConnection();
-        }
-        return connection;
-    }
-    
-    public Statement createStatement() throws SQLException {
-        if (connection == null) {
-            connect();
-        }
-        if (connection instanceof Connection) {
-            return register(((Connection) connection).createStatement());
-        }
-        if (connection instanceof XAConnection) {
-            return register(((XAConnection) connection).getConnection().createStatement());
-        }
-        return null;
-    }
-
-    public Connection register(final Connection connection) {
-        resources.addFirst(new Closeable() {
-            
-            @Override
-            public void close() throws IOException {
-                try {
-                    connection.close();
-                } catch (SQLException e) {
-                    // Ignore
-                }
-            }
-        });
-        return connection;
-    }
-
-    public Statement register(final Statement statement) {
-        resources.addFirst(new Closeable() {
-            
-            @Override
-            public void close() throws IOException {
-                try {
-                    statement.close();
-                } catch (SQLException e) {
-                    // Ignore
-                }
-            }
-        });
-        return statement;
-    }
-
-    public ResultSet register(final ResultSet resultSet) {
-        resources.addFirst(new Closeable() {
-            
-            @Override
-            public void close() throws IOException {
-                try {
-                    resultSet.close();
-                } catch (SQLException e) {
-                    // Ignore
-                }
-            }
-        });
-        return resultSet;
-    }
-    
-
-    private ServiceReference<?> lookupDataSource(String name) {
-        ServiceReference<?>[] references;
-        try {
-            references = bundleContext.getServiceReferences((String) null,
-                    "(&(|(" + Constants.OBJECTCLASS + "=" + DataSource.class.getName() + ")"
-                    + "(" + Constants.OBJECTCLASS + "=" + XADataSource.class.getName() + "))"
-                    + "(|(osgi.jndi.service.name=" + name + ")(datasource=" + name + ")(name=" + name + ")(service.id=" + name + ")))");
-        } catch (InvalidSyntaxException e) {
-            throw new IllegalArgumentException("Error finding datasource with name " + name, e);
-        }
-        if (references == null || references.length == 0) {
-            throw new IllegalArgumentException("No JDBC datasource found for " + name);
-        }
-        if (references.length > 1) {
-            throw new IllegalArgumentException("Multiple JDBC datasource found for " + name);
-        }
-        return references[0];
-    }
-
-    @Override
-    public void close() {
-        StreamUtils.close(resources.toArray(new Closeable[]{}));
-        if (reference != null) {
-            bundleContext.ungetService(reference);
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/core/src/main/java/org/apache/karaf/jdbc/internal/JdbcMBeanImpl.java
----------------------------------------------------------------------
diff --git a/jdbc/core/src/main/java/org/apache/karaf/jdbc/internal/JdbcMBeanImpl.java b/jdbc/core/src/main/java/org/apache/karaf/jdbc/internal/JdbcMBeanImpl.java
deleted file mode 100644
index 92bbba8..0000000
--- a/jdbc/core/src/main/java/org/apache/karaf/jdbc/internal/JdbcMBeanImpl.java
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jdbc.internal;
-
-import org.apache.karaf.jdbc.JdbcMBean;
-import org.apache.karaf.jdbc.JdbcService;
-
-import javax.management.MBeanException;
-import javax.management.openmbean.*;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Default implementation of the JDBC MBean.
- */
-public class JdbcMBeanImpl implements JdbcMBean {
-
-    private JdbcService jdbcService;
-
-    @Override
-    public TabularData getDatasources() throws MBeanException {
-        try {
-            CompositeType type = new CompositeType("DataSource", "JDBC DataSource",
-                    new String[]{ "name", "product", "version", "url "},
-                    new String[]{ "Name", "Database product", "Database version", "JDBC URL" },
-                    new OpenType[]{ SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, SimpleType.STRING });
-            TabularType tableType = new TabularType("JDBC DataSources", "Table of the JDBC DataSources",
-                    type, new String[]{ "name" });
-            TabularData table = new TabularDataSupport(tableType);
-
-            for (String datasource : jdbcService.datasources()) {
-                Map<String, String> info = jdbcService.info(datasource);
-                CompositeData data = new CompositeDataSupport(type,
-                        new String[]{ "name", "product", "version", "url" },
-                        new Object[]{ datasource, info.get("db.product"), info.get("db.version"), info.get("url") });
-                table.put(data);
-            }
-
-            return table;
-        } catch (Exception e) {
-            throw new MBeanException(null, e.getMessage());
-        }
-    }
-
-    @Override
-    public void create(String name, String type, String driver, String version, String url, String user, String password, boolean installBundles) throws MBeanException {
-        try {
-            jdbcService.create(name, type, driver, version, url, user, password, installBundles);
-        } catch (Exception e) {
-            throw new MBeanException(null, e.getMessage());
-        }
-    }
-
-    @Override
-    public void delete(String name) throws MBeanException {
-        try {
-            jdbcService.delete(name);
-        } catch (Exception e) {
-            throw new MBeanException(null, e.getMessage());
-        }
-    }
-
-    @Override
-    public Map<String, String> info(String datasource) throws MBeanException {
-        try {
-            return jdbcService.info(datasource);
-        } catch (Exception e) {
-            throw new MBeanException(null, e.getMessage());
-        }
-    }
-
-    @Override
-    public TabularData tables(String datasource) throws MBeanException {
-        try {
-            Map<String, List<String>> result = jdbcService.tables(datasource);
-            OpenType[] stringTypes = new OpenType[result.keySet().size()];
-            for (int i = 0; i < stringTypes.length; i++) {
-                stringTypes[i] = SimpleType.STRING;
-            }
-            String[] columns = result.keySet().toArray(new String[result.keySet().size()]);
-
-            CompositeType type = new CompositeType("Columns", "Columns",
-                    columns, columns, stringTypes);
-            TabularType rows = new TabularType("Result", "Result Rows", type, columns);
-            TabularData table = new TabularDataSupport(rows);
-
-            int rowCount = result.get(result.keySet().iterator().next()).size();
-
-            for (int i = 0; i < rowCount; i++) {
-                Object[] row = new Object[columns.length];
-                for (int j = 0; j < columns.length; j++) {
-                    row[j] = result.get(columns[j]).get(i);
-                }
-                CompositeData data = new CompositeDataSupport(type, columns, row);
-                table.put(data);
-            }
-
-            return table;
-        } catch (Exception e) {
-            e.printStackTrace();
-            throw new MBeanException(null, e.getMessage());
-        }
-    }
-
-    @Override
-    public void execute(String datasource, String command) throws MBeanException {
-        try {
-            jdbcService.execute(datasource, command);
-        } catch (Exception e) {
-            throw new MBeanException(null, e.getMessage());
-        }
-    }
-
-    @Override
-    public TabularData query(String datasource, String query) throws MBeanException {
-        try {
-            Map<String, List<String>> result = jdbcService.query(datasource, query);
-            OpenType[] stringTypes = new OpenType[result.keySet().size()];
-            for (int i = 0; i < stringTypes.length; i++) {
-                stringTypes[i] = SimpleType.STRING;
-            }
-            String[] columns = result.keySet().toArray(new String[result.keySet().size()]);
-
-            CompositeType type = new CompositeType("Columns", "Columns",
-                    columns, columns, stringTypes);
-            TabularType rows = new TabularType("Result", "Result Rows", type, columns);
-            TabularData table = new TabularDataSupport(rows);
-
-            int rowCount = result.get(result.keySet().iterator().next()).size();
-
-            for (int i = 0; i < rowCount; i++) {
-                Object[] row = new Object[columns.length];
-                for (int j = 0; j < columns.length; j++) {
-                    row[j] = result.get(columns[j]).get(i);
-                }
-                CompositeData data = new CompositeDataSupport(type, columns, row);
-                table.put(data);
-            }
-
-            return table;
-        } catch (Exception e) {
-            throw new MBeanException(null, e.getMessage());
-        }
-    }
-
-    public JdbcService getJdbcService() {
-        return jdbcService;
-    }
-
-    public void setJdbcService(JdbcService jdbcService) {
-        this.jdbcService = jdbcService;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/core/src/main/java/org/apache/karaf/jdbc/internal/JdbcServiceImpl.java
----------------------------------------------------------------------
diff --git a/jdbc/core/src/main/java/org/apache/karaf/jdbc/internal/JdbcServiceImpl.java b/jdbc/core/src/main/java/org/apache/karaf/jdbc/internal/JdbcServiceImpl.java
deleted file mode 100644
index 50cf8ff..0000000
--- a/jdbc/core/src/main/java/org/apache/karaf/jdbc/internal/JdbcServiceImpl.java
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jdbc.internal;
-
-import org.apache.karaf.jdbc.JdbcService;
-import org.apache.karaf.util.TemplateUtils;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.ServiceReference;
-
-import javax.sql.DataSource;
-import javax.sql.XADataSource;
-
-import java.io.*;
-import java.sql.*;
-import java.util.*;
-
-/**
- * Default implementation of the JDBC Service.
- */
-public class JdbcServiceImpl implements JdbcService {
-
-    public static enum TYPES {
-        DB2("wrap:mvn:com.ibm.db2.jdbc/db2jcc/", "9.7", "datasource-db2.xml"),
-        DERBY("mvn:org.apache.derby/derby/", "10.8.2.2", "datasource-derby.xml"),
-        GENERIC(null, null, "datasource-generic.xml"),
-        H2("mvn:com.h2database/h2/", "1.3.163", "datasource-h2.xml"),
-        HSQL("mvn:org.hsqldb/hsqldb/", "2.3.2", "datasource-hsql.xml"),
-        MYSQL("mvn:mysql/mysql-connector-java/", "5.1.18", "datasource-mysql.xml"),
-        MSSQL("wrap:mvn:net.sourceforge.jtds/jtds/", "1.2.4", "datasource-mssql.xml"),
-        ORACLE("wrap:mvn:ojdbc/ojdbc/", "11.2.0.2.0", "datasource-oracle.xml"),
-        POSTGRES("wrap:mvn:postgresql/postgresql/", "9.1-901.jdbc4", "datasource-postgres.xml");
-
-        private final String bundleUrl;
-        private final String defaultVersion;
-        private final String templateFile;
-
-        TYPES(String bundleUrl, String defaultVersion, String templateFile) {
-            this.bundleUrl = bundleUrl;
-            this.defaultVersion = defaultVersion;
-            this.templateFile = templateFile;
-        }
-
-        public void installBundle(BundleContext bundleContext, String version) throws Exception {
-            String location = this.bundleUrl + getWithDefault(version, this.defaultVersion);
-            bundleContext.installBundle(location, null).start();
-        }
-
-        private String getWithDefault(String st, String defaultSt) {
-            return (st == null)? defaultSt : st;
-        }
-
-        public void copyDataSourceFile(File outFile, HashMap<String, String> properties) {
-            InputStream is = this.getClass().getResourceAsStream(templateFile);
-            if (is == null) {
-                throw new IllegalArgumentException("Template resource " + templateFile + " doesn't exist");
-            }
-            TemplateUtils.createFromTemplate(outFile, is, properties);
-        }
-
-    }
-
-    private BundleContext bundleContext;
-
-    @Override
-    public void create(String name, String type, String driverClassName, String version, String url, String user, String password, boolean tryToInstallBundles) throws Exception {
-        if (type == null) {
-            throw new IllegalStateException("No database type supplied");
-        }
-        TYPES dbType = TYPES.valueOf(type.toUpperCase());
-
-        if (tryToInstallBundles) {
-            dbType.installBundle(bundleContext, version);
-        }
-
-        File karafBase = new File(System.getProperty("karaf.base"));
-        File deployFolder = new File(karafBase, "deploy");
-        File outFile = new File(deployFolder, "datasource-" + name + ".xml");
-
-        HashMap<String, String> properties = new HashMap<String, String>();
-        properties.put("name", name);
-        properties.put("driver", driverClassName);
-        properties.put("url", url);
-        properties.put("user", user);
-        properties.put("password", password);
-
-        dbType.copyDataSourceFile(outFile, properties);
-    }
-
-    @Override
-    public void delete(String name) throws Exception {
-        File karafBase = new File(System.getProperty("karaf.base"));
-        File deployFolder = new File(karafBase, "deploy");
-        File datasourceFile = new File(deployFolder, "datasource-" + name + ".xml");
-        if (!datasourceFile.exists()) {
-            throw new IllegalArgumentException("The JDBC datasource file "+ datasourceFile.getPath() + " doesn't exist");
-        }
-        datasourceFile.delete();
-    }
-
-    @Override
-    public List<String> datasources() throws Exception {
-        List<String> datasources = new ArrayList<String>();
-
-        ServiceReference<?>[] references = bundleContext.getServiceReferences((String) null, "(|(" + Constants.OBJECTCLASS + "=" + DataSource.class.getName() + ")("
-        + Constants.OBJECTCLASS + "=" + XADataSource.class.getName() + "))");
-        if (references != null) {
-            for (ServiceReference reference : references) {
-                if (reference.getProperty("osgi.jndi.service.name") != null) {
-                    datasources.add((String) reference.getProperty("osgi.jndi.service.name"));
-                } else if (reference.getProperty("datasource") != null) {
-                    datasources.add((String) reference.getProperty("datasource"));
-                } else if (reference.getProperty("name") != null) {
-                    datasources.add((String) reference.getProperty("name"));
-                } else {
-                    datasources.add(reference.getProperty(Constants.SERVICE_ID).toString());
-                }
-            }
-        }
-        return datasources;
-    }
-
-    @Override
-    public List<String> datasourceFileNames() throws Exception {
-        File karafBase = new File(System.getProperty("karaf.base"));
-        File deployFolder = new File(karafBase, "deploy");
-
-        String[] datasourceFileNames = deployFolder.list(new FilenameFilter() {
-
-            @Override
-            public boolean accept(File dir, String name) {
-                return name.startsWith("datasource-") && name.endsWith(".xml");
-            }
-        });
-
-        return Arrays.asList(datasourceFileNames);
-    }
-
-    @Override
-    public Map<String, List<String>> query(String datasource, String query) throws Exception {
-        JdbcConnector jdbcConnector = new JdbcConnector(bundleContext, datasource);
-        try {
-            Map<String, List<String>> map = new HashMap<String, List<String>>();
-            Statement statement = jdbcConnector.createStatement();
-            ResultSet resultSet = jdbcConnector.register(statement.executeQuery(query));
-            ResultSetMetaData metaData = resultSet.getMetaData();
-            for (int c = 1; c <= metaData.getColumnCount(); c++) {
-                map.put(metaData.getColumnLabel(c), new ArrayList<String>());
-            }
-            while (resultSet.next()) {
-                for (int c = 1; c <= metaData.getColumnCount(); c++) {
-                    map.get(metaData.getColumnLabel(c)).add(resultSet.getString(c));
-                }
-            }
-            return map;
-        } finally {
-            jdbcConnector.close();
-        }
-    }
-
-    @Override
-    public void execute(String datasource, String command) throws Exception {
-        JdbcConnector jdbcConnector = new JdbcConnector(bundleContext, datasource);
-        try {
-            jdbcConnector.createStatement().execute(command);
-        } finally {
-            jdbcConnector.close();
-        }
-    }
-
-    @Override
-    public Map<String, List<String>> tables(String datasource) throws Exception {
-        JdbcConnector jdbcConnector = new JdbcConnector(bundleContext, datasource);
-        try {
-
-            DatabaseMetaData dbMetaData = jdbcConnector.connect().getMetaData();
-            ResultSet resultSet = jdbcConnector.register(dbMetaData.getTables(null, null, null, null));
-            ResultSetMetaData metaData = resultSet.getMetaData();
-            Map<String, List<String>> map = new HashMap<String, List<String>>();
-            for (int c = 1; c <= metaData.getColumnCount(); c++) {
-                map.put(metaData.getColumnLabel(c), new ArrayList<String>());
-            }
-            while (resultSet.next()) {
-                for (int c = 1; c <= metaData.getColumnCount(); c++) {
-                    map.get(metaData.getColumnLabel(c)).add(resultSet.getString(c));
-                }
-            }
-            return map;
-        } finally {
-            jdbcConnector.close();
-        }
-    }
-
-    @Override
-    public Map<String, String> info(String datasource) throws Exception {
-        JdbcConnector jdbcConnector = new JdbcConnector(bundleContext, datasource);
-        try {
-            DatabaseMetaData dbMetaData = jdbcConnector.connect().getMetaData();
-            Map<String, String> map = new HashMap<String, String>();
-            map.put("db.product", dbMetaData.getDatabaseProductName());
-            map.put("db.version", dbMetaData.getDatabaseProductVersion());
-            map.put("url", dbMetaData.getURL());
-            map.put("username", dbMetaData.getUserName());
-            map.put("driver.name", dbMetaData.getDriverName());
-            map.put("driver.version", dbMetaData.getDriverVersion());
-            return map;
-        } finally {
-            jdbcConnector.close();
-        }
-    }
-
-    public void setBundleContext(BundleContext bundleContext) {
-        this.bundleContext = bundleContext;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/core/src/main/resources/OSGI-INF/blueprint/jdbc-core.xml
----------------------------------------------------------------------
diff --git a/jdbc/core/src/main/resources/OSGI-INF/blueprint/jdbc-core.xml b/jdbc/core/src/main/resources/OSGI-INF/blueprint/jdbc-core.xml
deleted file mode 100644
index e961697..0000000
--- a/jdbc/core/src/main/resources/OSGI-INF/blueprint/jdbc-core.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?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.
-    -->
-<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
-           xmlns:ext="http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.0.0"
-           default-activation="lazy">
-
-    <ext:property-placeholder placeholder-prefix="$[" placeholder-suffix="]"/>
-
-    <bean id="jdbcService" class="org.apache.karaf.jdbc.internal.JdbcServiceImpl">
-        <property name="bundleContext" ref="blueprintBundleContext"/>
-    </bean>
-
-    <service ref="jdbcService" interface="org.apache.karaf.jdbc.JdbcService" />
-
-    <!-- Management -->
-    <bean id="jdbcMBeanImpl" class="org.apache.karaf.jdbc.internal.JdbcMBeanImpl">
-        <property name="jdbcService" ref="jdbcService"/>
-    </bean>
-
-    <service ref="jdbcMBeanImpl" auto-export="interfaces">
-        <service-properties>
-            <entry key="jmx.objectname" value="org.apache.karaf:type=jdbc,name=$[karaf.name]"/>
-        </service-properties>
-    </service>
-
-</blueprint>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/core/src/main/resources/OSGI-INF/bundle.info
----------------------------------------------------------------------
diff --git a/jdbc/core/src/main/resources/OSGI-INF/bundle.info b/jdbc/core/src/main/resources/OSGI-INF/bundle.info
deleted file mode 100644
index bc7a1cd..0000000
--- a/jdbc/core/src/main/resources/OSGI-INF/bundle.info
+++ /dev/null
@@ -1,18 +0,0 @@
-h1. Synopsis
-
-${project.name}
-
-${project.description}
-
-Maven URL:
-[mvn:${project.groupId}/${project.artifactId}/${project.version}]
-
-h1. Description
-
-This bundle is the core implementation of the JDBC service support.
-
-The JDBC service allows you to create datasources, see the defined datasources, execute query on a datasource, etc.
-
-h1. See also
-
-JDBC - section of the Karaf User Guide

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-db2.xml
----------------------------------------------------------------------
diff --git a/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-db2.xml b/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-db2.xml
deleted file mode 100644
index da220a5..0000000
--- a/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-db2.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?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.
-    -->
-<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
-
-    <bean id="dataSource" class="com.ibm.db2.jcc.DB2DataSource">
-        <property name="url" value="${url}"/>
-        <property name="user" value="${user}"/>
-        <property name="password" value="${password}"/>
-    </bean>
-
-    <service interface="javax.sql.DataSource" ref="dataSource">
-        <service-properties>
-            <entry key="osgi.jndi.service.name" value="jdbc/${name}"/>
-        </service-properties>
-    </service>
-
-</blueprint>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-derby.xml
----------------------------------------------------------------------
diff --git a/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-derby.xml b/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-derby.xml
deleted file mode 100644
index 440a439..0000000
--- a/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-derby.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?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.
-    -->
-<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
-           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-           default-activation="eager">
-
-    <bean id="dataSource" class="org.apache.derby.jdbc.EmbeddedXADataSource">
-        <property name="databaseName" value="${name}"/>
-        <property name="createDatabase" value="create" />
-    </bean>
-
-    <service ref="dataSource" interface="javax.sql.DataSource">
-        <service-properties>
-            <entry key="osgi.jndi.service.name" value="jdbc/${name}"/>
-        </service-properties>
-    </service>
-
-    <service ref="dataSource" interface="javax.sql.XADataSource">
-        <service-properties>
-            <entry key="osgi.jndi.service.name" value="jdbc/${name}xa"/>
-        </service-properties>
-    </service>
-
-</blueprint>


[14/33] git commit: Make sure aries-util is not referenced in the framework car

Posted by gn...@apache.org.
Make sure aries-util is not referenced in the framework car


Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/edd82fda
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/edd82fda
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/edd82fda

Branch: refs/heads/master
Commit: edd82fda337ed048b7c8fa24bb51c917d89bdaea
Parents: 0c8e8a8
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Fri Apr 11 19:16:08 2014 +0200
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Fri Apr 11 19:20:04 2014 +0200

----------------------------------------------------------------------
 assemblies/features/framework/pom.xml |  4 ----
 shell/core/pom.xml                    | 10 ----------
 2 files changed, 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/edd82fda/assemblies/features/framework/pom.xml
----------------------------------------------------------------------
diff --git a/assemblies/features/framework/pom.xml b/assemblies/features/framework/pom.xml
index 4675b0a..fd73a47 100644
--- a/assemblies/features/framework/pom.xml
+++ b/assemblies/features/framework/pom.xml
@@ -173,10 +173,6 @@
         </dependency>
 
         <dependency>
-            <groupId>org.apache.karaf.region</groupId>
-            <artifactId>org.apache.karaf.region.core</artifactId>
-        </dependency>
-        <dependency>
             <groupId>org.apache.karaf.features</groupId>
             <artifactId>org.apache.karaf.features.core</artifactId>
         </dependency>

http://git-wip-us.apache.org/repos/asf/karaf/blob/edd82fda/shell/core/pom.xml
----------------------------------------------------------------------
diff --git a/shell/core/pom.xml b/shell/core/pom.xml
index 92c7555..572430c 100644
--- a/shell/core/pom.xml
+++ b/shell/core/pom.xml
@@ -68,16 +68,6 @@
         </dependency>
 
         <dependency>
-            <groupId>org.apache.aries.blueprint</groupId>
-            <artifactId>org.apache.aries.blueprint.api</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.aries.blueprint</groupId>
-            <artifactId>org.apache.aries.blueprint.core</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
             <groupId>org.apache.felix</groupId>
             <artifactId>org.apache.felix.gogo.runtime</artifactId>
             <scope>provided</scope>


[16/33] Revert "[KARAF-2852] Merge features/core and features/command"

Posted by gn...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/test/java/org/apache/karaf/features/internal/service/BundleManagerTest.java
----------------------------------------------------------------------
diff --git a/features/src/test/java/org/apache/karaf/features/internal/service/BundleManagerTest.java b/features/src/test/java/org/apache/karaf/features/internal/service/BundleManagerTest.java
deleted file mode 100644
index bed8104..0000000
--- a/features/src/test/java/org/apache/karaf/features/internal/service/BundleManagerTest.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.service;
-
-import org.apache.karaf.features.TestBase;
-
-public class BundleManagerTest extends TestBase {
-
-    /*
-    @Test
-    public void testfindBundlestoRefreshWithHostToRefresh() throws Exception {
-        Bundle hostBundle = createDummyBundle(12345l, "Host", headers());
-        Bundle fragmentBundle = createDummyBundle(54321l, "fragment", headers(Constants.FRAGMENT_HOST, "Host"));
-
-        BundleContext bundleContext = EasyMock.createMock(BundleContext.class);
-        BundleManager bundleManager = new BundleManager(bundleContext);
-
-        // Host was already installed, fragment is new
-        Set<Bundle> existing = new HashSet<Bundle>(Arrays.asList(hostBundle, fragmentBundle));
-        Set<Bundle> installed = new HashSet<Bundle>(Arrays.asList(fragmentBundle));
-        
-        replay(bundleContext);
-        Set<Bundle> bundles = bundleManager.findBundlesWithFragmentsToRefresh(existing, installed);
-        EasyMock.verify(bundleContext);
-
-        Assert.assertEquals(1, bundles.size());
-        Assert.assertEquals(hostBundle, bundles.iterator().next());
-    }
-    
-    @Test
-    public void testfindBundlestoRefreshWithOptionalPackages() throws Exception {
-        Bundle exporterBundle = createDummyBundle(12345l, "exporter", headers(Constants.EXPORT_PACKAGE, "org.my.package"));
-        Bundle importerBundle = createDummyBundle(54321l, "importer", headers(Constants.IMPORT_PACKAGE, "org.my.package;resolution:=optional"));
-
-        BundleContext bundleContext = EasyMock.createMock(BundleContext.class);
-        BundleManager bundleManager = new BundleManager(bundleContext);
-
-        // Importer was already installed, exporter is new
-        Set<Bundle> existing = new HashSet<Bundle>(Arrays.asList(importerBundle, exporterBundle));
-        Set<Bundle> installed = new HashSet<Bundle>(Arrays.asList(exporterBundle));
-        
-        replay(bundleContext);
-        Set<Bundle> bundles = bundleManager.findBundlesWithOptionalPackagesToRefresh(existing, installed);
-        EasyMock.verify(bundleContext);
-
-        Assert.assertEquals(1, bundles.size());
-        Assert.assertEquals(importerBundle, bundles.iterator().next());
-    }
-    */
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/test/java/org/apache/karaf/features/internal/service/FeaturesServiceImplTest.java
----------------------------------------------------------------------
diff --git a/features/src/test/java/org/apache/karaf/features/internal/service/FeaturesServiceImplTest.java b/features/src/test/java/org/apache/karaf/features/internal/service/FeaturesServiceImplTest.java
deleted file mode 100644
index b8b5fc0..0000000
--- a/features/src/test/java/org/apache/karaf/features/internal/service/FeaturesServiceImplTest.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.service;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.fail;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Map;
-
-import org.apache.karaf.features.Feature;
-import org.apache.karaf.features.TestBase;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * Test cases for {@link org.apache.karaf.features.internal.service.FeaturesServiceImpl}
- */
-public class FeaturesServiceImplTest extends TestBase {
-    
-    File dataFile;
-
-    @Before
-    public void setUp() throws IOException {
-        dataFile = File.createTempFile("features", null, null);
-    }
-
-    @Test
-    public void testGetFeature() throws Exception {
-        Feature transactionFeature = feature("transaction", "1.0.0");
-        final Map<String, Map<String, Feature>> features = features(transactionFeature);
-        final FeaturesServiceImpl impl = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, "", null, null, null) {
-            protected Map<String,Map<String,Feature>> getFeatures() throws Exception {
-                return features;
-            }
-        };
-        assertNotNull(impl.getFeature("transaction", org.apache.karaf.features.internal.model.Feature.DEFAULT_VERSION));
-        assertSame(transactionFeature, impl.getFeature("transaction", org.apache.karaf.features.internal.model.Feature.DEFAULT_VERSION));
-    }
-    
-    @Test
-    public void testGetFeatureStripVersion() throws Exception {
-        final FeaturesServiceImpl impl = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, "", null, null, null) {
-            protected Map<String,Map<String,Feature>> getFeatures() throws Exception {
-                return features(feature("transaction", "1.0.0"));
-            }
-        };
-        Feature feature = impl.getFeature("transaction", "  1.0.0  ");
-        assertNotNull(feature);
-        assertSame("transaction", feature.getName());
-    }
-    
-    @Test
-    public void testGetFeatureNotAvailable() throws Exception {
-        final FeaturesServiceImpl impl = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, "", null, null, null) {
-            protected Map<String,Map<String,Feature>> getFeatures() throws Exception {
-                return features(feature("transaction", "1.0.0"));
-            }
-        };
-        assertNull(impl.getFeature("activemq", org.apache.karaf.features.internal.model.Feature.DEFAULT_VERSION));
-    }
-    
-    @Test
-    public void testGetFeatureHighestAvailable() throws Exception {
-        final Map<String, Map<String, Feature>> features = features(
-                feature("transaction", "1.0.0"),
-                feature("transaction", "2.0.0")
-        );
-        final FeaturesServiceImpl impl = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, "", null, null, null) {
-            protected Map<String,Map<String,Feature>> getFeatures() throws Exception {
-                return features;
-            }
-        };
-        assertNotNull(impl.getFeature("transaction", org.apache.karaf.features.internal.model.Feature.DEFAULT_VERSION));
-        assertSame("2.0.0", impl.getFeature("transaction", org.apache.karaf.features.internal.model.Feature.DEFAULT_VERSION).getVersion());
-    }
-
-    /**
-     * This test ensures that every feature get installed only once, even if it appears multiple times in the list
-     * of transitive feature dependencies (KARAF-1600)
-     */
-    /*
-    @Test
-    @SuppressWarnings("unchecked")
-    public void testNoDuplicateFeaturesInstallation() throws Exception {
-        final List<Feature> installed = new LinkedList<Feature>();
-        BundleManager bundleManager = EasyMock.createMock(BundleManager.class);
-        expect(bundleManager.installBundleIfNeeded(EasyMock.anyObject(String.class), EasyMock.anyInt(), EasyMock.anyObject(String.class)))
-            .andReturn(new BundleInstallerResult(createDummyBundle(1l, "", headers()), true)).anyTimes();
-        bundleManager.refreshBundles(EasyMock.anyObject(Set.class), EasyMock.anyObject(Set.class), EasyMock.anyObject(EnumSet.class));
-        EasyMock.expectLastCall();
-        final FeaturesServiceImpl impl = new FeaturesServiceImpl(bundleManager, null) {
-            // override methods which refers to bundle context to avoid mocking everything
-            @Override
-            protected boolean loadState() {
-                return true;
-            }
-
-            @Override
-            protected void saveState() {
-
-            }
-
-            @Override
-            protected void doInstallFeature(InstallationState state, Feature feature, boolean verbose) throws Exception {
-                installed.add(feature);
-
-                super.doInstallFeature(state, feature, verbose);
-            }
-
-        };
-        replay(bundleManager);
-        impl.addRepository(getClass().getResource("repo2.xml").toURI());
-        impl.installFeature("all");
-
-        // copying the features to a set to filter out the duplicates
-        Set<Feature> noduplicates = new HashSet<Feature>();
-        noduplicates.addAll(installed);
-
-        assertEquals("Every feature should only have been installed once", installed.size(), noduplicates.size());
-    }
-
-    @Test
-    public void testGetOptionalImportsOnly() {
-        BundleManager bundleManager = new BundleManager(null, 0l);
-
-        List<Clause> result = bundleManager.getOptionalImports("org.apache.karaf,org.apache.karaf.optional;resolution:=optional");
-        assertEquals("One optional import expected", 1, result.size());
-        assertEquals("org.apache.karaf.optional", result.get(0).getName());
-
-        result = bundleManager.getOptionalImports(null);
-        assertNotNull(result);
-        assertEquals("No optional imports expected", 0, result.size());
-    }
-    */
-
-    static class Storage extends StateStorage {
-        @Override
-        protected InputStream getInputStream() throws IOException {
-            return null;
-        }
-        @Override
-        protected OutputStream getOutputStream() throws IOException {
-            return null;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/test/java/org/apache/karaf/features/internal/service/FeaturesValidationTest.java
----------------------------------------------------------------------
diff --git a/features/src/test/java/org/apache/karaf/features/internal/service/FeaturesValidationTest.java b/features/src/test/java/org/apache/karaf/features/internal/service/FeaturesValidationTest.java
deleted file mode 100644
index 9e33ee3..0000000
--- a/features/src/test/java/org/apache/karaf/features/internal/service/FeaturesValidationTest.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.service;
-
-import java.io.InputStream;
-import java.net.URL;
-
-import org.apache.karaf.features.Repository;
-import org.apache.karaf.features.internal.model.Features;
-import org.apache.karaf.features.internal.model.JaxbUtil;
-import org.junit.Test;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-
-public class FeaturesValidationTest {
-
-    @Test
-    public void testNs10() throws Exception {
-        FeatureValidationUtil.validate(getClass().getResource("f02.xml").toURI());
-    }
-
-    @Test
-    public void testNs10Unmarshall() throws Exception {
-        URL url = getClass().getResource("f02.xml");
-        Features features = JaxbUtil.unmarshal(url.toExternalForm(), true);
-        assertNotNull(features);
-    }
-
-    @Test
-    public void testNs10NoName() throws Exception {
-        FeatureValidationUtil.validate(getClass().getResource("f03.xml").toURI());
-    }
-
-    @Test
-    public void testNs10NoNameUnmarshall() throws Exception {
-        URL url = getClass().getResource("f03.xml");
-        Features features = JaxbUtil.unmarshal(url.toExternalForm(), true);
-        assertNotNull(features);
-    }
-
-    @Test
-    public void testNs11() throws Exception {
-        FeatureValidationUtil.validate(getClass().getResource("f04.xml").toURI());
-    }
-
-    @Test
-    public void testNs11Unmarshall() throws Exception {
-        URL url = getClass().getResource("f04.xml");
-        Features features = JaxbUtil.unmarshal(url.toExternalForm(), true);
-        assertNotNull(features);
-    }
-
-    @Test
-    public void testNs11NoName() throws Exception {
-        try {
-            FeatureValidationUtil.validate(getClass().getResource("f05.xml").toURI());
-            fail("Validation should have failed");
-        } catch (Exception e) {
-            // ok
-        }
-    }
-
-    @Test
-    public void testNs12() throws Exception {
-        FeatureValidationUtil.validate(getClass().getResource("f06.xml").toURI());
-    }
-
-    @Test
-    public void testNs12Unmarshall() throws Exception {
-        URL url = getClass().getResource("f06.xml");
-        Features features = JaxbUtil.unmarshal(url.toExternalForm(), true);
-        assertNotNull(features);
-    }
-
-    @Test
-    public void testNs13() throws Exception {
-        FeatureValidationUtil.validate(getClass().getResource("f07.xml").toURI());
-    }
-
-    @Test
-    public void testNs13Unmarshall() throws Exception {
-        URL url = getClass().getResource("f07.xml");
-        Features features = JaxbUtil.unmarshal(url.toExternalForm(), true);
-        assertNotNull(features);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/test/java/org/apache/karaf/features/internal/service/OverridesTest.java
----------------------------------------------------------------------
diff --git a/features/src/test/java/org/apache/karaf/features/internal/service/OverridesTest.java b/features/src/test/java/org/apache/karaf/features/internal/service/OverridesTest.java
deleted file mode 100644
index d9093d5..0000000
--- a/features/src/test/java/org/apache/karaf/features/internal/service/OverridesTest.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.service;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.felix.utils.manifest.Clause;
-import org.apache.felix.utils.manifest.Parser;
-import org.apache.karaf.features.BundleInfo;
-import org.apache.karaf.features.internal.model.Bundle;
-import org.apache.karaf.features.internal.resolver.ResourceBuilder;
-import org.apache.karaf.features.internal.resolver.UriNamespace;
-import org.junit.Before;
-import org.junit.Test;
-import org.ops4j.pax.tinybundles.core.TinyBundles;
-import org.osgi.framework.BundleException;
-import org.osgi.resource.Resource;
-
-import static org.apache.karaf.features.internal.resolver.UriNamespace.getUri;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-public class OverridesTest {
-
-    private String bsn = "bsn";
-    private Resource b100;
-    private Resource b101;
-    private Resource b102;
-    private Resource b110;
-    private Resource c100;
-    private Resource c101;
-    private Resource c110;
-
-    @Before
-    public void setUp() throws BundleException {
-        b100 = resource("karaf-100.jar")
-                .set("Bundle-SymbolicName", bsn)
-                .set("Bundle-Version", "1.0.0")
-                .build();
-
-        b101 = resource("karaf-101.jar")
-                .set("Bundle-SymbolicName", bsn)
-                .set("Bundle-Version", "1.0.1")
-                .build();
-
-        b102 = resource("karaf-102.jar")
-                .set("Bundle-SymbolicName", bsn)
-                .set("Bundle-Version", "1.0.2")
-                .build();
-
-        b110 = resource("karaf-110.jar")
-                .set("Bundle-SymbolicName", bsn)
-                .set("Bundle-Version", "1.1.0")
-                .build();
-
-        c100 = resource("karafc-100.jar")
-                .set("Bundle-SymbolicName", bsn)
-                .set("Bundle-Version", "1.0.0")
-                .set("Bundle-Vendor", "Apache")
-                .build();
-
-        c101 = resource("karafc-101.jar")
-                .set("Bundle-SymbolicName", bsn)
-                .set("Bundle-Version", "1.0.1")
-                .set("Bundle-Vendor", "NotApache")
-                .build();
-
-        c110 = resource("karafc-110.jar")
-                .set("Bundle-SymbolicName", bsn)
-                .set("Bundle-Version", "1.1.0")
-                .set("Bundle-Vendor", "NotApache")
-                .build();
-    }
-
-    @Test
-    public void testDifferentVendors() throws IOException {
-        Map<String, Resource> map = asResourceMap(c100, c101, c110);
-        assertEquals(c100, map.get(getUri(c100)));
-        Overrides.override(map, Arrays.asList(getUri(c101), getUri(c110)));
-        assertEquals(c101, map.get(getUri(c100)));
-    }
-
-    @Test
-    public void testMatching101() throws IOException {
-        Map<String, Resource> map = asResourceMap(b100, b101, b110);
-        assertEquals(b100, map.get(getUri(b100)));
-        Overrides.override(map, Arrays.asList(getUri(b101), getUri(b110)));
-        assertEquals(b101, map.get(getUri(b100)));
-    }
-
-    @Test
-    public void testMatching102() throws IOException {
-        Map<String, Resource> map = asResourceMap(b100, b101, b102, b110);
-        assertEquals(b100, map.get(getUri(b100)));
-        Overrides.override(map, Arrays.asList(getUri(b101), getUri(b102), getUri(b110)));
-        assertEquals(b102, map.get(getUri(b100)));
-    }
-
-    @Test
-    public void testMatchingRange() throws IOException {
-        Map<String, Resource> map = asResourceMap(b100, b101, b110);
-        assertEquals(b100, map.get(getUri(b100)));
-        Overrides.override(map, Arrays.asList(getUri(b101), getUri(b110) + ";range=\"[1.0, 2.0)\""));
-        assertEquals(b110, map.get(getUri(b100)));
-    }
-
-    @Test
-    public void testNotMatching() throws IOException {
-        Map<String, Resource> map = asResourceMap(b100, b110);
-        assertEquals(b100, map.get(getUri(b100)));
-        Overrides.override(map, Arrays.asList(getUri(b110)));
-        assertEquals(b100, map.get(getUri(b100)));
-    }
-
-    @Test
-    public void testLoadOverrides() {
-        Set<String> overrides = Overrides.loadOverrides(getClass().getResource("overrides.properties").toExternalForm());
-        assertEquals(2, overrides.size());
-
-        Clause karafAdminCommand = null;
-        Clause karafAdminCore = null;
-        for (Clause clause : Parser.parseClauses(overrides.toArray(new String[overrides.size()]))) {
-            if (clause.getName().equals("mvn:org.apache.karaf.admin/org.apache.karaf.admin.command/2.3.0.redhat-61033X")) {
-                karafAdminCommand = clause;
-            }
-            if (clause.getName().equals("mvn:org.apache.karaf.admin/org.apache.karaf.admin.core/2.3.0.redhat-61033X")) {
-                karafAdminCore = clause;
-            }
-        }
-        assertNotNull("Missing admin.command bundle override", karafAdminCommand);
-        assertNotNull("Missing admin.core bundle override", karafAdminCore);
-        assertNotNull("Missing range on admin.core override", karafAdminCore.getAttribute(Overrides.OVERRIDE_RANGE));
-    }
-
-    /**
-     * Copies the content of {@link java.io.InputStream} to {@link java.io.OutputStream}.
-     *
-     * @param input
-     * @param output
-     * @throws java.io.IOException
-     */
-    private void copy(final InputStream input, final OutputStream output) throws IOException {
-        byte[] buffer = new byte[1024 * 16];
-        int n;
-        while (-1 != (n = input.read(buffer))) {
-            output.write(buffer, 0, n);
-            output.flush();
-        }
-        input.close();
-        output.close();
-    }
-
-    static Builder resource(String uri) {
-        return new Builder(uri);
-    }
-
-    static Map<String, Resource> asResourceMap(Resource... resources) {
-        Map<String, Resource> map = new HashMap<String, Resource>();
-        for (Resource resource : resources) {
-            map.put(getUri(resource), resource);
-        }
-        return map;
-    }
-
-    static class Builder {
-        String uri;
-        Map<String,String> headers = new HashMap<String,String>();
-        Builder(String uri) {
-            this.uri = uri;
-            this.headers.put("Bundle-ManifestVersion", "2");
-        }
-        Builder set(String key, String value) {
-            this.headers.put(key, value);
-            return this;
-        }
-        Resource build() throws BundleException {
-            return ResourceBuilder.build(uri, headers);
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/test/resources/org/apache/karaf/features/internal/service/f01.xml
----------------------------------------------------------------------
diff --git a/features/src/test/resources/org/apache/karaf/features/internal/service/f01.xml b/features/src/test/resources/org/apache/karaf/features/internal/service/f01.xml
deleted file mode 100644
index 814c722..0000000
--- a/features/src/test/resources/org/apache/karaf/features/internal/service/f01.xml
+++ /dev/null
@@ -1,92 +0,0 @@
-<?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 name="karaf-2.0.0">
-    <feature name="spring" version="3.0.3.RELEASE">
-        <bundle>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.aopalliance/1.0_6</bundle>
-        <bundle>mvn:org.springframework/spring-core/3.0.3.RELEASE</bundle>
-        <bundle>mvn:org.springframework/spring-asm/3.0.3.RELEASE</bundle>
-        <bundle>mvn:org.springframework/spring-expression/3.0.3.RELEASE</bundle>
-        <bundle>mvn:org.springframework/spring-beans/3.0.3.RELEASE</bundle>
-        <bundle>mvn:org.springframework/spring-aop/3.0.3.RELEASE</bundle>
-        <bundle>mvn:org.springframework/spring-context/3.0.3.RELEASE</bundle>
-        <bundle>mvn:org.springframework/spring-context-support/3.0.3.RELEASE</bundle>
-    </feature>
-    <feature name="spring-dm" version="1.2.0">
-        <feature version="3.0.3.RELEASE">spring</feature>
-        <bundle>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.cglib/2.2.2_1</bundle>
-        <bundle>mvn:org.springframework.osgi/spring-osgi-io/1.2.0</bundle>
-        <bundle>mvn:org.springframework.osgi/spring-osgi-core/1.2.0</bundle>
-        <bundle>mvn:org.springframework.osgi/spring-osgi-extender/1.2.0</bundle>
-        <bundle>mvn:org.springframework.osgi/spring-osgi-annotation/1.2.0</bundle>
-        <bundle>mvn:org.apache.karaf.deployer/org.apache.karaf.deployer.spring/2.0.0</bundle>
-    </feature>
-    <feature name="wrapper" version="2.0.0">
-        <bundle>mvn:org.apache.karaf.shell/org.apache.karaf.shell.wrapper/2.0.0</bundle>
-    </feature>
-    <feature name="obr" version="2.0.0">
-        <bundle>mvn:org.apache.felix/org.apache.felix.bundlerepository/1.6.4</bundle>
-        <bundle>mvn:org.apache.karaf.shell/org.apache.karaf.shell.obr/2.0.0</bundle>
-        <bundle>mvn:org.apache.karaf.features/org.apache.karaf.features.obr/2.0.0</bundle>
-    </feature>
-    <feature name="http" version="2.0.0">
-        <config name="org.ops4j.pax.web">
-            org.osgi.service.http.port=8181
-        </config>
-        <bundle>mvn:org.apache.geronimo.specs/geronimo-servlet_2.5_spec/1.1.2</bundle>
-        <bundle>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.jetty-bundle/6.1.22_1</bundle>
-        <bundle>mvn:org.ops4j.pax.web/pax-web-api/0.7.2</bundle>
-        <bundle>mvn:org.ops4j.pax.web/pax-web-spi/0.7.2</bundle>
-        <bundle>mvn:org.ops4j.pax.web/pax-web-runtime/0.7.2</bundle>
-        <bundle>mvn:org.ops4j.pax.web/pax-web-jetty/0.7.2</bundle>
-    </feature>
-    <feature name="war" version="2.0.0">
-        <feature version="2.0.0">http</feature>
-        <bundle>mvn:org.ops4j.pax.web/pax-web-jsp/0.7.2</bundle>
-        <bundle>mvn:org.ops4j.pax.web/pax-web-extender-war/0.7.2</bundle>
-        <bundle>mvn:org.ops4j.pax.web/pax-web-extender-whiteboard/0.7.2</bundle>
-        <bundle>mvn:org.ops4j.pax.url/pax-url-war/1.1.3</bundle>
-        <bundle>mvn:org.apache.karaf.deployer/org.apache.karaf.deployer.war/2.0.0</bundle>
-    </feature>
-    <feature name="webconsole" version="2.0.0">
-        <feature version="2.0.0">http</feature>
-        <config name="org.apache.karaf.webconsole">
-            realm=karaf
-        </config>
-        <bundle>mvn:org.apache.felix/org.apache.felix.metatype/1.0.2</bundle>
-        <bundle>mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.branding/2.0.0</bundle>
-        <bundle>mvn:org.apache.felix/org.apache.felix.webconsole/3.1.0</bundle>
-        <bundle>mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.admin/2.0.0</bundle>
-        <bundle>mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.features/2.0.0</bundle>
-        <bundle>mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.gogo/2.0.0</bundle>
-    </feature>
-    <feature name="ssh" version="2.0.0">
-        <config name="org.apache.karaf.shell.ssh">
-            sshPort=8101
-            sshHost=0.0.0.0
-            sshRealm=karaf
-        </config>
-        <bundle>mvn:org.apache.mina/mina-core/2.0.0-RC1</bundle>
-        <bundle>mvn:org.apache.sshd/sshd-core/0.4.0</bundle>
-        <bundle>mvn:org.apache.karaf.shell/org.apache.karaf.shell.ssh/2.0.0</bundle>
-    </feature>
-    <feature name="management" version="2.0.0">
-        <bundle>mvn:org.apache.karaf/org.apache.karaf.management/2.0.0</bundle>
-        <bundle>mvn:org.apache.aries.jmx/org.apache.aries.jmx/0.1-r964701</bundle>
-        <bundle>mvn:org.apache.aries.jmx/org.apache.aries.jmx.blueprint/0.1-r964701</bundle>
-    </feature>
-</features>

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/test/resources/org/apache/karaf/features/internal/service/f02.xml
----------------------------------------------------------------------
diff --git a/features/src/test/resources/org/apache/karaf/features/internal/service/f02.xml b/features/src/test/resources/org/apache/karaf/features/internal/service/f02.xml
deleted file mode 100644
index 1578faa..0000000
--- a/features/src/test/resources/org/apache/karaf/features/internal/service/f02.xml
+++ /dev/null
@@ -1,164 +0,0 @@
-<?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 name="karaf-2.2.0" xmlns="http://karaf.apache.org/xmlns/features/v1.0.0">
-    <feature name="spring" version="2.5.6.SEC02" resolver="(obr)">
-        <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.aopalliance/1.0_6</bundle>
-        <bundle>mvn:org.springframework/spring-core/2.5.6.SEC02</bundle>
-        <bundle>mvn:org.springframework/spring-beans/2.5.6.SEC02</bundle>
-        <bundle>mvn:org.springframework/spring-aop/2.5.6.SEC02</bundle>
-        <bundle>mvn:org.springframework/spring-context/2.5.6.SEC02</bundle>
-        <bundle>mvn:org.springframework/spring-context-support/2.5.6.SEC02</bundle>
-    </feature>
-    <feature name="spring-web" version="2.5.6.SEC02" resolver="(obr)">
-    	<feature version="2.5.6.SEC02">spring</feature>
-    	<feature version="2.2.0">http</feature>
-    	<bundle>mvn:org.springframework/spring-web/2.5.6.SEC02</bundle>
-		<bundle>mvn:org.springframework/spring-webmvc/2.5.6.SEC02</bundle>
-    </feature>
-    <feature name="spring" version="3.0.5.RELEASE" resolver="(obr)">
-        <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.aopalliance/1.0_6</bundle>
-        <bundle>mvn:org.springframework/spring-core/3.0.5.RELEASE</bundle>
-        <bundle>mvn:org.springframework/spring-asm/3.0.5.RELEASE</bundle>
-        <bundle>mvn:org.springframework/spring-expression/3.0.5.RELEASE</bundle>
-        <bundle>mvn:org.springframework/spring-beans/3.0.5.RELEASE</bundle>
-        <bundle>mvn:org.springframework/spring-aop/3.0.5.RELEASE</bundle>
-        <bundle>mvn:org.springframework/spring-context/3.0.5.RELEASE</bundle>
-        <bundle>mvn:org.springframework/spring-context-support/3.0.5.RELEASE</bundle>
-    </feature>
-    <feature name="spring-web" version="3.0.5.RELEASE" resolver="(obr)">
-    	<feature version="3.0.5.RELEASE">spring</feature>
-    	<feature version="2.2.0">http</feature>
-    	<bundle>mvn:org.springframework/spring-web/3.0.5.RELEASE</bundle>
-		<bundle>mvn:org.springframework/spring-webmvc/3.0.5.RELEASE</bundle>
-    </feature>
-    <feature name="spring-dm" version="1.2.1" resolver="(obr)">
-        <feature version="[2.5.6,4)">spring</feature>
-        <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.cglib/2.2.2_1</bundle>
-        <bundle>mvn:org.springframework.osgi/spring-osgi-io/1.2.1</bundle>
-        <bundle>mvn:org.springframework.osgi/spring-osgi-core/1.2.1</bundle>
-        <bundle>mvn:org.springframework.osgi/spring-osgi-extender/1.2.1</bundle>
-        <bundle>mvn:org.springframework.osgi/spring-osgi-annotation/1.2.1</bundle>
-        <bundle>mvn:org.apache.karaf.deployer/org.apache.karaf.deployer.spring/2.2.0</bundle>
-    </feature>
-    <feature name="spring-dm-web" version="1.2.1" resolver="(obr)">
-    	<feature version="1.2.1">spring-dm</feature>
-    	<feature version="[2.5.6,4)">spring-web</feature>
-    	<feature version="2.2.0">http</feature>
-		<bundle>mvn:org.springframework.osgi/spring-osgi-web/1.2.1</bundle>
-    </feature>
-    <feature name="wrapper" version="2.2.0">
-        <bundle>mvn:org.apache.karaf.shell/org.apache.karaf.shell.wrapper/2.2.0</bundle>
-    </feature>
-    <feature name="obr" version="2.2.0">
-        <bundle>mvn:org.apache.felix/org.apache.felix.bundlerepository/1.6.4</bundle>
-        <bundle>mvn:org.apache.karaf.shell/org.apache.karaf.shell.obr/2.2.0</bundle>
-        <bundle>mvn:org.apache.karaf.features/org.apache.karaf.features.obr/2.2.0</bundle>
-    </feature>
-    <feature name="config" version="2.2.0">
-        <bundle start-level='30'>mvn:org.apache.karaf.shell/org.apache.karaf.shell.config/2.2.0</bundle>
-    </feature>
-	<feature name="jetty" version="7.2.2.v20101205" resolver="(obr)">
-		<bundle dependency='true'>mvn:org.apache.geronimo.specs/geronimo-servlet_2.5_spec/1.1.2</bundle>
-        <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.asm/3.3_1</bundle>
-	    <bundle>mvn:org.eclipse.jetty/jetty-util/7.2.2.v20101205</bundle>
-	    <bundle>mvn:org.eclipse.jetty/jetty-io/7.2.2.v20101205</bundle>
-	    <bundle>mvn:org.eclipse.jetty/jetty-http/7.2.2.v20101205</bundle>
-	    <bundle>mvn:org.eclipse.jetty/jetty-continuation/7.2.2.v20101205</bundle>
-	    <bundle>mvn:org.eclipse.jetty/jetty-server/7.2.2.v20101205</bundle>
-	    <bundle>mvn:org.eclipse.jetty/jetty-security/7.2.2.v20101205</bundle>
-	    <bundle>mvn:org.eclipse.jetty/jetty-servlet/7.2.2.v20101205</bundle>
-    	<bundle>mvn:org.eclipse.jetty/jetty-xml/7.2.2.v20101205</bundle>
-	</feature>
-	<feature name="jetty-jaas" version="7.2.2.v20101205" resolver="(obr)">
-		<feature version="[7.0,8.0)">jetty</feature>
-		<bundle dependency='true'>mvn:javax.mail/mail/1.4.3</bundle>
-		<bundle dependency='true'>mvn:org.apache.geronimo.specs/geronimo-jta_1.1_spec/1.1.1</bundle>
-		<bundle>mvn:org.eclipse.jetty/jetty-webapp/7.2.2.v20101205</bundle>
-		<bundle>mvn:org.eclipse.jetty/jetty-jndi/7.2.2.v20101205</bundle>
-		<bundle>mvn:org.eclipse.jetty/jetty-plus/7.2.2.v20101205</bundle>
-	</feature>
-    <feature name="http" version="2.2.0" resolver="(obr)">
-    	<configfile finalname="/etc/jetty.xml">mvn:org.apache.karaf/apache-karaf/2.2.0/xml/jettyconfig</configfile>
-		<config name="org.ops4j.pax.web">
-            org.osgi.service.http.port=8181
-            javax.servlet.context.tempdir=${karaf.data}/pax-web-jsp
-            org.ops4j.pax.web.config.file=${karaf.etc}/jetty.xml
-        </config>
-        <feature version="[7.0,8.0)">jetty</feature>
-    	<bundle>mvn:org.ops4j.pax.web/pax-web-api/1.0.1</bundle>
-        <bundle>mvn:org.ops4j.pax.web/pax-web-spi/1.0.1</bundle>
-        <bundle>mvn:org.ops4j.pax.web/pax-web-runtime/1.0.1</bundle>
-        <bundle>mvn:org.ops4j.pax.web/pax-web-jetty/1.0.1</bundle>
-    </feature>
-    <feature name="war" version="2.2.0" resolver="(obr)">
-        <config name="org.ops4j.pax.url.war">
-            org.ops4j.pax.url.war.importPaxLoggingPackages=true
-        </config>
-        <feature>http</feature>
-        <bundle start-level='30'>mvn:org.apache.karaf.shell/org.apache.karaf.shell.web/2.2.0</bundle>
-        <bundle>mvn:org.ops4j.pax.web/pax-web-jsp/1.0.1</bundle>
-        <bundle>mvn:org.ops4j.pax.web/pax-web-extender-war/1.0.1</bundle>
-        <bundle>mvn:org.ops4j.pax.web/pax-web-extender-whiteboard/1.0.1</bundle>
-        <bundle>mvn:org.ops4j.pax.web/pax-web-deployer/1.0.1</bundle>
-        <bundle>mvn:org.ops4j.pax.url/pax-url-war/1.2.5</bundle>
-    </feature>
-    <feature name="kar" version="2.2.0">
-        <bundle>mvn:org.apache.karaf.deployer/org.apache.karaf.deployer.kar/2.2.0</bundle>
-    </feature>
-    <feature name="webconsole-base" version="2.2.0">
-        <config name="org.apache.karaf.webconsole">
-            realm=karaf
-        </config>
-        <feature>http</feature>
-        <bundle>mvn:org.apache.felix/org.apache.felix.metatype/1.0.4</bundle>
-        <bundle>mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.branding/2.2.0</bundle>
-        <bundle>mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.console/2.2.0</bundle>
-    </feature>
-    <feature name="webconsole" version="2.2.0">
-        <feature version="2.2.0">webconsole-base</feature>
-        <bundle>mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.admin/2.2.0</bundle>
-        <bundle>mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.features/2.2.0</bundle>
-        <bundle>mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.gogo/2.2.0</bundle>
-		<bundle>mvn:org.apache.felix/org.apache.felix.webconsole.plugins.event/1.0.2</bundle>
-    </feature>
-    <feature name="ssh" version="2.2.0">
-        <config name="org.apache.karaf.shell">
-            sshPort=8101
-            sshHost=0.0.0.0
-            sshRealm=karaf
-            hostKey=${karaf.etc}/host.key
-        </config>
-        <bundle dependency='true'>mvn:org.apache.mina/mina-core/2.0.1</bundle>
-        <bundle dependency='true'>mvn:org.apache.sshd/sshd-core/0.5.0</bundle>
-        <bundle>mvn:org.apache.karaf.shell/org.apache.karaf.shell.ssh/2.2.0</bundle>
-    </feature>
-    <feature name="management" version="2.2.0">
-        <bundle>mvn:org.apache.karaf/org.apache.karaf.management/2.2.0</bundle>
-        <bundle>mvn:org.apache.aries.jmx/org.apache.aries.jmx/0.3</bundle>
-        <bundle>mvn:org.apache.aries.jmx/org.apache.aries.jmx.blueprint/0.3</bundle>
-    </feature>
-    <feature name="eventadmin" version="2.2.0">
-		<bundle start-level='30'>mvn:org.apache.felix/org.apache.felix.eventadmin/1.2.8</bundle>
-    </feature>
-    <feature name="jasypt-encryption" version="2.2.0" resolver="(obr)">
-        <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.commons-codec/1.3_3</bundle>
-        <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.commons-lang/2.4_4</bundle>
-        <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.jasypt/1.7_1</bundle>
-        <bundle>mvn:org.apache.karaf.jaas/org.apache.karaf.jaas.jasypt/2.2.0</bundle>
-    </feature>
-</features>

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/test/resources/org/apache/karaf/features/internal/service/f03.xml
----------------------------------------------------------------------
diff --git a/features/src/test/resources/org/apache/karaf/features/internal/service/f03.xml b/features/src/test/resources/org/apache/karaf/features/internal/service/f03.xml
deleted file mode 100644
index c058095..0000000
--- a/features/src/test/resources/org/apache/karaf/features/internal/service/f03.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?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 xmlns="http://karaf.apache.org/xmlns/features/v1.0.0">
-    <feature name="spring" version="2.5.6.SEC02" resolver="(obr)">
-        <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.aopalliance/1.0_6</bundle>
-        <bundle>mvn:org.springframework/spring-core/2.5.6.SEC02</bundle>
-        <bundle>mvn:org.springframework/spring-beans/2.5.6.SEC02</bundle>
-        <bundle>mvn:org.springframework/spring-aop/2.5.6.SEC02</bundle>
-        <bundle>mvn:org.springframework/spring-context/2.5.6.SEC02</bundle>
-        <bundle>mvn:org.springframework/spring-context-support/2.5.6.SEC02</bundle>
-    </feature>
-</features>

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/test/resources/org/apache/karaf/features/internal/service/f04.xml
----------------------------------------------------------------------
diff --git a/features/src/test/resources/org/apache/karaf/features/internal/service/f04.xml b/features/src/test/resources/org/apache/karaf/features/internal/service/f04.xml
deleted file mode 100644
index 85f28ad..0000000
--- a/features/src/test/resources/org/apache/karaf/features/internal/service/f04.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?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 name="karaf" xmlns="http://karaf.apache.org/xmlns/features/v1.1.0">
-    <feature name="spring" version="2.5.6.SEC02" resolver="(obr)">
-        <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.aopalliance/1.0_6</bundle>
-        <bundle>mvn:org.springframework/spring-core/2.5.6.SEC02</bundle>
-        <bundle>mvn:org.springframework/spring-beans/2.5.6.SEC02</bundle>
-        <bundle>mvn:org.springframework/spring-aop/2.5.6.SEC02</bundle>
-        <bundle>mvn:org.springframework/spring-context/2.5.6.SEC02</bundle>
-        <bundle>mvn:org.springframework/spring-context-support/2.5.6.SEC02</bundle>
-    </feature>
-</features>
-

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/test/resources/org/apache/karaf/features/internal/service/f05.xml
----------------------------------------------------------------------
diff --git a/features/src/test/resources/org/apache/karaf/features/internal/service/f05.xml b/features/src/test/resources/org/apache/karaf/features/internal/service/f05.xml
deleted file mode 100644
index 15d84e2..0000000
--- a/features/src/test/resources/org/apache/karaf/features/internal/service/f05.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?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 xmlns="http://karaf.apache.org/xmlns/features/v1.1.0">
-    <feature name="spring" version="2.5.6.SEC02" resolver="(obr)">
-        <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.aopalliance/1.0_6</bundle>
-        <bundle>mvn:org.springframework/spring-core/2.5.6.SEC02</bundle>
-        <bundle>mvn:org.springframework/spring-beans/2.5.6.SEC02</bundle>
-        <bundle>mvn:org.springframework/spring-aop/2.5.6.SEC02</bundle>
-        <bundle>mvn:org.springframework/spring-context/2.5.6.SEC02</bundle>
-        <bundle>mvn:org.springframework/spring-context-support/2.5.6.SEC02</bundle>
-    </feature>
-</features>
-

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/test/resources/org/apache/karaf/features/internal/service/f06.xml
----------------------------------------------------------------------
diff --git a/features/src/test/resources/org/apache/karaf/features/internal/service/f06.xml b/features/src/test/resources/org/apache/karaf/features/internal/service/f06.xml
deleted file mode 100644
index 51e78f1..0000000
--- a/features/src/test/resources/org/apache/karaf/features/internal/service/f06.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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 name="karaf" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0">
-    <feature name="spring" version="2.5.6.SEC02" resolver="(obr)">
-        <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.aopalliance/1.0_4</bundle>
-        <bundle>mvn:org.springframework/spring-core/2.5.6.SEC02</bundle>
-        <bundle>mvn:org.springframework/spring-beans/2.5.6.SEC02</bundle>
-        <bundle>mvn:org.springframework/spring-aop/2.5.6.SEC02</bundle>
-        <bundle>mvn:org.springframework/spring-context/2.5.6.SEC02</bundle>
-        <bundle>mvn:org.springframework/spring-context-support/2.5.6.SEC02</bundle>
-        <conditional>
-            <condition>http</condition>
-            <bundle>mvn:org.springframework/spring-web/2.5.6.SEC02</bundle>
-        </conditional>
-        <conditional>
-            <condition>req:osgi.ee;filter:="(&amp;(osgi.ee=JavaSE)(!(version>=1.7)))"</condition>
-            <bundle start="true" start-level="30">mvn:org.apache.mina/mina-core/${mina.version}</bundle>
-        </conditional>
-    </feature>
-</features>
-

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/test/resources/org/apache/karaf/features/internal/service/f07.xml
----------------------------------------------------------------------
diff --git a/features/src/test/resources/org/apache/karaf/features/internal/service/f07.xml b/features/src/test/resources/org/apache/karaf/features/internal/service/f07.xml
deleted file mode 100644
index 5b7dd90..0000000
--- a/features/src/test/resources/org/apache/karaf/features/internal/service/f07.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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 name="karaf" xmlns="http://karaf.apache.org/xmlns/features/v1.3.0">
-    <feature name="spring" version="2.5.6.SEC02" resolver="(obr)">
-        <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.aopalliance/1.0_4</bundle>
-        <bundle>mvn:org.springframework/spring-core/2.5.6.SEC02</bundle>
-        <bundle>mvn:org.springframework/spring-beans/2.5.6.SEC02</bundle>
-        <bundle>mvn:org.springframework/spring-aop/2.5.6.SEC02</bundle>
-        <bundle>mvn:org.springframework/spring-context/2.5.6.SEC02</bundle>
-        <bundle>mvn:org.springframework/spring-context-support/2.5.6.SEC02</bundle>
-        <conditional>
-            <condition>http</condition>
-            <bundle>mvn:org.springframework/spring-web/2.5.6.SEC02</bundle>
-        </conditional>
-        <capability>
-            service-reference;effective:=active;objectClass=org.apache.aries.proxy.ProxyManager
-        </capability>
-    </feature>
-</features>
-

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/test/resources/org/apache/karaf/features/internal/service/overrides.properties
----------------------------------------------------------------------
diff --git a/features/src/test/resources/org/apache/karaf/features/internal/service/overrides.properties b/features/src/test/resources/org/apache/karaf/features/internal/service/overrides.properties
deleted file mode 100644
index d34fa7e..0000000
--- a/features/src/test/resources/org/apache/karaf/features/internal/service/overrides.properties
+++ /dev/null
@@ -1,23 +0,0 @@
-
-################################################################################
-#
-#    Licensed to the Apache Software Foundation (ASF) under one or more
-#    contributor license agreements.  See the NOTICE file distributed with
-#    this work for additional information regarding copyright ownership.
-#    The ASF licenses this file to You under the Apache License, Version 2.0
-#    (the "License"); you may not use this file except in compliance with
-#    the License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS,
-#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-#    See the License for the specific language governing permissions and
-#    limitations under the License.
-#
-################################################################################
-
-# Sample etc/overrides.properties file for testing purposes
-mvn:org.apache.karaf.admin/org.apache.karaf.admin.command/2.3.0.redhat-61033X
-mvn:org.apache.karaf.admin/org.apache.karaf.admin.core/2.3.0.redhat-61033X;range=[2.3.0,2.5)

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/test/resources/org/apache/karaf/features/internal/service/repo2.xml
----------------------------------------------------------------------
diff --git a/features/src/test/resources/org/apache/karaf/features/internal/service/repo2.xml b/features/src/test/resources/org/apache/karaf/features/internal/service/repo2.xml
deleted file mode 100644
index 5fd51d0..0000000
--- a/features/src/test/resources/org/apache/karaf/features/internal/service/repo2.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<!--
-
-    Licensed to the Apache Software Foundation (ASF) under one or more
-    contributor license agreements.  See the NOTICE file distributed with
-    this work for additional information regarding copyright ownership.
-    The ASF licenses this file to You under the Apache License, Version 2.0
-    (the "License"); you may not use this file except in compliance with
-    the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT 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 name="repo2">
-    <feature name="common">
-        <bundle>b1</bundle>
-    </feature>
-    <feature name="f1">
-        <feature>common</feature>
-        <bundle>b2</bundle>
-    </feature>
-    <feature name="f2">
-        <feature>common</feature>
-        <feature>f1</feature>
-        <bundle>b3</bundle>
-    </feature>
-    <feature name="f3">
-        <feature>f1</feature>
-        <feature>f2</feature>
-    	<bundle>b4</bundle>
-    </feature>
-    <feature name="all">
-        <feature>f1</feature>
-        <feature>f2</feature>
-        <feature>f3</feature>
-    </feature>
-</features>

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/test/resources/org/apache/karaf/features/repo1.xml
----------------------------------------------------------------------
diff --git a/features/src/test/resources/org/apache/karaf/features/repo1.xml b/features/src/test/resources/org/apache/karaf/features/repo1.xml
deleted file mode 100644
index 641ef12..0000000
--- a/features/src/test/resources/org/apache/karaf/features/repo1.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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 name="test" xmlns="http://karaf.apache.org/xmlns/features/v1.1.0">
-    <repository>urn:r1</repository>
-    <feature name="f1" region="foo">
-        <config name="c1">
-            k=v
-        </config>
-        <bundle>b1</bundle>
-        <bundle>b2</bundle>
-    </feature>
-    <feature name="f2">
-        <feature>f1</feature>
-        <bundle>b3</bundle>
-    </feature>
-    <feature name="f3">
-    	<configfile finalname="cf1" override="true">cfloc</configfile>
-    	<bundle>b4</bundle> 
-    </feature>
-</features>

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/test/resources/org/apache/karaf/features/repo2.xml
----------------------------------------------------------------------
diff --git a/features/src/test/resources/org/apache/karaf/features/repo2.xml b/features/src/test/resources/org/apache/karaf/features/repo2.xml
deleted file mode 100644
index f5e96ae..0000000
--- a/features/src/test/resources/org/apache/karaf/features/repo2.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?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 name="test" xmlns="http://karaf.apache.org/xmlns/features/v1.0.0">
-    <repository>
-        urn:r1
-    </repository>
-    <feature name="f1" region="foo">
-        <config name="c1">
-            k=v
-        </config>
-        <bundle>b1</bundle>
-        <bundle>b2</bundle>
-    </feature>
-    <feature name="f2">
-        <feature>f1</feature>
-        <bundle>b3</bundle>
-    </feature>
-    <feature name="f3">
-    	<configfile finalname="cf1" override="true">cfloc</configfile>
-    	<bundle>b4</bundle> 
-    </feature>
-</features>

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/test/resources/org/apache/karaf/features/repo3.xml
----------------------------------------------------------------------
diff --git a/features/src/test/resources/org/apache/karaf/features/repo3.xml b/features/src/test/resources/org/apache/karaf/features/repo3.xml
deleted file mode 100644
index ffe08ed..0000000
--- a/features/src/test/resources/org/apache/karaf/features/repo3.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?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 name="test" xmlns="http://karaf.apache.org/xmlns/features/v1.3.0">
-    <feature name="f1">
-        <capability>
-            cap
-        </capability>
-        <requirement>
-            req
-        </requirement>
-    </feature>
-</features>

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/instance/pom.xml
----------------------------------------------------------------------
diff --git a/instance/pom.xml b/instance/pom.xml
index baeb2f9..8d6ba13 100644
--- a/instance/pom.xml
+++ b/instance/pom.xml
@@ -70,7 +70,7 @@
 
         <dependency>
             <groupId>org.apache.karaf.features</groupId>
-            <artifactId>org.apache.karaf.features.core</artifactId>
+            <artifactId>org.apache.karaf.features.command</artifactId>
             <optional>true</optional>
         </dependency>
 

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/kar/pom.xml
----------------------------------------------------------------------
diff --git a/kar/pom.xml b/kar/pom.xml
index 78629f6..8612252 100644
--- a/kar/pom.xml
+++ b/kar/pom.xml
@@ -65,7 +65,7 @@
         </dependency>
         <dependency>
             <groupId>org.apache.karaf.features</groupId>
-            <artifactId>org.apache.karaf.features.core</artifactId>
+            <artifactId>org.apache.karaf.features.command</artifactId>
             <scope>provided</scope>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 48c5951..6a0dcb4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -509,6 +509,11 @@
             </dependency>
             <dependency>
                 <groupId>org.apache.karaf.features</groupId>
+                <artifactId>org.apache.karaf.features.command</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.karaf.features</groupId>
                 <artifactId>org.apache.karaf.features.obr</artifactId>
                 <version>${project.version}</version>
             </dependency>


[18/33] Revert "[KARAF-2852] Merge features/core and features/command"

Posted by gn...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/service/Overrides.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/service/Overrides.java b/features/src/main/java/org/apache/karaf/features/internal/service/Overrides.java
deleted file mode 100644
index 233a8a2..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/service/Overrides.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.service;
-
-import java.io.BufferedReader;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.felix.utils.manifest.Clause;
-import org.apache.felix.utils.manifest.Parser;
-import org.apache.felix.utils.version.VersionRange;
-import org.osgi.framework.Version;
-import org.osgi.resource.Resource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import static org.apache.felix.resolver.Util.getSymbolicName;
-import static org.apache.felix.resolver.Util.getVersion;
-
-/**
- * Helper class to deal with overriden bundles at feature installation time.
- */
-public class Overrides {
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(Overrides.class);
-
-    protected static final String OVERRIDE_RANGE = "range";
-
-    /**
-     * Compute a list of bundles to install, taking into account overrides.
-     *
-     * The file containing the overrides will be loaded from the given url.
-     * Blank lines and lines starting with a '#' will be ignored, all other lines
-     * are considered as urls to override bundles.
-     *
-     * The list of resources to resolve will be scanned and for each bundle,
-     * if a bundle override matches that resource, it will be used instead.
-     *
-     * Matching is done on bundle symbolic name (they have to be the same)
-     * and version (the bundle override version needs to be greater than the
-     * resource to be resolved, and less than the next minor version.  A range
-     * directive can be added to the override url in which case, the matching
-     * will succeed if the resource to be resolved is within the given range.
-     *
-     * @param resources the list of resources to resolve
-     * @param overrides list of bundle overrides
-     */
-    public static void override(Map<String, Resource> resources, Collection<String> overrides) {
-        // Do override replacement
-        for (Clause override : Parser.parseClauses(overrides.toArray(new String[overrides.size()]))) {
-            String url = override.getName();
-            String vr  = override.getAttribute(OVERRIDE_RANGE);
-            Resource over = resources.get(url);
-            if (over == null) {
-                // Ignore invalid overrides
-                continue;
-            }
-            for (String uri : new ArrayList<String>(resources.keySet())) {
-                Resource res = resources.get(uri);
-                if (getSymbolicName(res).equals(getSymbolicName(over))) {
-                    VersionRange range;
-                    if (vr == null) {
-                        // default to micro version compatibility
-                        Version v1 = getVersion(res);
-                        Version v2 = new Version(v1.getMajor(), v1.getMinor() + 1, 0);
-                        range = new VersionRange(false, v1, v2, true);
-                    } else {
-                        range = VersionRange.parseVersionRange(vr);
-                    }
-                    // The resource matches, so replace it with the overridden resource
-                    // if the override is actually a newer version than what we currently have
-                    if (range.contains(getVersion(over)) && getVersion(res).compareTo(getVersion(over)) < 0) {
-                        resources.put(uri, over);
-                    }
-                }
-            }
-        }
-    }
-
-    public static Set<String> loadOverrides(String overridesUrl) {
-        Set<String> overrides = new HashSet<String>();
-        try {
-            if (overridesUrl != null) {
-                InputStream is = new URL(overridesUrl).openStream();
-                try {
-                    BufferedReader reader = new BufferedReader(new InputStreamReader(is));
-                    String line;
-                    while ((line = reader.readLine()) != null) {
-                        line = line.trim();
-                        if (!line.isEmpty() && !line.startsWith("#")) {
-                            overrides.add(line);
-                        }
-                    }
-                } finally {
-                    is.close();
-                }
-            }
-        } catch (Exception e) {
-            LOGGER.debug("Unable to load overrides bundles list", e);
-        }
-        return overrides;
-    }
-
-    public static String extractUrl(String override) {
-        Clause[] cs = Parser.parseClauses(new String[] { override });
-        if (cs.length != 1) {
-            throw new IllegalStateException("Override contains more than one clause: " + override);
-        }
-        return cs[0].getName();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/service/RepositoryImpl.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/service/RepositoryImpl.java b/features/src/main/java/org/apache/karaf/features/internal/service/RepositoryImpl.java
deleted file mode 100644
index 56e5102..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/service/RepositoryImpl.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.service;
-
-import java.io.FilterInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InterruptedIOException;
-import java.net.URI;
-
-import org.apache.karaf.features.Repository;
-import org.apache.karaf.features.internal.model.Features;
-import org.apache.karaf.features.internal.model.JaxbUtil;
-
-/**
- * The repository implementation.
- */
-public class RepositoryImpl implements Repository {
-
-    private final URI uri;
-    private Features features;
-
-    public RepositoryImpl(URI uri) {
-        this.uri = uri;
-    }
-
-    public URI getURI() {
-        return uri;
-    }
-
-    public String getName() throws IOException {
-        load();
-        return features.getName();
-    }
-
-    public URI[] getRepositories() throws Exception {
-        load();
-        URI[] result = new URI[features.getRepository().size()];
-        for (int i = 0; i < features.getRepository().size(); i++) {
-            String uri = features.getRepository().get(i);
-            uri = uri.trim();
-            result[i] = URI.create(uri);
-        }
-        return result;
-    }
-
-    public org.apache.karaf.features.Feature[] getFeatures() throws Exception {
-        load();
-        return features.getFeature().toArray(new org.apache.karaf.features.Feature[features.getFeature().size()]);
-    }
-
-
-    public void load() throws IOException {
-        load(false);
-    }
-
-    public void load(boolean validate) throws IOException {
-        if (features == null) {
-            try {
-                InputStream inputStream = uri.toURL().openStream();
-                inputStream = new FilterInputStream(inputStream) {
-    				@Override
-    				public int read(byte[] b, int off, int len) throws IOException {
-    					if (Thread.currentThread().isInterrupted()) {
-    						throw new InterruptedIOException();
-    					}
-    					return super.read(b, off, len);
-    				}
-    			};
-                try {
-                    features = JaxbUtil.unmarshal(uri.toASCIIString(), inputStream, validate);
-                } finally {
-                    inputStream.close();
-                }
-            } catch (IllegalArgumentException e) {
-                throw (IOException) new IOException(e.getMessage() + " : " + uri).initCause(e);
-            } catch (Exception e) {
-                throw (IOException) new IOException(e.getMessage() + " : " + uri).initCause(e);
-            }
-        }
-    }
-
-    @Override
-    public boolean isValid() {
-        throw new UnsupportedOperationException();
-    }
-}
-

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/service/RequirementSort.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/service/RequirementSort.java b/features/src/main/java/org/apache/karaf/features/internal/service/RequirementSort.java
deleted file mode 100644
index 96b99ee..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/service/RequirementSort.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.service;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.Set;
-
-import org.apache.karaf.features.internal.resolver.CapabilitySet;
-import org.apache.karaf.features.internal.resolver.SimpleFilter;
-import org.osgi.framework.Constants;
-import org.osgi.resource.Capability;
-import org.osgi.resource.Requirement;
-import org.osgi.resource.Resource;
-
-public class RequirementSort<T extends Resource>  {
-
-    /**
-     * Sorts {@link Resource} based on their {@link Requirement}s and {@link Capability}s.
-     */
-    public static <T extends Resource> Collection<T> sort(Collection<T> resources) {
-        Set<String> namespaces = new HashSet<String>();
-        for (Resource r : resources) {
-            for (Capability cap : r.getCapabilities(null)) {
-                namespaces.add(cap.getNamespace());
-            }
-        }
-        CapabilitySet capSet = new CapabilitySet(new ArrayList<String>(namespaces));
-        for (Resource r : resources) {
-            for (Capability cap : r.getCapabilities(null)) {
-                capSet.addCapability(cap);
-            }
-        }
-        Set<T> sorted = new LinkedHashSet<T>();
-        Set<T> visited = new LinkedHashSet<T>();
-        for (T r : resources) {
-            visit(r, visited, sorted, capSet);
-        }
-        return sorted;
-    }
-
-
-    private static <T extends Resource> void visit(T resource, Set<T> visited, Set<T> sorted, CapabilitySet capSet) {
-        if (!visited.add(resource)) {
-            return;
-        }
-        for (T r : collectDependencies(resource, capSet)) {
-            visit(r, visited, sorted, capSet);
-        }
-        sorted.add(resource);
-    }
-
-    @SuppressWarnings("unchecked")
-    private static <T extends Resource> Set<T> collectDependencies(T resource, CapabilitySet capSet) {
-        Set<T> result = new LinkedHashSet<T>();
-        for (Requirement requirement : resource.getRequirements(null)) {
-            String filter = requirement.getDirectives().get(Constants.FILTER_DIRECTIVE);
-            SimpleFilter sf = (filter != null)
-                    ? SimpleFilter.parse(filter)
-                    : new SimpleFilter(null, null, SimpleFilter.MATCH_ALL);
-            for (Capability cap : capSet.match(sf, true)) {
-                result.add((T) cap.getResource());
-            }
-        }
-        return result;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/service/SimpleDownloader.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/service/SimpleDownloader.java b/features/src/main/java/org/apache/karaf/features/internal/service/SimpleDownloader.java
deleted file mode 100644
index d1f16b9..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/service/SimpleDownloader.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.service;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.net.URL;
-
-import org.apache.karaf.features.internal.deployment.Downloader;
-import org.apache.karaf.features.internal.deployment.StreamProvider;
-import org.apache.karaf.features.internal.util.MultiException;
-
-public class SimpleDownloader implements Downloader {
-
-    private final MultiException exception = new MultiException("Error");
-
-    @Override
-    public void await() throws InterruptedException, MultiException {
-        exception.throwIfExceptions();
-    }
-
-    @Override
-    public void download(final String location, final DownloadCallback downloadCallback) throws MalformedURLException {
-        final URL url = new URL(location);
-        try {
-            downloadCallback.downloaded(new StreamProvider() {
-                @Override
-                public InputStream open() throws IOException {
-                    return url.openStream();
-                }
-            });
-        } catch (Exception e) {
-            exception.addException(e);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/service/State.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/service/State.java b/features/src/main/java/org/apache/karaf/features/internal/service/State.java
deleted file mode 100644
index c84f4e0..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/service/State.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.service;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-public class State {
-
-    public final AtomicBoolean bootDone = new AtomicBoolean();
-    public final Set<String> repositories = new TreeSet<String>();
-    public final Set<String> features = new TreeSet<String>();
-    public final Set<String> installedFeatures = new TreeSet<String>();
-    public final Set<Long> managedBundles = new TreeSet<Long>();
-    public final Map<String, Long> bundleChecksums = new HashMap<String, Long>();
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/service/StateStorage.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/service/StateStorage.java b/features/src/main/java/org/apache/karaf/features/internal/service/StateStorage.java
deleted file mode 100644
index 574e52e..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/service/StateStorage.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.service;
-
-import java.io.Closeable;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-import java.util.TreeSet;
-
-import org.apache.karaf.features.Feature;
-
-public abstract class StateStorage {
-
-    public void load(State state) throws IOException {
-        state.repositories.clear();
-        state.features.clear();
-        state.installedFeatures.clear();
-        state.managedBundles.clear();
-        InputStream is = getInputStream();
-        if (is != null) {
-            try {
-                Properties props = new Properties();
-                props.load(is);
-                state.bootDone.set(loadBool(props, "bootDone"));
-                state.repositories.addAll(loadSet(props, "repositories."));
-                state.features.addAll(loadSet(props, "features."));
-                state.installedFeatures.addAll(loadSet(props, "installed."));
-                state.managedBundles.addAll(toLongSet(loadSet(props, "managed.")));
-                state.bundleChecksums.putAll(toStringLongMap(loadMap(props, "checksums.")));
-            } finally {
-                close(is);
-            }
-        }
-    }
-
-    public void save(State state) throws IOException {
-        OutputStream os = getOutputStream();
-        if (os != null) {
-            try {
-                Properties props = new Properties();
-                saveBool(props, "bootDone", state.bootDone.get());
-                saveSet(props, "repositories.", state.repositories);
-                saveSet(props, "features.", state.features);
-                saveSet(props, "installed.", state.installedFeatures);
-                saveSet(props, "managed.", toStringSet(state.managedBundles));
-                saveMap(props, "checksums.", toStringStringMap(state.bundleChecksums));
-                props.store(os, "FeaturesService State");
-            } finally {
-                close(os);
-            }
-        }
-    }
-
-    protected abstract InputStream getInputStream() throws IOException;
-    protected abstract OutputStream getOutputStream() throws IOException;
-
-    protected boolean loadBool(Properties props, String key) {
-        return Boolean.parseBoolean(props.getProperty(key));
-    }
-
-    protected void saveBool(Properties props, String key, boolean val) {
-        props.setProperty(key, Boolean.toString(val));
-    }
-
-    protected Set<String> toStringSet(Set<Long> set) {
-        Set<String> ns = new TreeSet<String>();
-        for (long l : set) {
-            ns.add(Long.toString(l));
-        }
-        return ns;
-    }
-
-    protected Set<Long> toLongSet(Set<String> set) {
-        Set<Long> ns = new TreeSet<Long>();
-        for (String s : set) {
-            ns.add(Long.parseLong(s));
-        }
-        return ns;
-    }
-
-    protected void saveSet(Properties props, String prefix, Set<String> set) {
-        List<String> l = new ArrayList<String>(set);
-        props.put(prefix + "count", Integer.toString(l.size()));
-        for (int i = 0; i < l.size(); i++) {
-            props.put(prefix + "item." + i, l.get(i));
-        }
-    }
-
-    protected Set<String> loadSet(Properties props, String prefix) {
-        Set<String> l = new HashSet<String>();
-        String countStr = (String) props.get(prefix + "count");
-        if (countStr != null) {
-            int count = Integer.parseInt(countStr);
-            for (int i = 0; i < count; i++) {
-                l.add((String) props.get(prefix + "item." + i));
-            }
-        }
-        return l;
-    }
-
-    protected Map<String, String> toStringStringMap(Map<String, Long> map) {
-        Map<String, String> nm = new HashMap<String, String>();
-        for (Map.Entry<String, Long> entry : map.entrySet()) {
-            nm.put(entry.getKey(), Long.toString(entry.getValue()));
-        }
-        return nm;
-    }
-
-    protected Map<String, Long> toStringLongMap(Map<String, String> map) {
-        Map<String, Long> nm = new HashMap<String, Long>();
-        for (Map.Entry<String, String> entry : map.entrySet()) {
-            nm.put(entry.getKey(), Long.parseLong(entry.getValue()));
-        }
-        return nm;
-    }
-
-
-    protected void saveMap(Properties props, String prefix, Map<String, String> map) {
-        List<Map.Entry<String, String>> l = new ArrayList<Map.Entry<String, String>>(map.entrySet());
-        props.put(prefix + "count", Integer.toString(l.size()));
-        for (int i = 0; i < l.size(); i++) {
-            props.put(prefix + "key." + i, l.get(i).getKey());
-            props.put(prefix + "val." + i, l.get(i).getValue());
-        }
-    }
-
-    protected Map<String, String> loadMap(Properties props, String prefix) {
-        Map<String, String> l = new HashMap<String, String>();
-        String countStr = (String) props.get(prefix + "count");
-        if (countStr != null) {
-            int count = Integer.parseInt(countStr);
-            for (int i = 0; i < count; i++) {
-                String key = (String) props.get(prefix + "key." + i);
-                String val = (String) props.get(prefix + "val." + i);
-                l.put(key, val);
-            }
-        }
-        return l;
-    }
-
-
-    protected void close(Closeable closeable) {
-        if (closeable != null) {
-            try {
-                closeable.close();
-            } catch (IOException e) {
-                // Ignore
-            }
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/util/ChecksumUtils.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/util/ChecksumUtils.java b/features/src/main/java/org/apache/karaf/features/internal/util/ChecksumUtils.java
deleted file mode 100644
index 19fc706..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/util/ChecksumUtils.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.util;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.zip.CRC32;
-
-public class ChecksumUtils {
-
-    private ChecksumUtils() {
-    }
-
-    /**
-     * Compute a cheksum for the file or directory that consists of the name, length and the last modified date
-     * for a file and its children in case of a directory
-     *
-     * @param is the input stream
-     * @return a checksum identifying any change
-     */
-    public static long checksum(InputStream is) throws IOException
-    {
-        try {
-            CRC32 crc = new CRC32();
-            byte[] buffer = new byte[8192];
-            int l;
-            while ((l = is.read(buffer)) > 0) {
-                crc.update(buffer, 0, l);
-            }
-            return crc.getValue();
-        } finally {
-            if (is != null) {
-                try {
-                    is.close();
-                } catch (IOException e) {
-                    // Ignore
-                }
-            }
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/util/JsonReader.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/util/JsonReader.java b/features/src/main/java/org/apache/karaf/features/internal/util/JsonReader.java
deleted file mode 100644
index a53d8a5..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/util/JsonReader.java
+++ /dev/null
@@ -1,349 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.util;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- */
-public class JsonReader {
-
-    public static Object read(Reader reader) throws IOException {
-        return new JsonReader(reader).parse();
-    }
-
-    public static Object read(InputStream is) throws IOException {
-        return new JsonReader(new InputStreamReader(is)).parse();
-    }
-
-    //
-    // Implementation
-    //
-
-    private final Reader reader;
-    private final StringBuilder recorder;
-    private int current;
-    private int line = 1;
-    private int column = 0;
-
-    JsonReader(Reader reader) {
-        this.reader = reader;
-        recorder = new StringBuilder();
-    }
-
-    public Object parse() throws IOException {
-        read();
-        skipWhiteSpace();
-        Object result = readValue();
-        skipWhiteSpace();
-        if (!endOfText()) {
-            throw error("Unexpected character");
-        }
-        return result;
-    }
-
-    private Object readValue() throws IOException {
-        switch (current) {
-            case 'n':
-                return readNull();
-            case 't':
-                return readTrue();
-            case 'f':
-                return readFalse();
-            case '"':
-                return readString();
-            case '[':
-                return readArray();
-            case '{':
-                return readObject();
-            case '-':
-            case '0':
-            case '1':
-            case '2':
-            case '3':
-            case '4':
-            case '5':
-            case '6':
-            case '7':
-            case '8':
-            case '9':
-                return readNumber();
-            default:
-                throw expected("value");
-        }
-    }
-
-    private Collection<?> readArray() throws IOException {
-        read();
-        Collection<Object> array = new ArrayList<Object>();
-        skipWhiteSpace();
-        if (readChar(']')) {
-            return array;
-        }
-        do {
-            skipWhiteSpace();
-            array.add(readValue());
-            skipWhiteSpace();
-        } while (readChar(','));
-        if (!readChar(']')) {
-            throw expected("',' or ']'");
-        }
-        return array;
-    }
-
-    private Map<String, Object> readObject() throws IOException {
-        read();
-        Map<String, Object> object = new HashMap<String, Object>();
-        skipWhiteSpace();
-        if (readChar('}')) {
-            return object;
-        }
-        do {
-            skipWhiteSpace();
-            String name = readName();
-            skipWhiteSpace();
-            if (!readChar(':')) {
-                throw expected("':'");
-            }
-            skipWhiteSpace();
-            object.put(name, readValue());
-            skipWhiteSpace();
-        } while (readChar(','));
-        if (!readChar('}')) {
-            throw expected("',' or '}'");
-        }
-        return object;
-    }
-
-    private Object readNull() throws IOException {
-        read();
-        readRequiredChar('u');
-        readRequiredChar('l');
-        readRequiredChar('l');
-        return null;
-    }
-
-    private Boolean readTrue() throws IOException {
-        read();
-        readRequiredChar('r');
-        readRequiredChar('u');
-        readRequiredChar('e');
-        return Boolean.TRUE;
-    }
-
-    private Boolean readFalse() throws IOException {
-        read();
-        readRequiredChar('a');
-        readRequiredChar('l');
-        readRequiredChar('s');
-        readRequiredChar('e');
-        return Boolean.FALSE;
-    }
-
-    private void readRequiredChar(char ch) throws IOException {
-        if (!readChar(ch)) {
-            throw expected("'" + ch + "'");
-        }
-    }
-
-    private String readString() throws IOException {
-        read();
-        recorder.setLength(0);
-        while (current != '"') {
-            if (current == '\\') {
-                readEscape();
-            } else if (current < 0x20) {
-                throw expected("valid string character");
-            } else {
-                recorder.append((char) current);
-                read();
-            }
-        }
-        read();
-        return recorder.toString();
-    }
-
-    private void readEscape() throws IOException {
-        read();
-        switch (current) {
-            case '"':
-            case '/':
-            case '\\':
-                recorder.append((char) current);
-                break;
-            case 'b':
-                recorder.append('\b');
-                break;
-            case 'f':
-                recorder.append('\f');
-                break;
-            case 'n':
-                recorder.append('\n');
-                break;
-            case 'r':
-                recorder.append('\r');
-                break;
-            case 't':
-                recorder.append('\t');
-                break;
-            case 'u':
-                char[] hexChars = new char[4];
-                for (int i = 0; i < 4; i++) {
-                    read();
-                    if (!isHexDigit(current)) {
-                        throw expected("hexadecimal digit");
-                    }
-                    hexChars[i] = (char) current;
-                }
-                recorder.append((char) Integer.parseInt(String.valueOf(hexChars), 16));
-                break;
-            default:
-                throw expected("valid escape sequence");
-        }
-        read();
-    }
-
-    private Number readNumber() throws IOException {
-        recorder.setLength(0);
-        readAndAppendChar('-');
-        int firstDigit = current;
-        if (!readAndAppendDigit()) {
-            throw expected("digit");
-        }
-        if (firstDigit != '0') {
-            while (readAndAppendDigit()) {
-            }
-        }
-        readFraction();
-        readExponent();
-        return Double.parseDouble(recorder.toString());
-    }
-
-    private boolean readFraction() throws IOException {
-        if (!readAndAppendChar('.')) {
-            return false;
-        }
-        if (!readAndAppendDigit()) {
-            throw expected("digit");
-        }
-        while (readAndAppendDigit()) {
-        }
-        return true;
-    }
-
-    private boolean readExponent() throws IOException {
-        if (!readAndAppendChar('e') && !readAndAppendChar('E')) {
-            return false;
-        }
-        if (!readAndAppendChar('+')) {
-            readAndAppendChar('-');
-        }
-        if (!readAndAppendDigit()) {
-            throw expected("digit");
-        }
-        while (readAndAppendDigit()) {
-        }
-        return true;
-    }
-
-    private String readName() throws IOException {
-        if (current != '"') {
-            throw expected("name");
-        }
-        readString();
-        return recorder.toString();
-    }
-
-    private boolean readAndAppendChar(char ch) throws IOException {
-        if (current != ch) {
-            return false;
-        }
-        recorder.append(ch);
-        read();
-        return true;
-    }
-
-    private boolean readChar(char ch) throws IOException {
-        if (current != ch) {
-            return false;
-        }
-        read();
-        return true;
-    }
-
-    private boolean readAndAppendDigit() throws IOException {
-        if (!isDigit(current)) {
-            return false;
-        }
-        recorder.append((char) current);
-        read();
-        return true;
-    }
-
-    private void skipWhiteSpace() throws IOException {
-        while (isWhiteSpace(current) && !endOfText()) {
-            read();
-        }
-    }
-
-    private void read() throws IOException {
-        if (endOfText()) {
-            throw error("Unexpected end of input");
-        }
-        column++;
-        if (current == '\n') {
-            line++;
-            column = 0;
-        }
-        current = reader.read();
-    }
-
-    private boolean endOfText() {
-        return current == -1;
-    }
-
-    private IOException expected(String expected) {
-        if (endOfText()) {
-            return error("Unexpected end of input");
-        }
-        return error("Expected " + expected);
-    }
-
-    private IOException error(String message) {
-        return new IOException(message + " at " + line + ":" + column);
-    }
-
-    private static boolean isWhiteSpace(int ch) {
-        return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
-    }
-
-    private static boolean isDigit(int ch) {
-        return ch >= '0' && ch <= '9';
-    }
-
-    private static boolean isHexDigit(int ch) {
-        return ch >= '0' && ch <= '9' || ch >= 'a' && ch <= 'f' || ch >= 'A' && ch <= 'F';
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/util/JsonWriter.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/util/JsonWriter.java b/features/src/main/java/org/apache/karaf/features/internal/util/JsonWriter.java
deleted file mode 100644
index cba27fb..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/util/JsonWriter.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.util;
-
-import java.io.IOException;
-import java.io.Writer;
-import java.util.Collection;
-import java.util.Map;
-
-/**
- */
-public class JsonWriter {
-
-    public static void write(Writer writer, Object value) throws IOException {
-        if (value instanceof Map) {
-            writeObject(writer, (Map) value);
-        } else if (value instanceof Collection) {
-            writeArray(writer, (Collection) value);
-        } else if (value instanceof Number) {
-            writeNumber(writer, (Number) value);
-        } else if (value instanceof String) {
-            writeString(writer, (String) value);
-        } else if (value instanceof Boolean) {
-            writeBoolean(writer, (Boolean) value);
-        } else if (value == null) {
-            writeNull(writer);
-        } else {
-            throw new IllegalArgumentException("Unsupported value: " + value);
-        }
-    }
-
-    private static void writeObject(Writer writer, Map<?, ?> value) throws IOException {
-        writer.append('{');
-        boolean first = true;
-        for (Map.Entry entry : value.entrySet()) {
-            if (!first) {
-                writer.append(',');
-            } else {
-                first = false;
-            }
-            writeString(writer, (String) entry.getKey());
-            writer.append(':');
-            write(writer, entry.getValue());
-        }
-        writer.append('}');
-    }
-
-    private static void writeString(Writer writer, String value) throws IOException {
-        writer.append('"');
-        for (int i = 0; i < value.length(); i++) {
-            char c = value.charAt(i);
-            switch (c) {
-                case '\"':
-                case '\\':
-                case '\b':
-                case '\f':
-                case '\n':
-                case '\r':
-                case '\t':
-                    writer.append('\\');
-                    writer.append(c);
-                    break;
-                default:
-                    if (c < ' ' || (c >= '\u0080' && c < '\u00a0') || (c >= '\u2000' && c < '\u2100')) {
-                        String s = Integer.toHexString(c);
-                        writer.append('\\');
-                        writer.append('u');
-                        for (int j = s.length(); j < 4; j++) {
-                            writer.append('0');
-                        }
-                        writer.append(s);
-                    } else {
-                        writer.append(c);
-                    }
-                    break;
-            }
-        }
-        writer.append('"');
-    }
-
-    private static void writeNumber(Writer writer, Number value) throws IOException {
-        writer.append(value.toString());
-    }
-
-    private static void writeBoolean(Writer writer, Boolean value) throws IOException {
-        writer.append(Boolean.toString(value));
-    }
-
-    private static void writeArray(Writer writer, Collection<?> value) throws IOException {
-        writer.append('[');
-        boolean first = true;
-        for (Object obj : value) {
-            if (!first) {
-                writer.append(',');
-            } else {
-                first = false;
-            }
-            write(writer, obj);
-        }
-        writer.append(']');
-    }
-
-    private static void writeNull(Writer writer) throws IOException {
-        writer.append("null");
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/util/Macro.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/util/Macro.java b/features/src/main/java/org/apache/karaf/features/internal/util/Macro.java
deleted file mode 100644
index d30b7b5..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/util/Macro.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.util;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.apache.felix.utils.version.VersionTable;
-import org.osgi.framework.Version;
-
-public class Macro {
-
-    public static String transform(String macro, String value) {
-        if (macro.startsWith("${") && macro.endsWith("}")) {
-            String[] args = macro.substring(2, macro.length() - 1).split(";");
-            if ("version".equals(args[0])) {
-                if (args.length != 2) {
-                    throw new IllegalArgumentException("Invalid syntax for macro: " + macro);
-                }
-                return version(args[1], VersionTable.getVersion(value));
-            } else if ("range".equals(args[0])) {
-                if (args.length != 2) {
-                    throw new IllegalArgumentException("Invalid syntax for macro: " + macro);
-                }
-                return range(args[1], VersionTable.getVersion(value));
-            } else {
-                throw new IllegalArgumentException("Unknown macro: " + macro);
-            }
-        }
-        return value;
-    }
-
-    /**
-     * Modify a version to set a version policy. Thed policy is a mask that is
-     * mapped to a version.
-     *
-     * <pre>
-     * +           increment
-     * -           decrement
-     * =           maintain
-     * &tilde;           discard
-     *
-     * ==+      = maintain major, minor, increment micro, discard qualifier
-     * &tilde;&tilde;&tilde;=     = just get the qualifier
-     * version=&quot;[${version;==;${@}},${version;=+;${@}})&quot;
-	 * </pre>
-	 *
-	 * @param args
-     * @return
-     */
-    final static String	MASK_STRING			= "[\\-+=~0123456789]{0,3}[=~]?";
-
-    static String version(String mask, Version version) {
-        StringBuilder sb = new StringBuilder();
-        String del = "";
-
-        for (int i = 0; i < mask.length(); i++) {
-            char c = mask.charAt(i);
-            String result = null;
-            if (c != '~') {
-                if (i > 3) {
-                    throw new IllegalArgumentException("Version mask can only specify 3 digits");
-                } else if (i == 3) {
-                    result = version.getQualifier();
-                    if (result.isEmpty()) {
-                        result = null;
-                    }
-                } else if (Character.isDigit(c)) {
-                    // Handle masks like +00, =+0
-                    result = String.valueOf(c);
-                } else {
-                    int x = 0;
-                    switch (i) {
-                        case 0: x = version.getMajor(); break;
-                        case 1: x = version.getMinor(); break;
-                        case 2: x = version.getMicro(); break;
-                    }
-                    switch (c) {
-                        case '+' :
-                            x++;
-                            break;
-                        case '-' :
-                            x--;
-                            break;
-                        case '=' :
-                            break;
-                    }
-                    result = Integer.toString(x);
-                }
-                if (result != null) {
-                    sb.append(del);
-                    del = ".";
-                    sb.append(result);
-                }
-            }
-        }
-        return sb.toString();
-    }
-
-    /**
-     * Schortcut for version policy
-     *
-     * <pre>
-     * -provide-policy : ${policy;[==,=+)}
-     * -consume-policy : ${policy;[==,+)}
-     * </pre>
-     *
-     * @param args
-     * @return
-     */
-
-    static Pattern	RANGE_MASK		= Pattern.compile("(\\[|\\()(" + MASK_STRING + "),(" + MASK_STRING + ")(\\]|\\))");
-
-    static String range(String spec, Version version) {
-        Matcher m = RANGE_MASK.matcher(spec);
-        m.matches();
-        String floor = m.group(1);
-        String floorMask = m.group(2);
-        String ceilingMask = m.group(3);
-        String ceiling = m.group(4);
-
-        String left = version(floorMask, version);
-        String right = version(ceilingMask, version);
-
-        return floor + left + "," + right + ceiling;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/util/MultiException.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/util/MultiException.java b/features/src/main/java/org/apache/karaf/features/internal/util/MultiException.java
deleted file mode 100644
index 36af452..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/util/MultiException.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.util;
-
-import java.io.PrintStream;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-
-@SuppressWarnings("serial")
-public class MultiException extends Exception {
-
-    private List<Exception> exceptions = new ArrayList<Exception>();
-
-    public MultiException(String message) {
-        super(message);
-    }
-
-    public MultiException(String message, List<Exception> exceptions) {
-        super(message);
-        this.exceptions = exceptions;
-    }
-
-    public void addException(Exception e) {
-        exceptions.add(e);
-    }
-
-    public void throwIfExceptions() throws MultiException {
-        if (!exceptions.isEmpty()) {
-            throw this;
-        }
-    }
-    
-    public Throwable[] getCauses() {
-        return exceptions.toArray(new Throwable[exceptions.size()]);
-    }
-
-    @Override
-    public void printStackTrace()
-    {
-        super.printStackTrace();
-        for (Exception e : exceptions) {
-            e.printStackTrace();
-        }
-    }
-
-
-    /* ------------------------------------------------------------------------------- */
-    /**
-     * @see Throwable#printStackTrace(java.io.PrintStream)
-     */
-    @Override
-    public void printStackTrace(PrintStream out)
-    {
-        super.printStackTrace(out);
-        for (Exception e : exceptions) {
-            e.printStackTrace(out);
-        }
-    }
-
-    @Override
-    public void printStackTrace(PrintWriter out)
-    {
-        super.printStackTrace(out);
-        for (Exception e : exceptions) {
-            e.printStackTrace(out);
-        }
-    }
-
-    public static void throwIf(String message, List<Exception> exceptions) throws MultiException {
-        if (exceptions != null && !exceptions.isEmpty()) {
-            StringBuilder sb = new StringBuilder(message);
-            sb.append(":");
-            for (Exception e : exceptions) {
-                sb.append("\n\t");
-                sb.append(e.getMessage());
-            }
-            throw new MultiException(sb.toString(), exceptions);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/management/FeaturesServiceMBean.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/management/FeaturesServiceMBean.java b/features/src/main/java/org/apache/karaf/features/management/FeaturesServiceMBean.java
deleted file mode 100644
index 6afbbed..0000000
--- a/features/src/main/java/org/apache/karaf/features/management/FeaturesServiceMBean.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.management;
-
-import javax.management.openmbean.TabularData;
-
-public interface FeaturesServiceMBean {
-
-    TabularData getFeatures() throws Exception;
-
-    TabularData getRepositories() throws Exception;
-
-    void addRepository(String url) throws Exception;
-
-    void addRepository(String url, boolean install) throws Exception;
-
-    void removeRepository(String url) throws Exception;
-
-    void removeRepository(String url, boolean uninstall) throws Exception;
-
-    void installFeature(String name) throws Exception;
-
-    void installFeature(String name, boolean noRefresh) throws Exception;
-
-    void installFeature(String name, boolean noRefresh, boolean noStart) throws Exception;
-
-    void installFeature(String name, String version) throws Exception;
-
-    void installFeature(String name, String version, boolean noRefresh) throws Exception;
-
-    void installFeature(String name, String version, boolean noRefresh, boolean noStart) throws Exception;
-
-    TabularData infoFeature(String name) throws Exception;
-
-    TabularData infoFeature(String name, String version) throws Exception;
-
-    void uninstallFeature(String name) throws Exception;
-
-    void uninstallFeature(String name, boolean noRefresh) throws Exception;
-
-    void uninstallFeature(String name, String version) throws Exception;
-
-    void uninstallFeature(String name, String version, boolean noRefresh) throws Exception;
-
-    String FEATURE_NAME = "Name";
-
-    String FEATURE_VERSION = "Version";
-
-    String FEATURE_DEPENDENCIES = "Dependencies";
-
-    String FEATURE_BUNDLES = "Bundles";
-
-    String FEATURE_CONFIGURATIONS = "Configurations";
-    
-    String FEATURE_CONFIGURATIONFILES = "Configuration Files";
-
-    String FEATURE_INSTALLED = "Installed";
-
-    String FEATURE_CONFIG_PID = "Pid";
-    String FEATURE_CONFIG_ELEMENTS = "Elements";
-    String FEATURE_CONFIG_ELEMENT_KEY = "Key";
-    String FEATURE_CONFIG_ELEMENT_VALUE = "Value";
-    
-    String FEATURE_CONFIG_FILES_ELEMENTS = "Files";
-
-    /**
-     * The type of the event which is emitted for features events
-     */
-    String FEATURE_EVENT_TYPE = "org.apache.karaf.features.featureEvent";
-
-    String FEATURE_EVENT_EVENT_TYPE = "Type";
-
-    String FEATURE_EVENT_EVENT_TYPE_INSTALLED = "Installed";
-
-    String FEATURE_EVENT_EVENT_TYPE_UNINSTALLED = "Uninstalled";
-
-    /**
-     * The item names in the CompositeData representing a feature
-     */
-    String[] FEATURE = { FEATURE_NAME, FEATURE_VERSION, FEATURE_DEPENDENCIES, FEATURE_BUNDLES,
-                         FEATURE_CONFIGURATIONS, FEATURE_CONFIGURATIONFILES, FEATURE_INSTALLED };
-
-    String[] FEATURE_IDENTIFIER = { FEATURE_NAME, FEATURE_VERSION };
-
-    String[] FEATURE_CONFIG = { FEATURE_CONFIG_PID, FEATURE_CONFIG_ELEMENTS };
-    
-    String[] FEATURE_CONFIG_FILES = { FEATURE_CONFIG_FILES_ELEMENTS };
-
-    String[] FEATURE_CONFIG_ELEMENT = { FEATURE_CONFIG_ELEMENT_KEY, FEATURE_CONFIG_ELEMENT_VALUE };
-
-    /**
-     * The item names in the CompositeData representing the event raised for
-     * feature events within the OSGi container by this bean
-     */
-    String[] FEATURE_EVENT = { FEATURE_NAME, FEATURE_VERSION, FEATURE_EVENT_EVENT_TYPE };
-
-
-    String REPOSITORY_NAME = "Name";
-
-    String REPOSITORY_URI = "Uri";
-
-    String REPOSITORY_REPOSITORIES = "Repositories";
-
-    String REPOSITORY_FEATURES = "Features";
-
-    /**
-     * The type of the event which is emitted for repositories events
-     */
-    String REPOSITORY_EVENT_TYPE = "org.apache.karaf.features.repositoryEvent";
-
-    String REPOSITORY_EVENT_EVENT_TYPE = "Type";
-
-    String REPOSITORY_EVENT_EVENT_TYPE_ADDED = "Added";
-
-    String REPOSITORY_EVENT_EVENT_TYPE_REMOVED = "Removed";
-
-    /**
-     * The item names in the CompositeData representing a feature
-     */
-    String[] REPOSITORY = { REPOSITORY_NAME, REPOSITORY_URI,  REPOSITORY_REPOSITORIES, REPOSITORY_FEATURES };
-
-    /**
-     * The item names in the CompositeData representing the event raised for
-     * feature events within the OSGi container by this bean
-     */
-    String[] REPOSITORY_EVENT = { REPOSITORY_URI, REPOSITORY_EVENT_EVENT_TYPE };
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/management/codec/JmxFeature.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/management/codec/JmxFeature.java b/features/src/main/java/org/apache/karaf/features/management/codec/JmxFeature.java
deleted file mode 100644
index 54fa3c0..0000000
--- a/features/src/main/java/org/apache/karaf/features/management/codec/JmxFeature.java
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.management.codec;
-
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.management.openmbean.TabularData;
-import javax.management.openmbean.TabularType;
-import javax.management.openmbean.OpenDataException;
-import javax.management.openmbean.CompositeType;
-import javax.management.openmbean.OpenType;
-import javax.management.openmbean.SimpleType;
-import javax.management.openmbean.ArrayType;
-import javax.management.openmbean.CompositeData;
-import javax.management.openmbean.CompositeDataSupport;
-import javax.management.openmbean.TabularDataSupport;
-
-import org.apache.karaf.features.BundleInfo;
-import org.apache.karaf.features.ConfigFileInfo;
-import org.apache.karaf.features.Dependency;
-import org.apache.karaf.features.Feature;
-import org.apache.karaf.features.management.FeaturesServiceMBean;
-
-public class JmxFeature {
-
-    /**
-     * The CompositeType which represents a single feature
-     */
-    public final static CompositeType FEATURE;
-
-    /**
-     * The TabularType which represents a list of features
-     */
-    public final static TabularType FEATURE_TABLE;
-
-    public final static CompositeType FEATURE_IDENTIFIER;
-
-    public final static TabularType FEATURE_IDENTIFIER_TABLE;
-
-    public final static CompositeType FEATURE_CONFIG_ELEMENT;
-
-    public final static TabularType FEATURE_CONFIG_ELEMENT_TABLE;
-
-    public final static CompositeType FEATURE_CONFIG;
-
-    public final static TabularType FEATURE_CONFIG_TABLE;
-
-    public final static CompositeType FEATURE_CONFIG_FILES;
-    
-    public final static TabularType FEATURE_CONFIG_FILES_TABLE;
-    
-    private final CompositeData data;
-
-    public JmxFeature(Feature feature, boolean installed) {
-        try {
-            String[] itemNames = FeaturesServiceMBean.FEATURE;
-            Object[] itemValues = new Object[itemNames.length];
-            itemValues[0] = feature.getName();
-            itemValues[1] = feature.getVersion();
-            itemValues[2] = getDependencyIdentifierTable(feature.getDependencies());
-            itemValues[3] = getBundleUris(feature.getBundles());
-            itemValues[4] = getConfigTable(feature.getConfigurations());
-            itemValues[5] = getConfigFileList(feature.getConfigurationFiles());
-            itemValues[6] = installed;
-            data = new CompositeDataSupport(FEATURE, itemNames, itemValues);
-        } catch (OpenDataException e) {
-            throw new IllegalStateException("Cannot form feature open data", e);
-        }
-    }
-
-    public CompositeData asCompositeData() {
-        return data;
-    }
-
-    public static TabularData tableFrom(Collection<JmxFeature> features) {
-        TabularDataSupport table = new TabularDataSupport(FEATURE_TABLE);
-        for (JmxFeature feature : features) {
-            table.put(feature.asCompositeData());
-        }
-        return table;
-    }
-
-     private static TabularData getDependencyIdentifierTable(List<Dependency> features) throws OpenDataException {
-        TabularDataSupport table = new TabularDataSupport(FEATURE_IDENTIFIER_TABLE);
-        Set<String> featureSet = new HashSet<String>();
-        for (Dependency feature : features) {
-            if (featureSet.contains(feature.getName() + feature.getVersion())) {
-                continue;
-            } else {
-                featureSet.add(feature.getName() + feature.getVersion());
-            }
-            String[] itemNames = new String[] { FeaturesServiceMBean.FEATURE_NAME, FeaturesServiceMBean.FEATURE_VERSION };
-            Object[] itemValues = new Object[] { feature.getName(), feature.getVersion() };
-            CompositeData ident = new CompositeDataSupport(FEATURE_IDENTIFIER, itemNames, itemValues);
-            table.put(ident);
-        }
-        return table;
-    }
-
-    static String[] getBundleUris(List<BundleInfo> infos) {
-        String[] array = new String[infos.size()];
-        for (int i = 0; i < array.length; i++) {
-            array[i] = infos.get(i).getLocation();
-        }
-        return array;
-    }
-
-    static TabularData getConfigTable(Map<String, Map<String, String>> configs) throws OpenDataException {
-        TabularDataSupport table = new TabularDataSupport(FEATURE_CONFIG_TABLE);
-        for (Map.Entry<String, Map<String, String>> entry : configs.entrySet()) {
-            String[] itemNames = FeaturesServiceMBean.FEATURE_CONFIG;
-            Object[] itemValues = new Object[2];
-            itemValues[0] = entry.getKey();
-            itemValues[1] = getConfigElementTable(entry.getValue());
-            CompositeData config = new CompositeDataSupport(FEATURE_CONFIG, itemNames, itemValues);
-            table.put(config);
-        }
-        return table;
-    }
-    
-    static TabularData getConfigFileList(List<ConfigFileInfo> configFiles) throws OpenDataException {
-        TabularDataSupport table = new TabularDataSupport(FEATURE_CONFIG_FILES_TABLE);
-        for (ConfigFileInfo configFile : configFiles) {
-            String[] itemNames = FeaturesServiceMBean.FEATURE_CONFIG_FILES;
-            Object[] itemValues = { configFile.getFinalname() };
-            CompositeData config = new CompositeDataSupport(FEATURE_CONFIG_FILES, itemNames, itemValues);
-            table.put(config);
-        }
-        return table;
-    }
-
-    static TabularData getConfigElementTable(Map<String, String> config) throws OpenDataException {
-        TabularDataSupport table = new TabularDataSupport(FEATURE_CONFIG_ELEMENT_TABLE);
-        for (Map.Entry<String, String> entry : config.entrySet()) {
-            String[] itemNames = FeaturesServiceMBean.FEATURE_CONFIG_ELEMENT;
-            Object[] itemValues = { entry.getKey(), entry.getValue() };
-            CompositeData element = new CompositeDataSupport(FEATURE_CONFIG_ELEMENT, itemNames, itemValues);
-            table.put(element);
-        }
-        return table;
-    }
-
-
-    static {
-        FEATURE_IDENTIFIER = createFeatureIdentifierType();
-        FEATURE_IDENTIFIER_TABLE = createFeatureIdentifierTableType();
-        FEATURE_CONFIG_ELEMENT = createFeatureConfigElementType();
-        FEATURE_CONFIG_ELEMENT_TABLE = createFeatureConfigElementTableType();
-        FEATURE_CONFIG = createFeatureConfigType();
-        FEATURE_CONFIG_TABLE = createFeatureConfigTableType();
-        FEATURE_CONFIG_FILES =  createFeatureConfigFilesType();
-        FEATURE_CONFIG_FILES_TABLE = createFeatureConfigFilesTableType();
-        FEATURE = createFeatureType();
-        FEATURE_TABLE = createFeatureTableType();
-    }
-
-    private static CompositeType createFeatureIdentifierType() {
-        try {
-            String description = "This type identify a Karaf features";
-            String[] itemNames = FeaturesServiceMBean.FEATURE_IDENTIFIER;
-            OpenType[] itemTypes = new OpenType[itemNames.length];
-            String[] itemDescriptions = new String[itemNames.length];
-            itemTypes[0] = SimpleType.STRING;
-            itemTypes[1] = SimpleType.STRING;
-
-            itemDescriptions[0] = "The id of the feature";
-            itemDescriptions[1] = "The version of the feature";
-
-            return new CompositeType("FeatureIdentifier", description, itemNames,
-                    itemDescriptions, itemTypes);
-        } catch (OpenDataException e) {
-            throw new IllegalStateException("Unable to build featureIdentifier type", e);
-        }
-    }
-
-    private static TabularType createFeatureIdentifierTableType() {
-        try {
-            return new TabularType("Features", "The table of featureIdentifiers",
-                    FEATURE_IDENTIFIER, new String[] { FeaturesServiceMBean.FEATURE_NAME, FeaturesServiceMBean.FEATURE_VERSION });
-        } catch (OpenDataException e) {
-            throw new IllegalStateException("Unable to build featureIdentifier table type", e);
-        }
-    }
-
-    private static CompositeType createFeatureConfigElementType() {
-        try {
-            String description = "This type encapsulates Karaf feature config element";
-            String[] itemNames = FeaturesServiceMBean.FEATURE_CONFIG_ELEMENT;
-            OpenType[] itemTypes = new OpenType[itemNames.length];
-            String[] itemDescriptions = new String[itemNames.length];
-            itemTypes[0] = SimpleType.STRING;
-            itemTypes[1] = SimpleType.STRING;
-
-            itemDescriptions[0] = "The key";
-            itemDescriptions[1] = "The value";
-
-            return new CompositeType("ConfigElement", description, itemNames,
-                    itemDescriptions, itemTypes);
-        } catch (OpenDataException e) {
-            throw new IllegalStateException("Unable to build configElement type", e);
-        }
-    }
-
-    private static TabularType createFeatureConfigElementTableType() {
-        try {
-            return new TabularType("ConfigElement", "The table of configurations elements",
-                    FEATURE_CONFIG_ELEMENT, new String[] { FeaturesServiceMBean.FEATURE_CONFIG_ELEMENT_KEY});
-        } catch (OpenDataException e) {
-            throw new IllegalStateException("Unable to build feature table type", e);
-        }
-    }
-
-    private static CompositeType createFeatureConfigType() {
-        try {
-            String description = "This type encapsulates Karaf feature config";
-            String[] itemNames = FeaturesServiceMBean.FEATURE_CONFIG;
-            OpenType[] itemTypes = new OpenType[itemNames.length];
-            String[] itemDescriptions = new String[itemNames.length];
-            itemTypes[0] = SimpleType.STRING;
-            itemTypes[1] = FEATURE_CONFIG_ELEMENT_TABLE;
-
-            itemDescriptions[0] = "The PID of the config";
-            itemDescriptions[1] = "The configuration elements";
-
-            return new CompositeType("Config", description, itemNames,
-                    itemDescriptions, itemTypes);
-        } catch (OpenDataException e) {
-            throw new IllegalStateException("Unable to build configElement type", e);
-        }
-    }
-    
-    private static CompositeType createFeatureConfigFilesType() {
-        try {
-            String description = "This type encapsulates Karaf feature config files";
-            String[] itemNames = FeaturesServiceMBean.FEATURE_CONFIG_FILES;
-            OpenType[] itemTypes = new OpenType[itemNames.length];
-            String[] itemDescriptions = new String[itemNames.length];
-            itemTypes[0] = SimpleType.STRING;
-
-            itemDescriptions[0] = "The configuration file";
-
-            return new CompositeType("Config", description, itemNames,
-                    itemDescriptions, itemTypes);
-        } catch (OpenDataException e) {
-            throw new IllegalStateException("Unable to build configElement type", e);
-        }
-    }
-
-    private static TabularType createFeatureConfigTableType() {
-        try {
-            return new TabularType("Features", "The table of configurations",
-                    FEATURE_CONFIG, new String[] { FeaturesServiceMBean.FEATURE_CONFIG_PID});
-        } catch (OpenDataException e) {
-            throw new IllegalStateException("Unable to build feature table type", e);
-        }
-    }
-    
-    private static TabularType createFeatureConfigFilesTableType() {
-        try {
-            return new TabularType("Features", "The table of configuration files",
-            		FEATURE_CONFIG_FILES, new String[] { FeaturesServiceMBean.FEATURE_CONFIG_FILES_ELEMENTS });
-        } catch (OpenDataException e) {
-            throw new IllegalStateException("Unable to build feature table type", e);
-        }
-    }
-
-    private static CompositeType createFeatureType() {
-        try {
-            String description = "This type encapsulates Karaf features";
-            String[] itemNames = FeaturesServiceMBean.FEATURE;
-            OpenType[] itemTypes = new OpenType[itemNames.length];
-            String[] itemDescriptions = new String[itemNames.length];
-            itemTypes[0] = SimpleType.STRING;
-            itemTypes[1] = SimpleType.STRING;
-            itemTypes[2] = FEATURE_IDENTIFIER_TABLE;
-            itemTypes[3] = new ArrayType(1, SimpleType.STRING);
-            itemTypes[4] = FEATURE_CONFIG_TABLE;
-            itemTypes[5] = FEATURE_CONFIG_FILES_TABLE;
-            itemTypes[6] = SimpleType.BOOLEAN;
-
-            itemDescriptions[0] = "The name of the feature";
-            itemDescriptions[1] = "The version of the feature";
-            itemDescriptions[2] = "The feature dependencies";
-            itemDescriptions[3] = "The feature bundles";
-            itemDescriptions[4] = "The feature configurations";
-            itemDescriptions[5] = "The feature configuration files";
-            itemDescriptions[6] = "Whether the feature is installed";
-
-            return new CompositeType("Feature", description, itemNames,
-                    itemDescriptions, itemTypes);
-        } catch (OpenDataException e) {
-            throw new IllegalStateException("Unable to build feature type", e);
-        }
-    }
-
-    private static TabularType createFeatureTableType() {
-        try {
-            return new TabularType("Features", "The table of all features",
-                    FEATURE, new String[] { FeaturesServiceMBean.FEATURE_NAME, FeaturesServiceMBean.FEATURE_VERSION });
-        } catch (OpenDataException e) {
-            throw new IllegalStateException("Unable to build feature table type", e);
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/management/codec/JmxFeatureEvent.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/management/codec/JmxFeatureEvent.java b/features/src/main/java/org/apache/karaf/features/management/codec/JmxFeatureEvent.java
deleted file mode 100644
index 81f446b..0000000
--- a/features/src/main/java/org/apache/karaf/features/management/codec/JmxFeatureEvent.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.management.codec;
-
-import javax.management.openmbean.CompositeData;
-import javax.management.openmbean.CompositeDataSupport;
-import javax.management.openmbean.OpenDataException;
-import javax.management.openmbean.CompositeType;
-import javax.management.openmbean.OpenType;
-import javax.management.openmbean.SimpleType;
-
-import org.apache.karaf.features.FeatureEvent;
-import org.apache.karaf.features.management.FeaturesServiceMBean;
-
-public class JmxFeatureEvent {
-
-    public static final CompositeType FEATURE_EVENT;
-
-    private final CompositeData data;
-
-    public JmxFeatureEvent(FeatureEvent event) {
-        try {
-            String[] itemNames = FeaturesServiceMBean.FEATURE_EVENT;
-            Object[] itemValues = new Object[itemNames.length];
-            itemValues[0] = event.getFeature().getName();
-            itemValues[1] = event.getFeature().getVersion();
-            switch (event.getType()) {
-                case FeatureInstalled:   itemValues[2] = FeaturesServiceMBean.FEATURE_EVENT_EVENT_TYPE_INSTALLED; break;
-                case FeatureUninstalled: itemValues[2] = FeaturesServiceMBean.FEATURE_EVENT_EVENT_TYPE_UNINSTALLED; break;
-                default: throw new IllegalStateException("Unsupported event type: " + event.getType());
-            }
-            data = new CompositeDataSupport(FEATURE_EVENT, itemNames, itemValues);
-        } catch (OpenDataException e) {
-            throw new IllegalStateException("Cannot form feature event open data", e);
-        }
-    }
-
-    public CompositeData asCompositeData() {
-        return data;
-    }
-
-    static {
-        FEATURE_EVENT = createFeatureEventType();
-    }
-
-    private static CompositeType createFeatureEventType() {
-        try {
-            String description = "This type identify a Karaf feature event";
-            String[] itemNames = FeaturesServiceMBean.FEATURE_EVENT;
-            OpenType[] itemTypes = new OpenType[itemNames.length];
-            String[] itemDescriptions = new String[itemNames.length];
-            itemTypes[0] = SimpleType.STRING;
-            itemTypes[1] = SimpleType.STRING;
-            itemTypes[2] = SimpleType.STRING;
-
-            itemDescriptions[0] = "The id of the feature";
-            itemDescriptions[1] = "The version of the feature";
-            itemDescriptions[2] = "The type of the event";
-
-            return new CompositeType("FeatureEvent", description, itemNames,
-                    itemDescriptions, itemTypes);
-        } catch (OpenDataException e) {
-            throw new IllegalStateException("Unable to build featureEvent type", e);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/management/codec/JmxRepository.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/management/codec/JmxRepository.java b/features/src/main/java/org/apache/karaf/features/management/codec/JmxRepository.java
deleted file mode 100644
index fee1ab2..0000000
--- a/features/src/main/java/org/apache/karaf/features/management/codec/JmxRepository.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.management.codec;
-
-import java.util.Collection;
-import java.util.Arrays;
-import java.net.URI;
-import java.util.List;
-
-import javax.management.openmbean.TabularData;
-import javax.management.openmbean.CompositeType;
-import javax.management.openmbean.TabularType;
-import javax.management.openmbean.OpenType;
-import javax.management.openmbean.SimpleType;
-import javax.management.openmbean.OpenDataException;
-import javax.management.openmbean.ArrayType;
-import javax.management.openmbean.CompositeData;
-import javax.management.openmbean.TabularDataSupport;
-import javax.management.openmbean.CompositeDataSupport;
-
-import org.apache.karaf.features.Feature;
-import org.apache.karaf.features.Repository;
-import org.apache.karaf.features.management.FeaturesServiceMBean;
-
-public class JmxRepository {
-
-    public final static CompositeType REPOSITORY;
-
-    public final static TabularType REPOSITORY_TABLE;
-
-    private final CompositeData data;
-
-    public JmxRepository(Repository repository) {
-        try {
-            String[] itemNames = FeaturesServiceMBean.REPOSITORY;
-            Object[] itemValues = new Object[itemNames.length];
-            itemValues[0] = repository.getName();
-            itemValues[1] = repository.getURI().toString();
-            itemValues[2] = toStringArray(repository.getRepositories());
-            itemValues[3] = getFeatureIdentifierTable(Arrays.asList(repository.getFeatures()));
-            data = new CompositeDataSupport(REPOSITORY, itemNames, itemValues);
-        } catch (Exception e) {
-            throw new IllegalStateException("Cannot form repository open data", e);
-        }
-    }
-
-    public CompositeData asCompositeData() {
-        return data;
-    }
-
-    public static TabularData tableFrom(Collection<JmxRepository> repositories) {
-        TabularDataSupport table = new TabularDataSupport(REPOSITORY_TABLE);
-        for (JmxRepository repository : repositories) {
-            table.put(repository.asCompositeData());
-        }
-        return table;
-    }
-
-    private static String[] toStringArray(URI[] uris) {
-        if (uris == null) {
-            return null;
-        }
-        String[] res = new String[uris.length];
-        for (int i = 0; i < res.length; i++) {
-            res[i] = uris[i].toString();
-        }
-        return res;
-    }
-
-    static TabularData getFeatureIdentifierTable(List<Feature> features) throws OpenDataException {
-        TabularDataSupport table = new TabularDataSupport(JmxFeature.FEATURE_IDENTIFIER_TABLE);
-        for (Feature feature : features) {
-            String[] itemNames = new String[] { FeaturesServiceMBean.FEATURE_NAME, FeaturesServiceMBean.FEATURE_VERSION };
-            Object[] itemValues = new Object[] { feature.getName(), feature.getVersion() };
-            CompositeData ident = new CompositeDataSupport(JmxFeature.FEATURE_IDENTIFIER, itemNames, itemValues);
-            table.put(ident);
-        }
-        return table;
-    }
-
-    static {
-        REPOSITORY = createRepositoryType();
-        REPOSITORY_TABLE = createRepositoryTableType();
-    }
-
-    private static CompositeType createRepositoryType() {
-        try {
-            String description = "This type identify a Karaf repository";
-            String[] itemNames = FeaturesServiceMBean.REPOSITORY;
-            OpenType[] itemTypes = new OpenType[itemNames.length];
-            String[] itemDescriptions = new String[itemNames.length];
-            itemTypes[0] = SimpleType.STRING;
-            itemTypes[1] = SimpleType.STRING;
-            itemTypes[2] = new ArrayType(1, SimpleType.STRING);
-            itemTypes[3] = JmxFeature.FEATURE_IDENTIFIER_TABLE;
-
-            itemDescriptions[0] = "The name of the repository";
-            itemDescriptions[1] = "The uri of the repository";
-            itemDescriptions[2] = "The dependent repositories";
-            itemDescriptions[3] = "The list of included features";
-
-            return new CompositeType("Repository", description, itemNames,
-                    itemDescriptions, itemTypes);
-        } catch (OpenDataException e) {
-            throw new IllegalStateException("Unable to build repository type", e);
-        }
-    }
-
-    private static TabularType createRepositoryTableType() {
-        try {
-            return new TabularType("Features", "The table of repositories",
-                    REPOSITORY, new String[] { FeaturesServiceMBean.REPOSITORY_URI });
-        } catch (OpenDataException e) {
-            throw new IllegalStateException("Unable to build repository table type", e);
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/management/codec/JmxRepositoryEvent.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/management/codec/JmxRepositoryEvent.java b/features/src/main/java/org/apache/karaf/features/management/codec/JmxRepositoryEvent.java
deleted file mode 100644
index e00e85d..0000000
--- a/features/src/main/java/org/apache/karaf/features/management/codec/JmxRepositoryEvent.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.management.codec;
-
-import javax.management.openmbean.CompositeData;
-import javax.management.openmbean.CompositeType;
-import javax.management.openmbean.CompositeDataSupport;
-import javax.management.openmbean.OpenDataException;
-import javax.management.openmbean.OpenType;
-import javax.management.openmbean.SimpleType;
-
-import org.apache.karaf.features.RepositoryEvent;
-import org.apache.karaf.features.management.FeaturesServiceMBean;
-
-public class JmxRepositoryEvent {
-
-    public static final CompositeType REPOSITORY_EVENT;
-
-    private final CompositeData data;
-
-    public JmxRepositoryEvent(RepositoryEvent event) {
-        try {
-            String[] itemNames = FeaturesServiceMBean.REPOSITORY_EVENT;
-            Object[] itemValues = new Object[itemNames.length];
-            itemValues[0] = event.getRepository().getURI().toString();
-            switch (event.getType()) {
-                case RepositoryAdded:   itemValues[1] = FeaturesServiceMBean.REPOSITORY_EVENT_EVENT_TYPE_ADDED; break;
-                case RepositoryRemoved: itemValues[1] = FeaturesServiceMBean.REPOSITORY_EVENT_EVENT_TYPE_REMOVED; break;
-                default: throw new IllegalStateException("Unsupported event type: " + event.getType());
-            }
-            data = new CompositeDataSupport(REPOSITORY_EVENT, itemNames, itemValues);
-        } catch (OpenDataException e) {
-            throw new IllegalStateException("Cannot form repository event open data", e);
-        }
-    }
-
-    public CompositeData asCompositeData() {
-        return data;
-    }
-
-    static {
-        REPOSITORY_EVENT = createRepositoryEventType();
-    }
-
-    private static CompositeType createRepositoryEventType() {
-        try {
-            String description = "This type identify a Karaf repository event";
-            String[] itemNames = FeaturesServiceMBean.REPOSITORY_EVENT;
-            OpenType[] itemTypes = new OpenType[itemNames.length];
-            String[] itemDescriptions = new String[itemNames.length];
-            itemTypes[0] = SimpleType.STRING;
-            itemTypes[1] = SimpleType.STRING;
-
-            itemDescriptions[0] = "The uri of the repository";
-            itemDescriptions[1] = "The type of event";
-
-            return new CompositeType("RepositoryEvent", description, itemNames,
-                    itemDescriptions, itemTypes);
-        } catch (OpenDataException e) {
-            throw new IllegalStateException("Unable to build repositoryEvent type", e);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/resources/OSGI-INF/bundle.info
----------------------------------------------------------------------
diff --git a/features/src/main/resources/OSGI-INF/bundle.info b/features/src/main/resources/OSGI-INF/bundle.info
deleted file mode 100644
index d5b4180..0000000
--- a/features/src/main/resources/OSGI-INF/bundle.info
+++ /dev/null
@@ -1,20 +0,0 @@
-h1. Synopsis
-
-${project.name}
-
-${project.description}
-
-Maven URL:
-[mvn:${project.groupId}/${project.artifactId}/${project.version}]
-
-h1. Description
-
-This bundle is the core implementation of the Karaf features support.
-
-Karaf provides a simple, yet flexible, way to provision applications or "features". Such a mechanism is mainly
-provided by a set of commands available in the features shell. The provisioning system uses xml "repositories"
-that define a set of features.
-
-h1. See also
-
-Provisioning - section of the Karaf User Guide


[29/33] Revert "[KARAF-2852] Merge features/core and features/command"

Posted by gn...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/resolver/CandidateComparator.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/CandidateComparator.java b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/CandidateComparator.java
new file mode 100644
index 0000000..ad4cc85
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/CandidateComparator.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.karaf.features.internal.resolver;
+
+import java.util.Comparator;
+
+import org.osgi.framework.Version;
+import org.osgi.framework.namespace.BundleNamespace;
+import org.osgi.framework.namespace.PackageNamespace;
+import org.osgi.framework.wiring.BundleCapability;
+import org.osgi.resource.Capability;
+
+public class CandidateComparator implements Comparator<Capability>
+{
+    public int compare(Capability cap1, Capability cap2)
+    {
+        int c = 0;
+        // Always prefer system bundle
+        if (cap1 instanceof BundleCapability && !(cap2 instanceof BundleCapability)) {
+            c = -1;
+        } else if (!(cap1 instanceof BundleCapability) && cap2 instanceof BundleCapability) {
+            c = 1;
+        }
+        // Compare revision capabilities.
+        if ((c == 0) && cap1.getNamespace().equals(BundleNamespace.BUNDLE_NAMESPACE))
+        {
+            c = ((Comparable) cap1.getAttributes().get(BundleNamespace.BUNDLE_NAMESPACE))
+                    .compareTo(cap2.getAttributes().get(BundleNamespace.BUNDLE_NAMESPACE));
+            if (c == 0)
+            {
+                Version v1 = (!cap1.getAttributes().containsKey(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE))
+                        ? Version.emptyVersion
+                        : (Version) cap1.getAttributes().get(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE);
+                Version v2 = (!cap2.getAttributes().containsKey(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE))
+                        ? Version.emptyVersion
+                        : (Version) cap2.getAttributes().get(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE);
+                // Compare these in reverse order, since we want
+                // highest version to have priority.
+                c = compareVersions(v2, v1);
+            }
+        }
+        // Compare package capabilities.
+        else if ((c == 0) && cap1.getNamespace().equals(PackageNamespace.PACKAGE_NAMESPACE))
+        {
+            c = ((Comparable) cap1.getAttributes().get(PackageNamespace.PACKAGE_NAMESPACE))
+                    .compareTo(cap2.getAttributes().get(PackageNamespace.PACKAGE_NAMESPACE));
+            if (c == 0)
+            {
+                Version v1 = (!cap1.getAttributes().containsKey(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE))
+                        ? Version.emptyVersion
+                        : (Version) cap1.getAttributes().get(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE);
+                Version v2 = (!cap2.getAttributes().containsKey(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE))
+                        ? Version.emptyVersion
+                        : (Version) cap2.getAttributes().get(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE);
+                // Compare these in reverse order, since we want
+                // highest version to have priority.
+                c = compareVersions(v2, v1);
+                // if same version, rather compare on the bundle version
+                if (c == 0)
+                {
+                    v1 = (!cap1.getAttributes().containsKey(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE))
+                            ? Version.emptyVersion
+                            : (Version) cap1.getAttributes().get(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE);
+                    v2 = (!cap2.getAttributes().containsKey(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE))
+                            ? Version.emptyVersion
+                            : (Version) cap2.getAttributes().get(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE);
+                    // Compare these in reverse order, since we want
+                    // highest version to have priority.
+                    c = compareVersions(v2, v1);
+                }
+            }
+        }
+        // Compare feature capabilities
+        else if ((c == 0) && cap1.getNamespace().equals(FeatureNamespace.FEATURE_NAMESPACE))
+        {
+            c = ((Comparable) cap1.getAttributes().get(FeatureNamespace.FEATURE_NAMESPACE))
+                    .compareTo(cap2.getAttributes().get(FeatureNamespace.FEATURE_NAMESPACE));
+            if (c == 0)
+            {
+                Version v1 = (!cap1.getAttributes().containsKey(FeatureNamespace.CAPABILITY_VERSION_ATTRIBUTE))
+                        ? Version.emptyVersion
+                        : (Version) cap1.getAttributes().get(FeatureNamespace.CAPABILITY_VERSION_ATTRIBUTE);
+                Version v2 = (!cap2.getAttributes().containsKey(FeatureNamespace.CAPABILITY_VERSION_ATTRIBUTE))
+                        ? Version.emptyVersion
+                        : (Version) cap2.getAttributes().get(FeatureNamespace.CAPABILITY_VERSION_ATTRIBUTE);
+                // Compare these in reverse order, since we want
+                // highest version to have priority.
+                c = compareVersions(v2, v1);
+            }
+        }
+        return c;
+    }
+
+    private int compareVersions(Version v1, Version v2) {
+        int c = v1.getMajor() - v2.getMajor();
+        if (c != 0) {
+            return c;
+        }
+        c = v1.getMinor() - v2.getMinor();
+        if (c != 0) {
+            return c;
+        }
+        c = v1.getMicro() - v2.getMicro();
+        if (c != 0) {
+            return c;
+        }
+        String q1 = cleanQualifierForComparison(v1.getQualifier());
+        String q2 = cleanQualifierForComparison(v2.getQualifier());
+        return q1.compareTo(q2);
+    }
+
+    private String cleanQualifierForComparison(String qualifier) {
+        return qualifier.replaceAll("(redhat-[0-9]{3})([0-9]{3})", "$1-$2");
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/resolver/CapabilityImpl.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/CapabilityImpl.java b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/CapabilityImpl.java
new file mode 100644
index 0000000..bfe9b40
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/CapabilityImpl.java
@@ -0,0 +1,165 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.resolver;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import org.osgi.framework.Constants;
+import org.osgi.resource.Capability;
+import org.osgi.resource.Resource;
+
+public class CapabilityImpl extends BaseClause implements Capability {
+
+    private final Resource m_resource;
+    private final String m_namespace;
+    private final Map<String, String> m_dirs;
+    private final Map<String, Object> m_attrs;
+    private final List<String> m_uses;
+    private final List<List<String>> m_includeFilter;
+    private final List<List<String>> m_excludeFilter;
+    private final Set<String> m_mandatory;
+
+    public CapabilityImpl(Capability capability) {
+        this(null, capability.getNamespace(), capability.getDirectives(), capability.getAttributes());
+    }
+
+    public CapabilityImpl(Resource resource, String namespace,
+                          Map<String, String> dirs, Map<String, Object> attrs) {
+        m_namespace = namespace;
+        m_resource = resource;
+        m_dirs = dirs;
+        m_attrs = attrs;
+
+        // Find all export directives: uses, mandatory, include, and exclude.
+
+        List<String> uses = Collections.emptyList();
+        String value = m_dirs.get(Constants.USES_DIRECTIVE);
+        if (value != null) {
+            // Parse these uses directive.
+            StringTokenizer tok = new StringTokenizer(value, ",");
+            uses = new ArrayList<String>(tok.countTokens());
+            while (tok.hasMoreTokens()) {
+                uses.add(tok.nextToken().trim());
+            }
+        }
+        m_uses = uses;
+
+        value = m_dirs.get(Constants.INCLUDE_DIRECTIVE);
+        if (value != null) {
+            List<String> filters = ResourceBuilder.parseDelimitedString(value, ",");
+            m_includeFilter = new ArrayList<List<String>>(filters.size());
+            for (String filter : filters) {
+                List<String> substrings = SimpleFilter.parseSubstring(filter);
+                m_includeFilter.add(substrings);
+            }
+        } else {
+            m_includeFilter = null;
+        }
+
+        value = m_dirs.get(Constants.EXCLUDE_DIRECTIVE);
+        if (value != null) {
+            List<String> filters = ResourceBuilder.parseDelimitedString(value, ",");
+            m_excludeFilter = new ArrayList<List<String>>(filters.size());
+            for (String filter : filters) {
+                List<String> substrings = SimpleFilter.parseSubstring(filter);
+                m_excludeFilter.add(substrings);
+            }
+        } else {
+            m_excludeFilter = null;
+        }
+
+        Set<String> mandatory = Collections.emptySet();
+        value = m_dirs.get(Constants.MANDATORY_DIRECTIVE);
+        if (value != null) {
+            List<String> names = ResourceBuilder.parseDelimitedString(value, ",");
+            mandatory = new HashSet<String>(names.size());
+            for (String name : names) {
+                // If attribute exists, then record it as mandatory.
+                if (m_attrs.containsKey(name)) {
+                    mandatory.add(name);
+                }
+                // Otherwise, report an error.
+                else {
+                    throw new IllegalArgumentException("Mandatory attribute '" + name + "' does not exist.");
+                }
+            }
+        }
+        m_mandatory = mandatory;
+    }
+
+    public Resource getResource() {
+        return m_resource;
+    }
+
+    public String getNamespace() {
+        return m_namespace;
+    }
+
+    public Map<String, String> getDirectives() {
+        return m_dirs;
+    }
+
+    public Map<String, Object> getAttributes() {
+        return m_attrs;
+    }
+
+    public boolean isAttributeMandatory(String name) {
+        return !m_mandatory.isEmpty() && m_mandatory.contains(name);
+    }
+
+    public List<String> getUses() {
+        return m_uses;
+    }
+
+    public boolean isIncluded(String name) {
+        if ((m_includeFilter == null) && (m_excludeFilter == null)) {
+            return true;
+        }
+
+        // Get the class name portion of the target class.
+        String className = getClassName(name);
+
+        // If there are no include filters then all classes are included
+        // by default, otherwise try to find one match.
+        boolean included = (m_includeFilter == null);
+        for (int i = 0; !included && m_includeFilter != null && i < m_includeFilter.size(); i++) {
+            included = SimpleFilter.compareSubstring(m_includeFilter.get(i), className);
+        }
+
+        // If there are no exclude filters then no classes are excluded
+        // by default, otherwise try to find one match.
+        boolean excluded = false;
+        for (int i = 0; (!excluded) && (m_excludeFilter != null) && (i < m_excludeFilter.size()); i++) {
+            excluded = SimpleFilter.compareSubstring(m_excludeFilter.get(i), className);
+        }
+        return included && !excluded;
+    }
+
+    private static String getClassName(String className) {
+        if (className == null) {
+            className = "";
+        }
+        return (className.lastIndexOf('.') < 0) ? "" : className.substring(className.lastIndexOf('.') + 1);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/resolver/CapabilitySet.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/CapabilitySet.java b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/CapabilitySet.java
new file mode 100644
index 0000000..4c5656d
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/CapabilitySet.java
@@ -0,0 +1,612 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.resolver;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+
+import org.osgi.framework.Constants;
+import org.osgi.resource.Capability;
+
+public class CapabilitySet
+{
+    private final Map<String, Map<Object, Set<Capability>>> m_indices;
+    private final Set<Capability> m_capSet = new HashSet<Capability>();
+
+public void dump()
+{
+    for (Entry<String, Map<Object, Set<Capability>>> entry : m_indices.entrySet())
+    {
+        boolean header1 = false;
+        for (Entry<Object, Set<Capability>> entry2 : entry.getValue().entrySet())
+        {
+            boolean header2 = false;
+            for (Capability cap : entry2.getValue())
+            {
+                if (!header1)
+                {
+                    System.out.println(entry.getKey() + ":");
+                    header1 = true;
+                }
+                if (!header2)
+                {
+                    System.out.println("   " + entry2.getKey());
+                    header2 = true;
+                }
+                System.out.println("      " + cap);
+            }
+        }
+    }
+}
+
+    public CapabilitySet(List<String> indexProps)
+    {
+        m_indices = new TreeMap<String, Map<Object, Set<Capability>>>();
+        for (int i = 0; (indexProps != null) && (i < indexProps.size()); i++)
+        {
+            m_indices.put(
+                indexProps.get(i), new HashMap<Object, Set<Capability>>());
+        }
+    }
+
+    public void addCapability(Capability cap)
+    {
+        m_capSet.add(cap);
+
+        // Index capability.
+        for (Entry<String, Map<Object, Set<Capability>>> entry : m_indices.entrySet())
+        {
+            Object value = cap.getAttributes().get(entry.getKey());
+            if (value != null)
+            {
+                if (value.getClass().isArray())
+                {
+                    value = convertArrayToList(value);
+                }
+
+                Map<Object, Set<Capability>> index = entry.getValue();
+
+                if (value instanceof Collection)
+                {
+                    Collection c = (Collection) value;
+                    for (Object o : c)
+                    {
+                        indexCapability(index, cap, o);
+                    }
+                }
+                else
+                {
+                    indexCapability(index, cap, value);
+                }
+            }
+        }
+    }
+
+    private void indexCapability(
+        Map<Object, Set<Capability>> index, Capability cap, Object capValue)
+    {
+        Set<Capability> caps = index.get(capValue);
+        if (caps == null)
+        {
+            caps = new HashSet<Capability>();
+            index.put(capValue, caps);
+        }
+        caps.add(cap);
+    }
+
+    public void removeCapability(Capability cap)
+    {
+        if (m_capSet.remove(cap))
+        {
+            for (Entry<String, Map<Object, Set<Capability>>> entry : m_indices.entrySet())
+            {
+                Object value = cap.getAttributes().get(entry.getKey());
+                if (value != null)
+                {
+                    if (value.getClass().isArray())
+                    {
+                        value = convertArrayToList(value);
+                    }
+
+                    Map<Object, Set<Capability>> index = entry.getValue();
+
+                    if (value instanceof Collection)
+                    {
+                        Collection c = (Collection) value;
+                        for (Object o : c)
+                        {
+                            deindexCapability(index, cap, o);
+                        }
+                    }
+                    else
+                    {
+                        deindexCapability(index, cap, value);
+                    }
+                }
+            }
+        }
+    }
+
+    private void deindexCapability(
+        Map<Object, Set<Capability>> index, Capability cap, Object value)
+    {
+        Set<Capability> caps = index.get(value);
+        if (caps != null)
+        {
+            caps.remove(cap);
+            if (caps.isEmpty())
+            {
+                index.remove(value);
+            }
+        }
+    }
+
+    public Set<Capability> match(SimpleFilter sf, boolean obeyMandatory)
+    {
+        Set<Capability> matches = match(m_capSet, sf);
+        return (obeyMandatory)
+            ? matchMandatory(matches, sf)
+            : matches;
+    }
+
+    private Set<Capability> match(Set<Capability> caps, SimpleFilter sf)
+    {
+        Set<Capability> matches = new HashSet<Capability>();
+
+        if (sf.getOperation() == SimpleFilter.MATCH_ALL)
+        {
+            matches.addAll(caps);
+        }
+        else if (sf.getOperation() == SimpleFilter.AND)
+        {
+            // Evaluate each subfilter against the remaining capabilities.
+            // For AND we calculate the intersection of each subfilter.
+            // We can short-circuit the AND operation if there are no
+            // remaining capabilities.
+            List<SimpleFilter> sfs = (List<SimpleFilter>) sf.getValue();
+            for (int i = 0; (caps.size() > 0) && (i < sfs.size()); i++)
+            {
+                matches = match(caps, sfs.get(i));
+                caps = matches;
+            }
+        }
+        else if (sf.getOperation() == SimpleFilter.OR)
+        {
+            // Evaluate each subfilter against the remaining capabilities.
+            // For OR we calculate the union of each subfilter.
+            List<SimpleFilter> sfs = (List<SimpleFilter>) sf.getValue();
+            for (int i = 0; i < sfs.size(); i++)
+            {
+                matches.addAll(match(caps, sfs.get(i)));
+            }
+        }
+        else if (sf.getOperation() == SimpleFilter.NOT)
+        {
+            // Evaluate each subfilter against the remaining capabilities.
+            // For OR we calculate the union of each subfilter.
+            matches.addAll(caps);
+            List<SimpleFilter> sfs = (List<SimpleFilter>) sf.getValue();
+            for (int i = 0; i < sfs.size(); i++)
+            {
+                matches.removeAll(match(caps, sfs.get(i)));
+            }
+        }
+        else
+        {
+            Map<Object, Set<Capability>> index = m_indices.get(sf.getName());
+            if ((sf.getOperation() == SimpleFilter.EQ) && (index != null))
+            {
+                Set<Capability> existingCaps = index.get(sf.getValue());
+                if (existingCaps != null)
+                {
+                    matches.addAll(existingCaps);
+                    matches.retainAll(caps);
+                }
+            }
+            else
+            {
+                for (Iterator<Capability> it = caps.iterator(); it.hasNext(); )
+                {
+                    Capability cap = it.next();
+                    Object lhs = cap.getAttributes().get(sf.getName());
+                    if (lhs != null)
+                    {
+                        if (compare(lhs, sf.getValue(), sf.getOperation()))
+                        {
+                            matches.add(cap);
+                        }
+                    }
+                }
+            }
+        }
+
+        return matches;
+    }
+
+    public static boolean matches(Capability cap, SimpleFilter sf)
+    {
+        return matchesInternal(cap, sf) && matchMandatory(cap, sf);
+    }
+
+    private static boolean matchesInternal(Capability cap, SimpleFilter sf)
+    {
+        boolean matched = true;
+
+        if (sf.getOperation() == SimpleFilter.MATCH_ALL)
+        {
+            matched = true;
+        }
+        else if (sf.getOperation() == SimpleFilter.AND)
+        {
+            // Evaluate each subfilter against the remaining capabilities.
+            // For AND we calculate the intersection of each subfilter.
+            // We can short-circuit the AND operation if there are no
+            // remaining capabilities.
+            List<SimpleFilter> sfs = (List<SimpleFilter>) sf.getValue();
+            for (int i = 0; matched && (i < sfs.size()); i++)
+            {
+                matched = matchesInternal(cap, sfs.get(i));
+            }
+        }
+        else if (sf.getOperation() == SimpleFilter.OR)
+        {
+            // Evaluate each subfilter against the remaining capabilities.
+            // For OR we calculate the union of each subfilter.
+            matched = false;
+            List<SimpleFilter> sfs = (List<SimpleFilter>) sf.getValue();
+            for (int i = 0; !matched && (i < sfs.size()); i++)
+            {
+                matched = matchesInternal(cap, sfs.get(i));
+            }
+        }
+        else if (sf.getOperation() == SimpleFilter.NOT)
+        {
+            // Evaluate each subfilter against the remaining capabilities.
+            // For OR we calculate the union of each subfilter.
+            List<SimpleFilter> sfs = (List<SimpleFilter>) sf.getValue();
+            for (int i = 0; i < sfs.size(); i++)
+            {
+                matched = !(matchesInternal(cap, sfs.get(i)));
+            }
+        }
+        else
+        {
+            matched = false;
+            Object lhs = cap.getAttributes().get(sf.getName());
+            if (lhs != null)
+            {
+                matched = compare(lhs, sf.getValue(), sf.getOperation());
+            }
+        }
+
+        return matched;
+    }
+
+    private static Set<Capability> matchMandatory(
+        Set<Capability> caps, SimpleFilter sf)
+    {
+        for (Iterator<Capability> it = caps.iterator(); it.hasNext(); )
+        {
+            Capability cap = it.next();
+            if (!matchMandatory(cap, sf))
+            {
+                it.remove();
+            }
+        }
+        return caps;
+    }
+
+    private static boolean matchMandatory(Capability cap, SimpleFilter sf)
+    {
+        if (cap instanceof CapabilityImpl) {
+            for (Entry<String, Object> entry : cap.getAttributes().entrySet())
+            {
+                if (((CapabilityImpl) cap).isAttributeMandatory(entry.getKey())
+                    && !matchMandatoryAttribute(entry.getKey(), sf))
+                {
+                    return false;
+                }
+            }
+        } else {
+            String value = cap.getDirectives().get(Constants.MANDATORY_DIRECTIVE);
+            if (value != null) {
+                List<String> names = ResourceBuilder.parseDelimitedString(value, ",");
+                for (Entry<String, Object> entry : cap.getAttributes().entrySet())
+                {
+                    if (names.contains(entry.getKey())
+                            && !matchMandatoryAttribute(entry.getKey(), sf))
+                    {
+                        return false;
+                    }
+                }
+            }
+
+        }
+        return true;
+    }
+
+    private static boolean matchMandatoryAttribute(String attrName, SimpleFilter sf)
+    {
+        if ((sf.getName() != null) && sf.getName().equals(attrName))
+        {
+            return true;
+        }
+        else if (sf.getOperation() == SimpleFilter.AND)
+        {
+            List list = (List) sf.getValue();
+            for (int i = 0; i < list.size(); i++)
+            {
+                SimpleFilter sf2 = (SimpleFilter) list.get(i);
+                if ((sf2.getName() != null)
+                    && sf2.getName().equals(attrName))
+                {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private static final Class<?>[] STRING_CLASS = new Class[] { String.class };
+
+    private static boolean compare(Object lhs, Object rhsUnknown, int op)
+    {
+        if (lhs == null)
+        {
+            return false;
+        }
+
+        // If this is a PRESENT operation, then just return true immediately
+        // since we wouldn't be here if the attribute wasn't present.
+        if (op == SimpleFilter.PRESENT)
+        {
+            return true;
+        }
+
+        // If the type is comparable, then we can just return the
+        // result immediately.
+        if (lhs instanceof Comparable)
+        {
+            // Spec says SUBSTRING is false for all types other than string.
+            if ((op == SimpleFilter.SUBSTRING) && !(lhs instanceof String))
+            {
+                return false;
+            }
+
+            Object rhs;
+            if (op == SimpleFilter.SUBSTRING)
+            {
+                rhs = rhsUnknown;
+            }
+            else
+            {
+                try
+                {
+                    rhs = coerceType(lhs, (String) rhsUnknown);
+                }
+                catch (Exception ex)
+                {
+                    return false;
+                }
+            }
+
+            switch (op)
+            {
+                case SimpleFilter.EQ :
+                    try
+                    {
+                        return (((Comparable) lhs).compareTo(rhs) == 0);
+                    }
+                    catch (Exception ex)
+                    {
+                        return false;
+                    }
+                case SimpleFilter.GTE :
+                    try
+                    {
+                        return (((Comparable) lhs).compareTo(rhs) >= 0);
+                    }
+                    catch (Exception ex)
+                    {
+                        return false;
+                    }
+                case SimpleFilter.LTE :
+                    try
+                    {
+                        return (((Comparable) lhs).compareTo(rhs) <= 0);
+                    }
+                    catch (Exception ex)
+                    {
+                        return false;
+                    }
+                case SimpleFilter.APPROX :
+                    return compareApproximate(((Comparable) lhs), rhs);
+                case SimpleFilter.SUBSTRING :
+                    return SimpleFilter.compareSubstring((List<String>) rhs, (String) lhs);
+                default:
+                    throw new RuntimeException(
+                        "Unknown comparison operator: " + op);
+            }
+        }
+        // Booleans do not implement comparable, so special case them.
+        else if (lhs instanceof Boolean)
+        {
+            Object rhs;
+            try
+            {
+                rhs = coerceType(lhs, (String) rhsUnknown);
+            }
+            catch (Exception ex)
+            {
+                return false;
+            }
+
+            switch (op)
+            {
+                case SimpleFilter.EQ :
+                case SimpleFilter.GTE :
+                case SimpleFilter.LTE :
+                case SimpleFilter.APPROX :
+                    return (lhs.equals(rhs));
+                default:
+                    throw new RuntimeException(
+                        "Unknown comparison operator: " + op);
+            }
+        }
+
+        // If the LHS is not a comparable or boolean, check if it is an
+        // array. If so, convert it to a list so we can treat it as a
+        // collection.
+        if (lhs.getClass().isArray())
+        {
+            lhs = convertArrayToList(lhs);
+        }
+
+        // If LHS is a collection, then call compare() on each element
+        // of the collection until a match is found.
+        if (lhs instanceof Collection)
+        {
+            for (Iterator iter = ((Collection) lhs).iterator(); iter.hasNext(); )
+            {
+                if (compare(iter.next(), rhsUnknown, op))
+                {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        // Spec says SUBSTRING is false for all types other than string.
+        if ((op == SimpleFilter.SUBSTRING) && !(lhs instanceof String))
+        {
+            return false;
+        }
+
+        // Since we cannot identify the LHS type, then we can only perform
+        // equality comparison.
+        try
+        {
+            return lhs.equals(coerceType(lhs, (String) rhsUnknown));
+        }
+        catch (Exception ex)
+        {
+            return false;
+        }
+    }
+
+    private static boolean compareApproximate(Object lhs, Object rhs)
+    {
+        if (rhs instanceof String)
+        {
+            return removeWhitespace((String) lhs)
+                .equalsIgnoreCase(removeWhitespace((String) rhs));
+        }
+        else if (rhs instanceof Character)
+        {
+            return Character.toLowerCase(((Character) lhs))
+                == Character.toLowerCase(((Character) rhs));
+        }
+        return lhs.equals(rhs);
+    }
+
+    private static String removeWhitespace(String s)
+    {
+        StringBuffer sb = new StringBuffer(s.length());
+        for (int i = 0; i < s.length(); i++)
+        {
+            if (!Character.isWhitespace(s.charAt(i)))
+            {
+                sb.append(s.charAt(i));
+            }
+        }
+        return sb.toString();
+    }
+
+    private static Object coerceType(Object lhs, String rhsString) throws Exception
+    {
+        // If the LHS expects a string, then we can just return
+        // the RHS since it is a string.
+        if (lhs.getClass() == rhsString.getClass())
+        {
+            return rhsString;
+        }
+
+        // Try to convert the RHS type to the LHS type by using
+        // the string constructor of the LHS class, if it has one.
+        Object rhs = null;
+        try
+        {
+            // The Character class is a special case, since its constructor
+            // does not take a string, so handle it separately.
+            if (lhs instanceof Character)
+            {
+                rhs = new Character(rhsString.charAt(0));
+            }
+            else
+            {
+                // Spec says we should trim number types.
+                if ((lhs instanceof Number) || (lhs instanceof Boolean))
+                {
+                    rhsString = rhsString.trim();
+                }
+                Constructor ctor = lhs.getClass().getConstructor(STRING_CLASS);
+                ctor.setAccessible(true);
+                rhs = ctor.newInstance(new Object[] { rhsString });
+            }
+        }
+        catch (Exception ex)
+        {
+            throw new Exception(
+                "Could not instantiate class "
+                    + lhs.getClass().getName()
+                    + " from string constructor with argument '"
+                    + rhsString + "' because " + ex);
+        }
+
+        return rhs;
+    }
+
+    /**
+     * This is an ugly utility method to convert an array of primitives
+     * to an array of primitive wrapper objects. This method simplifies
+     * processing LDAP filters since the special case of primitive arrays
+     * can be ignored.
+     * @param array An array of primitive types.
+     * @return An corresponding array using pritive wrapper objects.
+    **/
+    private static List convertArrayToList(Object array)
+    {
+        int len = Array.getLength(array);
+        List list = new ArrayList(len);
+        for (int i = 0; i < len; i++)
+        {
+            list.add(Array.get(array, i));
+        }
+        return list;
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/resolver/FeatureNamespace.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/FeatureNamespace.java b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/FeatureNamespace.java
new file mode 100644
index 0000000..e211618
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/FeatureNamespace.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.karaf.features.internal.resolver;
+
+import java.util.List;
+
+import org.osgi.framework.Version;
+import org.osgi.resource.Capability;
+import org.osgi.resource.Namespace;
+import org.osgi.resource.Resource;
+
+/**
+ */
+public final class FeatureNamespace extends Namespace {
+
+    public static final String FEATURE_NAMESPACE = "karaf.feature";
+
+    public static final String	CAPABILITY_VERSION_ATTRIBUTE	= "version";
+
+    /**
+     * The attribute value identifying the resource
+     * {@link org.osgi.framework.namespace.IdentityNamespace#CAPABILITY_TYPE_ATTRIBUTE type} as an OSGi bundle.
+     *
+     * @see org.osgi.framework.namespace.IdentityNamespace#CAPABILITY_TYPE_ATTRIBUTE
+     */
+    public static final String	TYPE_FEATURE = "karaf.feature";
+
+    public static String getName(Resource resource)
+    {
+        List<Capability> caps = resource.getCapabilities(null);
+        for (Capability cap : caps)
+        {
+            if (cap.getNamespace().equals(FEATURE_NAMESPACE))
+            {
+                return cap.getAttributes().get(FEATURE_NAMESPACE).toString();
+            }
+        }
+        return null;
+    }
+
+    public static Version getVersion(Resource resource)
+    {
+        List<Capability> caps = resource.getCapabilities(null);
+        for (Capability cap : caps)
+        {
+            if (cap.getNamespace().equals(FEATURE_NAMESPACE))
+            {
+                return (Version)
+                        cap.getAttributes().get(CAPABILITY_VERSION_ATTRIBUTE);
+            }
+        }
+        return null;
+    }
+
+
+    private FeatureNamespace() {
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/resolver/FeatureResource.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/FeatureResource.java b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/FeatureResource.java
new file mode 100644
index 0000000..e3b0101
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/FeatureResource.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.resolver;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.utils.version.VersionRange;
+import org.apache.felix.utils.version.VersionTable;
+import org.apache.karaf.features.BundleInfo;
+import org.apache.karaf.features.Conditional;
+import org.apache.karaf.features.Dependency;
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.internal.util.Macro;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+import org.osgi.framework.namespace.IdentityNamespace;
+import org.osgi.resource.Capability;
+import org.osgi.resource.Requirement;
+import org.osgi.resource.Resource;
+
+/**
+*/
+public class FeatureResource extends ResourceImpl {
+
+    private final Feature feature;
+
+    public static Resource build(Feature feature, Conditional conditional, String featureRange, Map<String, Resource> locToRes) throws BundleException {
+        Feature fcond = conditional.asFeature(feature.getName(), feature.getVersion());
+        FeatureResource resource = (FeatureResource) build(fcond, featureRange, locToRes);
+        for (String cond : conditional.getCondition()) {
+            if (cond.startsWith("req:")) {
+                cond = cond.substring("req:".length());
+                List<Requirement> reqs = ResourceBuilder.parseRequirement(resource, cond);
+                resource.addRequirements(reqs);
+            } else {
+                org.apache.karaf.features.internal.model.Dependency dep = new org.apache.karaf.features.internal.model.Dependency();
+                String[] p = cond.split("/");
+                dep.setName(p[0]);
+                if (p.length > 1) {
+                    dep.setVersion(p[1]);
+                }
+                addDependency(resource, dep, featureRange);
+            }
+        }
+        org.apache.karaf.features.internal.model.Dependency dep = new org.apache.karaf.features.internal.model.Dependency();
+        dep.setName(feature.getName());
+        dep.setVersion(feature.getVersion());
+        addDependency(resource, dep, featureRange);
+        return resource;
+    }
+
+    public static Resource build(Feature feature, String featureRange, Map<String, Resource> locToRes) throws BundleException {
+        FeatureResource resource = new FeatureResource(feature);
+        Map<String, String> dirs = new HashMap<String, String>();
+        Map<String, Object> attrs = new HashMap<String, Object>();
+        attrs.put(FeatureNamespace.FEATURE_NAMESPACE, feature.getName());
+        attrs.put(FeatureNamespace.CAPABILITY_VERSION_ATTRIBUTE, VersionTable.getVersion(feature.getVersion()));
+        resource.addCapability(new CapabilityImpl(resource, FeatureNamespace.FEATURE_NAMESPACE, dirs, attrs));
+        for (BundleInfo info : feature.getBundles()) {
+            if (!info.isDependency()) {
+                Resource res = locToRes.get(info.getLocation());
+                if (res == null) {
+                    throw new IllegalStateException("Resource not found for url " + info.getLocation());
+                }
+                List<Capability> caps = res.getCapabilities(IdentityNamespace.IDENTITY_NAMESPACE);
+                if (caps.size() != 1) {
+                    throw new IllegalStateException("Resource does not have a single " + IdentityNamespace.IDENTITY_NAMESPACE + " capability");
+                }
+                dirs = new HashMap<String, String>();
+                attrs = new HashMap<String, Object>();
+                attrs.put(IdentityNamespace.IDENTITY_NAMESPACE, caps.get(0).getAttributes().get(IdentityNamespace.IDENTITY_NAMESPACE));
+                attrs.put(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE, caps.get(0).getAttributes().get(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE));
+                attrs.put(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, new VersionRange((Version) caps.get(0).getAttributes().get(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE), true));
+                resource.addRequirement(new RequirementImpl(resource, IdentityNamespace.IDENTITY_NAMESPACE, dirs, attrs));
+            }
+        }
+        for (Dependency dep : feature.getDependencies()) {
+            addDependency(resource, dep, featureRange);
+        }
+        for (org.apache.karaf.features.Capability cap : feature.getCapabilities()) {
+            resource.addCapabilities(ResourceBuilder.parseCapability(resource, cap.getValue()));
+        }
+        for (org.apache.karaf.features.Requirement req : feature.getRequirements()) {
+            resource.addRequirements(ResourceBuilder.parseRequirement(resource, req.getValue()));
+        }
+        return resource;
+    }
+
+    protected static void addDependency(FeatureResource resource, Dependency dep, String featureRange) {
+        Map<String, String> dirs;
+        Map<String, Object> attrs;
+        String name = dep.getName();
+        String version = dep.getVersion();
+        if (version.equals("0.0.0")) {
+            version = null;
+        } else if (!version.startsWith("[") && !version.startsWith("(")) {
+            version = Macro.transform(featureRange, version);
+        }
+        dirs = new HashMap<String, String>();
+        attrs = new HashMap<String, Object>();
+        attrs.put(FeatureNamespace.FEATURE_NAMESPACE, name);
+        if (version != null) {
+            attrs.put(FeatureNamespace.CAPABILITY_VERSION_ATTRIBUTE, new VersionRange(version));
+        }
+        resource.addRequirement(new RequirementImpl(resource, FeatureNamespace.FEATURE_NAMESPACE, dirs, attrs));
+    }
+
+    public FeatureResource(Feature feature) {
+        super(feature.getName(), FeatureNamespace.TYPE_FEATURE, VersionTable.getVersion(feature.getVersion()));
+        this.feature = feature;
+    }
+
+    public Feature getFeature() {
+        return feature;
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/resolver/IdentityCapability.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/IdentityCapability.java b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/IdentityCapability.java
new file mode 100644
index 0000000..cdc00d1
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/IdentityCapability.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.karaf.features.internal.resolver;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.osgi.framework.Version;
+import org.osgi.framework.namespace.IdentityNamespace;
+import org.osgi.resource.Capability;
+import org.osgi.resource.Resource;
+
+class IdentityCapability extends BaseClause implements Capability
+{
+    private final Resource m_resource;
+    private final Map<String, String> m_dirs;
+    private final Map<String, Object> m_attrs;
+
+    public IdentityCapability(Resource resource, String name, String type, Version version)
+    {
+        m_resource = resource;
+        m_dirs = new HashMap<String, String>();
+        m_attrs = new HashMap<String, Object>();
+        m_attrs.put(IdentityNamespace.IDENTITY_NAMESPACE, name);
+        m_attrs.put(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE, type);
+        m_attrs.put(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, version);
+    }
+
+    public String getNamespace()
+    {
+        return IdentityNamespace.IDENTITY_NAMESPACE;
+    }
+
+    public Map<String, String> getDirectives()
+    {
+        return m_dirs;
+    }
+
+    public Map<String, Object> getAttributes()
+    {
+        return m_attrs;
+    }
+
+    public Resource getResource()
+    {
+        return m_resource;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/resolver/RequirementImpl.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/RequirementImpl.java b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/RequirementImpl.java
new file mode 100644
index 0000000..a4ef775
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/RequirementImpl.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.karaf.features.internal.resolver;
+
+import java.util.Map;
+
+import org.osgi.framework.Constants;
+import org.osgi.resource.Capability;
+import org.osgi.resource.Requirement;
+import org.osgi.resource.Resource;
+
+public class RequirementImpl extends BaseClause implements Requirement {
+    private final Resource m_resource;
+    private final String m_namespace;
+    private final SimpleFilter m_filter;
+    private final boolean m_optional;
+    private final Map<String, String> m_dirs;
+    private final Map<String, Object> m_attrs;
+
+    public RequirementImpl(
+            Resource resource, String namespace,
+            Map<String, String> dirs, Map<String, Object> attrs, SimpleFilter filter) {
+        m_resource = resource;
+        m_namespace = namespace;
+        m_dirs = dirs;
+        m_attrs = attrs;
+        m_filter = filter;
+        // Find resolution import directives.
+        m_optional = Constants.RESOLUTION_OPTIONAL.equals(m_dirs.get(Constants.RESOLUTION_DIRECTIVE));
+    }
+
+    public RequirementImpl(
+            Resource resource, String namespace,
+            Map<String, String> dirs, Map<String, Object> attrs) {
+        this(resource, namespace, dirs, attrs, SimpleFilter.convert(attrs));
+    }
+
+    public String getNamespace() {
+        return m_namespace;
+    }
+
+    public Map<String, String> getDirectives() {
+        return m_dirs;
+    }
+
+    public Map<String, Object> getAttributes() {
+        return m_attrs;
+    }
+
+    public Resource getResource() {
+        return m_resource;
+    }
+
+    public boolean matches(Capability cap) {
+        return CapabilitySet.matches(cap, getFilter());
+    }
+
+    public boolean isOptional() {
+        return m_optional;
+    }
+
+    public SimpleFilter getFilter() {
+        return m_filter;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResolveContextImpl.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResolveContextImpl.java b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResolveContextImpl.java
new file mode 100644
index 0000000..e2ff793
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResolveContextImpl.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.karaf.features.internal.resolver;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.osgi.framework.Constants;
+import org.osgi.resource.Capability;
+import org.osgi.resource.Requirement;
+import org.osgi.resource.Resource;
+import org.osgi.resource.Wiring;
+import org.osgi.service.repository.Repository;
+import org.osgi.service.resolver.HostedCapability;
+import org.osgi.service.resolver.ResolveContext;
+
+/**
+*/
+public class ResolveContextImpl extends ResolveContext {
+
+    private final Set<Resource> mandatory;
+    private final Set<Resource> optional;
+    private final Repository repository;
+    private final Map<Resource, Wiring> wirings;
+    private final boolean resolveOptional;
+
+    private final CandidateComparator candidateComparator = new CandidateComparator();
+
+    public ResolveContextImpl(Set<Resource> mandatory,
+                              Set<Resource> optional,
+                              Repository repository,
+                              boolean resolveOptional) {
+        this.mandatory = mandatory;
+        this.optional = optional;
+        this.repository = repository;
+        this.wirings = new HashMap<Resource, Wiring>();
+        this.resolveOptional = resolveOptional;
+    }
+
+    @Override
+    public Collection<Resource> getMandatoryResources() {
+        return mandatory;
+    }
+
+    @Override
+    public Collection<Resource> getOptionalResources() {
+        return optional;
+    }
+
+    @Override
+    public List<Capability> findProviders(Requirement requirement) {
+        List<Capability> caps = new ArrayList<Capability>();
+        Map<Requirement, Collection<Capability>> resMap =
+                repository.findProviders(Collections.singleton(requirement));
+        Collection<Capability> res = resMap != null ? resMap.get(requirement) : null;
+        if (res != null) {
+            caps.addAll(res);
+        }
+        Collections.sort(caps, candidateComparator);
+        return caps;
+    }
+    @Override
+    public int insertHostedCapability(List capabilities, HostedCapability hostedCapability) {
+        for (int i=0; i < capabilities.size(); i++) {
+            Capability cap = (Capability) capabilities.get(i);
+            if (candidateComparator.compare(hostedCapability, cap) <= 0) {
+                capabilities.add(i, hostedCapability);
+                return i;
+            }
+        }
+        capabilities.add(hostedCapability);
+        return capabilities.size() - 1;
+    }
+    @Override
+    public boolean isEffective(Requirement requirement) {
+        return resolveOptional ||
+                !Constants.RESOLUTION_OPTIONAL.equals(requirement.getDirectives().get(Constants.RESOLUTION_DIRECTIVE));
+    }
+    @Override
+    public Map<Resource, Wiring> getWirings() {
+        return wirings;
+    }
+}


[33/33] git commit: [KARAF-2902] Separate section for Karaf-xxx headers and sort headers

Posted by gn...@apache.org.
[KARAF-2902] Separate section for Karaf-xxx headers and sort headers


Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/fd4b3f67
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/fd4b3f67
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/fd4b3f67

Branch: refs/heads/master
Commit: fd4b3f67799c1d37f6756e1a9d2fe4c3c780f4e9
Parents: 6727c1b
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Fri Apr 11 19:19:13 2014 +0200
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Fri Apr 11 19:20:04 2014 +0200

----------------------------------------------------------------------
 .../apache/karaf/bundle/command/Headers.java    | 27 ++++++++++++++++----
 1 file changed, 22 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/fd4b3f67/bundle/core/src/main/java/org/apache/karaf/bundle/command/Headers.java
----------------------------------------------------------------------
diff --git a/bundle/core/src/main/java/org/apache/karaf/bundle/command/Headers.java b/bundle/core/src/main/java/org/apache/karaf/bundle/command/Headers.java
index 16083ff..5cf92c3 100644
--- a/bundle/core/src/main/java/org/apache/karaf/bundle/command/Headers.java
+++ b/bundle/core/src/main/java/org/apache/karaf/bundle/command/Headers.java
@@ -24,6 +24,7 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.TreeMap;
 
 import org.apache.felix.utils.manifest.Attribute;
 import org.apache.felix.utils.manifest.Clause;
@@ -48,6 +49,7 @@ import org.osgi.framework.wiring.BundleWiring;
 @Service
 public class Headers extends BundlesCommand {
 
+    protected final static String KARAF_PREFIX = "Karaf-";
     protected final static String BUNDLE_PREFIX = "Bundle-";
     protected final static String PACKAGE_SUFFFIX = "-Package";
     protected final static String SERVICE_SUFFIX = "-Service";
@@ -90,10 +92,11 @@ public class Headers extends BundlesCommand {
 
     protected String generateFormattedOutput(Bundle bundle) {
         StringBuilder output = new StringBuilder();
-        Map<String, Object> otherAttribs = new HashMap<String, Object>();
-        Map<String, Object> bundleAttribs = new HashMap<String, Object>();
-        Map<String, Object> serviceAttribs = new HashMap<String, Object>();
-        Map<String, Object> packagesAttribs = new HashMap<String, Object>();
+        Map<String, Object> otherAttribs = new TreeMap<String, Object>();
+        Map<String, Object> karafAttribs = new TreeMap<String, Object>();
+        Map<String, Object> bundleAttribs = new TreeMap<String, Object>();
+        Map<String, Object> serviceAttribs = new TreeMap<String, Object>();
+        Map<String, Object> packagesAttribs = new TreeMap<String, Object>();
         Dictionary<String, String> dict = bundle.getHeaders();
         Enumeration<String> keys = dict.keys();
 
@@ -101,7 +104,10 @@ public class Headers extends BundlesCommand {
         while (keys.hasMoreElements()) {
             String k = (String) keys.nextElement();
             Object v = dict.get(k);
-            if (k.startsWith(BUNDLE_PREFIX)) {
+            if (k.startsWith(KARAF_PREFIX)) {
+                // starts with Karaf-xxx
+                karafAttribs.put(k, v);
+            } else if (k.startsWith(BUNDLE_PREFIX)) {
                 // starts with Bundle-xxx
                 bundleAttribs.put(k, v);
             } else if (k.endsWith(SERVICE_SUFFIX) || k.endsWith(CAPABILITY_SUFFIX)) {
@@ -124,6 +130,8 @@ public class Headers extends BundlesCommand {
         // -----------------------
         // all other attributes
         //
+        // all Karaf attributes
+        //
         // all Bundle attributes
         //
         // all Service attributes
@@ -138,6 +146,15 @@ public class Headers extends BundlesCommand {
             output.append('\n');
         }
 
+        it = karafAttribs.entrySet().iterator();
+        while (it.hasNext()) {
+            Map.Entry<String, Object> e = it.next();
+            output.append(String.format("%s = %s\n", e.getKey(), ShellUtil.getValueString(e.getValue())));
+        }
+        if (karafAttribs.size() > 0) {
+            output.append('\n');
+        }
+
         it = bundleAttribs.entrySet().iterator();
         while (it.hasNext()) {
             Map.Entry<String, Object> e = it.next();


[19/33] Revert "[KARAF-2852] Merge features/core and features/command"

Posted by gn...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/service/Artifact.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/service/Artifact.java b/features/src/main/java/org/apache/karaf/features/internal/service/Artifact.java
deleted file mode 100644
index 44e9a7c..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/service/Artifact.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.service;
-
-import java.net.URI;
-
-/**
- * Simple abstraction of a maven artifact to avoid external deps
- */
-public class Artifact {
-    String groupId;
-    String artifactId;
-    String version;
-    String extension;
-    String classifier;
-    
-    public Artifact(String coords) {
-        String[] coordsAr = coords.split(":");
-        if (coordsAr.length != 5) {
-            throw new IllegalArgumentException("Maven URL " + coords + " is malformed or not complete");
-        }
-        this.groupId = coordsAr[0];
-        this.artifactId = coordsAr[1];
-        this.version = coordsAr[4];
-        this.extension = coordsAr[2];
-        this.classifier = coordsAr[3];
-    }
-    
-    public Artifact(String coords, String version) {
-        this(coords);
-        this.version = version;
-    }
-    
-    public URI getMavenUrl(String version) {
-        String uriSt = "mvn:" + this.groupId + "/" + this.artifactId + "/" + version + "/" + this.extension + "/" + this.classifier;
-        try {
-            return new URI(uriSt);
-        } catch (Exception e) {
-            return null;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/service/BootFeaturesInstaller.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/service/BootFeaturesInstaller.java b/features/src/main/java/org/apache/karaf/features/internal/service/BootFeaturesInstaller.java
deleted file mode 100644
index 5b362b8..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/service/BootFeaturesInstaller.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.service;
-
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.EnumSet;
-import java.util.HashSet;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.apache.karaf.features.BootFinished;
-import org.apache.karaf.features.Feature;
-import org.apache.karaf.features.FeaturesService;
-import org.osgi.framework.BundleContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class BootFeaturesInstaller {
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(BootFeaturesInstaller.class);
-
-    public static String VERSION_PREFIX = "version=";
-
-    private final FeaturesServiceImpl featuresService;
-    private final BundleContext bundleContext;
-    private final String repositories;
-    private final String features;
-    private final boolean asynchronous;
-
-    /**
-     *
-     * @param features list of boot features separated by comma. Optionally contains ;version=x.x.x to specify a specific feature version
-     */
-    public BootFeaturesInstaller(BundleContext bundleContext,
-                                 FeaturesServiceImpl featuresService,
-                                 String repositories,
-                                 String features,
-                                 boolean asynchronous) {
-        this.bundleContext = bundleContext;
-        this.featuresService = featuresService;
-        this.repositories = repositories;
-        this.features = features;
-        this.asynchronous = asynchronous;
-    }
-
-    /**
-     * Install boot features
-     */
-    public void start() {
-        if (featuresService.isBootDone()) {
-            publishBootFinished();
-            return;
-        }
-        if (asynchronous) {
-            new Thread("Initial Features Provisioning") {
-                public void run() {
-                    installBootFeatures();
-                }
-            }.start();
-        } else {
-            installBootFeatures();
-        }
-    }
-
-    protected void installBootFeatures() {
-        try {
-            for (String repo : repositories.split(",")) {
-                repo = repo.trim();
-                if (!repo.isEmpty()) {
-                    try {
-                        featuresService.addRepository(URI.create(repo));
-                    } catch (Exception e) {
-                        LOGGER.error("Error installing boot feature repository " + repo, e);
-                    }
-                }
-            }
-
-            List<Set<String>> stagedFeatures = parseBootFeatures(features);
-            for (Set<String> features : stagedFeatures) {
-                featuresService.installFeatures(features, EnumSet.of(FeaturesService.Option.NoFailOnFeatureNotFound));
-            }
-            featuresService.bootDone();
-            publishBootFinished();
-        } catch (Exception e) {
-            // Special handling in case the bundle has been refreshed.
-            // In such a case, simply exits without logging any exception
-            // as the restart should cause the feature service to finish
-            // the work.
-            if (e instanceof IllegalStateException) {
-                try {
-                    bundleContext.getBundle();
-                } catch (IllegalStateException ies) {
-                    return;
-                }
-            }
-            LOGGER.error("Error installing boot features", e);
-        }
-    }
-
-    /**
-     *
-     * @param featureSt either feature name or <featurename>;version=<version>
-     * @return feature matching the feature string
-     * @throws Exception
-     */
-    private Feature getFeature(String featureSt) throws Exception {
-        String[] parts = featureSt.trim().split(";");
-        String featureName = parts[0];
-        String featureVersion = null;
-        for (String part : parts) {
-            // if the part starts with "version=" it contains the version info
-            if (part.startsWith(VERSION_PREFIX)) {
-                featureVersion = part.substring(VERSION_PREFIX.length());
-            }
-        }
-        if (featureVersion == null) {
-            // no version specified - use default version
-            featureVersion = org.apache.karaf.features.internal.model.Feature.DEFAULT_VERSION;
-        }
-        return featuresService.getFeature(featureName, featureVersion);
-    }
-
-    protected List<Set<String>> parseBootFeatures(String bootFeatures) {
-        Pattern pattern = Pattern.compile("(\\((.+))\\),|.+");
-        Matcher matcher = pattern.matcher(bootFeatures);
-        List<Set<String>> result = new ArrayList<Set<String>>();
-        while (matcher.find()) {
-            String group = matcher.group(2) != null ? matcher.group(2) : matcher.group();
-            result.add(parseFeatureList(group));
-        }
-        return result;
-    }
-
-    protected Set<String> parseFeatureList(String group) {
-        HashSet<String> features = new HashSet<String>();
-        for (String feature : Arrays.asList(group.trim().split("\\s*,\\s*"))) {
-            if (feature.length() > 0) {
-                features.add(feature);
-            }
-        }
-        return features;
-    }
-
-    private void publishBootFinished() {
-        if (bundleContext != null) {
-            BootFinished bootFinished = new BootFinished() {};
-            bundleContext.registerService(BootFinished.class, bootFinished, new Hashtable<String, String>());
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/service/EventAdminListener.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/service/EventAdminListener.java b/features/src/main/java/org/apache/karaf/features/internal/service/EventAdminListener.java
deleted file mode 100644
index b6eaae5..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/service/EventAdminListener.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.service;
-
-import java.util.Dictionary;
-import java.util.Hashtable;
-
-import org.apache.karaf.features.EventConstants;
-import org.apache.karaf.features.FeatureEvent;
-import org.apache.karaf.features.FeaturesListener;
-import org.apache.karaf.features.RepositoryEvent;
-import org.osgi.framework.BundleContext;
-import org.osgi.service.event.Event;
-import org.osgi.service.event.EventAdmin;
-import org.osgi.util.tracker.ServiceTracker;
-
-/**
- * A listener to publish events to EventAdmin
- */
-public class EventAdminListener implements FeaturesListener {
-
-    private final ServiceTracker<EventAdmin, EventAdmin> tracker;
-
-    public EventAdminListener(BundleContext context) {
-        tracker = new ServiceTracker<EventAdmin, EventAdmin>(context, EventAdmin.class.getName(), null);
-        tracker.open();
-    }
-
-    public void featureEvent(FeatureEvent event) {
-        EventAdmin eventAdmin = tracker.getService();
-        if (eventAdmin == null) {
-            return;
-        }
-        Dictionary<String, Object> props = new Hashtable<String, Object>();
-        props.put(EventConstants.TYPE, event.getType());
-        props.put(EventConstants.EVENT, event);
-        props.put(EventConstants.TIMESTAMP, System.currentTimeMillis());
-        props.put(EventConstants.FEATURE_NAME, event.getFeature().getName());
-        props.put(EventConstants.FEATURE_VERSION, event.getFeature().getVersion());
-        String topic;
-        switch (event.getType()) {
-            case FeatureInstalled:
-                topic = EventConstants.TOPIC_FEATURES_INSTALLED;
-                break;
-            case FeatureUninstalled:
-                topic = EventConstants.TOPIC_FEATURES_UNINSTALLED;
-                break;
-            default:
-                throw new IllegalStateException("Unknown features event type: " + event.getType());
-        }
-        eventAdmin.postEvent(new Event(topic, props));
-    }
-
-    public void repositoryEvent(RepositoryEvent event) {
-        EventAdmin eventAdmin = tracker.getService();
-        if (eventAdmin == null) {
-            return;
-        }
-        Dictionary<String, Object> props = new Hashtable<String, Object>();
-        props.put(EventConstants.TYPE, event.getType());
-        props.put(EventConstants.EVENT, event);
-        props.put(EventConstants.TIMESTAMP, System.currentTimeMillis());
-        props.put(EventConstants.REPOSITORY_URI, event.getRepository().getURI().toString());
-        String topic;
-        switch (event.getType()) {
-            case RepositoryAdded:
-                topic = EventConstants.TOPIC_REPOSITORY_ADDED;
-                break;
-            case RepositoryRemoved:
-                topic = EventConstants.TOPIC_REPOSITORY_REMOVED;
-                break;
-            default:
-                throw new IllegalStateException("Unknown repository event type: " + event.getType());
-        }
-        eventAdmin.postEvent(new Event(topic, props));
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/service/FeatureConfigInstaller.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/service/FeatureConfigInstaller.java b/features/src/main/java/org/apache/karaf/features/internal/service/FeatureConfigInstaller.java
deleted file mode 100644
index 0e9038d..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/service/FeatureConfigInstaller.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.service;
-
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.Dictionary;
-import java.util.Hashtable;
-
-import org.apache.karaf.features.ConfigFileInfo;
-import org.apache.karaf.features.Feature;
-import org.osgi.framework.Constants;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.service.cm.Configuration;
-import org.osgi.service.cm.ConfigurationAdmin;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class FeatureConfigInstaller {
-	private static final Logger LOGGER = LoggerFactory.getLogger(FeaturesServiceImpl.class);
-    private static final String CONFIG_KEY = "org.apache.karaf.features.configKey";
-
-    private final ConfigurationAdmin configAdmin;
-    
-    public FeatureConfigInstaller(ConfigurationAdmin configAdmin) {
-		this.configAdmin = configAdmin;
-	}
-
-    private 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};
-        }
-    }
-
-    private Configuration createConfiguration(ConfigurationAdmin configurationAdmin,
-                                                String pid, String factoryPid) throws IOException, InvalidSyntaxException {
-        if (factoryPid != null) {
-            return configurationAdmin.createFactoryConfiguration(factoryPid, null);
-        } else {
-            return configurationAdmin.getConfiguration(pid, null);
-        }
-    }
-
-    private Configuration findExistingConfiguration(ConfigurationAdmin configurationAdmin,
-                                                      String pid, String factoryPid) throws IOException, InvalidSyntaxException {
-        String filter;
-        if (factoryPid == null) {
-            filter = "(" + Constants.SERVICE_PID + "=" + pid + ")";
-        } else {
-            String key = createConfigurationKey(pid, factoryPid);
-            filter = "(" + CONFIG_KEY + "=" + key + ")";
-        }
-        Configuration[] configurations = configurationAdmin.listConfigurations(filter);
-        if (configurations != null && configurations.length > 0) {
-            return configurations[0];
-        }
-        return null;
-    }
-
-    void installFeatureConfigs(Feature feature) throws IOException, InvalidSyntaxException {
-        for (String config : feature.getConfigurations().keySet()) {
-            Dictionary<String,String> props = new Hashtable<String, String>(feature.getConfigurations().get(config));
-            String[] pid = parsePid(config);
-            Configuration cfg = findExistingConfiguration(configAdmin, pid[0], pid[1]);
-            if (cfg == null) {
-                cfg = createConfiguration(configAdmin, pid[0], pid[1]);
-                String key = createConfigurationKey(pid[0], pid[1]);
-                props.put(CONFIG_KEY, key);
-                if (cfg.getBundleLocation() != null) {
-                    cfg.setBundleLocation(null);
-                }
-                cfg.update(props);
-            }
-        }
-        for (ConfigFileInfo configFile : feature.getConfigurationFiles()) {
-            installConfigurationFile(configFile.getLocation(), configFile.getFinalname(), configFile.isOverride());
-        }
-    }
-
-    private String createConfigurationKey(String pid, String factoryPid) {
-        return factoryPid == null ? pid : pid + "-" + factoryPid;
-    }
-
-    private void installConfigurationFile(String fileLocation, String finalname, boolean override) throws IOException {
-    	String basePath = System.getProperty("karaf.base");
-    	
-    	if (finalname.contains("${")) {
-    		//remove any placeholder or variable part, this is not valid.
-    		int marker = finalname.indexOf("}");
-    		finalname = finalname.substring(marker+1);
-    	}
-    	
-    	finalname = basePath + File.separator + finalname;
-    	
-    	File file = new File(finalname); 
-    	if (file.exists()) {
-            if (!override) {
-                LOGGER.debug("Configuration file {} already exist, don't override it", finalname);
-                return;
-            } else {
-                LOGGER.info("Configuration file {} already exist, overriding it", finalname);
-            }
-    	} else {
-            LOGGER.info("Creating configuration file {}", finalname);
-        }
-
-        InputStream is = null;
-        FileOutputStream fop = null;
-        try {
-            is = new BufferedInputStream(new URL(fileLocation).openStream());
-
-            if (!file.exists()) {
-                File parentFile = file.getParentFile();
-                if (parentFile != null)
-                    parentFile.mkdirs();
-                file.createNewFile();
-            }
-
-            fop = new FileOutputStream(file);
-        
-            int bytesRead;
-            byte[] buffer = new byte[1024];
-            
-            while ((bytesRead = is.read(buffer)) != -1) {
-                fop.write(buffer, 0, bytesRead);
-            }
-        } catch (RuntimeException e) {
-            LOGGER.error(e.getMessage());
-            throw e;
-        } catch (MalformedURLException e) {
-        	LOGGER.error(e.getMessage());
-            throw e;
-		} finally {
-			if (is != null)
-				is.close();
-            if (fop != null) {
-			    fop.flush();
-			    fop.close();
-            }
-		}
-            
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/service/FeatureFinder.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/service/FeatureFinder.java b/features/src/main/java/org/apache/karaf/features/internal/service/FeatureFinder.java
deleted file mode 100644
index d6defe0..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/service/FeatureFinder.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.service;
-
-import java.net.URI;
-import java.util.Dictionary;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-import org.osgi.service.cm.ConfigurationException;
-import org.osgi.service.cm.ManagedService;
-
-public class FeatureFinder implements ManagedService {
-
-    final Map<String, String> nameToArtifactMap = new HashMap<String, String>();
-
-    public String[] getNames() {
-        synchronized (nameToArtifactMap) {
-            Set<String> strings = nameToArtifactMap.keySet();
-            return strings.toArray(new String[strings.size()]);
-        }
-    }
-
-    public URI getUriFor(String name, String version) {
-        String coords;
-        synchronized (nameToArtifactMap) {
-            coords = nameToArtifactMap.get(name);
-        }
-        if (coords == null) {
-            return null;
-        }
-        Artifact artifact = new Artifact(coords);
-        return artifact.getMavenUrl(version);
-    }
-
-    @SuppressWarnings("rawtypes")
-    public void updated(Dictionary properties) throws ConfigurationException {
-        synchronized (nameToArtifactMap) {
-            if (properties != null) {
-                nameToArtifactMap.clear();
-                Enumeration keys = properties.keys();
-                while (keys.hasMoreElements()) {
-                    String key = (String) keys.nextElement();
-                    if (!"felix.fileinstall.filename".equals(key) && !"service.pid".equals(key)) {
-                        nameToArtifactMap.put(key, (String) properties.get(key));
-                    }
-                }
-            }
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/service/FeatureValidationUtil.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/service/FeatureValidationUtil.java b/features/src/main/java/org/apache/karaf/features/internal/service/FeatureValidationUtil.java
deleted file mode 100644
index 6903dc0..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/service/FeatureValidationUtil.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-package org.apache.karaf.features.internal.service;
-
-import java.net.URI;
-
-import org.apache.karaf.features.internal.model.JaxbUtil;
-
-/**
- * Utility class which fires XML Schema validation.
- */
-public class FeatureValidationUtil {
-
-    /**
-     * Runs schema validation.
-     * 
-     * @param uri Uri to validate.
-     * @throws Exception When validation fails.
-     */
-    public static void validate(URI uri) throws Exception {
-        JaxbUtil.unmarshal(uri.toASCIIString(), true);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java b/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
deleted file mode 100644
index 0243dc0..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
+++ /dev/null
@@ -1,1416 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.service;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.TreeSet;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-import org.apache.felix.utils.version.VersionRange;
-import org.apache.felix.utils.version.VersionTable;
-import org.apache.karaf.features.BundleInfo;
-import org.apache.karaf.features.Feature;
-import org.apache.karaf.features.FeatureEvent;
-import org.apache.karaf.features.FeaturesListener;
-import org.apache.karaf.features.FeaturesService;
-import org.apache.karaf.features.Repository;
-import org.apache.karaf.features.RepositoryEvent;
-import org.apache.karaf.features.internal.deployment.DeploymentBuilder;
-import org.apache.karaf.features.internal.deployment.StreamProvider;
-import org.apache.karaf.features.internal.resolver.FeatureNamespace;
-import org.apache.karaf.features.internal.resolver.UriNamespace;
-import org.apache.karaf.features.internal.util.ChecksumUtils;
-import org.apache.karaf.features.internal.util.Macro;
-import org.apache.karaf.features.internal.util.MultiException;
-import org.apache.karaf.util.collections.CopyOnWriteArrayIdentityList;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleException;
-import org.osgi.framework.Constants;
-import org.osgi.framework.FrameworkEvent;
-import org.osgi.framework.FrameworkListener;
-import org.osgi.framework.ServiceReference;
-import org.osgi.framework.Version;
-import org.osgi.framework.startlevel.BundleStartLevel;
-import org.osgi.framework.wiring.BundleRevision;
-import org.osgi.framework.wiring.BundleWire;
-import org.osgi.framework.wiring.BundleWiring;
-import org.osgi.framework.wiring.FrameworkWiring;
-import org.osgi.resource.Resource;
-import org.osgi.resource.Wire;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import static org.apache.felix.resolver.Util.getSymbolicName;
-import static org.apache.felix.resolver.Util.getVersion;
-
-/**
- *
- */
-public class FeaturesServiceImpl implements FeaturesService {
-
-    public static final String UPDATE_SNAPSHOTS_NONE = "none";
-    public static final String UPDATE_SNAPSHOTS_CRC = "crc";
-    public static final String UPDATE_SNAPSHOTS_ALWAYS = "always";
-    public static final String DEFAULT_UPDATE_SNAPSHOTS = UPDATE_SNAPSHOTS_CRC;
-
-    public static final String DEFAULT_FEATURE_RESOLUTION_RANGE = "${range;[====,====]}";
-    public static final String DEFAULT_BUNDLE_UPDATE_RANGE = "${range;[==,=+)}";
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(FeaturesServiceImpl.class);
-    private static final String SNAPSHOT = "SNAPSHOT";
-    private static final String MAVEN = "mvn:";
-
-    /**
-     * Our bundle.
-     * We use it to check bundle operations affecting our own bundle.
-     */
-    private final Bundle bundle;
-
-    /**
-     * The system bundle context.
-     * For all bundles related operations, we use the system bundle context
-     * to allow this bundle to be stopped and still allow the deployment to
-     * take place.
-     */
-    private final BundleContext systemBundleContext;
-    /**
-     * Used to load and save the {@link State} of this service.
-     */
-    private final StateStorage storage;
-    private final FeatureFinder featureFinder;
-    private final EventAdminListener eventAdminListener;
-    private final FeatureConfigInstaller configInstaller;
-    private final String overrides;
-    /**
-     * Range to use when a version is specified on a feature dependency.
-     * The default is {@link FeaturesServiceImpl#DEFAULT_FEATURE_RESOLUTION_RANGE}
-     */
-    private final String featureResolutionRange;
-    /**
-     * Range to use when verifying if a bundle should be updated or
-     * new bundle installed.
-     * The default is {@link FeaturesServiceImpl#DEFAULT_BUNDLE_UPDATE_RANGE}
-     */
-    private final String bundleUpdateRange;
-    /**
-     * Use CRC to check snapshot bundles and update them if changed.
-     * Either:
-     *   - none : never update snapshots
-     *   - always : always update snapshots
-     *   - crc : use CRC to detect changes
-     */
-    private final String updateSnaphots;
-
-    private final List<FeaturesListener> listeners = new CopyOnWriteArrayIdentityList<FeaturesListener>();
-
-    // Synchronized on lock
-    private final Object lock = new Object();
-    private final State state = new State();
-    private final Map<String, Repository> repositoryCache = new HashMap<String, Repository>();
-    private Map<String, Map<String, Feature>> featureCache;
-
-
-    public FeaturesServiceImpl(Bundle bundle,
-                               BundleContext systemBundleContext,
-                               StateStorage storage,
-                               FeatureFinder featureFinder,
-                               EventAdminListener eventAdminListener,
-                               FeatureConfigInstaller configInstaller,
-                               String overrides,
-                               String featureResolutionRange,
-                               String bundleUpdateRange,
-                               String updateSnaphots) {
-        this.bundle = bundle;
-        this.systemBundleContext = systemBundleContext;
-        this.storage = storage;
-        this.featureFinder = featureFinder;
-        this.eventAdminListener = eventAdminListener;
-        this.configInstaller = configInstaller;
-        this.overrides = overrides;
-        this.featureResolutionRange = featureResolutionRange;
-        this.bundleUpdateRange = bundleUpdateRange;
-        this.updateSnaphots = updateSnaphots;
-        loadState();
-    }
-
-    //
-    // State support
-    //
-
-    protected void loadState() {
-        try {
-            synchronized (lock) {
-                storage.load(state);
-            }
-        } catch (IOException e) {
-            LOGGER.warn("Error loading FeaturesService state", e);
-        }
-    }
-
-    protected void saveState() {
-        try {
-            synchronized (lock) {
-                // Make sure we don't store bundle checksums if
-                // it has been disabled through configadmin
-                // so that we don't keep out-of-date checksums.
-                if (!UPDATE_SNAPSHOTS_CRC.equalsIgnoreCase(updateSnaphots)) {
-                    state.bundleChecksums.clear();
-                }
-                storage.save(state);
-            }
-        } catch (IOException e) {
-            LOGGER.warn("Error saving FeaturesService state", e);
-        }
-    }
-
-    boolean isBootDone() {
-        synchronized (lock) {
-            return state.bootDone.get();
-        }
-    }
-
-    void bootDone() {
-        synchronized (lock) {
-            state.bootDone.set(true);
-            saveState();
-        }
-    }
-
-    //
-    // Listeners support
-    //
-
-    public void registerListener(FeaturesListener listener) {
-        listeners.add(listener);
-        try {
-            Set<String> repositories = new TreeSet<String>();
-            Set<String> installedFeatures = new TreeSet<String>();
-            synchronized (lock) {
-                repositories.addAll(state.repositories);
-                installedFeatures.addAll(state.installedFeatures);
-            }
-            for (String uri : repositories) {
-                Repository repository = new RepositoryImpl(URI.create(uri));
-                listener.repositoryEvent(new RepositoryEvent(repository, RepositoryEvent.EventType.RepositoryAdded, true));
-            }
-            for (String id : installedFeatures) {
-                Feature feature = org.apache.karaf.features.internal.model.Feature.valueOf(id);
-                listener.featureEvent(new FeatureEvent(feature, FeatureEvent.EventType.FeatureInstalled, true));
-            }
-        } catch (Exception e) {
-            LOGGER.error("Error notifying listener about the current state", e);
-        }
-    }
-
-    public void unregisterListener(FeaturesListener listener) {
-        listeners.remove(listener);
-    }
-
-    protected void callListeners(FeatureEvent event) {
-        if (eventAdminListener != null) {
-            eventAdminListener.featureEvent(event);
-        }
-        for (FeaturesListener listener : listeners) {
-            listener.featureEvent(event);
-        }
-    }
-
-    protected void callListeners(RepositoryEvent event) {
-        if (eventAdminListener != null) {
-            eventAdminListener.repositoryEvent(event);
-        }
-        for (FeaturesListener listener : listeners) {
-            listener.repositoryEvent(event);
-        }
-    }
-
-    //
-    // Feature Finder support
-    //
-
-    @Override
-    public URI getRepositoryUriFor(String name, String version) {
-        return featureFinder.getUriFor(name, version);
-    }
-
-    @Override
-    public String[] getRepositoryNames() {
-        return featureFinder.getNames();
-    }
-
-
-    //
-    // Repositories support
-    //
-
-    public Repository loadRepository(URI uri) throws Exception {
-        RepositoryImpl repo = new RepositoryImpl(uri);
-        repo.load(true);
-        return repo;
-    }
-
-    @Override
-    public void validateRepository(URI uri) throws Exception {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void addRepository(URI uri) throws Exception {
-        addRepository(uri, false);
-    }
-
-    @Override
-    public void addRepository(URI uri, boolean install) throws Exception {
-        if (install) {
-            // TODO: implement
-            throw new UnsupportedOperationException();
-        }
-        Repository repository = loadRepository(uri);
-        synchronized (lock) {
-            // Clean cache
-            repositoryCache.put(uri.toString(), repository);
-            featureCache = null;
-            // Add repo
-            if (!state.repositories.add(uri.toString())) {
-                return;
-            }
-            saveState();
-        }
-        callListeners(new RepositoryEvent(repository, RepositoryEvent.EventType.RepositoryAdded, false));
-    }
-
-    @Override
-    public void removeRepository(URI uri) throws Exception {
-        removeRepository(uri, true);
-    }
-
-    @Override
-    public void removeRepository(URI uri, boolean uninstall) throws Exception {
-        // TODO: check we don't have any feature installed from this repository
-        Repository repo;
-        synchronized (lock) {
-            // Remove repo
-            if (!state.repositories.remove(uri.toString())) {
-                return;
-            }
-            // Clean cache
-            featureCache = null;
-            repo = repositoryCache.get(uri.toString());
-            List<String> toRemove = new ArrayList<String>();
-            toRemove.add(uri.toString());
-            while (!toRemove.isEmpty()) {
-                Repository rep = repositoryCache.remove(toRemove.remove(0));
-                if (rep != null) {
-                    for (URI u : rep.getRepositories()) {
-                        toRemove.add(u.toString());
-                    }
-                }
-            }
-            saveState();
-        }
-        if (repo == null) {
-            repo = new RepositoryImpl(uri);
-        }
-        callListeners(new RepositoryEvent(repo, RepositoryEvent.EventType.RepositoryRemoved, false));
-    }
-
-    @Override
-    public void restoreRepository(URI uri) throws Exception {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void refreshRepository(URI uri) throws Exception {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public Repository[] listRepositories() throws Exception {
-        // Make sure the cache is loaded
-        getFeatures();
-        synchronized (lock) {
-            return repositoryCache.values().toArray(new Repository[repositoryCache.size()]);
-        }
-    }
-
-    @Override
-    public Repository[] listRequiredRepositories() throws Exception {
-        // Make sure the cache is loaded
-        getFeatures();
-        synchronized (lock) {
-            List<Repository> repos = new ArrayList<Repository>();
-            for (Map.Entry<String, Repository> entry : repositoryCache.entrySet()) {
-                if (state.repositories.contains(entry.getKey())) {
-                    repos.add(entry.getValue());
-                }
-            }
-            return repos.toArray(new Repository[repos.size()]);
-        }
-    }
-
-    @Override
-    public Repository getRepository(String name) throws Exception {
-        // Make sure the cache is loaded
-        getFeatures();
-        synchronized (lock) {
-            for (Repository repo : this.repositoryCache.values()) {
-                if (name.equals(repo.getName())) {
-                    return repo;
-                }
-            }
-            return null;
-        }
-    }
-
-    //
-    // Features support
-    //
-
-    public Feature getFeature(String name) throws Exception {
-        return getFeature(name, null);
-    }
-
-    public Feature getFeature(String name, String version) throws Exception {
-        Map<String, Feature> versions = getFeatures().get(name);
-        return getFeatureMatching(versions, version);
-    }
-
-    protected Feature getFeatureMatching(Map<String, Feature> versions, String version) {
-        if (version != null) {
-            version = version.trim();
-            if (version.equals(org.apache.karaf.features.internal.model.Feature.DEFAULT_VERSION)) {
-                version = "";
-            }
-        } else {
-            version = "";
-        }
-        if (versions == null || versions.isEmpty()) {
-            return null;
-        } else {
-            Feature feature = version.isEmpty() ? null : versions.get(version);
-            if (feature == null) {
-                // Compute version range. If an version has been given, assume exact range
-                VersionRange versionRange = version.isEmpty() ?
-                        new VersionRange(Version.emptyVersion) :
-                        new VersionRange(version, true, true);
-                Version latest = Version.emptyVersion;
-                for (String available : versions.keySet()) {
-                    Version availableVersion = VersionTable.getVersion(available);
-                    if (availableVersion.compareTo(latest) >= 0 && versionRange.contains(availableVersion)) {
-                        feature = versions.get(available);
-                        latest = availableVersion;
-                    }
-                }
-            }
-            return feature;
-        }
-    }
-
-    public Feature[] listFeatures() throws Exception {
-        Set<Feature> features = new HashSet<Feature>();
-        for (Map<String, Feature> featureWithDifferentVersion : getFeatures().values()) {
-            for (Feature f : featureWithDifferentVersion.values()) {
-                features.add(f);
-            }
-        }
-        return features.toArray(new Feature[features.size()]);
-    }
-
-    protected Map<String, Map<String, Feature>> getFeatures() throws Exception {
-        List<String> uris;
-        synchronized (lock) {
-            if (featureCache != null) {
-                return featureCache;
-            }
-            uris = new ArrayList<String>(state.repositories);
-        }
-        //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
-        List<String> toLoad = new ArrayList<String>(uris);
-        while (!toLoad.isEmpty()) {
-            String uri = toLoad.remove(0);
-            Repository repo;
-            synchronized (lock) {
-                repo = repositoryCache.get(uri);
-            }
-            if (repo == null) {
-                RepositoryImpl rep = new RepositoryImpl(URI.create(uri));
-                rep.load();
-                repo = rep;
-                synchronized (lock) {
-                    repositoryCache.put(uri, repo);
-                }
-            }
-            for (URI u : repo.getRepositories()) {
-                toLoad.add(u.toString());
-            }
-        }
-        List<Repository> repos;
-        synchronized (lock) {
-            repos = new ArrayList<Repository>(repositoryCache.values());
-        }
-        // * then load all features
-        for (Repository repo : repos) {
-            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);
-                }
-            }
-        }
-        synchronized (lock) {
-            if (uris.size() == state.repositories.size() &&
-                    state.repositories.containsAll(uris)) {
-                featureCache = map;
-            }
-        }
-        return map;
-    }
-
-    //
-    // Installed features
-    //
-
-    @Override
-    public Feature[] listInstalledFeatures() throws Exception {
-        Set<Feature> features = new HashSet<Feature>();
-        Map<String, Map<String, Feature>> allFeatures = getFeatures();
-        synchronized (lock) {
-            for (Map<String, Feature> featureWithDifferentVersion : allFeatures.values()) {
-                for (Feature f : featureWithDifferentVersion.values()) {
-                    if (isInstalled(f)) {
-                        features.add(f);
-                    }
-                }
-            }
-        }
-        return features.toArray(new Feature[features.size()]);
-    }
-
-    @Override
-    public Feature[] listRequiredFeatures() throws Exception {
-        Set<Feature> features = new HashSet<Feature>();
-        Map<String, Map<String, Feature>> allFeatures = getFeatures();
-        synchronized (lock) {
-            for (Map<String, Feature> featureWithDifferentVersion : allFeatures.values()) {
-                for (Feature f : featureWithDifferentVersion.values()) {
-                    if (isRequired(f)) {
-                        features.add(f);
-                    }
-                }
-            }
-        }
-        return features.toArray(new Feature[features.size()]);
-    }
-
-
-    @Override
-    public boolean isInstalled(Feature f) {
-        String id = normalize(f.getId());
-        synchronized (lock) {
-            return state.installedFeatures.contains(id);
-        }
-    }
-
-    @Override
-    public boolean isRequired(Feature f) {
-        String id = normalize(f.getId());
-        synchronized (lock) {
-            return state.features.contains(id);
-        }
-    }
-
-    //
-    // Installation and uninstallation of features
-    //
-
-    public void installFeature(String name) throws Exception {
-        installFeature(name, EnumSet.noneOf(Option.class));
-    }
-
-    public void installFeature(String name, String version) throws Exception {
-        installFeature(version != null ? name + "/" + version : name, EnumSet.noneOf(Option.class));
-    }
-
-    public void installFeature(String name, EnumSet<Option> options) throws Exception {
-        installFeatures(Collections.singleton(name), options);
-    }
-
-    public void installFeature(String name, String version, EnumSet<Option> options) throws Exception {
-        installFeature(version != null ? name + "/" + version : name, options);
-    }
-
-    public void installFeature(Feature feature, EnumSet<Option> options) throws Exception {
-        installFeature(feature.getId());
-    }
-
-    @Override
-    public void uninstallFeature(String name, String version) throws Exception {
-        uninstallFeature(version != null ? name + "/" + version : name);
-    }
-
-    @Override
-    public void uninstallFeature(String name, String version, EnumSet<Option> options) throws Exception {
-        uninstallFeature(version != null ? name + "/" + version : name, options);
-    }
-
-    @Override
-    public void uninstallFeature(String name) throws Exception {
-        uninstallFeature(name, EnumSet.noneOf(Option.class));
-    }
-
-    @Override
-    public void uninstallFeature(String name, EnumSet<Option> options) throws Exception {
-        uninstallFeatures(Collections.singleton(name), options);
-    }
-
-
-    //
-    //
-    //
-    //   RESOLUTION
-    //
-    //
-    //
-
-
-
-
-
-
-    public void installFeatures(Set<String> features, EnumSet<Option> options) throws Exception {
-        Set<String> required;
-        Set<String> installed;
-        Set<Long> managed;
-        synchronized (lock) {
-            required = new HashSet<String>(state.features);
-            installed = new HashSet<String>(state.installedFeatures);
-            managed = new HashSet<Long>(state.managedBundles);
-        }
-        List<String> featuresToAdd = new ArrayList<String>();
-        Map<String, Map<String, Feature>> featuresMap = getFeatures();
-        for (String feature : features) {
-            feature = normalize(feature);
-            String name = feature.substring(0, feature.indexOf("/"));
-            String version = feature.substring(feature.indexOf("/") + 1);
-            Feature f = getFeatureMatching(featuresMap.get(name), version);
-            if (f == null) {
-                if (!options.contains(Option.NoFailOnFeatureNotFound)) {
-                    throw new IllegalArgumentException("No matching features for " + feature);
-                }
-            } else {
-                featuresToAdd.add(normalize(f.getId()));
-            }
-        }
-        featuresToAdd = new ArrayList<String>(new LinkedHashSet<String>(featuresToAdd));
-        StringBuilder sb = new StringBuilder();
-        sb.append("Adding features: ");
-        for (int i = 0; i < featuresToAdd.size(); i++) {
-            if (i > 0) {
-                sb.append(", ");
-            }
-            sb.append(featuresToAdd.get(i));
-        }
-        print(sb.toString(), options.contains(Option.Verbose));
-        required.addAll(featuresToAdd);
-        doInstallFeaturesInThread(required, installed, managed, options);
-    }
-
-    public void uninstallFeatures(Set<String> features, EnumSet<Option> options) throws Exception {
-        Set<String> required;
-        Set<String> installed;
-        Set<Long> managed;
-        synchronized (lock) {
-            required = new HashSet<String>(state.features);
-            installed = new HashSet<String>(state.installedFeatures);
-            managed = new HashSet<Long>(state.managedBundles);
-        }
-        List<String> featuresToRemove = new ArrayList<String>();
-        for (String feature : new HashSet<String>(features)) {
-            List<String> toRemove = new ArrayList<String>();
-            feature = normalize(feature);
-            if (feature.endsWith("/0.0.0")) {
-                String nameSep = feature.substring(0, feature.indexOf("/") + 1);
-                for (String f : required) {
-                    if (normalize(f).startsWith(nameSep)) {
-                        toRemove.add(f);
-                    }
-                }
-            } else {
-                toRemove.add(feature);
-            }
-            toRemove.retainAll(required);
-            if (toRemove.isEmpty()) {
-                throw new IllegalArgumentException("Feature named '" + feature + "' is not installed");
-            } else if (toRemove.size() > 1) {
-                String name = feature.substring(0, feature.indexOf("/"));
-                StringBuilder sb = new StringBuilder();
-                sb.append("Feature named '").append(name).append("' has multiple versions installed (");
-                for (int i = 0; i < toRemove.size(); i++) {
-                    if (i > 0) {
-                        sb.append(", ");
-                    }
-                    sb.append(toRemove.get(i));
-                }
-                sb.append("). Please specify the version to uninstall.");
-                throw new IllegalArgumentException(sb.toString());
-            }
-            featuresToRemove.addAll(toRemove);
-        }
-        featuresToRemove = new ArrayList<String>(new LinkedHashSet<String>(featuresToRemove));
-        StringBuilder sb = new StringBuilder();
-        sb.append("Removing features: ");
-        for (int i = 0; i < featuresToRemove.size(); i++) {
-            if (i > 0) {
-                sb.append(", ");
-            }
-            sb.append(featuresToRemove.get(i));
-        }
-        print(sb.toString(), options.contains(Option.Verbose));
-        required.removeAll(featuresToRemove);
-        doInstallFeaturesInThread(required, installed, managed, options);
-    }
-
-    protected String normalize(String feature) {
-        if (!feature.contains("/")) {
-            feature += "/0.0.0";
-        }
-        int idx = feature.indexOf("/");
-        String name = feature.substring(0, idx);
-        String version = feature.substring(idx + 1);
-        return name + "/" + VersionTable.getVersion(version).toString();
-    }
-
-    /**
-     * Actual deployment needs to be done in a separate thread.
-     * The reason is that if the console is refreshed, the current thread which is running
-     * the command may be interrupted while waiting for the refresh to be done, leading
-     * to bundles not being started after the refresh.
-     */
-    public void doInstallFeaturesInThread(final Set<String> features,
-                                          final Set<String> installed,
-                                          final Set<Long> managed,
-                                          final EnumSet<Option> options) throws Exception {
-        ExecutorService executor = Executors.newCachedThreadPool();
-        try {
-            executor.submit(new Callable<Object>() {
-                @Override
-                public Object call() throws Exception {
-                    doInstallFeatures(features, installed, managed, options);
-                    return null;
-                }
-            }).get();
-        } catch (ExecutionException e) {
-            Throwable t = e.getCause();
-            if (t instanceof RuntimeException) {
-                throw ((RuntimeException) t);
-            } else if (t instanceof Error) {
-                throw ((Error) t);
-            } else if (t instanceof Exception) {
-                throw (Exception) t;
-            } else {
-                throw e;
-            }
-        } finally {
-            executor.shutdown();
-        }
-    }
-
-    public void doInstallFeatures(Set<String> features,    // all request features
-                                  Set<String> installed,   // installed features
-                                  Set<Long> managed,       // currently managed bundles
-                                  EnumSet<Option> options  // installation options
-                    ) throws Exception {
-
-        boolean noRefreshUnmanaged = options.contains(Option.NoAutoRefreshUnmanagedBundles);
-        boolean noRefreshManaged = options.contains(Option.NoAutoRefreshManagedBundles);
-        boolean noRefresh = options.contains(Option.NoAutoRefreshBundles);
-        boolean noStart = options.contains(Option.NoAutoStartBundles);
-        boolean verbose = options.contains(Option.Verbose);
-        boolean simulate = options.contains(Option.Simulate);
-
-        // Get a list of resolved and unmanaged bundles to use as capabilities during resolution
-        List<Resource> systemBundles = new ArrayList<Resource>();
-        Bundle[] bundles = systemBundleContext.getBundles();
-        for (Bundle bundle : bundles) {
-            if (bundle.getState() >= Bundle.RESOLVED && !managed.contains(bundle.getBundleId())) {
-                Resource res = bundle.adapt(BundleRevision.class);
-                systemBundles.add(res);
-            }
-        }
-        // Resolve
-        // TODO: requirements
-        // TODO: bundles
-        // TODO: regions: on isolated regions, we may need different resolution for each region
-        Set<String>  overrides    = Overrides.loadOverrides(this.overrides);
-        Repository[] repositories = listRepositories();
-        DeploymentBuilder builder = createDeploymentBuilder(repositories);
-        builder.setFeatureRange(featureResolutionRange);
-        builder.download(features,
-                         Collections.<String>emptySet(),
-                         Collections.<String>emptySet(),
-                         overrides,
-                         Collections.<String>emptySet());
-        Map<Resource, List<Wire>> resolution = builder.resolve(systemBundles);
-        Collection<Resource> allResources = resolution.keySet();
-        Map<String, StreamProvider> providers = builder.getProviders();
-
-        // Install conditionals
-        List<String> installedFeatureIds = getFeatureIds(allResources);
-        List<String> newFeatures = new ArrayList<String>(installedFeatureIds);
-        newFeatures.removeAll(installed);
-        List<String> delFeatures = new ArrayList<String>(installed);
-        delFeatures.removeAll(installedFeatureIds);
-
-        //
-        // Compute list of installable resources (those with uris)
-        //
-        List<Resource> resources = getBundles(allResources);
-
-        // Compute information for each bundle
-        Map<String, BundleInfo> bundleInfos = new HashMap<String, BundleInfo>();
-        for (Feature feature : getFeatures(repositories, getFeatureIds(allResources))) {
-            for (BundleInfo bi : feature.getBundles()) {
-                BundleInfo oldBi = bundleInfos.get(bi.getLocation());
-                if (oldBi != null) {
-                    bi = mergeBundleInfo(bi, oldBi);
-                }
-                bundleInfos.put(bi.getLocation(), bi);
-            }
-        }
-
-        // TODO: handle bundleInfo.isStart()
-
-        // Get all resources that will be used to satisfy the old features set
-        Set<Resource> resourceLinkedToOldFeatures = new HashSet<Resource>();
-        if (noStart) {
-            for (Resource resource : resolution.keySet()) {
-                String name = FeatureNamespace.getName(resource);
-                if (name != null) {
-                    Version version = FeatureNamespace.getVersion(resource);
-                    String id = version != null ? name + "/" + version : name;
-                    if (installed.contains(id)) {
-                        addTransitive(resource, resourceLinkedToOldFeatures, resolution);
-                    }
-                }
-            }
-        }
-
-        //
-        // Compute deployment
-        //
-        Map<String, Long> bundleChecksums = new HashMap<String, Long>();
-        synchronized (lock) {
-            bundleChecksums.putAll(state.bundleChecksums);
-        }
-        Deployment deployment = computeDeployment(managed, bundles, providers, resources, bundleChecksums);
-
-        if (deployment.toDelete.isEmpty() &&
-                deployment.toUpdate.isEmpty() &&
-                deployment.toInstall.isEmpty()) {
-            print("No deployment change.", verbose);
-            return;
-        }
-        //
-        // Log deployment
-        //
-        logDeployment(deployment, verbose);
-
-        //
-        // Compute the set of bundles to refresh
-        //
-        Set<Bundle> toRefresh = new HashSet<Bundle>();
-        toRefresh.addAll(deployment.toDelete);
-        toRefresh.addAll(deployment.toUpdate.keySet());
-
-        if (!noRefreshManaged) {
-            int size;
-            do {
-                size = toRefresh.size();
-                for (Bundle bundle : bundles) {
-                    // Continue if we already know about this bundle
-                    if (toRefresh.contains(bundle)) {
-                        continue;
-                    }
-                    // Ignore non resolved bundle
-                    BundleWiring wiring = bundle.adapt(BundleWiring.class);
-                    if (wiring == null) {
-                        continue;
-                    }
-                    // Get through the old resolution and flag this bundle
-                    // if it was wired to a bundle to be refreshed
-                    for (BundleWire wire : wiring.getRequiredWires(null)) {
-                        if (toRefresh.contains(wire.getProvider().getBundle())) {
-                            toRefresh.add(bundle);
-                            break;
-                        }
-                    }
-                    // Get through the new resolution and flag this bundle
-                    // if it's wired to any new bundle
-                    List<Wire> newWires = resolution.get(wiring.getRevision());
-                    if (newWires != null) {
-                        for (Wire wire : newWires) {
-                            Bundle b = null;
-                            if (wire.getProvider() instanceof BundleRevision) {
-                                b = ((BundleRevision) wire.getProvider()).getBundle();
-                            } else {
-                                b = deployment.resToBnd.get(wire.getProvider());
-                            }
-                            if (b == null || toRefresh.contains(b)) {
-                                toRefresh.add(bundle);
-                                break;
-                            }
-                        }
-                    }
-                }
-            } while (toRefresh.size() > size);
-        }
-        if (noRefreshUnmanaged) {
-            Set<Bundle> newSet = new HashSet<Bundle>();
-            for (Bundle bundle : toRefresh) {
-                if (managed.contains(bundle.getBundleId())) {
-                    newSet.add(bundle);
-                }
-            }
-            toRefresh = newSet;
-        }
-
-
-        if (simulate) {
-            if (!toRefresh.isEmpty()) {
-                print("  Bundles to refresh:", verbose);
-                for (Bundle bundle : toRefresh) {
-                    print("    " + bundle.getSymbolicName() + " / " + bundle.getVersion(), verbose);
-                }
-            }
-            return;
-        }
-
-        Set<Bundle> toStart = new HashSet<Bundle>();
-
-        //
-        // Execute deployment
-        //
-
-        // TODO: handle update on the features service itself
-        if (deployment.toUpdate.containsKey(bundle) ||
-                deployment.toDelete.contains(bundle)) {
-
-            LOGGER.warn("Updating or uninstalling of the FeaturesService is not supported");
-            deployment.toUpdate.remove(bundle);
-            deployment.toDelete.remove(bundle);
-
-        }
-
-        //
-        // Perform bundle operations
-        //
-
-        // Stop bundles by chunks
-        Set<Bundle> toStop = new HashSet<Bundle>();
-        toStop.addAll(deployment.toUpdate.keySet());
-        toStop.addAll(deployment.toDelete);
-        removeFragmentsAndBundlesInState(toStop, Bundle.UNINSTALLED | Bundle.RESOLVED | Bundle.STOPPING);
-        if (!toStop.isEmpty()) {
-            print("Stopping bundles:", verbose);
-            while (!toStop.isEmpty()) {
-                List<Bundle> bs = getBundlesToStop(toStop);
-                for (Bundle bundle : bs) {
-                    print("  " + bundle.getSymbolicName() + " / " + bundle.getVersion(), verbose);
-                    bundle.stop(Bundle.STOP_TRANSIENT);
-                    toStop.remove(bundle);
-                }
-            }
-        }
-        if (!deployment.toDelete.isEmpty()) {
-            print("Uninstalling bundles:", verbose);
-            for (Bundle bundle : deployment.toDelete) {
-                print("  " + bundle.getSymbolicName() + " / " + bundle.getVersion(), verbose);
-                bundle.uninstall();
-                managed.remove(bundle.getBundleId());
-            }
-        }
-        if (!deployment.toUpdate.isEmpty()) {
-            print("Updating bundles:", verbose);
-            for (Map.Entry<Bundle, Resource> entry : deployment.toUpdate.entrySet()) {
-                Bundle bundle = entry.getKey();
-                Resource resource = entry.getValue();
-                String uri = UriNamespace.getUri(resource);
-                print("  " + uri, verbose);
-                InputStream is = getBundleInputStream(resource, providers);
-                bundle.update(is);
-                toStart.add(bundle);
-                BundleInfo bi = bundleInfos.get(uri);
-                if (bi != null && bi.getStartLevel() > 0) {
-                    bundle.adapt(BundleStartLevel.class).setStartLevel(bi.getStartLevel());
-                }
-                // TODO: handle region
-            }
-        }
-        if (!deployment.toInstall.isEmpty()) {
-            print("Installing bundles:", verbose);
-            for (Resource resource : deployment.toInstall) {
-                String uri = UriNamespace.getUri(resource);
-                print("  " + uri, verbose);
-                InputStream is = getBundleInputStream(resource, providers);
-                Bundle bundle = systemBundleContext.installBundle(uri, is);
-                managed.add(bundle.getBundleId());
-                if (!noStart || resourceLinkedToOldFeatures.contains(resource)) {
-                    toStart.add(bundle);
-                }
-                deployment.resToBnd.put(resource, bundle);
-                // save a checksum of installed snapshot bundle
-                if (UPDATE_SNAPSHOTS_CRC.equals(updateSnaphots)
-                        && isUpdateable(resource) && !deployment.newCheckums.containsKey(bundle.getLocation())) {
-                    deployment.newCheckums.put(bundle.getLocation(), ChecksumUtils.checksum(getBundleInputStream(resource, providers)));
-                }
-                BundleInfo bi = bundleInfos.get(uri);
-                if (bi != null && bi.getStartLevel() > 0) {
-                    bundle.adapt(BundleStartLevel.class).setStartLevel(bi.getStartLevel());
-                }
-                // TODO: handle region
-            }
-        }
-
-        //
-        // Update and save state
-        //
-        synchronized (lock) {
-            state.bundleChecksums.putAll(deployment.newCheckums);
-            state.features.clear();
-            state.features.addAll(features);
-            state.installedFeatures.clear();
-            state.installedFeatures.addAll(installedFeatureIds);
-            state.managedBundles.clear();
-            state.managedBundles.addAll(managed);
-            saveState();
-        }
-
-        //
-        // Install configurations
-        //
-        if (configInstaller != null && !newFeatures.isEmpty()) {
-            for (Repository repository : repositories) {
-                for (Feature feature : repository.getFeatures()) {
-                    if (newFeatures.contains(feature.getId())) {
-                        configInstaller.installFeatureConfigs(feature);
-                    }
-                }
-            }
-        }
-
-        // TODO: remove this hack, but it avoids loading the class after the bundle is refreshed
-        new CopyOnWriteArrayIdentityList().iterator();
-        RequirementSort.sort(Collections.<Resource>emptyList());
-
-        if (!noRefresh) {
-            toStop = new HashSet<Bundle>();
-            toStop.addAll(toRefresh);
-            removeFragmentsAndBundlesInState(toStop, Bundle.UNINSTALLED | Bundle.RESOLVED | Bundle.STOPPING);
-            if (!toStop.isEmpty()) {
-                print("Stopping bundles:", verbose);
-                while (!toStop.isEmpty()) {
-                    List<Bundle> bs = getBundlesToStop(toStop);
-                    for (Bundle bundle : bs) {
-                        print("  " + bundle.getSymbolicName() + " / " + bundle.getVersion(), verbose);
-                        bundle.stop(Bundle.STOP_TRANSIENT);
-                        toStop.remove(bundle);
-                        toStart.add(bundle);
-                    }
-                }
-            }
-
-            if (!toRefresh.isEmpty()) {
-                print("Refreshing bundles:", verbose);
-                for (Bundle bundle : toRefresh) {
-                    print("  " + bundle.getSymbolicName() + " / " + bundle.getVersion(), verbose);
-                }
-                if (!toRefresh.isEmpty()) {
-                    refreshPackages(toRefresh);
-                }
-            }
-        }
-
-        // Compute bundles to start
-        removeFragmentsAndBundlesInState(toStart, Bundle.UNINSTALLED | Bundle.ACTIVE | Bundle.STARTING);
-        if (!toStart.isEmpty()) {
-            // Compute correct start order
-            List<Exception> exceptions = new ArrayList<Exception>();
-            print("Starting bundles:", verbose);
-            while (!toStart.isEmpty()) {
-                List<Bundle> bs = getBundlesToStart(toStart);
-                for (Bundle bundle : bs) {
-                    LOGGER.info("  " + bundle.getSymbolicName() + " / " + bundle.getVersion());
-                    try {
-                        bundle.start();
-                    } catch (BundleException e) {
-                        exceptions.add(e);
-                    }
-                    toStart.remove(bundle);
-                }
-            }
-            if (!exceptions.isEmpty()) {
-                throw new MultiException("Error restarting bundles", exceptions);
-            }
-        }
-
-        // Call listeners
-        for (Feature feature : getFeatures(repositories, delFeatures)) {
-            callListeners(new FeatureEvent(feature, FeatureEvent.EventType.FeatureUninstalled, false));
-        }
-        for (Feature feature : getFeatures(repositories, newFeatures)) {
-            callListeners(new FeatureEvent(feature, FeatureEvent.EventType.FeatureInstalled, false));
-        }
-
-        print("Done.", verbose);
-    }
-
-    private void addTransitive(Resource resource, Set<Resource> resources, Map<Resource, List<Wire>> resolution) {
-        if (resources.add(resource)) {
-            for (Wire wire : resolution.get(resource)) {
-                addTransitive(wire.getProvider(), resources, resolution);
-            }
-        }
-    }
-
-    protected BundleInfo mergeBundleInfo(BundleInfo bi, BundleInfo oldBi) {
-        // TODO: we need a proper merge strategy when a bundle
-        // TODO: comes from different features
-        return bi;
-    }
-
-    private void print(String message, boolean verbose) {
-        LOGGER.info(message);
-        if (verbose) {
-            System.out.println(message);
-        }
-    }
-
-    private void removeFragmentsAndBundlesInState(Collection<Bundle> bundles, int state) {
-        for (Bundle bundle : new ArrayList<Bundle>(bundles)) {
-            if ((bundle.getState() & state) != 0
-                     || bundle.getHeaders().get(Constants.FRAGMENT_HOST) != null) {
-                bundles.remove(bundle);
-            }
-        }
-    }
-
-    protected void logDeployment(Deployment deployment, boolean verbose) {
-        print("Changes to perform:", verbose);
-        if (!deployment.toDelete.isEmpty()) {
-            print("  Bundles to uninstall:", verbose);
-            for (Bundle bundle : deployment.toDelete) {
-                print("    " + bundle.getSymbolicName() + " / " + bundle.getVersion(), verbose);
-            }
-        }
-        if (!deployment.toUpdate.isEmpty()) {
-            print("  Bundles to update:", verbose);
-            for (Map.Entry<Bundle, Resource> entry : deployment.toUpdate.entrySet()) {
-                print("    " + entry.getKey().getSymbolicName() + " / " + entry.getKey().getVersion() + " with " + UriNamespace.getUri(entry.getValue()), verbose);
-            }
-        }
-        if (!deployment.toInstall.isEmpty()) {
-            print("  Bundles to install:", verbose);
-            for (Resource resource : deployment.toInstall) {
-                print("    " + UriNamespace.getUri(resource), verbose);
-            }
-        }
-    }
-
-    protected Deployment computeDeployment(
-                                Set<Long> managed,
-                                Bundle[] bundles,
-                                Map<String, StreamProvider> providers,
-                                List<Resource> resources,
-                                Map<String, Long> bundleChecksums) throws IOException {
-        Deployment deployment = new Deployment();
-
-        // TODO: regions
-        List<Resource> toDeploy = new ArrayList<Resource>(resources);
-
-        // First pass: go through all installed bundles and mark them
-        // as either to ignore or delete
-        for (Bundle bundle : bundles) {
-            if (bundle.getSymbolicName() != null && bundle.getBundleId() != 0) {
-                Resource resource = null;
-                for (Resource res : toDeploy) {
-                    if (bundle.getSymbolicName().equals(getSymbolicName(res))) {
-                        if (bundle.getVersion().equals(getVersion(res))) {
-                            resource = res;
-                            break;
-                        }
-                    }
-                }
-                // We found a matching bundle
-                if (resource != null) {
-                    // In case of snapshots, check if the snapshot is out of date
-                    // and flag it as to update
-                    if (managed.contains(bundle.getBundleId()) && isUpdateable(resource)) {
-                        // Always update snapshots
-                        if (UPDATE_SNAPSHOTS_ALWAYS.equalsIgnoreCase(updateSnaphots)) {
-                            LOGGER.debug("Update snapshot for " + bundle.getLocation());
-                            deployment.toUpdate.put(bundle, resource);
-                        }
-                        else if (UPDATE_SNAPSHOTS_CRC.equalsIgnoreCase(updateSnaphots)) {
-                            // if the checksum are different
-                            InputStream is = null;
-                            try {
-                                is = getBundleInputStream(resource, providers);
-                                long newCrc = ChecksumUtils.checksum(is);
-                                long oldCrc = bundleChecksums.containsKey(bundle.getLocation()) ? bundleChecksums.get(bundle.getLocation()) : 0l;
-                                if (newCrc != oldCrc) {
-                                    LOGGER.debug("New snapshot available for " + bundle.getLocation());
-                                    deployment.toUpdate.put(bundle, resource);
-                                    deployment.newCheckums.put(bundle.getLocation(), newCrc);
-                                }
-                            } finally {
-                                if (is != null) {
-                                    is.close();
-                                }
-                            }
-                        }
-                    }
-                    // We're done for this resource
-                    toDeploy.remove(resource);
-                    deployment.resToBnd.put(resource, bundle);
-                // There's no matching resource
-                // If the bundle is managed, we need to delete it
-                } else if (managed.contains(bundle.getBundleId())) {
-                    deployment.toDelete.add(bundle);
-                }
-            }
-        }
-
-        // Second pass on remaining resources
-        for (Resource resource : toDeploy) {
-            TreeMap<Version, Bundle> matching = new TreeMap<Version, Bundle>();
-            VersionRange range = new VersionRange(Macro.transform(bundleUpdateRange, getVersion(resource).toString()));
-            for (Bundle bundle : deployment.toDelete) {
-                if (bundle.getSymbolicName().equals(getSymbolicName(resource)) && range.contains(bundle.getVersion())) {
-                    matching.put(bundle.getVersion(), bundle);
-                }
-            }
-            if (!matching.isEmpty()) {
-                Bundle bundle = matching.lastEntry().getValue();
-                deployment.toUpdate.put(bundle, resource);
-                deployment.toDelete.remove(bundle);
-                deployment.resToBnd.put(resource, bundle);
-            } else {
-                deployment.toInstall.add(resource);
-            }
-        }
-        return deployment;
-    }
-
-    protected List<Resource> getBundles(Collection<Resource> allResources) {
-        Map<String, Resource> deploy = new TreeMap<String, Resource>();
-        for (Resource res : allResources) {
-            String uri = UriNamespace.getUri(res);
-            if (uri != null) {
-                deploy.put(uri, res);
-            }
-        }
-        return new ArrayList<Resource>(deploy.values());
-    }
-
-    protected List<Feature> getFeatures(Repository[] repositories, List<String> featureIds) throws Exception {
-        List<Feature> installedFeatures = new ArrayList<Feature>();
-        for (Repository repository : repositories) {
-            for (Feature feature : repository.getFeatures()) {
-                String id = feature.getName() + "/" + VersionTable.getVersion(feature.getVersion());
-                if (featureIds.contains(id)) {
-                    installedFeatures.add(feature);
-                }
-            }
-        }
-        return installedFeatures;
-    }
-
-    protected List<String> getFeatureIds(Collection<Resource> allResources) {
-        List<String> installedFeatureIds = new ArrayList<String>();
-        for (Resource resource : allResources) {
-            String name = FeatureNamespace.getName(resource);
-            if (name != null) {
-                Version version = FeatureNamespace.getVersion(resource);
-                String id = version != null ? name + "/" + version : name;
-                installedFeatureIds.add(id);
-            }
-        }
-        return installedFeatureIds;
-    }
-
-    protected DeploymentBuilder createDeploymentBuilder(Repository[] repositories) {
-        return new DeploymentBuilder(new SimpleDownloader(), Arrays.asList(repositories));
-    }
-
-
-    protected boolean isUpdateable(Resource resource) {
-        return (getVersion(resource).getQualifier().endsWith(SNAPSHOT) ||
-                UriNamespace.getUri(resource).contains(SNAPSHOT) ||
-                !UriNamespace.getUri(resource).contains(MAVEN));
-    }
-
-    protected List<Bundle> getBundlesToStart(Collection<Bundle> bundles) {
-        // TODO: make this pluggable ?
-        // TODO: honor respectStartLvlDuringFeatureStartup
-
-        // We hit FELIX-2949 if we don't use the correct order as Felix resolver isn't greedy.
-        // In order to minimize that, we make sure we resolve the bundles in the order they
-        // are given back by the resolution, meaning that all root bundles (i.e. those that were
-        // not flagged as dependencies in features) are started before the others.   This should
-        // make sure those important bundles are started first and minimize the problem.
-
-        // Restart the features service last, regardless of any other consideration
-        // so that we don't end up with the service trying to do stuff before we're done
-        boolean restart = bundles.remove(bundle);
-
-        List<BundleRevision> revs = new ArrayList<BundleRevision>();
-        for (Bundle bundle : bundles) {
-            revs.add(bundle.adapt(BundleRevision.class));
-        }
-        List<Bundle> sorted = new ArrayList<Bundle>();
-        for (BundleRevision rev : RequirementSort.sort(revs)) {
-            sorted.add(rev.getBundle());
-        }
-        if (restart) {
-            sorted.add(bundle);
-        }
-        return sorted;
-    }
-
-    protected List<Bundle> getBundlesToStop(Collection<Bundle> bundles) {
-        // TODO: make this pluggable ?
-        // TODO: honor respectStartLvlDuringFeatureUninstall
-
-        List<Bundle> bundlesToDestroy = new ArrayList<Bundle>();
-        for (Bundle bundle : bundles) {
-            ServiceReference[] references = bundle.getRegisteredServices();
-            int usage = 0;
-            if (references != null) {
-                for (ServiceReference reference : references) {
-                    usage += getServiceUsage(reference, bundles);
-                }
-            }
-            LOGGER.debug("Usage for bundle {} is {}", bundle, usage);
-            if (usage == 0) {
-                bundlesToDestroy.add(bundle);
-            }
-        }
-        if (!bundlesToDestroy.isEmpty()) {
-            Collections.sort(bundlesToDestroy, new Comparator<Bundle>() {
-                public int compare(Bundle b1, Bundle b2) {
-                    return (int) (b2.getLastModified() - b1.getLastModified());
-                }
-            });
-            LOGGER.debug("Selected bundles {} for destroy (no services in use)", bundlesToDestroy);
-        } else {
-            ServiceReference ref = null;
-            for (Bundle bundle : bundles) {
-                ServiceReference[] references = bundle.getRegisteredServices();
-                for (ServiceReference reference : references) {
-                    if (getServiceUsage(reference, bundles) == 0) {
-                        continue;
-                    }
-                    if (ref == null || reference.compareTo(ref) < 0) {
-                        LOGGER.debug("Currently selecting bundle {} for destroy (with reference {})", bundle, reference);
-                        ref = reference;
-                    }
-                }
-            }
-            if (ref != null) {
-                bundlesToDestroy.add(ref.getBundle());
-            }
-            LOGGER.debug("Selected bundle {} for destroy (lowest ranking service)", bundlesToDestroy);
-        }
-        return bundlesToDestroy;
-    }
-
-    private static int getServiceUsage(ServiceReference ref, Collection<Bundle> bundles) {
-        Bundle[] usingBundles = ref.getUsingBundles();
-        int nb = 0;
-        if (usingBundles != null) {
-            for (Bundle bundle : usingBundles) {
-                if (bundles.contains(bundle)) {
-                    nb++;
-                }
-            }
-        }
-        return nb;
-    }
-
-    protected InputStream getBundleInputStream(Resource resource, Map<String, StreamProvider> providers) throws IOException {
-        String uri = UriNamespace.getUri(resource);
-        if (uri == null) {
-            throw new IllegalStateException("Resource has no uri");
-        }
-        StreamProvider provider = providers.get(uri);
-        if (provider == null) {
-            throw new IllegalStateException("Resource " + uri + " has no StreamProvider");
-        }
-        return provider.open();
-    }
-
-    protected void refreshPackages(Collection<Bundle> bundles) throws InterruptedException {
-        final CountDownLatch latch = new CountDownLatch(1);
-        FrameworkWiring fw = systemBundleContext.getBundle().adapt(FrameworkWiring.class);
-        fw.refreshBundles(bundles, new FrameworkListener() {
-            @Override
-            public void frameworkEvent(FrameworkEvent event) {
-                if (event.getType() == FrameworkEvent.ERROR) {
-                    LOGGER.error("Framework error", event.getThrowable());
-                }
-                latch.countDown();
-            }
-        });
-        latch.await();
-    }
-
-
-    static class Deployment {
-        Map<String, Long> newCheckums = new HashMap<String, Long>();
-        Map<Resource, Bundle> resToBnd = new HashMap<Resource, Bundle>();
-        List<Resource> toInstall = new ArrayList<Resource>();
-        List<Bundle> toDelete = new ArrayList<Bundle>();
-        Map<Bundle, Resource> toUpdate = new HashMap<Bundle, Resource>();
-    }
-
-}


[02/33] [KARAF-2852] Merge jdbc/core and jdbc/command

Posted by gn...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-generic.xml
----------------------------------------------------------------------
diff --git a/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-generic.xml b/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-generic.xml
deleted file mode 100644
index 090daee..0000000
--- a/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-generic.xml
+++ /dev/null
@@ -1,141 +0,0 @@
-<?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.
-    -->
-<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
-
-    <bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
-        <property name="driverClassName" value="${driver}"/>
-        <property name="url" value="${url}"/>
-        <property name="user" value="${user}"/>
-        <property name="password" value="${password}"/>
-        <property name="maxIdle" value="1"/>
-    </bean>
-
-    <bean id="connectionFactory" class="org.apache.commons.dbcp.DataSourceConnectionFactory">
-        <argument ref="dataSource" />
-    </bean>
-
-    <bean id="connectionPool" class="org.apache.commons.pool.impl.GenericObjectPool" >
-        <!-- No default factory -->
-        <argument><null/></argument> <!-- factory -->
-        <!--
-            controls the maximum number of objects that can be allocated by the pool (checked out to clients, or
-            idle awaiting checkout) at a given time. When non-positive, there is no limit to the number of objects that can
-            be managed by the pool at one time. When maxActive is reached, the pool is said to be exhausted.
-            The default setting for this parameter is 8.
-         -->
-        <argument value="8" /> <!-- maxActive -->
-        <!--
-            specifies the behavior of the borrowObject() method when the pool is exhausted:
-
-            When whenExhaustedAction is WHEN_EXHAUSTED_FAIL, borrowObject() will throw a NoSuchElementException
-            When whenExhaustedAction is WHEN_EXHAUSTED_GROW, borrowObject() will create a new object and return it
-            (essentially making maxActive meaningless.)
-            When whenExhaustedAction is WHEN_EXHAUSTED_BLOCK, borrowObject() will block (invoke Object.wait()) until
-            a new or idle object is available. If a positive maxWait value is supplied, then borrowObject() will block for at most that many milliseconds, after which a NoSuchElementException will be thrown. If maxWait is non-positive, the borrowObject() method will block indefinitely.
-
-            The default whenExhaustedAction setting is WHEN_EXHAUSTED_BLOCK and the default maxWait setting is -1.
-            By default, therefore, borrowObject will block indefinitely until an idle instance becomes available.
-        -->
-        <argument value="WHEN_EXHAUSTED_BLOCK" /> <!-- whenExhaustedAction -->
-        <!--
-            the maximum amount of time to wait for an idle object when the pool is exhausted and whenExhaustedAction
-            is WHEN_EXHAUSTED_BLOCK (otherwise ignored)
-        -->
-        <argument value="-1" /> <!-- maxWait -->
-        <!--
-            controls the maximum number of objects that can sit idle in the pool at any time.
-            When negative, there is no limit to the number of objects that may be idle at one time.
-            The default setting for this parameter is 8.
-        -->
-        <argument value="8" /> <!-- maxIdle -->
-        <!--
-           sets the minimum number of objects allowed in the pool before the evictor thread (if active) spawns
-           new objects.
-        -->
-        <argument value="0" /> <!-- minIdle -->
-        <!--
-            when true, objects will be validated before being returned by the borrowObject() method.
-        -->
-        <argument value="false" /> <!-- testOnBorrow -->
-        <!--
-            when true, objects will be validated before being returned to the pool within the returnObject(T).
-        -->
-        <argument value="false" /> <!-- testOnReturn -->
-        <!--
-            sets the number of milliseconds to sleep between runs of the idle object evictor thread.
-        -->
-        <argument value="-1" /> <!-- timeBetweenEvictionRunsMillis -->
-        <!--
-            the number of idle objects to examine per run within the idle object eviction thread (if any)
-        -->
-        <argument value="3" /> <!-- numTestsPerEvictionRun -->
-        <!--
-            sets the minimum amount of time an object may sit idle in the pool before it is eligible for eviction by
-            the idle object evictor (if any). When non-positive, no objects will be evicted from the pool due to idle
-            time alone.
-        -->
-        <argument value="1800000" /> <!-- minEvictableIdleTimeMillis -->
-        <!--
-            when true, objects will be validated by the idle object evictor (if any). If an object fails to validate,
-            it will be dropped from the pool.
-        -->
-        <argument value="false" /> <!-- testWhileIdle -->
-        <!--
-            softMinEvictableIdleTimeMillis specifies the minimum amount of time an object may sit idle in the pool before
-            it is eligible for eviction by the idle object evictor (if any), with the extra condition that at least "minIdle"
-            object instances remain in the pool. When non-positive, no objects will be evicted from the pool due to idle time alone.
-            This setting has no effect unless timeBetweenEvictionRunsMillis > 0. and it is superceded by
-            minEvictableIdleTimeMillis (that is, if minEvictableIdleTimeMillis is positive, then
-            softMinEvictableIdleTimeMillis is ignored). The default setting for this parameter is -1 (disabled).
-        -->
-        <argument value="-1" /> <!-- softMinEvictableIdleTimeMillis -->
-        <!--
-            lifo determines whether or not the pool returns idle objects in last-in-first-out order. The default setting for this parameter is true.
-        -->
-        <argument value="true" /> <!-- lifo -->
-    </bean>
-
-    <bean id="pooledConnectionFactory" class="org.apache.commons.dbcp.PoolableConnectionFactory" >
-        <argument ref="connectionFactory" />
-        <argument ref="connectionPool" />
-        <argument><null/></argument>
-        <!--
-            a query to use to validate Connections. Should return at least one row. Using null turns off validation.
-        -->
-        <argument><null/></argument> <!-- validationQuery -->
-        <!--
-            the default "read only" setting for borrowed connections
-        -->
-        <argument value="false" /> <!-- defaultReadOnly -->
-        <!--
-            the default "auto commit" setting for returned connections
-        -->
-        <argument value="true" /> <!-- defaultAutoCommit -->
-    </bean>
-
-    <bean id="pooledDataSource" class="org.apache.commons.dbcp.PoolingDataSource" depends-on="pooledConnectionFactory">
-        <argument ref="connectionPool" />
-    </bean>
-
-    <service ref="pooledDataSource" interface="javax.sql.DataSource">
-        <service-properties>
-            <entry key="osgi.jndi.service.name" value="jdbc/${name}"/>
-        </service-properties>
-    </service>
-
-</blueprint>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-h2.xml
----------------------------------------------------------------------
diff --git a/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-h2.xml b/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-h2.xml
deleted file mode 100644
index 19805f4..0000000
--- a/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-h2.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?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.
-    -->
-<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
-
-    <bean id="dataSource" class="org.h2.jdbcx.JdbcDataSource">
-        <property name="URL" value="${url}"/>
-        <property name="user" value="${user}"/>
-        <property name="password" value="${password}"/>
-    </bean>
-
-    <service interface="javax.sql.DataSource" ref="dataSource">
-        <service-properties>
-            <entry key="osgi.jndi.service.name" value="jdbc/${name}"/>
-        </service-properties>
-    </service>
-</blueprint>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-hsql.xml
----------------------------------------------------------------------
diff --git a/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-hsql.xml b/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-hsql.xml
deleted file mode 100644
index 3ea9ba8..0000000
--- a/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-hsql.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?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.
-    -->
-<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
-
-    <bean id="dataSource" class="org.hsqldb.jdbc.JDBCDataSource">
-        <property name="url" value="${url}"/>
-        <property name="user" value="${user}"/>
-        <property name="password" value="${password}"/>
-    </bean>
-
-    <service interface="javax.sql.DataSource" ref="dataSource">
-        <service-properties>
-            <entry key="osgi.jndi.service.name" value="jdbc/${name}"/>
-        </service-properties>
-    </service>
-</blueprint>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-mssql.xml
----------------------------------------------------------------------
diff --git a/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-mssql.xml b/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-mssql.xml
deleted file mode 100644
index 35e6ed9..0000000
--- a/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-mssql.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?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.
-    -->
-<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
-
-    <bean id="dataSource" class="net.sourceforge.jtds.jdbcx.JtdsDataSource">
-        <property name="serverName" value="${url}"/>
-        <property name="databaseName" value="${name}"/>
-        <property name="user" value="${user}"/>
-        <property name="password" value="${password}"/>
-    </bean>
-
-    <service interface="javax.sql.DataSource" ref="dataSource">
-        <service-properties>
-            <entry key="osgi.jndi.service.name" value="jdbc/${name}"/>
-        </service-properties>
-    </service>
-</blueprint>

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-mysql.xml
----------------------------------------------------------------------
diff --git a/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-mysql.xml b/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-mysql.xml
deleted file mode 100644
index 012ecaf..0000000
--- a/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-mysql.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?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.
-    -->
-<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
-
-    <bean id="dataSource" class="com.mysql.jdbc.jdbc2.optional.MysqlDataSource">
-        <property name="url" value="${url}"/>
-        <property name="user" value="${user}"/>
-        <property name="password" value="${password}"/>
-    </bean>
-
-    <service interface="javax.sql.DataSource" ref="dataSource">
-        <service-properties>
-            <entry key="osgi.jndi.service.name" value="jdbc/${name}"/>
-        </service-properties>
-    </service>
-</blueprint>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-oracle.xml
----------------------------------------------------------------------
diff --git a/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-oracle.xml b/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-oracle.xml
deleted file mode 100644
index 8168b16..0000000
--- a/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-oracle.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?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.
-    -->
-<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
-
-    <bean id="dataSource" class="oracle.jdbc.pool.OracleDataSource">
-        <property name="URL" value="${url}"/>
-        <property name="user" value="${user}"/>
-        <property name="password" value="${password}"/>
-    </bean>
-
-    <service interface="javax.sql.DataSource" ref="dataSource">
-        <service-properties>
-            <entry key="osgi.jndi.service.name" value="jdbc/${name}"/>
-        </service-properties>
-    </service>
-</blueprint>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-postgres.xml
----------------------------------------------------------------------
diff --git a/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-postgres.xml b/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-postgres.xml
deleted file mode 100644
index 1845c48..0000000
--- a/jdbc/core/src/main/resources/org/apache/karaf/jdbc/internal/datasource-postgres.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?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.
-    -->
-<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
-
-    <bean id="dataSource" class="org.postgresql.ds.PGPoolingDataSource" destroy-method="close">
-        <property name="serverName" value="${url}"/>
-        <property name="user" value="${user}"/>
-        <property name="password" value="${password}"/>
-        <property name="dataSourceName" value="${name}"/>
-        <property name="initialConnections" value="2"/>
-        <property name="maxConnections" value="4" />
-    </bean>
-
-    <service interface="javax.sql.DataSource" ref="dataSource">
-        <service-properties>
-            <entry key="osgi.jndi.service.name" value="jdbc/${name}"/>
-        </service-properties>
-    </service>
-</blueprint>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/pom.xml
----------------------------------------------------------------------
diff --git a/jdbc/pom.xml b/jdbc/pom.xml
index 631dc54..a6dce66 100644
--- a/jdbc/pom.xml
+++ b/jdbc/pom.xml
@@ -29,13 +29,68 @@
     </parent>
 
     <groupId>org.apache.karaf.jdbc</groupId>
-    <artifactId>jdbc</artifactId>
-    <packaging>pom</packaging>
-    <name>Apache Karaf :: JDBC</name>
-
-    <modules>
-        <module>core</module>
-        <module>command</module>
-    </modules>
+    <artifactId>org.apache.karaf.jdbc.core</artifactId>
+    <packaging>bundle</packaging>
+    <name>Apache Karaf :: JDBC :: Core</name>
+    <description>This bundle provides core implementation of the JDBC service.</description>
+
+    <properties>
+        <appendedResourcesDirectory>${basedir}/../../etc/appended-resources</appendedResourcesDirectory>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.karaf</groupId>
+            <artifactId>org.apache.karaf.util</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.karaf.shell</groupId>
+            <artifactId>org.apache.karaf.shell.core</artifactId>
+            <optional>true</optional>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <resources>
+            <resource>
+                <directory>${project.basedir}/src/main/resources</directory>
+                <includes>
+                    <include>**/*</include>
+                </includes>
+            </resource>
+            <resource>
+                <directory>${project.basedir}/src/main/resources</directory>
+                <filtering>true</filtering>
+                <includes>
+                    <include>**/*.info</include>
+                </includes>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Export-Package>
+                            org.apache.karaf.jdbc
+                        </Export-Package>
+                        <Private-Package>
+                            org.apache.karaf.jdbc.command,
+                            org.apache.karaf.jdbc.command.completers,
+                            org.apache.karaf.jdbc.internal,
+                            org.apache.karaf.util
+                        </Private-Package>
+                        <Karaf-Commands>*</Karaf-Commands>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
 
 </project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/src/main/java/org/apache/karaf/jdbc/JdbcMBean.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/karaf/jdbc/JdbcMBean.java b/jdbc/src/main/java/org/apache/karaf/jdbc/JdbcMBean.java
new file mode 100644
index 0000000..26165c8
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/karaf/jdbc/JdbcMBean.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.karaf.jdbc;
+
+import javax.management.MBeanException;
+import javax.management.openmbean.TabularData;
+import java.util.Map;
+
+/**
+ * JDBC MBean
+ */
+public interface JdbcMBean {
+
+    /**
+     * Get the list of JDBC datasources.
+     *
+     * @return a tabular data containing the list of JDBC datasources.
+     * @throws MBeanException
+     */
+    TabularData getDatasources() throws MBeanException;
+
+    /**
+     * Create a JDBC datasource.
+     *
+     * @param name the JDBC datasource name.
+     * @param type the JDBC datasource type (generic, MySQL, Oracle, Postgres, H2, HSQL, Derby, MSSQL).
+     * @param driver the JDBC datasource driver class name (can be null).
+     * @param version the target JDBC driver version (can be null).
+     * @param url the JDBC URL.
+     * @param user the database username.
+     * @param password the database password.
+     * @param installBundles true to install the bundles providing the JDBC driver, false to not install.
+     * @throws MBeanException
+     */
+    void create(String name, String type, String driver, String version, String url, String user, String password, boolean installBundles) throws MBeanException;
+
+    /**
+     * Delete a JDBC datasource.
+     *
+     * @param name the JDBC datasource name (the one used at creation time).
+     * @throws MBeanException
+     */
+    void delete(String name) throws MBeanException;
+
+    /**
+     * Get details about a JDBC datasource.
+     *
+     * @param datasource the JDBC datasource name.
+     * @return a map (property/value) containing JDBC datasource details.
+     * @throws MBeanException
+     */
+    Map<String, String> info(String datasource) throws MBeanException;
+
+    /**
+     * Get the tables available on a JDBC datasource.
+     *
+     * @param datasource the JDBC datasource name.
+     * @return a tabular data containg datasource tables.
+     * @throws MBeanException
+     */
+    TabularData tables(String datasource) throws MBeanException;
+
+    /**
+     * Execute a SQL command on a JDBC datasource.
+     *
+     * @param datasource the JDBC datasource name.
+     * @param command the SQL command to execute.
+     * @throws MBeanException
+     */
+    void execute(String datasource, String command) throws MBeanException;
+
+    /**
+     * Execute a SQL query on a JDBC datasource.
+     *
+     * @param datasource the JDBC datasource name.
+     * @param query the SQL query to execute.
+     * @return a tabular data with the result of execute (columns/values).
+     * @throws MBeanException
+     */
+    TabularData query(String datasource, String query) throws MBeanException;
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/src/main/java/org/apache/karaf/jdbc/JdbcService.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/karaf/jdbc/JdbcService.java b/jdbc/src/main/java/org/apache/karaf/jdbc/JdbcService.java
new file mode 100644
index 0000000..d883a07
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/karaf/jdbc/JdbcService.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.jdbc;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * JDBC Service.
+ */
+public interface JdbcService {
+
+    /**
+     * Create a JDBC datasource (using a default template).
+     *
+     * @param name the JDBC datasource name.
+     * @param type the backend database type (generic, Oracle, MySQL, ...)
+     * @param driverClassName the JDBC driver classname.
+     * @param version the JDBC driver version to use.
+     * @param url the JDBC URL.
+     * @param user the database user name.
+     * @param password the database password.
+     * @param tryToInstallBundles true to try to automatically install the required bundles (JDBC driver, etc) when possible, false else.
+     */
+    void create(String name, String type, String driverClassName, String version, String url, String user, String password, boolean tryToInstallBundles) throws Exception;
+
+    /**
+     * Delete a JDBC datasource identified by a name.
+     *
+     * @param name the JDBC datasource name.
+     */
+    void delete(String name) throws Exception;
+
+    /**
+     * List the JDBC datasources available.
+     *
+     * @return a list of datasources name.
+     */
+    List<String> datasources() throws Exception;
+
+    /**
+     * List the JDBC datasources configuration file names present in the deploy folder.
+     *
+     * @return a list of the JDBC datasources configuration file names.
+     */
+    List<String> datasourceFileNames() throws Exception;
+
+    /**
+     * Execute a SQL query on a given JDBC datasource.
+     *
+     * @param datasource the JDBC datasource name.
+     * @param query the SQL query to execute.
+     * @return the SQL query result (as a String).
+     */
+    Map<String, List<String>> query(String datasource, String query) throws Exception;
+
+    /**
+     * Execute a SQL command on a given JDBC datasource.
+     *
+     * @param datasource the JDBC datasource name.
+     * @param command the SQL command to execute.
+     */
+    void execute(String datasource, String command) throws Exception;
+
+    /**
+     * List the tables available on a given JDBC datasource.
+     *
+     * @param datasource the JDBC datasource name.
+     * @return the list of table names.
+     */
+    Map<String, List<String>> tables(String datasource) throws Exception;
+
+    /**
+     * Get detailed info about a JDBC datasource.
+     *
+     * @param datasource the JDBC datasource name.
+     * @return a map of info (name/value).
+     */
+    Map<String, String> info(String datasource) throws Exception;
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/src/main/java/org/apache/karaf/jdbc/command/CreateCommand.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/karaf/jdbc/command/CreateCommand.java b/jdbc/src/main/java/org/apache/karaf/jdbc/command/CreateCommand.java
new file mode 100644
index 0000000..89ed49c
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/karaf/jdbc/command/CreateCommand.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.karaf.jdbc.command;
+
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.completers.StringsCompleter;
+
+@Command(scope = "jdbc", name = "create", description = "Create a JDBC datasource")
+@Service
+public class CreateCommand extends JdbcCommandSupport {
+
+    @Argument(index = 0, name = "name", description = "The JDBC datasource name", required = true, multiValued = false)
+    String name;
+
+    @Option(name = "-t", aliases = { "--type" }, description = "The JDBC datasource type (generic, MySQL, Oracle, Postgres, H2, HSQL, Derby, MSSQL)", required = false, multiValued = false)
+    @Completion(value = StringsCompleter.class, values = { "db2", "derby", "generic", "h2", "hsql", "mysql", "oracle", "postgres", "mssql" })
+    String type;
+
+    @Option(name = "-d", aliases = { "--driver" }, description = "The classname of the JDBC driver to use. NB: this option is used only the type generic", required = false, multiValued = false)
+    String driver;
+
+    @Option(name = "-v", aliases = { "--version" }, description = "The version of the driver to use", required = false, multiValued = false)
+    String version;
+
+    @Option(name = "-url", description = "The JDBC URL to use", required = false, multiValued = false)
+    String url;
+
+    @Option(name = "-u", aliases = { "--username" }, description = "The database username", required = false, multiValued = false)
+    String username;
+
+    @Option(name = "-p", aliases = { "--password" }, description = "The database password", required = false, multiValued = false)
+    String password;
+
+    @Option(name = "-i", aliases = { "--install-bundles" }, description = "Try to install the bundles providing the JDBC driver", required = false, multiValued = false)
+    boolean installBundles = false;
+
+    @Override
+    public Object execute() throws Exception {
+        this.getJdbcService().create(name, type, driver, version, url, username, password, installBundles);
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/src/main/java/org/apache/karaf/jdbc/command/DataSourcesCommand.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/karaf/jdbc/command/DataSourcesCommand.java b/jdbc/src/main/java/org/apache/karaf/jdbc/command/DataSourcesCommand.java
new file mode 100644
index 0000000..cb3edad
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/karaf/jdbc/command/DataSourcesCommand.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.karaf.jdbc.command;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.table.ShellTable;
+
+@Command(scope = "jdbc", name = "datasources", description = "List the JDBC datasources")
+@Service
+public class DataSourcesCommand extends JdbcCommandSupport {
+
+    @Override
+    public Object execute() throws Exception {
+        ShellTable table = new ShellTable();
+
+        table.column("Name");
+        table.column("Product");
+        table.column("Version");
+        table.column("URL");
+
+        List<String> datasources = this.getJdbcService().datasources();
+        for (String datasource : datasources) {
+            Map<String, String> info = this.getJdbcService().info(datasource);
+            table.addRow().addContent(datasource, info.get("db.product"), info.get("db.version"), info.get("url"));
+        }
+
+        table.print(System.out);
+
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/src/main/java/org/apache/karaf/jdbc/command/DeleteCommand.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/karaf/jdbc/command/DeleteCommand.java b/jdbc/src/main/java/org/apache/karaf/jdbc/command/DeleteCommand.java
new file mode 100644
index 0000000..6bf7236
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/karaf/jdbc/command/DeleteCommand.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.karaf.jdbc.command;
+
+import org.apache.karaf.jdbc.command.completers.DataSourcesFileNameCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "jdbc", name = "delete", description = "Delete a JDBC datasource")
+@Service
+public class DeleteCommand extends JdbcCommandSupport {
+
+    @Argument(index = 0, name = "name", description = "The JDBC datasource name (the one used at creation time)", required = true, multiValued = false)
+    @Completion(DataSourcesFileNameCompleter.class)
+    String name;
+
+    @Override
+    public Object execute() throws Exception {
+        this.getJdbcService().delete(name);
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/src/main/java/org/apache/karaf/jdbc/command/ExecuteCommand.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/karaf/jdbc/command/ExecuteCommand.java b/jdbc/src/main/java/org/apache/karaf/jdbc/command/ExecuteCommand.java
new file mode 100644
index 0000000..480ab51
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/karaf/jdbc/command/ExecuteCommand.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.karaf.jdbc.command;
+
+import org.apache.karaf.jdbc.command.completers.DataSourcesNameCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "jdbc", name = "execute", description = "Execute a SQL command on a given JDBC datasource")
+@Service
+public class ExecuteCommand extends JdbcCommandSupport {
+
+    @Argument(index = 0, name = "datasource", description = "The JDBC datasource", required = true, multiValued = false)
+    @Completion(DataSourcesNameCompleter.class)
+    String datasource;
+
+    @Argument(index = 1, name = "command", description = "The SQL command to execute", required = true, multiValued = false)
+    String command;
+
+    @Override
+    public Object execute() throws Exception {
+        this.getJdbcService().execute(datasource, command);
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/src/main/java/org/apache/karaf/jdbc/command/InfoCommand.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/karaf/jdbc/command/InfoCommand.java b/jdbc/src/main/java/org/apache/karaf/jdbc/command/InfoCommand.java
new file mode 100644
index 0000000..e53bbab
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/karaf/jdbc/command/InfoCommand.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.jdbc.command;
+
+import org.apache.karaf.jdbc.command.completers.DataSourcesNameCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.table.ShellTable;
+
+import java.util.Map;
+
+@Command(scope = "jdbc", name = "info", description = "Display details about a JDBC datasource")
+@Service
+public class InfoCommand extends JdbcCommandSupport {
+
+    @Argument(index = 0, name = "datasource", description = "The JDBC datasource name", required = true, multiValued = false)
+    @Completion(DataSourcesNameCompleter.class)
+    String datasource;
+
+    @Override
+    public Object execute() throws Exception {
+        ShellTable table = new ShellTable();
+
+        table.column("Property");
+        table.column("Value");
+
+        Map<String, String> info = this.getJdbcService().info(datasource);
+        for (String property : info.keySet()) {
+            table.addRow().addContent(property, info.get(property));
+        }
+
+        table.print(System.out);
+
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/src/main/java/org/apache/karaf/jdbc/command/JdbcCommandSupport.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/karaf/jdbc/command/JdbcCommandSupport.java b/jdbc/src/main/java/org/apache/karaf/jdbc/command/JdbcCommandSupport.java
new file mode 100644
index 0000000..cf1eb58
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/karaf/jdbc/command/JdbcCommandSupport.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.karaf.jdbc.command;
+
+import org.apache.karaf.jdbc.JdbcService;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+
+public abstract class JdbcCommandSupport implements Action {
+
+    @Reference
+    private JdbcService jdbcService;
+
+    public JdbcService getJdbcService() {
+        return jdbcService;
+    }
+
+    public void setJdbcService(JdbcService jdbcService) {
+        this.jdbcService = jdbcService;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/src/main/java/org/apache/karaf/jdbc/command/QueryCommand.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/karaf/jdbc/command/QueryCommand.java b/jdbc/src/main/java/org/apache/karaf/jdbc/command/QueryCommand.java
new file mode 100644
index 0000000..297288b
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/karaf/jdbc/command/QueryCommand.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.karaf.jdbc.command;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.karaf.jdbc.command.completers.DataSourcesNameCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.table.Row;
+import org.apache.karaf.shell.support.table.ShellTable;
+
+@Command(scope = "jdbc", name = "query", description = "Execute a SQL query on a JDBC datasource")
+@Service
+public class QueryCommand extends JdbcCommandSupport {
+
+    @Argument(index = 0, name = "datasource", description = "The JDBC datasource to use", required = true, multiValued = false)
+    @Completion(DataSourcesNameCompleter.class)
+    String datasource;
+
+    @Argument(index = 1, name = "query", description = "The SQL query to execute", required = true, multiValued = false)
+    String query;
+
+    @Override
+    public Object execute() throws Exception {
+        ShellTable table = new ShellTable();
+
+        Map<String, List<String>> map = this.getJdbcService().query(datasource, query);
+        int rowCount = 0;
+        for (String column : map.keySet()) {
+            table.column(column);
+            rowCount = map.get(column).size();
+        }
+
+        for (int i = 0; i < rowCount; i++) {
+            Row row = table.addRow();
+            for (String column : map.keySet()) {
+                row.addContent(map.get(column).get(i));
+            }
+        }
+
+        table.print(System.out);
+
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/src/main/java/org/apache/karaf/jdbc/command/TablesCommand.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/karaf/jdbc/command/TablesCommand.java b/jdbc/src/main/java/org/apache/karaf/jdbc/command/TablesCommand.java
new file mode 100644
index 0000000..04baa70
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/karaf/jdbc/command/TablesCommand.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.karaf.jdbc.command;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.karaf.jdbc.command.completers.DataSourcesNameCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.table.Row;
+import org.apache.karaf.shell.support.table.ShellTable;
+
+@Command(scope = "jdbc", name = "tables", description = "List the tables on a given JDBC datasource")
+@Service
+public class TablesCommand extends JdbcCommandSupport {
+
+    @Argument(index = 0, name = "datasource", description = "The JDBC datasource to use", required = true, multiValued = false)
+    @Completion(DataSourcesNameCompleter.class)
+    String datasource;
+
+    @Override
+    public Object execute() throws Exception {
+        ShellTable table = new ShellTable();
+
+        Map<String, List<String>> map = this.getJdbcService().tables(datasource);
+        int rowCount = 0;
+        for (String column : map.keySet()) {
+            table.column(column);
+            rowCount = map.get(column).size();
+        }
+
+        for (int i = 0; i < rowCount; i++) {
+            Row row = table.addRow();
+            for (String column : map.keySet()) {
+                row.addContent(map.get(column).get(i));
+            }
+        }
+
+        table.print(System.out);
+
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/src/main/java/org/apache/karaf/jdbc/command/completers/DataSourcesFileNameCompleter.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/karaf/jdbc/command/completers/DataSourcesFileNameCompleter.java b/jdbc/src/main/java/org/apache/karaf/jdbc/command/completers/DataSourcesFileNameCompleter.java
new file mode 100644
index 0000000..8ba0fe9
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/karaf/jdbc/command/completers/DataSourcesFileNameCompleter.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.karaf.jdbc.command.completers;
+
+import org.apache.karaf.jdbc.JdbcService;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.completers.StringsCompleter;
+
+import java.util.List;
+
+/**
+ * Completer on the JDBC datasources file name.
+ */
+@Service
+public class DataSourcesFileNameCompleter implements Completer {
+
+    @Reference
+    private JdbcService jdbcService;
+
+    @Override
+    public int complete(Session session, CommandLine commandLine, List<String> candidates) {
+        StringsCompleter delegate = new StringsCompleter();
+        try {
+            for (String datasourceFileName : jdbcService.datasourceFileNames()) {
+                delegate.getStrings().add(datasourceFileName.replace("datasource-", "").replace(".xml", ""));
+            }
+        } catch (Exception e) {
+            // nothing to do
+        }
+        return delegate.complete(session, commandLine, candidates);
+    }
+
+    public JdbcService getJdbcService() {
+        return jdbcService;
+    }
+
+    public void setJdbcService(JdbcService jdbcService) {
+        this.jdbcService = jdbcService;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/src/main/java/org/apache/karaf/jdbc/command/completers/DataSourcesNameCompleter.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/karaf/jdbc/command/completers/DataSourcesNameCompleter.java b/jdbc/src/main/java/org/apache/karaf/jdbc/command/completers/DataSourcesNameCompleter.java
new file mode 100644
index 0000000..238910f
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/karaf/jdbc/command/completers/DataSourcesNameCompleter.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.karaf.jdbc.command.completers;
+
+import org.apache.karaf.jdbc.JdbcService;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.completers.StringsCompleter;
+
+import java.util.List;
+
+/**
+ * Completer on the JDBC datasources name (JNDI or OSGi service property).
+ */
+@Service
+public class DataSourcesNameCompleter implements Completer {
+
+    @Reference
+    private JdbcService jdbcService;
+
+    @Override
+    public int complete(Session session, CommandLine commandLine, List<String> candidates) {
+        StringsCompleter delegate = new StringsCompleter();
+        try {
+            for (String datasource : jdbcService.datasources()) {
+                delegate.getStrings().add(datasource);
+            }
+        } catch (Exception e) {
+            // nothing to do
+        }
+        return delegate.complete(session, commandLine, candidates);
+    }
+
+    public JdbcService getJdbcService() {
+        return jdbcService;
+    }
+
+    public void setJdbcService(JdbcService jdbcService) {
+        this.jdbcService = jdbcService;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/src/main/java/org/apache/karaf/jdbc/internal/JdbcConnector.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/karaf/jdbc/internal/JdbcConnector.java b/jdbc/src/main/java/org/apache/karaf/jdbc/internal/JdbcConnector.java
new file mode 100644
index 0000000..11c7ca4
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/karaf/jdbc/internal/JdbcConnector.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.karaf.jdbc.internal;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.sql.*;
+import java.util.Deque;
+import java.util.LinkedList;
+
+import javax.sql.DataSource;
+import javax.sql.XAConnection;
+import javax.sql.XADataSource;
+
+import org.apache.karaf.util.StreamUtils;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+public class JdbcConnector implements Closeable {
+    private BundleContext bundleContext;
+    private String datasourceName;
+    private Connection connection;
+    private Deque<Closeable> resources;
+    private ServiceReference<?> reference;
+
+    public JdbcConnector(BundleContext bundleContext, String datasourceName) {
+        this.bundleContext = bundleContext;
+        this.datasourceName = datasourceName;
+        this.resources = new LinkedList<Closeable>();
+    }
+    
+    public Connection connect() throws SQLException {
+        reference = lookupDataSource(datasourceName);
+        Object datasource = bundleContext.getService(reference);
+        if (datasource instanceof DataSource) {
+            connection = ((DataSource) datasource).getConnection();
+        }
+        if (datasource instanceof XADataSource) {
+            connection = ((XADataSource) datasource).getXAConnection().getConnection();
+        }
+        return connection;
+    }
+    
+    public Statement createStatement() throws SQLException {
+        if (connection == null) {
+            connect();
+        }
+        if (connection instanceof Connection) {
+            return register(((Connection) connection).createStatement());
+        }
+        if (connection instanceof XAConnection) {
+            return register(((XAConnection) connection).getConnection().createStatement());
+        }
+        return null;
+    }
+
+    public Connection register(final Connection connection) {
+        resources.addFirst(new Closeable() {
+            
+            @Override
+            public void close() throws IOException {
+                try {
+                    connection.close();
+                } catch (SQLException e) {
+                    // Ignore
+                }
+            }
+        });
+        return connection;
+    }
+
+    public Statement register(final Statement statement) {
+        resources.addFirst(new Closeable() {
+            
+            @Override
+            public void close() throws IOException {
+                try {
+                    statement.close();
+                } catch (SQLException e) {
+                    // Ignore
+                }
+            }
+        });
+        return statement;
+    }
+
+    public ResultSet register(final ResultSet resultSet) {
+        resources.addFirst(new Closeable() {
+            
+            @Override
+            public void close() throws IOException {
+                try {
+                    resultSet.close();
+                } catch (SQLException e) {
+                    // Ignore
+                }
+            }
+        });
+        return resultSet;
+    }
+    
+
+    private ServiceReference<?> lookupDataSource(String name) {
+        ServiceReference<?>[] references;
+        try {
+            references = bundleContext.getServiceReferences((String) null,
+                    "(&(|(" + Constants.OBJECTCLASS + "=" + DataSource.class.getName() + ")"
+                    + "(" + Constants.OBJECTCLASS + "=" + XADataSource.class.getName() + "))"
+                    + "(|(osgi.jndi.service.name=" + name + ")(datasource=" + name + ")(name=" + name + ")(service.id=" + name + ")))");
+        } catch (InvalidSyntaxException e) {
+            throw new IllegalArgumentException("Error finding datasource with name " + name, e);
+        }
+        if (references == null || references.length == 0) {
+            throw new IllegalArgumentException("No JDBC datasource found for " + name);
+        }
+        if (references.length > 1) {
+            throw new IllegalArgumentException("Multiple JDBC datasource found for " + name);
+        }
+        return references[0];
+    }
+
+    @Override
+    public void close() {
+        StreamUtils.close(resources.toArray(new Closeable[]{}));
+        if (reference != null) {
+            bundleContext.ungetService(reference);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/src/main/java/org/apache/karaf/jdbc/internal/JdbcMBeanImpl.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/karaf/jdbc/internal/JdbcMBeanImpl.java b/jdbc/src/main/java/org/apache/karaf/jdbc/internal/JdbcMBeanImpl.java
new file mode 100644
index 0000000..92bbba8
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/karaf/jdbc/internal/JdbcMBeanImpl.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.karaf.jdbc.internal;
+
+import org.apache.karaf.jdbc.JdbcMBean;
+import org.apache.karaf.jdbc.JdbcService;
+
+import javax.management.MBeanException;
+import javax.management.openmbean.*;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Default implementation of the JDBC MBean.
+ */
+public class JdbcMBeanImpl implements JdbcMBean {
+
+    private JdbcService jdbcService;
+
+    @Override
+    public TabularData getDatasources() throws MBeanException {
+        try {
+            CompositeType type = new CompositeType("DataSource", "JDBC DataSource",
+                    new String[]{ "name", "product", "version", "url "},
+                    new String[]{ "Name", "Database product", "Database version", "JDBC URL" },
+                    new OpenType[]{ SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, SimpleType.STRING });
+            TabularType tableType = new TabularType("JDBC DataSources", "Table of the JDBC DataSources",
+                    type, new String[]{ "name" });
+            TabularData table = new TabularDataSupport(tableType);
+
+            for (String datasource : jdbcService.datasources()) {
+                Map<String, String> info = jdbcService.info(datasource);
+                CompositeData data = new CompositeDataSupport(type,
+                        new String[]{ "name", "product", "version", "url" },
+                        new Object[]{ datasource, info.get("db.product"), info.get("db.version"), info.get("url") });
+                table.put(data);
+            }
+
+            return table;
+        } catch (Exception e) {
+            throw new MBeanException(null, e.getMessage());
+        }
+    }
+
+    @Override
+    public void create(String name, String type, String driver, String version, String url, String user, String password, boolean installBundles) throws MBeanException {
+        try {
+            jdbcService.create(name, type, driver, version, url, user, password, installBundles);
+        } catch (Exception e) {
+            throw new MBeanException(null, e.getMessage());
+        }
+    }
+
+    @Override
+    public void delete(String name) throws MBeanException {
+        try {
+            jdbcService.delete(name);
+        } catch (Exception e) {
+            throw new MBeanException(null, e.getMessage());
+        }
+    }
+
+    @Override
+    public Map<String, String> info(String datasource) throws MBeanException {
+        try {
+            return jdbcService.info(datasource);
+        } catch (Exception e) {
+            throw new MBeanException(null, e.getMessage());
+        }
+    }
+
+    @Override
+    public TabularData tables(String datasource) throws MBeanException {
+        try {
+            Map<String, List<String>> result = jdbcService.tables(datasource);
+            OpenType[] stringTypes = new OpenType[result.keySet().size()];
+            for (int i = 0; i < stringTypes.length; i++) {
+                stringTypes[i] = SimpleType.STRING;
+            }
+            String[] columns = result.keySet().toArray(new String[result.keySet().size()]);
+
+            CompositeType type = new CompositeType("Columns", "Columns",
+                    columns, columns, stringTypes);
+            TabularType rows = new TabularType("Result", "Result Rows", type, columns);
+            TabularData table = new TabularDataSupport(rows);
+
+            int rowCount = result.get(result.keySet().iterator().next()).size();
+
+            for (int i = 0; i < rowCount; i++) {
+                Object[] row = new Object[columns.length];
+                for (int j = 0; j < columns.length; j++) {
+                    row[j] = result.get(columns[j]).get(i);
+                }
+                CompositeData data = new CompositeDataSupport(type, columns, row);
+                table.put(data);
+            }
+
+            return table;
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new MBeanException(null, e.getMessage());
+        }
+    }
+
+    @Override
+    public void execute(String datasource, String command) throws MBeanException {
+        try {
+            jdbcService.execute(datasource, command);
+        } catch (Exception e) {
+            throw new MBeanException(null, e.getMessage());
+        }
+    }
+
+    @Override
+    public TabularData query(String datasource, String query) throws MBeanException {
+        try {
+            Map<String, List<String>> result = jdbcService.query(datasource, query);
+            OpenType[] stringTypes = new OpenType[result.keySet().size()];
+            for (int i = 0; i < stringTypes.length; i++) {
+                stringTypes[i] = SimpleType.STRING;
+            }
+            String[] columns = result.keySet().toArray(new String[result.keySet().size()]);
+
+            CompositeType type = new CompositeType("Columns", "Columns",
+                    columns, columns, stringTypes);
+            TabularType rows = new TabularType("Result", "Result Rows", type, columns);
+            TabularData table = new TabularDataSupport(rows);
+
+            int rowCount = result.get(result.keySet().iterator().next()).size();
+
+            for (int i = 0; i < rowCount; i++) {
+                Object[] row = new Object[columns.length];
+                for (int j = 0; j < columns.length; j++) {
+                    row[j] = result.get(columns[j]).get(i);
+                }
+                CompositeData data = new CompositeDataSupport(type, columns, row);
+                table.put(data);
+            }
+
+            return table;
+        } catch (Exception e) {
+            throw new MBeanException(null, e.getMessage());
+        }
+    }
+
+    public JdbcService getJdbcService() {
+        return jdbcService;
+    }
+
+    public void setJdbcService(JdbcService jdbcService) {
+        this.jdbcService = jdbcService;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/src/main/java/org/apache/karaf/jdbc/internal/JdbcServiceImpl.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/karaf/jdbc/internal/JdbcServiceImpl.java b/jdbc/src/main/java/org/apache/karaf/jdbc/internal/JdbcServiceImpl.java
new file mode 100644
index 0000000..50cf8ff
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/karaf/jdbc/internal/JdbcServiceImpl.java
@@ -0,0 +1,231 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.jdbc.internal;
+
+import org.apache.karaf.jdbc.JdbcService;
+import org.apache.karaf.util.TemplateUtils;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+import javax.sql.DataSource;
+import javax.sql.XADataSource;
+
+import java.io.*;
+import java.sql.*;
+import java.util.*;
+
+/**
+ * Default implementation of the JDBC Service.
+ */
+public class JdbcServiceImpl implements JdbcService {
+
+    public static enum TYPES {
+        DB2("wrap:mvn:com.ibm.db2.jdbc/db2jcc/", "9.7", "datasource-db2.xml"),
+        DERBY("mvn:org.apache.derby/derby/", "10.8.2.2", "datasource-derby.xml"),
+        GENERIC(null, null, "datasource-generic.xml"),
+        H2("mvn:com.h2database/h2/", "1.3.163", "datasource-h2.xml"),
+        HSQL("mvn:org.hsqldb/hsqldb/", "2.3.2", "datasource-hsql.xml"),
+        MYSQL("mvn:mysql/mysql-connector-java/", "5.1.18", "datasource-mysql.xml"),
+        MSSQL("wrap:mvn:net.sourceforge.jtds/jtds/", "1.2.4", "datasource-mssql.xml"),
+        ORACLE("wrap:mvn:ojdbc/ojdbc/", "11.2.0.2.0", "datasource-oracle.xml"),
+        POSTGRES("wrap:mvn:postgresql/postgresql/", "9.1-901.jdbc4", "datasource-postgres.xml");
+
+        private final String bundleUrl;
+        private final String defaultVersion;
+        private final String templateFile;
+
+        TYPES(String bundleUrl, String defaultVersion, String templateFile) {
+            this.bundleUrl = bundleUrl;
+            this.defaultVersion = defaultVersion;
+            this.templateFile = templateFile;
+        }
+
+        public void installBundle(BundleContext bundleContext, String version) throws Exception {
+            String location = this.bundleUrl + getWithDefault(version, this.defaultVersion);
+            bundleContext.installBundle(location, null).start();
+        }
+
+        private String getWithDefault(String st, String defaultSt) {
+            return (st == null)? defaultSt : st;
+        }
+
+        public void copyDataSourceFile(File outFile, HashMap<String, String> properties) {
+            InputStream is = this.getClass().getResourceAsStream(templateFile);
+            if (is == null) {
+                throw new IllegalArgumentException("Template resource " + templateFile + " doesn't exist");
+            }
+            TemplateUtils.createFromTemplate(outFile, is, properties);
+        }
+
+    }
+
+    private BundleContext bundleContext;
+
+    @Override
+    public void create(String name, String type, String driverClassName, String version, String url, String user, String password, boolean tryToInstallBundles) throws Exception {
+        if (type == null) {
+            throw new IllegalStateException("No database type supplied");
+        }
+        TYPES dbType = TYPES.valueOf(type.toUpperCase());
+
+        if (tryToInstallBundles) {
+            dbType.installBundle(bundleContext, version);
+        }
+
+        File karafBase = new File(System.getProperty("karaf.base"));
+        File deployFolder = new File(karafBase, "deploy");
+        File outFile = new File(deployFolder, "datasource-" + name + ".xml");
+
+        HashMap<String, String> properties = new HashMap<String, String>();
+        properties.put("name", name);
+        properties.put("driver", driverClassName);
+        properties.put("url", url);
+        properties.put("user", user);
+        properties.put("password", password);
+
+        dbType.copyDataSourceFile(outFile, properties);
+    }
+
+    @Override
+    public void delete(String name) throws Exception {
+        File karafBase = new File(System.getProperty("karaf.base"));
+        File deployFolder = new File(karafBase, "deploy");
+        File datasourceFile = new File(deployFolder, "datasource-" + name + ".xml");
+        if (!datasourceFile.exists()) {
+            throw new IllegalArgumentException("The JDBC datasource file "+ datasourceFile.getPath() + " doesn't exist");
+        }
+        datasourceFile.delete();
+    }
+
+    @Override
+    public List<String> datasources() throws Exception {
+        List<String> datasources = new ArrayList<String>();
+
+        ServiceReference<?>[] references = bundleContext.getServiceReferences((String) null, "(|(" + Constants.OBJECTCLASS + "=" + DataSource.class.getName() + ")("
+        + Constants.OBJECTCLASS + "=" + XADataSource.class.getName() + "))");
+        if (references != null) {
+            for (ServiceReference reference : references) {
+                if (reference.getProperty("osgi.jndi.service.name") != null) {
+                    datasources.add((String) reference.getProperty("osgi.jndi.service.name"));
+                } else if (reference.getProperty("datasource") != null) {
+                    datasources.add((String) reference.getProperty("datasource"));
+                } else if (reference.getProperty("name") != null) {
+                    datasources.add((String) reference.getProperty("name"));
+                } else {
+                    datasources.add(reference.getProperty(Constants.SERVICE_ID).toString());
+                }
+            }
+        }
+        return datasources;
+    }
+
+    @Override
+    public List<String> datasourceFileNames() throws Exception {
+        File karafBase = new File(System.getProperty("karaf.base"));
+        File deployFolder = new File(karafBase, "deploy");
+
+        String[] datasourceFileNames = deployFolder.list(new FilenameFilter() {
+
+            @Override
+            public boolean accept(File dir, String name) {
+                return name.startsWith("datasource-") && name.endsWith(".xml");
+            }
+        });
+
+        return Arrays.asList(datasourceFileNames);
+    }
+
+    @Override
+    public Map<String, List<String>> query(String datasource, String query) throws Exception {
+        JdbcConnector jdbcConnector = new JdbcConnector(bundleContext, datasource);
+        try {
+            Map<String, List<String>> map = new HashMap<String, List<String>>();
+            Statement statement = jdbcConnector.createStatement();
+            ResultSet resultSet = jdbcConnector.register(statement.executeQuery(query));
+            ResultSetMetaData metaData = resultSet.getMetaData();
+            for (int c = 1; c <= metaData.getColumnCount(); c++) {
+                map.put(metaData.getColumnLabel(c), new ArrayList<String>());
+            }
+            while (resultSet.next()) {
+                for (int c = 1; c <= metaData.getColumnCount(); c++) {
+                    map.get(metaData.getColumnLabel(c)).add(resultSet.getString(c));
+                }
+            }
+            return map;
+        } finally {
+            jdbcConnector.close();
+        }
+    }
+
+    @Override
+    public void execute(String datasource, String command) throws Exception {
+        JdbcConnector jdbcConnector = new JdbcConnector(bundleContext, datasource);
+        try {
+            jdbcConnector.createStatement().execute(command);
+        } finally {
+            jdbcConnector.close();
+        }
+    }
+
+    @Override
+    public Map<String, List<String>> tables(String datasource) throws Exception {
+        JdbcConnector jdbcConnector = new JdbcConnector(bundleContext, datasource);
+        try {
+
+            DatabaseMetaData dbMetaData = jdbcConnector.connect().getMetaData();
+            ResultSet resultSet = jdbcConnector.register(dbMetaData.getTables(null, null, null, null));
+            ResultSetMetaData metaData = resultSet.getMetaData();
+            Map<String, List<String>> map = new HashMap<String, List<String>>();
+            for (int c = 1; c <= metaData.getColumnCount(); c++) {
+                map.put(metaData.getColumnLabel(c), new ArrayList<String>());
+            }
+            while (resultSet.next()) {
+                for (int c = 1; c <= metaData.getColumnCount(); c++) {
+                    map.get(metaData.getColumnLabel(c)).add(resultSet.getString(c));
+                }
+            }
+            return map;
+        } finally {
+            jdbcConnector.close();
+        }
+    }
+
+    @Override
+    public Map<String, String> info(String datasource) throws Exception {
+        JdbcConnector jdbcConnector = new JdbcConnector(bundleContext, datasource);
+        try {
+            DatabaseMetaData dbMetaData = jdbcConnector.connect().getMetaData();
+            Map<String, String> map = new HashMap<String, String>();
+            map.put("db.product", dbMetaData.getDatabaseProductName());
+            map.put("db.version", dbMetaData.getDatabaseProductVersion());
+            map.put("url", dbMetaData.getURL());
+            map.put("username", dbMetaData.getUserName());
+            map.put("driver.name", dbMetaData.getDriverName());
+            map.put("driver.version", dbMetaData.getDriverVersion());
+            return map;
+        } finally {
+            jdbcConnector.close();
+        }
+    }
+
+    public void setBundleContext(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/src/main/resources/OSGI-INF/blueprint/jdbc-core.xml
----------------------------------------------------------------------
diff --git a/jdbc/src/main/resources/OSGI-INF/blueprint/jdbc-core.xml b/jdbc/src/main/resources/OSGI-INF/blueprint/jdbc-core.xml
new file mode 100644
index 0000000..e961697
--- /dev/null
+++ b/jdbc/src/main/resources/OSGI-INF/blueprint/jdbc-core.xml
@@ -0,0 +1,41 @@
+<?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.
+    -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+           xmlns:ext="http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.0.0"
+           default-activation="lazy">
+
+    <ext:property-placeholder placeholder-prefix="$[" placeholder-suffix="]"/>
+
+    <bean id="jdbcService" class="org.apache.karaf.jdbc.internal.JdbcServiceImpl">
+        <property name="bundleContext" ref="blueprintBundleContext"/>
+    </bean>
+
+    <service ref="jdbcService" interface="org.apache.karaf.jdbc.JdbcService" />
+
+    <!-- Management -->
+    <bean id="jdbcMBeanImpl" class="org.apache.karaf.jdbc.internal.JdbcMBeanImpl">
+        <property name="jdbcService" ref="jdbcService"/>
+    </bean>
+
+    <service ref="jdbcMBeanImpl" auto-export="interfaces">
+        <service-properties>
+            <entry key="jmx.objectname" value="org.apache.karaf:type=jdbc,name=$[karaf.name]"/>
+        </service-properties>
+    </service>
+
+</blueprint>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/src/main/resources/OSGI-INF/bundle.info
----------------------------------------------------------------------
diff --git a/jdbc/src/main/resources/OSGI-INF/bundle.info b/jdbc/src/main/resources/OSGI-INF/bundle.info
new file mode 100644
index 0000000..bc7a1cd
--- /dev/null
+++ b/jdbc/src/main/resources/OSGI-INF/bundle.info
@@ -0,0 +1,18 @@
+h1. Synopsis
+
+${project.name}
+
+${project.description}
+
+Maven URL:
+[mvn:${project.groupId}/${project.artifactId}/${project.version}]
+
+h1. Description
+
+This bundle is the core implementation of the JDBC service support.
+
+The JDBC service allows you to create datasources, see the defined datasources, execute query on a datasource, etc.
+
+h1. See also
+
+JDBC - section of the Karaf User Guide

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-db2.xml
----------------------------------------------------------------------
diff --git a/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-db2.xml b/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-db2.xml
new file mode 100644
index 0000000..da220a5
--- /dev/null
+++ b/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-db2.xml
@@ -0,0 +1,32 @@
+<?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.
+    -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+
+    <bean id="dataSource" class="com.ibm.db2.jcc.DB2DataSource">
+        <property name="url" value="${url}"/>
+        <property name="user" value="${user}"/>
+        <property name="password" value="${password}"/>
+    </bean>
+
+    <service interface="javax.sql.DataSource" ref="dataSource">
+        <service-properties>
+            <entry key="osgi.jndi.service.name" value="jdbc/${name}"/>
+        </service-properties>
+    </service>
+
+</blueprint>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/a9b763f2/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-derby.xml
----------------------------------------------------------------------
diff --git a/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-derby.xml b/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-derby.xml
new file mode 100644
index 0000000..440a439
--- /dev/null
+++ b/jdbc/src/main/resources/org/apache/karaf/jdbc/internal/datasource-derby.xml
@@ -0,0 +1,39 @@
+<?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.
+    -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+           default-activation="eager">
+
+    <bean id="dataSource" class="org.apache.derby.jdbc.EmbeddedXADataSource">
+        <property name="databaseName" value="${name}"/>
+        <property name="createDatabase" value="create" />
+    </bean>
+
+    <service ref="dataSource" interface="javax.sql.DataSource">
+        <service-properties>
+            <entry key="osgi.jndi.service.name" value="jdbc/${name}"/>
+        </service-properties>
+    </service>
+
+    <service ref="dataSource" interface="javax.sql.XADataSource">
+        <service-properties>
+            <entry key="osgi.jndi.service.name" value="jdbc/${name}xa"/>
+        </service-properties>
+    </service>
+
+</blueprint>


[05/33] git commit: [KARAF-2888] Call listeners when features are installed or uninstalled

Posted by gn...@apache.org.
[KARAF-2888] Call listeners when features are installed or uninstalled


Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/6a19214e
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/6a19214e
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/6a19214e

Branch: refs/heads/master
Commit: 6a19214e566cec14c821aac849c8718a08eadaac
Parents: 4b6b7af
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Thu Apr 10 16:27:21 2014 +0200
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Fri Apr 11 19:20:02 2014 +0200

----------------------------------------------------------------------
 .../internal/service/FeaturesServiceImpl.java   | 28 +++++++++-----------
 1 file changed, 12 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/6a19214e/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java b/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
index 6c16650..e6dbc32 100644
--- a/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
+++ b/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
@@ -799,7 +799,10 @@ public class FeaturesServiceImpl implements FeaturesService {
 
         // Install conditionals
         List<String> installedFeatureIds = getFeatureIds(allResources);
-        List<Feature> installedFeatures = getFeatures(repositories, installedFeatureIds);
+        List<String> newFeatures = new ArrayList<String>(installedFeatureIds);
+        newFeatures.removeAll(installed);
+        List<String> delFeatures = new ArrayList<String>(installed);
+        delFeatures.removeAll(installedFeatureIds);
 
         //
         // Compute list of installable resources (those with uris)
@@ -955,25 +958,12 @@ public class FeaturesServiceImpl implements FeaturesService {
         //
         // Update and save state
         //
-        List<String> newFeatures = new ArrayList<String>();
         synchronized (lock) {
-            List<String> allFeatures = new ArrayList<String>();
-            for (Resource resource : allResources) {
-                String name = FeatureNamespace.getName(resource);
-                if (name != null) {
-                    Version version = FeatureNamespace.getVersion(resource);
-                    String id = version != null ? name + "/" + version : name;
-                    allFeatures.add(id);
-                    if (!state.installedFeatures.contains(id)) {
-                        newFeatures.add(id);
-                    }
-                }
-            }
             state.bundleChecksums.putAll(deployment.newCheckums);
             state.features.clear();
             state.features.addAll(features);
             state.installedFeatures.clear();
-            state.installedFeatures.addAll(allFeatures);
+            state.installedFeatures.addAll(installedFeatureIds);
             state.managedBundles.clear();
             state.managedBundles.addAll(managed);
             saveState();
@@ -1061,7 +1051,13 @@ public class FeaturesServiceImpl implements FeaturesService {
             }
         }
 
-        // TODO: call listeners for features added and removed
+        // Call listeners
+        for (Feature feature : getFeatures(repositories, delFeatures)) {
+            callListeners(new FeatureEvent(feature, FeatureEvent.EventType.FeatureUninstalled, false));
+        }
+        for (Feature feature : getFeatures(repositories, newFeatures)) {
+            callListeners(new FeatureEvent(feature, FeatureEvent.EventType.FeatureInstalled, false));
+        }
 
         print("Done.", verbose);
     }


[09/33] git commit: [KARAF-2888] Optimize start bundle sorting which is really slow

Posted by gn...@apache.org.
[KARAF-2888] Optimize start bundle sorting which is really slow


Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/78fbae7f
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/78fbae7f
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/78fbae7f

Branch: refs/heads/master
Commit: 78fbae7faa140f88b76358d89af044dcc8693411
Parents: 286939f
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Fri Apr 11 15:47:33 2014 +0200
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Fri Apr 11 19:20:03 2014 +0200

----------------------------------------------------------------------
 .../internal/service/FeaturesServiceImpl.java   |  5 +-
 .../internal/service/RequirementSort.java       | 87 +++++++-------------
 2 files changed, 33 insertions(+), 59 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/78fbae7f/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java b/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
index 65223d5..7008ef6 100644
--- a/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
+++ b/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
@@ -64,10 +64,7 @@ import org.osgi.framework.FrameworkEvent;
 import org.osgi.framework.FrameworkListener;
 import org.osgi.framework.ServiceReference;
 import org.osgi.framework.Version;
-import org.osgi.framework.namespace.PackageNamespace;
 import org.osgi.framework.startlevel.BundleStartLevel;
-import org.osgi.framework.wiring.BundleCapability;
-import org.osgi.framework.wiring.BundleRequirement;
 import org.osgi.framework.wiring.BundleRevision;
 import org.osgi.framework.wiring.BundleWire;
 import org.osgi.framework.wiring.BundleWiring;
@@ -1043,7 +1040,7 @@ public class FeaturesServiceImpl implements FeaturesService {
 
         // TODO: remove this hack, but it avoids loading the class after the bundle is refreshed
         new CopyOnWriteArrayIdentityList().iterator();
-        new RequirementSort();
+        RequirementSort.sort(Collections.<Resource>emptyList());
 
         if (!noRefresh) {
             toStop = new HashSet<Bundle>();

http://git-wip-us.apache.org/repos/asf/karaf/blob/78fbae7f/features/src/main/java/org/apache/karaf/features/internal/service/RequirementSort.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/service/RequirementSort.java b/features/src/main/java/org/apache/karaf/features/internal/service/RequirementSort.java
index e9ecece..96b99ee 100644
--- a/features/src/main/java/org/apache/karaf/features/internal/service/RequirementSort.java
+++ b/features/src/main/java/org/apache/karaf/features/internal/service/RequirementSort.java
@@ -16,92 +16,69 @@
  */
 package org.apache.karaf.features.internal.service;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Set;
 
-import org.apache.karaf.features.internal.resolver.RequirementImpl;
+import org.apache.karaf.features.internal.resolver.CapabilitySet;
 import org.apache.karaf.features.internal.resolver.SimpleFilter;
 import org.osgi.framework.Constants;
 import org.osgi.resource.Capability;
 import org.osgi.resource.Requirement;
 import org.osgi.resource.Resource;
 
-import java.util.Collection;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
-
-public class RequirementSort  {
+public class RequirementSort<T extends Resource>  {
 
     /**
      * Sorts {@link Resource} based on their {@link Requirement}s and {@link Capability}s.
-     * @param resources
-     * @return
      */
     public static <T extends Resource> Collection<T> sort(Collection<T> resources) {
+        Set<String> namespaces = new HashSet<String>();
+        for (Resource r : resources) {
+            for (Capability cap : r.getCapabilities(null)) {
+                namespaces.add(cap.getNamespace());
+            }
+        }
+        CapabilitySet capSet = new CapabilitySet(new ArrayList<String>(namespaces));
+        for (Resource r : resources) {
+            for (Capability cap : r.getCapabilities(null)) {
+                capSet.addCapability(cap);
+            }
+        }
         Set<T> sorted = new LinkedHashSet<T>();
         Set<T> visited = new LinkedHashSet<T>();
         for (T r : resources) {
-            visit(r, resources, visited, sorted);
+            visit(r, visited, sorted, capSet);
         }
         return sorted;
     }
 
 
-    private static <T extends Resource> void visit(T resource, Collection<T> resources, Set<T> visited, Set<T> sorted) {
-        if (visited.contains(resource)) {
+    private static <T extends Resource> void visit(T resource, Set<T> visited, Set<T> sorted, CapabilitySet capSet) {
+        if (!visited.add(resource)) {
             return;
         }
-        visited.add(resource);
-        for (T r : collectDependencies(resource, resources)) {
-            visit(r, resources, visited, sorted);
+        for (T r : collectDependencies(resource, capSet)) {
+            visit(r, visited, sorted, capSet);
         }
         sorted.add(resource);
     }
 
-    /**
-     * Finds the dependencies of the current resource.
-     * @param resource
-     * @param allResources
-     * @return
-     */
-    private static <T extends Resource> Set<T> collectDependencies(T resource, Collection<T> allResources) {
+    @SuppressWarnings("unchecked")
+    private static <T extends Resource> Set<T> collectDependencies(T resource, CapabilitySet capSet) {
         Set<T> result = new LinkedHashSet<T>();
-        List<Requirement> requirements = resource.getRequirements(null);
-        for (Requirement requirement : requirements) {
-            boolean isSatisfied = false;
-            for (Resource r : result) {
-                for (Capability capability : r.getCapabilities(null)) {
-                    if (isSatisfied(requirement, capability)) {
-                        isSatisfied = true;
-                        break;
-                    }
-                }
-            }
-
-            for (T r : allResources) {
-                if (!isSatisfied) {
-                    for (Capability capability : r.getCapabilities(null)) {
-                        if (isSatisfied(requirement, capability)) {
-                            result.add(r);
-                            break;
-                        }
-                    }
-                }
-            }
-        }
-        return result;
-    }
-
-    private static boolean isSatisfied(Requirement requirement, Capability capability) {
-        RequirementImpl br;
-        if (requirement instanceof RequirementImpl) {
-            br = (RequirementImpl) requirement;
-        } else {
+        for (Requirement requirement : resource.getRequirements(null)) {
             String filter = requirement.getDirectives().get(Constants.FILTER_DIRECTIVE);
             SimpleFilter sf = (filter != null)
                     ? SimpleFilter.parse(filter)
                     : new SimpleFilter(null, null, SimpleFilter.MATCH_ALL);
-            br = new RequirementImpl(null, requirement.getNamespace(), requirement.getDirectives(), requirement.getAttributes(), sf);
+            for (Capability cap : capSet.match(sf, true)) {
+                result.add((T) cap.getResource());
+            }
         }
-        return br.matches(capability);
+        return result;
     }
+
 }


[26/33] Revert "[KARAF-2852] Merge features/core and features/command"

Posted by gn...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/service/RepositoryImpl.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/RepositoryImpl.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/RepositoryImpl.java
new file mode 100644
index 0000000..56e5102
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/RepositoryImpl.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.karaf.features.internal.service;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InterruptedIOException;
+import java.net.URI;
+
+import org.apache.karaf.features.Repository;
+import org.apache.karaf.features.internal.model.Features;
+import org.apache.karaf.features.internal.model.JaxbUtil;
+
+/**
+ * The repository implementation.
+ */
+public class RepositoryImpl implements Repository {
+
+    private final URI uri;
+    private Features features;
+
+    public RepositoryImpl(URI uri) {
+        this.uri = uri;
+    }
+
+    public URI getURI() {
+        return uri;
+    }
+
+    public String getName() throws IOException {
+        load();
+        return features.getName();
+    }
+
+    public URI[] getRepositories() throws Exception {
+        load();
+        URI[] result = new URI[features.getRepository().size()];
+        for (int i = 0; i < features.getRepository().size(); i++) {
+            String uri = features.getRepository().get(i);
+            uri = uri.trim();
+            result[i] = URI.create(uri);
+        }
+        return result;
+    }
+
+    public org.apache.karaf.features.Feature[] getFeatures() throws Exception {
+        load();
+        return features.getFeature().toArray(new org.apache.karaf.features.Feature[features.getFeature().size()]);
+    }
+
+
+    public void load() throws IOException {
+        load(false);
+    }
+
+    public void load(boolean validate) throws IOException {
+        if (features == null) {
+            try {
+                InputStream inputStream = uri.toURL().openStream();
+                inputStream = new FilterInputStream(inputStream) {
+    				@Override
+    				public int read(byte[] b, int off, int len) throws IOException {
+    					if (Thread.currentThread().isInterrupted()) {
+    						throw new InterruptedIOException();
+    					}
+    					return super.read(b, off, len);
+    				}
+    			};
+                try {
+                    features = JaxbUtil.unmarshal(uri.toASCIIString(), inputStream, validate);
+                } finally {
+                    inputStream.close();
+                }
+            } catch (IllegalArgumentException e) {
+                throw (IOException) new IOException(e.getMessage() + " : " + uri).initCause(e);
+            } catch (Exception e) {
+                throw (IOException) new IOException(e.getMessage() + " : " + uri).initCause(e);
+            }
+        }
+    }
+
+    @Override
+    public boolean isValid() {
+        throw new UnsupportedOperationException();
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/service/RequirementSort.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/RequirementSort.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/RequirementSort.java
new file mode 100644
index 0000000..96b99ee
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/RequirementSort.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.karaf.features.internal.service;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.apache.karaf.features.internal.resolver.CapabilitySet;
+import org.apache.karaf.features.internal.resolver.SimpleFilter;
+import org.osgi.framework.Constants;
+import org.osgi.resource.Capability;
+import org.osgi.resource.Requirement;
+import org.osgi.resource.Resource;
+
+public class RequirementSort<T extends Resource>  {
+
+    /**
+     * Sorts {@link Resource} based on their {@link Requirement}s and {@link Capability}s.
+     */
+    public static <T extends Resource> Collection<T> sort(Collection<T> resources) {
+        Set<String> namespaces = new HashSet<String>();
+        for (Resource r : resources) {
+            for (Capability cap : r.getCapabilities(null)) {
+                namespaces.add(cap.getNamespace());
+            }
+        }
+        CapabilitySet capSet = new CapabilitySet(new ArrayList<String>(namespaces));
+        for (Resource r : resources) {
+            for (Capability cap : r.getCapabilities(null)) {
+                capSet.addCapability(cap);
+            }
+        }
+        Set<T> sorted = new LinkedHashSet<T>();
+        Set<T> visited = new LinkedHashSet<T>();
+        for (T r : resources) {
+            visit(r, visited, sorted, capSet);
+        }
+        return sorted;
+    }
+
+
+    private static <T extends Resource> void visit(T resource, Set<T> visited, Set<T> sorted, CapabilitySet capSet) {
+        if (!visited.add(resource)) {
+            return;
+        }
+        for (T r : collectDependencies(resource, capSet)) {
+            visit(r, visited, sorted, capSet);
+        }
+        sorted.add(resource);
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <T extends Resource> Set<T> collectDependencies(T resource, CapabilitySet capSet) {
+        Set<T> result = new LinkedHashSet<T>();
+        for (Requirement requirement : resource.getRequirements(null)) {
+            String filter = requirement.getDirectives().get(Constants.FILTER_DIRECTIVE);
+            SimpleFilter sf = (filter != null)
+                    ? SimpleFilter.parse(filter)
+                    : new SimpleFilter(null, null, SimpleFilter.MATCH_ALL);
+            for (Capability cap : capSet.match(sf, true)) {
+                result.add((T) cap.getResource());
+            }
+        }
+        return result;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/service/SimpleDownloader.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/SimpleDownloader.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/SimpleDownloader.java
new file mode 100644
index 0000000..d1f16b9
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/SimpleDownloader.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.service;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.apache.karaf.features.internal.deployment.Downloader;
+import org.apache.karaf.features.internal.deployment.StreamProvider;
+import org.apache.karaf.features.internal.util.MultiException;
+
+public class SimpleDownloader implements Downloader {
+
+    private final MultiException exception = new MultiException("Error");
+
+    @Override
+    public void await() throws InterruptedException, MultiException {
+        exception.throwIfExceptions();
+    }
+
+    @Override
+    public void download(final String location, final DownloadCallback downloadCallback) throws MalformedURLException {
+        final URL url = new URL(location);
+        try {
+            downloadCallback.downloaded(new StreamProvider() {
+                @Override
+                public InputStream open() throws IOException {
+                    return url.openStream();
+                }
+            });
+        } catch (Exception e) {
+            exception.addException(e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/service/State.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/State.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/State.java
new file mode 100644
index 0000000..c84f4e0
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/State.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.karaf.features.internal.service;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public class State {
+
+    public final AtomicBoolean bootDone = new AtomicBoolean();
+    public final Set<String> repositories = new TreeSet<String>();
+    public final Set<String> features = new TreeSet<String>();
+    public final Set<String> installedFeatures = new TreeSet<String>();
+    public final Set<Long> managedBundles = new TreeSet<Long>();
+    public final Map<String, Long> bundleChecksums = new HashMap<String, Long>();
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/service/StateStorage.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/StateStorage.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/StateStorage.java
new file mode 100644
index 0000000..ac54ab0
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/StateStorage.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.karaf.features.internal.service;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.karaf.features.Feature;
+
+public abstract class StateStorage {
+
+    public void load(State state) throws IOException {
+        state.repositories.clear();
+        state.features.clear();
+        state.installedFeatures.clear();
+        state.managedBundles.clear();
+        InputStream is = getInputStream();
+        if (is != null) {
+            try {
+                Properties props = new Properties();
+                props.load(is);
+                state.bootDone.set(loadBool(props, "bootDone"));
+                state.repositories.addAll(loadSet(props, "repositories."));
+                state.features.addAll(loadSet(props, "features."));
+                state.installedFeatures.addAll(loadSet(props, "installed."));
+                state.managedBundles.addAll(toLongSet(loadSet(props, "managed.")));
+                state.bundleChecksums.putAll(toStringLongMap(loadMap(props, "checksums.")));
+            } finally {
+                close(is);
+            }
+        }
+    }
+
+    public void save(State state) throws IOException {
+        OutputStream os = getOutputStream();
+        if (os != null) {
+            try {
+                Properties props = new Properties();
+                saveBool(props, "bootDone", state.bootDone.get());
+                saveSet(props, "repositories.", state.repositories);
+                saveSet(props, "features.", state.features);
+                saveSet(props, "installed.", state.installedFeatures);
+                saveSet(props, "managed.", toStringSet(state.managedBundles));
+                saveMap(props, "checksums.", toStringStringMap(state.bundleChecksums));
+                props.store(os, "FeaturesService State");
+            } finally {
+                close(os);
+            }
+        }
+    }
+
+    protected abstract InputStream getInputStream() throws IOException;
+    protected abstract OutputStream getOutputStream() throws IOException;
+
+    protected boolean loadBool(Properties props, String key) {
+        return Boolean.parseBoolean(props.getProperty(key));
+    }
+
+    protected void saveBool(Properties props, String key, boolean val) {
+        props.setProperty(key, Boolean.toString(val));
+    }
+
+    protected Set<String> toStringSet(Set<Long> set) {
+        Set<String> ns = new TreeSet<String>();
+        for (long l : set) {
+            ns.add(Long.toString(l));
+        }
+        return ns;
+    }
+
+    protected Set<Long> toLongSet(Set<String> set) {
+        Set<Long> ns = new TreeSet<Long>();
+        for (String s : set) {
+            ns.add(Long.parseLong(s));
+        }
+        return ns;
+    }
+
+    protected void saveSet(Properties props, String prefix, Set<String> set) {
+        List<String> l = new ArrayList<String>(set);
+        props.put(prefix + "count", Integer.toString(l.size()));
+        for (int i = 0; i < l.size(); i++) {
+            props.put(prefix + "item." + i, l.get(i));
+        }
+    }
+
+    protected Set<String> loadSet(Properties props, String prefix) {
+        Set<String> l = new HashSet<String>();
+        String countStr = (String) props.get(prefix + "count");
+        if (countStr != null) {
+            int count = Integer.parseInt(countStr);
+            for (int i = 0; i < count; i++) {
+                l.add((String) props.get(prefix + "item." + i));
+            }
+        }
+        return l;
+    }
+
+    protected Map<String, String> toStringStringMap(Map<String, Long> map) {
+        Map<String, String> nm = new HashMap<String, String>();
+        for (Map.Entry<String, Long> entry : map.entrySet()) {
+            nm.put(entry.getKey(), Long.toString(entry.getValue()));
+        }
+        return nm;
+    }
+
+    protected Map<String, Long> toStringLongMap(Map<String, String> map) {
+        Map<String, Long> nm = new HashMap<String, Long>();
+        for (Map.Entry<String, String> entry : map.entrySet()) {
+            nm.put(entry.getKey(), Long.parseLong(entry.getValue()));
+        }
+        return nm;
+    }
+
+
+    protected void saveMap(Properties props, String prefix, Map<String, String> map) {
+        List<Map.Entry<String, String>> l = new ArrayList<Map.Entry<String, String>>(map.entrySet());
+        props.put(prefix + "count", Integer.toString(l.size()));
+        for (int i = 0; i < l.size(); i++) {
+            props.put(prefix + "key." + i, l.get(i).getKey());
+            props.put(prefix + "val." + i, l.get(i).getValue());
+        }
+    }
+
+    protected Map<String, String> loadMap(Properties props, String prefix) {
+        Map<String, String> l = new HashMap<String, String>();
+        String countStr = (String) props.get(prefix + "count");
+        if (countStr != null) {
+            int count = Integer.parseInt(countStr);
+            for (int i = 0; i < count; i++) {
+                String key = (String) props.get(prefix + "key." + i);
+                String val = (String) props.get(prefix + "val." + i);
+                l.put(key, val);
+            }
+        }
+        return l;
+    }
+
+
+    protected void close(Closeable closeable) {
+        if (closeable != null) {
+            try {
+                closeable.close();
+            } catch (IOException e) {
+                // Ignore
+            }
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/util/ChecksumUtils.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/util/ChecksumUtils.java b/features/core/src/main/java/org/apache/karaf/features/internal/util/ChecksumUtils.java
new file mode 100644
index 0000000..19fc706
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/util/ChecksumUtils.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.karaf.features.internal.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.CRC32;
+
+public class ChecksumUtils {
+
+    private ChecksumUtils() {
+    }
+
+    /**
+     * Compute a cheksum for the file or directory that consists of the name, length and the last modified date
+     * for a file and its children in case of a directory
+     *
+     * @param is the input stream
+     * @return a checksum identifying any change
+     */
+    public static long checksum(InputStream is) throws IOException
+    {
+        try {
+            CRC32 crc = new CRC32();
+            byte[] buffer = new byte[8192];
+            int l;
+            while ((l = is.read(buffer)) > 0) {
+                crc.update(buffer, 0, l);
+            }
+            return crc.getValue();
+        } finally {
+            if (is != null) {
+                try {
+                    is.close();
+                } catch (IOException e) {
+                    // Ignore
+                }
+            }
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/util/JsonReader.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/util/JsonReader.java b/features/core/src/main/java/org/apache/karaf/features/internal/util/JsonReader.java
new file mode 100644
index 0000000..a53d8a5
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/util/JsonReader.java
@@ -0,0 +1,349 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ */
+public class JsonReader {
+
+    public static Object read(Reader reader) throws IOException {
+        return new JsonReader(reader).parse();
+    }
+
+    public static Object read(InputStream is) throws IOException {
+        return new JsonReader(new InputStreamReader(is)).parse();
+    }
+
+    //
+    // Implementation
+    //
+
+    private final Reader reader;
+    private final StringBuilder recorder;
+    private int current;
+    private int line = 1;
+    private int column = 0;
+
+    JsonReader(Reader reader) {
+        this.reader = reader;
+        recorder = new StringBuilder();
+    }
+
+    public Object parse() throws IOException {
+        read();
+        skipWhiteSpace();
+        Object result = readValue();
+        skipWhiteSpace();
+        if (!endOfText()) {
+            throw error("Unexpected character");
+        }
+        return result;
+    }
+
+    private Object readValue() throws IOException {
+        switch (current) {
+            case 'n':
+                return readNull();
+            case 't':
+                return readTrue();
+            case 'f':
+                return readFalse();
+            case '"':
+                return readString();
+            case '[':
+                return readArray();
+            case '{':
+                return readObject();
+            case '-':
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+                return readNumber();
+            default:
+                throw expected("value");
+        }
+    }
+
+    private Collection<?> readArray() throws IOException {
+        read();
+        Collection<Object> array = new ArrayList<Object>();
+        skipWhiteSpace();
+        if (readChar(']')) {
+            return array;
+        }
+        do {
+            skipWhiteSpace();
+            array.add(readValue());
+            skipWhiteSpace();
+        } while (readChar(','));
+        if (!readChar(']')) {
+            throw expected("',' or ']'");
+        }
+        return array;
+    }
+
+    private Map<String, Object> readObject() throws IOException {
+        read();
+        Map<String, Object> object = new HashMap<String, Object>();
+        skipWhiteSpace();
+        if (readChar('}')) {
+            return object;
+        }
+        do {
+            skipWhiteSpace();
+            String name = readName();
+            skipWhiteSpace();
+            if (!readChar(':')) {
+                throw expected("':'");
+            }
+            skipWhiteSpace();
+            object.put(name, readValue());
+            skipWhiteSpace();
+        } while (readChar(','));
+        if (!readChar('}')) {
+            throw expected("',' or '}'");
+        }
+        return object;
+    }
+
+    private Object readNull() throws IOException {
+        read();
+        readRequiredChar('u');
+        readRequiredChar('l');
+        readRequiredChar('l');
+        return null;
+    }
+
+    private Boolean readTrue() throws IOException {
+        read();
+        readRequiredChar('r');
+        readRequiredChar('u');
+        readRequiredChar('e');
+        return Boolean.TRUE;
+    }
+
+    private Boolean readFalse() throws IOException {
+        read();
+        readRequiredChar('a');
+        readRequiredChar('l');
+        readRequiredChar('s');
+        readRequiredChar('e');
+        return Boolean.FALSE;
+    }
+
+    private void readRequiredChar(char ch) throws IOException {
+        if (!readChar(ch)) {
+            throw expected("'" + ch + "'");
+        }
+    }
+
+    private String readString() throws IOException {
+        read();
+        recorder.setLength(0);
+        while (current != '"') {
+            if (current == '\\') {
+                readEscape();
+            } else if (current < 0x20) {
+                throw expected("valid string character");
+            } else {
+                recorder.append((char) current);
+                read();
+            }
+        }
+        read();
+        return recorder.toString();
+    }
+
+    private void readEscape() throws IOException {
+        read();
+        switch (current) {
+            case '"':
+            case '/':
+            case '\\':
+                recorder.append((char) current);
+                break;
+            case 'b':
+                recorder.append('\b');
+                break;
+            case 'f':
+                recorder.append('\f');
+                break;
+            case 'n':
+                recorder.append('\n');
+                break;
+            case 'r':
+                recorder.append('\r');
+                break;
+            case 't':
+                recorder.append('\t');
+                break;
+            case 'u':
+                char[] hexChars = new char[4];
+                for (int i = 0; i < 4; i++) {
+                    read();
+                    if (!isHexDigit(current)) {
+                        throw expected("hexadecimal digit");
+                    }
+                    hexChars[i] = (char) current;
+                }
+                recorder.append((char) Integer.parseInt(String.valueOf(hexChars), 16));
+                break;
+            default:
+                throw expected("valid escape sequence");
+        }
+        read();
+    }
+
+    private Number readNumber() throws IOException {
+        recorder.setLength(0);
+        readAndAppendChar('-');
+        int firstDigit = current;
+        if (!readAndAppendDigit()) {
+            throw expected("digit");
+        }
+        if (firstDigit != '0') {
+            while (readAndAppendDigit()) {
+            }
+        }
+        readFraction();
+        readExponent();
+        return Double.parseDouble(recorder.toString());
+    }
+
+    private boolean readFraction() throws IOException {
+        if (!readAndAppendChar('.')) {
+            return false;
+        }
+        if (!readAndAppendDigit()) {
+            throw expected("digit");
+        }
+        while (readAndAppendDigit()) {
+        }
+        return true;
+    }
+
+    private boolean readExponent() throws IOException {
+        if (!readAndAppendChar('e') && !readAndAppendChar('E')) {
+            return false;
+        }
+        if (!readAndAppendChar('+')) {
+            readAndAppendChar('-');
+        }
+        if (!readAndAppendDigit()) {
+            throw expected("digit");
+        }
+        while (readAndAppendDigit()) {
+        }
+        return true;
+    }
+
+    private String readName() throws IOException {
+        if (current != '"') {
+            throw expected("name");
+        }
+        readString();
+        return recorder.toString();
+    }
+
+    private boolean readAndAppendChar(char ch) throws IOException {
+        if (current != ch) {
+            return false;
+        }
+        recorder.append(ch);
+        read();
+        return true;
+    }
+
+    private boolean readChar(char ch) throws IOException {
+        if (current != ch) {
+            return false;
+        }
+        read();
+        return true;
+    }
+
+    private boolean readAndAppendDigit() throws IOException {
+        if (!isDigit(current)) {
+            return false;
+        }
+        recorder.append((char) current);
+        read();
+        return true;
+    }
+
+    private void skipWhiteSpace() throws IOException {
+        while (isWhiteSpace(current) && !endOfText()) {
+            read();
+        }
+    }
+
+    private void read() throws IOException {
+        if (endOfText()) {
+            throw error("Unexpected end of input");
+        }
+        column++;
+        if (current == '\n') {
+            line++;
+            column = 0;
+        }
+        current = reader.read();
+    }
+
+    private boolean endOfText() {
+        return current == -1;
+    }
+
+    private IOException expected(String expected) {
+        if (endOfText()) {
+            return error("Unexpected end of input");
+        }
+        return error("Expected " + expected);
+    }
+
+    private IOException error(String message) {
+        return new IOException(message + " at " + line + ":" + column);
+    }
+
+    private static boolean isWhiteSpace(int ch) {
+        return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
+    }
+
+    private static boolean isDigit(int ch) {
+        return ch >= '0' && ch <= '9';
+    }
+
+    private static boolean isHexDigit(int ch) {
+        return ch >= '0' && ch <= '9' || ch >= 'a' && ch <= 'f' || ch >= 'A' && ch <= 'F';
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/util/JsonWriter.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/util/JsonWriter.java b/features/core/src/main/java/org/apache/karaf/features/internal/util/JsonWriter.java
new file mode 100644
index 0000000..cba27fb
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/util/JsonWriter.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.util;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ */
+public class JsonWriter {
+
+    public static void write(Writer writer, Object value) throws IOException {
+        if (value instanceof Map) {
+            writeObject(writer, (Map) value);
+        } else if (value instanceof Collection) {
+            writeArray(writer, (Collection) value);
+        } else if (value instanceof Number) {
+            writeNumber(writer, (Number) value);
+        } else if (value instanceof String) {
+            writeString(writer, (String) value);
+        } else if (value instanceof Boolean) {
+            writeBoolean(writer, (Boolean) value);
+        } else if (value == null) {
+            writeNull(writer);
+        } else {
+            throw new IllegalArgumentException("Unsupported value: " + value);
+        }
+    }
+
+    private static void writeObject(Writer writer, Map<?, ?> value) throws IOException {
+        writer.append('{');
+        boolean first = true;
+        for (Map.Entry entry : value.entrySet()) {
+            if (!first) {
+                writer.append(',');
+            } else {
+                first = false;
+            }
+            writeString(writer, (String) entry.getKey());
+            writer.append(':');
+            write(writer, entry.getValue());
+        }
+        writer.append('}');
+    }
+
+    private static void writeString(Writer writer, String value) throws IOException {
+        writer.append('"');
+        for (int i = 0; i < value.length(); i++) {
+            char c = value.charAt(i);
+            switch (c) {
+                case '\"':
+                case '\\':
+                case '\b':
+                case '\f':
+                case '\n':
+                case '\r':
+                case '\t':
+                    writer.append('\\');
+                    writer.append(c);
+                    break;
+                default:
+                    if (c < ' ' || (c >= '\u0080' && c < '\u00a0') || (c >= '\u2000' && c < '\u2100')) {
+                        String s = Integer.toHexString(c);
+                        writer.append('\\');
+                        writer.append('u');
+                        for (int j = s.length(); j < 4; j++) {
+                            writer.append('0');
+                        }
+                        writer.append(s);
+                    } else {
+                        writer.append(c);
+                    }
+                    break;
+            }
+        }
+        writer.append('"');
+    }
+
+    private static void writeNumber(Writer writer, Number value) throws IOException {
+        writer.append(value.toString());
+    }
+
+    private static void writeBoolean(Writer writer, Boolean value) throws IOException {
+        writer.append(Boolean.toString(value));
+    }
+
+    private static void writeArray(Writer writer, Collection<?> value) throws IOException {
+        writer.append('[');
+        boolean first = true;
+        for (Object obj : value) {
+            if (!first) {
+                writer.append(',');
+            } else {
+                first = false;
+            }
+            write(writer, obj);
+        }
+        writer.append(']');
+    }
+
+    private static void writeNull(Writer writer) throws IOException {
+        writer.append("null");
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/util/Macro.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/util/Macro.java b/features/core/src/main/java/org/apache/karaf/features/internal/util/Macro.java
new file mode 100644
index 0000000..d30b7b5
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/util/Macro.java
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.util;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.felix.utils.version.VersionTable;
+import org.osgi.framework.Version;
+
+public class Macro {
+
+    public static String transform(String macro, String value) {
+        if (macro.startsWith("${") && macro.endsWith("}")) {
+            String[] args = macro.substring(2, macro.length() - 1).split(";");
+            if ("version".equals(args[0])) {
+                if (args.length != 2) {
+                    throw new IllegalArgumentException("Invalid syntax for macro: " + macro);
+                }
+                return version(args[1], VersionTable.getVersion(value));
+            } else if ("range".equals(args[0])) {
+                if (args.length != 2) {
+                    throw new IllegalArgumentException("Invalid syntax for macro: " + macro);
+                }
+                return range(args[1], VersionTable.getVersion(value));
+            } else {
+                throw new IllegalArgumentException("Unknown macro: " + macro);
+            }
+        }
+        return value;
+    }
+
+    /**
+     * Modify a version to set a version policy. Thed policy is a mask that is
+     * mapped to a version.
+     *
+     * <pre>
+     * +           increment
+     * -           decrement
+     * =           maintain
+     * &tilde;           discard
+     *
+     * ==+      = maintain major, minor, increment micro, discard qualifier
+     * &tilde;&tilde;&tilde;=     = just get the qualifier
+     * version=&quot;[${version;==;${@}},${version;=+;${@}})&quot;
+	 * </pre>
+	 *
+	 * @param args
+     * @return
+     */
+    final static String	MASK_STRING			= "[\\-+=~0123456789]{0,3}[=~]?";
+
+    static String version(String mask, Version version) {
+        StringBuilder sb = new StringBuilder();
+        String del = "";
+
+        for (int i = 0; i < mask.length(); i++) {
+            char c = mask.charAt(i);
+            String result = null;
+            if (c != '~') {
+                if (i > 3) {
+                    throw new IllegalArgumentException("Version mask can only specify 3 digits");
+                } else if (i == 3) {
+                    result = version.getQualifier();
+                    if (result.isEmpty()) {
+                        result = null;
+                    }
+                } else if (Character.isDigit(c)) {
+                    // Handle masks like +00, =+0
+                    result = String.valueOf(c);
+                } else {
+                    int x = 0;
+                    switch (i) {
+                        case 0: x = version.getMajor(); break;
+                        case 1: x = version.getMinor(); break;
+                        case 2: x = version.getMicro(); break;
+                    }
+                    switch (c) {
+                        case '+' :
+                            x++;
+                            break;
+                        case '-' :
+                            x--;
+                            break;
+                        case '=' :
+                            break;
+                    }
+                    result = Integer.toString(x);
+                }
+                if (result != null) {
+                    sb.append(del);
+                    del = ".";
+                    sb.append(result);
+                }
+            }
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Schortcut for version policy
+     *
+     * <pre>
+     * -provide-policy : ${policy;[==,=+)}
+     * -consume-policy : ${policy;[==,+)}
+     * </pre>
+     *
+     * @param args
+     * @return
+     */
+
+    static Pattern	RANGE_MASK		= Pattern.compile("(\\[|\\()(" + MASK_STRING + "),(" + MASK_STRING + ")(\\]|\\))");
+
+    static String range(String spec, Version version) {
+        Matcher m = RANGE_MASK.matcher(spec);
+        m.matches();
+        String floor = m.group(1);
+        String floorMask = m.group(2);
+        String ceilingMask = m.group(3);
+        String ceiling = m.group(4);
+
+        String left = version(floorMask, version);
+        String right = version(ceilingMask, version);
+
+        return floor + left + "," + right + ceiling;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/util/MultiException.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/util/MultiException.java b/features/core/src/main/java/org/apache/karaf/features/internal/util/MultiException.java
new file mode 100644
index 0000000..36af452
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/util/MultiException.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.util;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+@SuppressWarnings("serial")
+public class MultiException extends Exception {
+
+    private List<Exception> exceptions = new ArrayList<Exception>();
+
+    public MultiException(String message) {
+        super(message);
+    }
+
+    public MultiException(String message, List<Exception> exceptions) {
+        super(message);
+        this.exceptions = exceptions;
+    }
+
+    public void addException(Exception e) {
+        exceptions.add(e);
+    }
+
+    public void throwIfExceptions() throws MultiException {
+        if (!exceptions.isEmpty()) {
+            throw this;
+        }
+    }
+    
+    public Throwable[] getCauses() {
+        return exceptions.toArray(new Throwable[exceptions.size()]);
+    }
+
+    @Override
+    public void printStackTrace()
+    {
+        super.printStackTrace();
+        for (Exception e : exceptions) {
+            e.printStackTrace();
+        }
+    }
+
+
+    /* ------------------------------------------------------------------------------- */
+    /**
+     * @see Throwable#printStackTrace(java.io.PrintStream)
+     */
+    @Override
+    public void printStackTrace(PrintStream out)
+    {
+        super.printStackTrace(out);
+        for (Exception e : exceptions) {
+            e.printStackTrace(out);
+        }
+    }
+
+    @Override
+    public void printStackTrace(PrintWriter out)
+    {
+        super.printStackTrace(out);
+        for (Exception e : exceptions) {
+            e.printStackTrace(out);
+        }
+    }
+
+    public static void throwIf(String message, List<Exception> exceptions) throws MultiException {
+        if (exceptions != null && !exceptions.isEmpty()) {
+            StringBuilder sb = new StringBuilder(message);
+            sb.append(":");
+            for (Exception e : exceptions) {
+                sb.append("\n\t");
+                sb.append(e.getMessage());
+            }
+            throw new MultiException(sb.toString(), exceptions);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/management/FeaturesServiceMBean.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/management/FeaturesServiceMBean.java b/features/core/src/main/java/org/apache/karaf/features/management/FeaturesServiceMBean.java
new file mode 100644
index 0000000..6afbbed
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/management/FeaturesServiceMBean.java
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.management;
+
+import javax.management.openmbean.TabularData;
+
+public interface FeaturesServiceMBean {
+
+    TabularData getFeatures() throws Exception;
+
+    TabularData getRepositories() throws Exception;
+
+    void addRepository(String url) throws Exception;
+
+    void addRepository(String url, boolean install) throws Exception;
+
+    void removeRepository(String url) throws Exception;
+
+    void removeRepository(String url, boolean uninstall) throws Exception;
+
+    void installFeature(String name) throws Exception;
+
+    void installFeature(String name, boolean noRefresh) throws Exception;
+
+    void installFeature(String name, boolean noRefresh, boolean noStart) throws Exception;
+
+    void installFeature(String name, String version) throws Exception;
+
+    void installFeature(String name, String version, boolean noRefresh) throws Exception;
+
+    void installFeature(String name, String version, boolean noRefresh, boolean noStart) throws Exception;
+
+    TabularData infoFeature(String name) throws Exception;
+
+    TabularData infoFeature(String name, String version) throws Exception;
+
+    void uninstallFeature(String name) throws Exception;
+
+    void uninstallFeature(String name, boolean noRefresh) throws Exception;
+
+    void uninstallFeature(String name, String version) throws Exception;
+
+    void uninstallFeature(String name, String version, boolean noRefresh) throws Exception;
+
+    String FEATURE_NAME = "Name";
+
+    String FEATURE_VERSION = "Version";
+
+    String FEATURE_DEPENDENCIES = "Dependencies";
+
+    String FEATURE_BUNDLES = "Bundles";
+
+    String FEATURE_CONFIGURATIONS = "Configurations";
+    
+    String FEATURE_CONFIGURATIONFILES = "Configuration Files";
+
+    String FEATURE_INSTALLED = "Installed";
+
+    String FEATURE_CONFIG_PID = "Pid";
+    String FEATURE_CONFIG_ELEMENTS = "Elements";
+    String FEATURE_CONFIG_ELEMENT_KEY = "Key";
+    String FEATURE_CONFIG_ELEMENT_VALUE = "Value";
+    
+    String FEATURE_CONFIG_FILES_ELEMENTS = "Files";
+
+    /**
+     * The type of the event which is emitted for features events
+     */
+    String FEATURE_EVENT_TYPE = "org.apache.karaf.features.featureEvent";
+
+    String FEATURE_EVENT_EVENT_TYPE = "Type";
+
+    String FEATURE_EVENT_EVENT_TYPE_INSTALLED = "Installed";
+
+    String FEATURE_EVENT_EVENT_TYPE_UNINSTALLED = "Uninstalled";
+
+    /**
+     * The item names in the CompositeData representing a feature
+     */
+    String[] FEATURE = { FEATURE_NAME, FEATURE_VERSION, FEATURE_DEPENDENCIES, FEATURE_BUNDLES,
+                         FEATURE_CONFIGURATIONS, FEATURE_CONFIGURATIONFILES, FEATURE_INSTALLED };
+
+    String[] FEATURE_IDENTIFIER = { FEATURE_NAME, FEATURE_VERSION };
+
+    String[] FEATURE_CONFIG = { FEATURE_CONFIG_PID, FEATURE_CONFIG_ELEMENTS };
+    
+    String[] FEATURE_CONFIG_FILES = { FEATURE_CONFIG_FILES_ELEMENTS };
+
+    String[] FEATURE_CONFIG_ELEMENT = { FEATURE_CONFIG_ELEMENT_KEY, FEATURE_CONFIG_ELEMENT_VALUE };
+
+    /**
+     * The item names in the CompositeData representing the event raised for
+     * feature events within the OSGi container by this bean
+     */
+    String[] FEATURE_EVENT = { FEATURE_NAME, FEATURE_VERSION, FEATURE_EVENT_EVENT_TYPE };
+
+
+    String REPOSITORY_NAME = "Name";
+
+    String REPOSITORY_URI = "Uri";
+
+    String REPOSITORY_REPOSITORIES = "Repositories";
+
+    String REPOSITORY_FEATURES = "Features";
+
+    /**
+     * The type of the event which is emitted for repositories events
+     */
+    String REPOSITORY_EVENT_TYPE = "org.apache.karaf.features.repositoryEvent";
+
+    String REPOSITORY_EVENT_EVENT_TYPE = "Type";
+
+    String REPOSITORY_EVENT_EVENT_TYPE_ADDED = "Added";
+
+    String REPOSITORY_EVENT_EVENT_TYPE_REMOVED = "Removed";
+
+    /**
+     * The item names in the CompositeData representing a feature
+     */
+    String[] REPOSITORY = { REPOSITORY_NAME, REPOSITORY_URI,  REPOSITORY_REPOSITORIES, REPOSITORY_FEATURES };
+
+    /**
+     * The item names in the CompositeData representing the event raised for
+     * feature events within the OSGi container by this bean
+     */
+    String[] REPOSITORY_EVENT = { REPOSITORY_URI, REPOSITORY_EVENT_EVENT_TYPE };
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/management/codec/JmxFeature.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/management/codec/JmxFeature.java b/features/core/src/main/java/org/apache/karaf/features/management/codec/JmxFeature.java
new file mode 100644
index 0000000..54fa3c0
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/management/codec/JmxFeature.java
@@ -0,0 +1,323 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.management.codec;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.management.openmbean.TabularData;
+import javax.management.openmbean.TabularType;
+import javax.management.openmbean.OpenDataException;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+import javax.management.openmbean.ArrayType;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.TabularDataSupport;
+
+import org.apache.karaf.features.BundleInfo;
+import org.apache.karaf.features.ConfigFileInfo;
+import org.apache.karaf.features.Dependency;
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.management.FeaturesServiceMBean;
+
+public class JmxFeature {
+
+    /**
+     * The CompositeType which represents a single feature
+     */
+    public final static CompositeType FEATURE;
+
+    /**
+     * The TabularType which represents a list of features
+     */
+    public final static TabularType FEATURE_TABLE;
+
+    public final static CompositeType FEATURE_IDENTIFIER;
+
+    public final static TabularType FEATURE_IDENTIFIER_TABLE;
+
+    public final static CompositeType FEATURE_CONFIG_ELEMENT;
+
+    public final static TabularType FEATURE_CONFIG_ELEMENT_TABLE;
+
+    public final static CompositeType FEATURE_CONFIG;
+
+    public final static TabularType FEATURE_CONFIG_TABLE;
+
+    public final static CompositeType FEATURE_CONFIG_FILES;
+    
+    public final static TabularType FEATURE_CONFIG_FILES_TABLE;
+    
+    private final CompositeData data;
+
+    public JmxFeature(Feature feature, boolean installed) {
+        try {
+            String[] itemNames = FeaturesServiceMBean.FEATURE;
+            Object[] itemValues = new Object[itemNames.length];
+            itemValues[0] = feature.getName();
+            itemValues[1] = feature.getVersion();
+            itemValues[2] = getDependencyIdentifierTable(feature.getDependencies());
+            itemValues[3] = getBundleUris(feature.getBundles());
+            itemValues[4] = getConfigTable(feature.getConfigurations());
+            itemValues[5] = getConfigFileList(feature.getConfigurationFiles());
+            itemValues[6] = installed;
+            data = new CompositeDataSupport(FEATURE, itemNames, itemValues);
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Cannot form feature open data", e);
+        }
+    }
+
+    public CompositeData asCompositeData() {
+        return data;
+    }
+
+    public static TabularData tableFrom(Collection<JmxFeature> features) {
+        TabularDataSupport table = new TabularDataSupport(FEATURE_TABLE);
+        for (JmxFeature feature : features) {
+            table.put(feature.asCompositeData());
+        }
+        return table;
+    }
+
+     private static TabularData getDependencyIdentifierTable(List<Dependency> features) throws OpenDataException {
+        TabularDataSupport table = new TabularDataSupport(FEATURE_IDENTIFIER_TABLE);
+        Set<String> featureSet = new HashSet<String>();
+        for (Dependency feature : features) {
+            if (featureSet.contains(feature.getName() + feature.getVersion())) {
+                continue;
+            } else {
+                featureSet.add(feature.getName() + feature.getVersion());
+            }
+            String[] itemNames = new String[] { FeaturesServiceMBean.FEATURE_NAME, FeaturesServiceMBean.FEATURE_VERSION };
+            Object[] itemValues = new Object[] { feature.getName(), feature.getVersion() };
+            CompositeData ident = new CompositeDataSupport(FEATURE_IDENTIFIER, itemNames, itemValues);
+            table.put(ident);
+        }
+        return table;
+    }
+
+    static String[] getBundleUris(List<BundleInfo> infos) {
+        String[] array = new String[infos.size()];
+        for (int i = 0; i < array.length; i++) {
+            array[i] = infos.get(i).getLocation();
+        }
+        return array;
+    }
+
+    static TabularData getConfigTable(Map<String, Map<String, String>> configs) throws OpenDataException {
+        TabularDataSupport table = new TabularDataSupport(FEATURE_CONFIG_TABLE);
+        for (Map.Entry<String, Map<String, String>> entry : configs.entrySet()) {
+            String[] itemNames = FeaturesServiceMBean.FEATURE_CONFIG;
+            Object[] itemValues = new Object[2];
+            itemValues[0] = entry.getKey();
+            itemValues[1] = getConfigElementTable(entry.getValue());
+            CompositeData config = new CompositeDataSupport(FEATURE_CONFIG, itemNames, itemValues);
+            table.put(config);
+        }
+        return table;
+    }
+    
+    static TabularData getConfigFileList(List<ConfigFileInfo> configFiles) throws OpenDataException {
+        TabularDataSupport table = new TabularDataSupport(FEATURE_CONFIG_FILES_TABLE);
+        for (ConfigFileInfo configFile : configFiles) {
+            String[] itemNames = FeaturesServiceMBean.FEATURE_CONFIG_FILES;
+            Object[] itemValues = { configFile.getFinalname() };
+            CompositeData config = new CompositeDataSupport(FEATURE_CONFIG_FILES, itemNames, itemValues);
+            table.put(config);
+        }
+        return table;
+    }
+
+    static TabularData getConfigElementTable(Map<String, String> config) throws OpenDataException {
+        TabularDataSupport table = new TabularDataSupport(FEATURE_CONFIG_ELEMENT_TABLE);
+        for (Map.Entry<String, String> entry : config.entrySet()) {
+            String[] itemNames = FeaturesServiceMBean.FEATURE_CONFIG_ELEMENT;
+            Object[] itemValues = { entry.getKey(), entry.getValue() };
+            CompositeData element = new CompositeDataSupport(FEATURE_CONFIG_ELEMENT, itemNames, itemValues);
+            table.put(element);
+        }
+        return table;
+    }
+
+
+    static {
+        FEATURE_IDENTIFIER = createFeatureIdentifierType();
+        FEATURE_IDENTIFIER_TABLE = createFeatureIdentifierTableType();
+        FEATURE_CONFIG_ELEMENT = createFeatureConfigElementType();
+        FEATURE_CONFIG_ELEMENT_TABLE = createFeatureConfigElementTableType();
+        FEATURE_CONFIG = createFeatureConfigType();
+        FEATURE_CONFIG_TABLE = createFeatureConfigTableType();
+        FEATURE_CONFIG_FILES =  createFeatureConfigFilesType();
+        FEATURE_CONFIG_FILES_TABLE = createFeatureConfigFilesTableType();
+        FEATURE = createFeatureType();
+        FEATURE_TABLE = createFeatureTableType();
+    }
+
+    private static CompositeType createFeatureIdentifierType() {
+        try {
+            String description = "This type identify a Karaf features";
+            String[] itemNames = FeaturesServiceMBean.FEATURE_IDENTIFIER;
+            OpenType[] itemTypes = new OpenType[itemNames.length];
+            String[] itemDescriptions = new String[itemNames.length];
+            itemTypes[0] = SimpleType.STRING;
+            itemTypes[1] = SimpleType.STRING;
+
+            itemDescriptions[0] = "The id of the feature";
+            itemDescriptions[1] = "The version of the feature";
+
+            return new CompositeType("FeatureIdentifier", description, itemNames,
+                    itemDescriptions, itemTypes);
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Unable to build featureIdentifier type", e);
+        }
+    }
+
+    private static TabularType createFeatureIdentifierTableType() {
+        try {
+            return new TabularType("Features", "The table of featureIdentifiers",
+                    FEATURE_IDENTIFIER, new String[] { FeaturesServiceMBean.FEATURE_NAME, FeaturesServiceMBean.FEATURE_VERSION });
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Unable to build featureIdentifier table type", e);
+        }
+    }
+
+    private static CompositeType createFeatureConfigElementType() {
+        try {
+            String description = "This type encapsulates Karaf feature config element";
+            String[] itemNames = FeaturesServiceMBean.FEATURE_CONFIG_ELEMENT;
+            OpenType[] itemTypes = new OpenType[itemNames.length];
+            String[] itemDescriptions = new String[itemNames.length];
+            itemTypes[0] = SimpleType.STRING;
+            itemTypes[1] = SimpleType.STRING;
+
+            itemDescriptions[0] = "The key";
+            itemDescriptions[1] = "The value";
+
+            return new CompositeType("ConfigElement", description, itemNames,
+                    itemDescriptions, itemTypes);
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Unable to build configElement type", e);
+        }
+    }
+
+    private static TabularType createFeatureConfigElementTableType() {
+        try {
+            return new TabularType("ConfigElement", "The table of configurations elements",
+                    FEATURE_CONFIG_ELEMENT, new String[] { FeaturesServiceMBean.FEATURE_CONFIG_ELEMENT_KEY});
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Unable to build feature table type", e);
+        }
+    }
+
+    private static CompositeType createFeatureConfigType() {
+        try {
+            String description = "This type encapsulates Karaf feature config";
+            String[] itemNames = FeaturesServiceMBean.FEATURE_CONFIG;
+            OpenType[] itemTypes = new OpenType[itemNames.length];
+            String[] itemDescriptions = new String[itemNames.length];
+            itemTypes[0] = SimpleType.STRING;
+            itemTypes[1] = FEATURE_CONFIG_ELEMENT_TABLE;
+
+            itemDescriptions[0] = "The PID of the config";
+            itemDescriptions[1] = "The configuration elements";
+
+            return new CompositeType("Config", description, itemNames,
+                    itemDescriptions, itemTypes);
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Unable to build configElement type", e);
+        }
+    }
+    
+    private static CompositeType createFeatureConfigFilesType() {
+        try {
+            String description = "This type encapsulates Karaf feature config files";
+            String[] itemNames = FeaturesServiceMBean.FEATURE_CONFIG_FILES;
+            OpenType[] itemTypes = new OpenType[itemNames.length];
+            String[] itemDescriptions = new String[itemNames.length];
+            itemTypes[0] = SimpleType.STRING;
+
+            itemDescriptions[0] = "The configuration file";
+
+            return new CompositeType("Config", description, itemNames,
+                    itemDescriptions, itemTypes);
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Unable to build configElement type", e);
+        }
+    }
+
+    private static TabularType createFeatureConfigTableType() {
+        try {
+            return new TabularType("Features", "The table of configurations",
+                    FEATURE_CONFIG, new String[] { FeaturesServiceMBean.FEATURE_CONFIG_PID});
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Unable to build feature table type", e);
+        }
+    }
+    
+    private static TabularType createFeatureConfigFilesTableType() {
+        try {
+            return new TabularType("Features", "The table of configuration files",
+            		FEATURE_CONFIG_FILES, new String[] { FeaturesServiceMBean.FEATURE_CONFIG_FILES_ELEMENTS });
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Unable to build feature table type", e);
+        }
+    }
+
+    private static CompositeType createFeatureType() {
+        try {
+            String description = "This type encapsulates Karaf features";
+            String[] itemNames = FeaturesServiceMBean.FEATURE;
+            OpenType[] itemTypes = new OpenType[itemNames.length];
+            String[] itemDescriptions = new String[itemNames.length];
+            itemTypes[0] = SimpleType.STRING;
+            itemTypes[1] = SimpleType.STRING;
+            itemTypes[2] = FEATURE_IDENTIFIER_TABLE;
+            itemTypes[3] = new ArrayType(1, SimpleType.STRING);
+            itemTypes[4] = FEATURE_CONFIG_TABLE;
+            itemTypes[5] = FEATURE_CONFIG_FILES_TABLE;
+            itemTypes[6] = SimpleType.BOOLEAN;
+
+            itemDescriptions[0] = "The name of the feature";
+            itemDescriptions[1] = "The version of the feature";
+            itemDescriptions[2] = "The feature dependencies";
+            itemDescriptions[3] = "The feature bundles";
+            itemDescriptions[4] = "The feature configurations";
+            itemDescriptions[5] = "The feature configuration files";
+            itemDescriptions[6] = "Whether the feature is installed";
+
+            return new CompositeType("Feature", description, itemNames,
+                    itemDescriptions, itemTypes);
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Unable to build feature type", e);
+        }
+    }
+
+    private static TabularType createFeatureTableType() {
+        try {
+            return new TabularType("Features", "The table of all features",
+                    FEATURE, new String[] { FeaturesServiceMBean.FEATURE_NAME, FeaturesServiceMBean.FEATURE_VERSION });
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Unable to build feature table type", e);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/management/codec/JmxFeatureEvent.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/management/codec/JmxFeatureEvent.java b/features/core/src/main/java/org/apache/karaf/features/management/codec/JmxFeatureEvent.java
new file mode 100644
index 0000000..81f446b
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/management/codec/JmxFeatureEvent.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.karaf.features.management.codec;
+
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.OpenDataException;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+
+import org.apache.karaf.features.FeatureEvent;
+import org.apache.karaf.features.management.FeaturesServiceMBean;
+
+public class JmxFeatureEvent {
+
+    public static final CompositeType FEATURE_EVENT;
+
+    private final CompositeData data;
+
+    public JmxFeatureEvent(FeatureEvent event) {
+        try {
+            String[] itemNames = FeaturesServiceMBean.FEATURE_EVENT;
+            Object[] itemValues = new Object[itemNames.length];
+            itemValues[0] = event.getFeature().getName();
+            itemValues[1] = event.getFeature().getVersion();
+            switch (event.getType()) {
+                case FeatureInstalled:   itemValues[2] = FeaturesServiceMBean.FEATURE_EVENT_EVENT_TYPE_INSTALLED; break;
+                case FeatureUninstalled: itemValues[2] = FeaturesServiceMBean.FEATURE_EVENT_EVENT_TYPE_UNINSTALLED; break;
+                default: throw new IllegalStateException("Unsupported event type: " + event.getType());
+            }
+            data = new CompositeDataSupport(FEATURE_EVENT, itemNames, itemValues);
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Cannot form feature event open data", e);
+        }
+    }
+
+    public CompositeData asCompositeData() {
+        return data;
+    }
+
+    static {
+        FEATURE_EVENT = createFeatureEventType();
+    }
+
+    private static CompositeType createFeatureEventType() {
+        try {
+            String description = "This type identify a Karaf feature event";
+            String[] itemNames = FeaturesServiceMBean.FEATURE_EVENT;
+            OpenType[] itemTypes = new OpenType[itemNames.length];
+            String[] itemDescriptions = new String[itemNames.length];
+            itemTypes[0] = SimpleType.STRING;
+            itemTypes[1] = SimpleType.STRING;
+            itemTypes[2] = SimpleType.STRING;
+
+            itemDescriptions[0] = "The id of the feature";
+            itemDescriptions[1] = "The version of the feature";
+            itemDescriptions[2] = "The type of the event";
+
+            return new CompositeType("FeatureEvent", description, itemNames,
+                    itemDescriptions, itemTypes);
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Unable to build featureEvent type", e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/management/codec/JmxRepository.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/management/codec/JmxRepository.java b/features/core/src/main/java/org/apache/karaf/features/management/codec/JmxRepository.java
new file mode 100644
index 0000000..fee1ab2
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/management/codec/JmxRepository.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.karaf.features.management.codec;
+
+import java.util.Collection;
+import java.util.Arrays;
+import java.net.URI;
+import java.util.List;
+
+import javax.management.openmbean.TabularData;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.TabularType;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+import javax.management.openmbean.OpenDataException;
+import javax.management.openmbean.ArrayType;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularDataSupport;
+import javax.management.openmbean.CompositeDataSupport;
+
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.Repository;
+import org.apache.karaf.features.management.FeaturesServiceMBean;
+
+public class JmxRepository {
+
+    public final static CompositeType REPOSITORY;
+
+    public final static TabularType REPOSITORY_TABLE;
+
+    private final CompositeData data;
+
+    public JmxRepository(Repository repository) {
+        try {
+            String[] itemNames = FeaturesServiceMBean.REPOSITORY;
+            Object[] itemValues = new Object[itemNames.length];
+            itemValues[0] = repository.getName();
+            itemValues[1] = repository.getURI().toString();
+            itemValues[2] = toStringArray(repository.getRepositories());
+            itemValues[3] = getFeatureIdentifierTable(Arrays.asList(repository.getFeatures()));
+            data = new CompositeDataSupport(REPOSITORY, itemNames, itemValues);
+        } catch (Exception e) {
+            throw new IllegalStateException("Cannot form repository open data", e);
+        }
+    }
+
+    public CompositeData asCompositeData() {
+        return data;
+    }
+
+    public static TabularData tableFrom(Collection<JmxRepository> repositories) {
+        TabularDataSupport table = new TabularDataSupport(REPOSITORY_TABLE);
+        for (JmxRepository repository : repositories) {
+            table.put(repository.asCompositeData());
+        }
+        return table;
+    }
+
+    private static String[] toStringArray(URI[] uris) {
+        if (uris == null) {
+            return null;
+        }
+        String[] res = new String[uris.length];
+        for (int i = 0; i < res.length; i++) {
+            res[i] = uris[i].toString();
+        }
+        return res;
+    }
+
+    static TabularData getFeatureIdentifierTable(List<Feature> features) throws OpenDataException {
+        TabularDataSupport table = new TabularDataSupport(JmxFeature.FEATURE_IDENTIFIER_TABLE);
+        for (Feature feature : features) {
+            String[] itemNames = new String[] { FeaturesServiceMBean.FEATURE_NAME, FeaturesServiceMBean.FEATURE_VERSION };
+            Object[] itemValues = new Object[] { feature.getName(), feature.getVersion() };
+            CompositeData ident = new CompositeDataSupport(JmxFeature.FEATURE_IDENTIFIER, itemNames, itemValues);
+            table.put(ident);
+        }
+        return table;
+    }
+
+    static {
+        REPOSITORY = createRepositoryType();
+        REPOSITORY_TABLE = createRepositoryTableType();
+    }
+
+    private static CompositeType createRepositoryType() {
+        try {
+            String description = "This type identify a Karaf repository";
+            String[] itemNames = FeaturesServiceMBean.REPOSITORY;
+            OpenType[] itemTypes = new OpenType[itemNames.length];
+            String[] itemDescriptions = new String[itemNames.length];
+            itemTypes[0] = SimpleType.STRING;
+            itemTypes[1] = SimpleType.STRING;
+            itemTypes[2] = new ArrayType(1, SimpleType.STRING);
+            itemTypes[3] = JmxFeature.FEATURE_IDENTIFIER_TABLE;
+
+            itemDescriptions[0] = "The name of the repository";
+            itemDescriptions[1] = "The uri of the repository";
+            itemDescriptions[2] = "The dependent repositories";
+            itemDescriptions[3] = "The list of included features";
+
+            return new CompositeType("Repository", description, itemNames,
+                    itemDescriptions, itemTypes);
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Unable to build repository type", e);
+        }
+    }
+
+    private static TabularType createRepositoryTableType() {
+        try {
+            return new TabularType("Features", "The table of repositories",
+                    REPOSITORY, new String[] { FeaturesServiceMBean.REPOSITORY_URI });
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Unable to build repository table type", e);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/management/codec/JmxRepositoryEvent.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/management/codec/JmxRepositoryEvent.java b/features/core/src/main/java/org/apache/karaf/features/management/codec/JmxRepositoryEvent.java
new file mode 100644
index 0000000..e00e85d
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/management/codec/JmxRepositoryEvent.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.management.codec;
+
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.OpenDataException;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+
+import org.apache.karaf.features.RepositoryEvent;
+import org.apache.karaf.features.management.FeaturesServiceMBean;
+
+public class JmxRepositoryEvent {
+
+    public static final CompositeType REPOSITORY_EVENT;
+
+    private final CompositeData data;
+
+    public JmxRepositoryEvent(RepositoryEvent event) {
+        try {
+            String[] itemNames = FeaturesServiceMBean.REPOSITORY_EVENT;
+            Object[] itemValues = new Object[itemNames.length];
+            itemValues[0] = event.getRepository().getURI().toString();
+            switch (event.getType()) {
+                case RepositoryAdded:   itemValues[1] = FeaturesServiceMBean.REPOSITORY_EVENT_EVENT_TYPE_ADDED; break;
+                case RepositoryRemoved: itemValues[1] = FeaturesServiceMBean.REPOSITORY_EVENT_EVENT_TYPE_REMOVED; break;
+                default: throw new IllegalStateException("Unsupported event type: " + event.getType());
+            }
+            data = new CompositeDataSupport(REPOSITORY_EVENT, itemNames, itemValues);
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Cannot form repository event open data", e);
+        }
+    }
+
+    public CompositeData asCompositeData() {
+        return data;
+    }
+
+    static {
+        REPOSITORY_EVENT = createRepositoryEventType();
+    }
+
+    private static CompositeType createRepositoryEventType() {
+        try {
+            String description = "This type identify a Karaf repository event";
+            String[] itemNames = FeaturesServiceMBean.REPOSITORY_EVENT;
+            OpenType[] itemTypes = new OpenType[itemNames.length];
+            String[] itemDescriptions = new String[itemNames.length];
+            itemTypes[0] = SimpleType.STRING;
+            itemTypes[1] = SimpleType.STRING;
+
+            itemDescriptions[0] = "The uri of the repository";
+            itemDescriptions[1] = "The type of event";
+
+            return new CompositeType("RepositoryEvent", description, itemNames,
+                    itemDescriptions, itemTypes);
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Unable to build repositoryEvent type", e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/resources/OSGI-INF/bundle.info
----------------------------------------------------------------------
diff --git a/features/core/src/main/resources/OSGI-INF/bundle.info b/features/core/src/main/resources/OSGI-INF/bundle.info
new file mode 100644
index 0000000..d5b4180
--- /dev/null
+++ b/features/core/src/main/resources/OSGI-INF/bundle.info
@@ -0,0 +1,20 @@
+h1. Synopsis
+
+${project.name}
+
+${project.description}
+
+Maven URL:
+[mvn:${project.groupId}/${project.artifactId}/${project.version}]
+
+h1. Description
+
+This bundle is the core implementation of the Karaf features support.
+
+Karaf provides a simple, yet flexible, way to provision applications or "features". Such a mechanism is mainly
+provided by a set of commands available in the features shell. The provisioning system uses xml "repositories"
+that define a set of features.
+
+h1. See also
+
+Provisioning - section of the Karaf User Guide


[32/33] git commit: Revert "[KARAF-2852] Merge features/core and features/command"

Posted by gn...@apache.org.
Revert "[KARAF-2852] Merge features/core and features/command"

This reverts commit 999f4970fecd3710da36b709f2d484cd0db38d09.

We actually need to split the commands from the core service
in order to avoid a refresh when the shell is installed.


Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/0c8e8a81
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/0c8e8a81
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/0c8e8a81

Branch: refs/heads/master
Commit: 0c8e8a81e9d8103013f986604c5e840fe32cef5a
Parents: f2669e1
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Fri Apr 11 19:01:02 2014 +0200
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Fri Apr 11 19:20:04 2014 +0200

----------------------------------------------------------------------
 assemblies/apache-karaf/pom.xml                 |    2 +-
 .../standard/src/main/feature/feature.xml       |    1 +
 features/command/NOTICE                         |   71 +
 features/command/pom.xml                        |   90 ++
 .../command/FeaturesCommandSupport.java         |   42 +
 .../features/command/InfoFeatureCommand.java    |  290 ++++
 .../features/command/InstallFeatureCommand.java |   69 +
 .../command/ListFeatureVersionsCommand.java     |   62 +
 .../features/command/ListFeaturesCommand.java   |  106 ++
 .../karaf/features/command/RepoAddCommand.java  |   54 +
 .../karaf/features/command/RepoListCommand.java |   73 +
 .../features/command/RepoRefreshCommand.java    |   65 +
 .../features/command/RepoRemoveCommand.java     |   56 +
 .../command/UninstallFeatureCommand.java        |   62 +
 .../command/completers/AllFeatureCompleter.java |   33 +
 .../completers/AvailableFeatureCompleter.java   |   33 +
 .../completers/AvailableRepoNameCompleter.java  |   48 +
 .../completers/FeatureCompleterSupport.java     |   65 +
 .../completers/InstalledRepoNameCompleter.java  |   58 +
 .../completers/InstalledRepoUriCompleter.java   |   59 +
 .../completers/RequiredFeatureCompleter.java    |   33 +
 .../src/main/resources/OSGI-INF/bundle.info     |   30 +
 features/core/NOTICE                            |   71 +
 features/core/pom.xml                           |  141 ++
 .../org/apache/karaf/features/BootFinished.java |   24 +
 .../org/apache/karaf/features/BundleInfo.java   |   32 +
 .../org/apache/karaf/features/Capability.java   |   23 +
 .../org/apache/karaf/features/Conditional.java  |   35 +
 .../apache/karaf/features/ConfigFileInfo.java   |   27 +
 .../org/apache/karaf/features/Dependency.java   |   29 +
 .../apache/karaf/features/EventConstants.java   |   46 +
 .../java/org/apache/karaf/features/Feature.java |   63 +
 .../org/apache/karaf/features/FeatureEvent.java |   50 +
 .../apache/karaf/features/FeaturesListener.java |   25 +
 .../karaf/features/FeaturesNamespaces.java      |   41 +
 .../apache/karaf/features/FeaturesService.java  |  104 ++
 .../karaf/features/RegionsPersistence.java      |   26 +
 .../org/apache/karaf/features/Repository.java   |   37 +
 .../apache/karaf/features/RepositoryEvent.java  |   50 +
 .../org/apache/karaf/features/Requirement.java  |   23 +
 .../org/apache/karaf/features/Resolver.java     |   25 +
 .../internal/deployment/DeploymentBuilder.java  |  354 +++++
 .../internal/deployment/Downloader.java         |   35 +
 .../internal/deployment/StreamProvider.java     |   26 +
 .../management/FeaturesServiceMBeanImpl.java    |  290 ++++
 .../management/StandardEmitterMBean.java        |   65 +
 .../karaf/features/internal/model/Bundle.java   |  198 +++
 .../features/internal/model/Capability.java     |   91 ++
 .../features/internal/model/Conditional.java    |   69 +
 .../karaf/features/internal/model/Config.java   |  110 ++
 .../features/internal/model/ConfigFile.java     |  136 ++
 .../karaf/features/internal/model/Content.java  |  199 +++
 .../features/internal/model/Dependency.java     |  121 ++
 .../karaf/features/internal/model/Feature.java  |  374 +++++
 .../karaf/features/internal/model/Features.java |  155 ++
 .../karaf/features/internal/model/JaxbUtil.java |  224 +++
 .../features/internal/model/ObjectFactory.java  |  111 ++
 .../features/internal/model/Requirement.java    |   87 ++
 .../features/internal/model/package-info.java   |   21 +
 .../karaf/features/internal/osgi/Activator.java |  208 +++
 .../repository/AggregateRepository.java         |   55 +
 .../internal/repository/BaseRepository.java     |   86 ++
 .../internal/repository/CacheRepository.java    |   59 +
 .../repository/HttpMetadataProvider.java        |   88 ++
 .../internal/repository/MetadataProvider.java   |   29 +
 .../internal/repository/MetadataRepository.java |   43 +
 .../internal/repository/StaticRepository.java   |   33 +
 .../features/internal/resolver/BaseClause.java  |  114 ++
 .../internal/resolver/CandidateComparator.java  |  129 ++
 .../internal/resolver/CapabilityImpl.java       |  165 ++
 .../internal/resolver/CapabilitySet.java        |  612 ++++++++
 .../internal/resolver/FeatureNamespace.java     |   72 +
 .../internal/resolver/FeatureResource.java      |  133 ++
 .../internal/resolver/IdentityCapability.java   |   63 +
 .../internal/resolver/RequirementImpl.java      |   80 +
 .../internal/resolver/ResolveContextImpl.java   |  102 ++
 .../internal/resolver/ResourceBuilder.java      | 1129 ++++++++++++++
 .../internal/resolver/ResourceImpl.java         |  110 ++
 .../internal/resolver/ServiceNamespace.java     |   30 +
 .../internal/resolver/SimpleFilter.java         |  649 ++++++++
 .../internal/resolver/Slf4jResolverLog.java     |   49 +
 .../internal/resolver/UriNamespace.java         |   47 +
 .../features/internal/service/Artifact.java     |   56 +
 .../internal/service/BootFeaturesInstaller.java |  171 +++
 .../internal/service/EventAdminListener.java    |   91 ++
 .../service/FeatureConfigInstaller.java         |  167 +++
 .../internal/service/FeatureFinder.java         |   68 +
 .../internal/service/FeatureValidationUtil.java |   37 +
 .../internal/service/FeaturesServiceImpl.java   | 1416 ++++++++++++++++++
 .../features/internal/service/Overrides.java    |  132 ++
 .../internal/service/RepositoryImpl.java        |  102 ++
 .../internal/service/RequirementSort.java       |   84 ++
 .../internal/service/SimpleDownloader.java      |   51 +
 .../karaf/features/internal/service/State.java  |   34 +
 .../features/internal/service/StateStorage.java |  175 +++
 .../features/internal/util/ChecksumUtils.java   |   56 +
 .../features/internal/util/JsonReader.java      |  349 +++++
 .../features/internal/util/JsonWriter.java      |  120 ++
 .../karaf/features/internal/util/Macro.java     |  142 ++
 .../features/internal/util/MultiException.java  |   95 ++
 .../management/FeaturesServiceMBean.java        |  142 ++
 .../features/management/codec/JmxFeature.java   |  323 ++++
 .../management/codec/JmxFeatureEvent.java       |   80 +
 .../management/codec/JmxRepository.java         |  132 ++
 .../management/codec/JmxRepositoryEvent.java    |   77 +
 .../src/main/resources/OSGI-INF/bundle.info     |   20 +
 .../karaf/features/karaf-features-1.0.0.xsd     |  239 +++
 .../karaf/features/karaf-features-1.1.0.xsd     |  237 +++
 .../karaf/features/karaf-features-1.2.0.xsd     |  254 ++++
 .../karaf/features/karaf-features-1.3.0.xsd     |  280 ++++
 .../apache/karaf/features/ConditionalTest.java  |   54 +
 .../org/apache/karaf/features/FeatureTest.java  |   32 +
 .../karaf/features/FeaturesServiceTest.java     |  430 ++++++
 .../apache/karaf/features/RepositoryTest.java   |  140 ++
 .../org/apache/karaf/features/TestBase.java     |  105 ++
 .../service/BootFeaturesInstallerTest.java      |   93 ++
 .../internal/service/BundleManagerTest.java     |   64 +
 .../service/FeaturesServiceImplTest.java        |  167 +++
 .../service/FeaturesValidationTest.java         |  102 ++
 .../internal/service/OverridesTest.java         |  208 +++
 .../karaf/features/internal/service/f01.xml     |   92 ++
 .../karaf/features/internal/service/f02.xml     |  164 ++
 .../karaf/features/internal/service/f03.xml     |   27 +
 .../karaf/features/internal/service/f04.xml     |   28 +
 .../karaf/features/internal/service/f05.xml     |   28 +
 .../karaf/features/internal/service/f06.xml     |   36 +
 .../karaf/features/internal/service/f07.xml     |   35 +
 .../internal/service/overrides.properties       |   23 +
 .../karaf/features/internal/service/repo2.xml   |   41 +
 .../org/apache/karaf/features/repo1.xml         |   35 +
 .../org/apache/karaf/features/repo2.xml         |   37 +
 .../org/apache/karaf/features/repo3.xml         |   27 +
 features/pom.xml                                |  127 +-
 .../org/apache/karaf/features/BootFinished.java |   24 -
 .../org/apache/karaf/features/BundleInfo.java   |   32 -
 .../org/apache/karaf/features/Capability.java   |   23 -
 .../org/apache/karaf/features/Conditional.java  |   35 -
 .../apache/karaf/features/ConfigFileInfo.java   |   27 -
 .../org/apache/karaf/features/Dependency.java   |   29 -
 .../apache/karaf/features/EventConstants.java   |   46 -
 .../java/org/apache/karaf/features/Feature.java |   63 -
 .../org/apache/karaf/features/FeatureEvent.java |   50 -
 .../apache/karaf/features/FeaturesListener.java |   25 -
 .../karaf/features/FeaturesNamespaces.java      |   41 -
 .../apache/karaf/features/FeaturesService.java  |  104 --
 .../karaf/features/RegionsPersistence.java      |   26 -
 .../org/apache/karaf/features/Repository.java   |   37 -
 .../apache/karaf/features/RepositoryEvent.java  |   50 -
 .../org/apache/karaf/features/Requirement.java  |   23 -
 .../org/apache/karaf/features/Resolver.java     |   25 -
 .../command/FeaturesCommandSupport.java         |   42 -
 .../features/command/InfoFeatureCommand.java    |  290 ----
 .../features/command/InstallFeatureCommand.java |   69 -
 .../command/ListFeatureVersionsCommand.java     |   62 -
 .../features/command/ListFeaturesCommand.java   |  106 --
 .../karaf/features/command/RepoAddCommand.java  |   54 -
 .../karaf/features/command/RepoListCommand.java |   73 -
 .../features/command/RepoRefreshCommand.java    |   65 -
 .../features/command/RepoRemoveCommand.java     |   56 -
 .../command/UninstallFeatureCommand.java        |   62 -
 .../command/completers/AllFeatureCompleter.java |   33 -
 .../completers/AvailableFeatureCompleter.java   |   33 -
 .../completers/AvailableRepoNameCompleter.java  |   48 -
 .../completers/FeatureCompleterSupport.java     |   65 -
 .../completers/InstalledRepoNameCompleter.java  |   58 -
 .../completers/InstalledRepoUriCompleter.java   |   59 -
 .../completers/RequiredFeatureCompleter.java    |   33 -
 .../internal/deployment/DeploymentBuilder.java  |  354 -----
 .../internal/deployment/Downloader.java         |   35 -
 .../internal/deployment/StreamProvider.java     |   26 -
 .../management/FeaturesServiceMBeanImpl.java    |  290 ----
 .../management/StandardEmitterMBean.java        |   65 -
 .../karaf/features/internal/model/Bundle.java   |  198 ---
 .../features/internal/model/Capability.java     |   89 --
 .../features/internal/model/Conditional.java    |   69 -
 .../karaf/features/internal/model/Config.java   |  110 --
 .../features/internal/model/ConfigFile.java     |  136 --
 .../karaf/features/internal/model/Content.java  |  199 ---
 .../features/internal/model/Dependency.java     |  121 --
 .../karaf/features/internal/model/Feature.java  |  374 -----
 .../karaf/features/internal/model/Features.java |  155 --
 .../karaf/features/internal/model/JaxbUtil.java |  224 ---
 .../features/internal/model/ObjectFactory.java  |  111 --
 .../features/internal/model/Requirement.java    |   87 --
 .../features/internal/model/package-info.java   |   21 -
 .../karaf/features/internal/osgi/Activator.java |  208 ---
 .../repository/AggregateRepository.java         |   55 -
 .../internal/repository/BaseRepository.java     |   86 --
 .../internal/repository/CacheRepository.java    |   59 -
 .../repository/HttpMetadataProvider.java        |   88 --
 .../internal/repository/MetadataProvider.java   |   29 -
 .../internal/repository/MetadataRepository.java |   43 -
 .../internal/repository/StaticRepository.java   |   33 -
 .../features/internal/resolver/BaseClause.java  |  114 --
 .../internal/resolver/CandidateComparator.java  |  129 --
 .../internal/resolver/CapabilityImpl.java       |  165 --
 .../internal/resolver/CapabilitySet.java        |  612 --------
 .../internal/resolver/FeatureNamespace.java     |   72 -
 .../internal/resolver/FeatureResource.java      |  133 --
 .../internal/resolver/IdentityCapability.java   |   63 -
 .../internal/resolver/RequirementImpl.java      |   80 -
 .../internal/resolver/ResolveContextImpl.java   |  102 --
 .../internal/resolver/ResourceBuilder.java      | 1129 --------------
 .../internal/resolver/ResourceImpl.java         |  110 --
 .../internal/resolver/ServiceNamespace.java     |   30 -
 .../internal/resolver/SimpleFilter.java         |  649 --------
 .../internal/resolver/Slf4jResolverLog.java     |   49 -
 .../internal/resolver/UriNamespace.java         |   47 -
 .../features/internal/service/Artifact.java     |   56 -
 .../internal/service/BootFeaturesInstaller.java |  170 ---
 .../internal/service/EventAdminListener.java    |   91 --
 .../service/FeatureConfigInstaller.java         |  167 ---
 .../internal/service/FeatureFinder.java         |   68 -
 .../internal/service/FeatureValidationUtil.java |   37 -
 .../internal/service/FeaturesServiceImpl.java   | 1416 ------------------
 .../features/internal/service/Overrides.java    |  132 --
 .../internal/service/RepositoryImpl.java        |  102 --
 .../internal/service/RequirementSort.java       |   84 --
 .../internal/service/SimpleDownloader.java      |   51 -
 .../karaf/features/internal/service/State.java  |   34 -
 .../features/internal/service/StateStorage.java |  174 ---
 .../features/internal/util/ChecksumUtils.java   |   56 -
 .../features/internal/util/JsonReader.java      |  349 -----
 .../features/internal/util/JsonWriter.java      |  120 --
 .../karaf/features/internal/util/Macro.java     |  142 --
 .../features/internal/util/MultiException.java  |   95 --
 .../management/FeaturesServiceMBean.java        |  142 --
 .../features/management/codec/JmxFeature.java   |  323 ----
 .../management/codec/JmxFeatureEvent.java       |   80 -
 .../management/codec/JmxRepository.java         |  132 --
 .../management/codec/JmxRepositoryEvent.java    |   77 -
 .../src/main/resources/OSGI-INF/bundle.info     |   20 -
 .../karaf/features/karaf-features-1.0.0.xsd     |  239 ---
 .../karaf/features/karaf-features-1.1.0.xsd     |  237 ---
 .../karaf/features/karaf-features-1.2.0.xsd     |  254 ----
 .../karaf/features/karaf-features-1.3.0.xsd     |  280 ----
 .../apache/karaf/features/ConditionalTest.java  |   54 -
 .../org/apache/karaf/features/FeatureTest.java  |   32 -
 .../karaf/features/FeaturesServiceTest.java     |  429 ------
 .../apache/karaf/features/RepositoryTest.java   |  140 --
 .../org/apache/karaf/features/TestBase.java     |  105 --
 .../service/BootFeaturesInstallerTest.java      |   93 --
 .../internal/service/BundleManagerTest.java     |   64 -
 .../service/FeaturesServiceImplTest.java        |  167 ---
 .../service/FeaturesValidationTest.java         |  102 --
 .../internal/service/OverridesTest.java         |  202 ---
 .../karaf/features/internal/service/f01.xml     |   92 --
 .../karaf/features/internal/service/f02.xml     |  164 --
 .../karaf/features/internal/service/f03.xml     |   27 -
 .../karaf/features/internal/service/f04.xml     |   28 -
 .../karaf/features/internal/service/f05.xml     |   28 -
 .../karaf/features/internal/service/f06.xml     |   36 -
 .../karaf/features/internal/service/f07.xml     |   35 -
 .../internal/service/overrides.properties       |   23 -
 .../karaf/features/internal/service/repo2.xml   |   41 -
 .../org/apache/karaf/features/repo1.xml         |   35 -
 .../org/apache/karaf/features/repo2.xml         |   37 -
 .../org/apache/karaf/features/repo3.xml         |   27 -
 instance/pom.xml                                |    2 +-
 kar/pom.xml                                     |    2 +-
 pom.xml                                         |    5 +
 261 files changed, 16137 insertions(+), 15828 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/assemblies/apache-karaf/pom.xml
----------------------------------------------------------------------
diff --git a/assemblies/apache-karaf/pom.xml b/assemblies/apache-karaf/pom.xml
index ce631b8..a799b0a 100644
--- a/assemblies/apache-karaf/pom.xml
+++ b/assemblies/apache-karaf/pom.xml
@@ -161,8 +161,8 @@
                     </installedFeatures>
                     <bootFeatures>
                         <feature>aries-blueprint</feature>
-                        <feature>shell-compat</feature>
                         <feature>shell</feature>
+                        <feature>shell-compat</feature>
                         <feature>jaas</feature>
                         <feature>ssh</feature>
                         <feature>management</feature>

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/assemblies/features/standard/src/main/feature/feature.xml
----------------------------------------------------------------------
diff --git a/assemblies/features/standard/src/main/feature/feature.xml b/assemblies/features/standard/src/main/feature/feature.xml
index 86f8270..5e3fd11 100644
--- a/assemblies/features/standard/src/main/feature/feature.xml
+++ b/assemblies/features/standard/src/main/feature/feature.xml
@@ -73,6 +73,7 @@
         <bundle dependency="true" start-level="30">mvn:org.jledit/core/${jledit.version}</bundle>
         <bundle start-level="30">mvn:org.apache.karaf.shell/org.apache.karaf.shell.core/${project.version}</bundle>
         <bundle start-level="30">mvn:org.apache.karaf.shell/org.apache.karaf.shell.commands/${project.version}</bundle>
+        <bundle start-level="30">mvn:org.apache.karaf.features/org.apache.karaf.features.command/${project.version}</bundle>
     </feature>
 
     <feature name="shell-compat" description="Karaf Shell Compatibility" version="${project.version}">

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/NOTICE
----------------------------------------------------------------------
diff --git a/features/command/NOTICE b/features/command/NOTICE
new file mode 100644
index 0000000..b70f1f9
--- /dev/null
+++ b/features/command/NOTICE
@@ -0,0 +1,71 @@
+Apache Karaf
+Copyright 2010-2014 The Apache Software Foundation
+
+
+I. Included Software
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2010).
+Licensed under the Apache License 2.0.
+
+This product includes software developed at
+OW2 (http://www.ow2.org/).
+Licensed under the BSD License.
+
+This product includes software developed at
+OPS4J (http://www.ops4j.org/).
+Licensed under the Apache License 2.0.
+
+This product includes software developed at
+Eclipse Foundation (http://www.eclipse.org/).
+Licensed under the EPL.
+
+This product includes software written by
+Antony Lesuisse.
+Licensed under Public Domain.
+
+
+II. Used Software
+
+This product uses software developed at
+FUSE Source (http://www.fusesource.org/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+AOP Alliance (http://aopalliance.sourceforge.net/).
+Licensed under the Public Domain.
+
+This product uses software developed at
+Tanuki Software (http://www.tanukisoftware.com/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+Jasypt (http://jasypt.sourceforge.net/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+JLine (http://jline.sourceforge.net).
+Licensed under the BSD License.
+
+This product uses software developed at
+SLF4J (http://www.slf4j.org/).
+Licensed under the MIT License.
+
+This product uses software developed at
+SpringSource (http://www.springsource.org/).
+Licensed under the Apache License 2.0.
+
+This product includes software from http://www.json.org.
+Copyright (c) 2002 JSON.org
+
+
+III. License Summary
+- Apache License 2.0
+- BSD License
+- EPL License
+- MIT License

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/pom.xml
----------------------------------------------------------------------
diff --git a/features/command/pom.xml b/features/command/pom.xml
new file mode 100644
index 0000000..4f49bb1
--- /dev/null
+++ b/features/command/pom.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <!--
+
+        Licensed to the Apache Software Foundation (ASF) under one or more
+        contributor license agreements.  See the NOTICE file distributed with
+        this work for additional information regarding copyright ownership.
+        The ASF licenses this file to You under the Apache License, Version 2.0
+        (the "License"); you may not use this file except in compliance with
+        the License.  You may obtain a copy of the License at
+
+            http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software
+        distributed under the License is distributed on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        See the License for the specific language governing permissions and
+        limitations under the License.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.karaf.features</groupId>
+        <artifactId>features</artifactId>
+        <version>4.0.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>org.apache.karaf.features.command</artifactId>
+    <packaging>bundle</packaging>
+    <name>Apache Karaf :: Features :: Command</name>
+    <description>This bundle provides the Karaf shell commands to manipulate features.</description>
+
+    <properties>
+        <appendedResourcesDirectory>${basedir}/../../etc/appended-resources</appendedResourcesDirectory>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.karaf.features</groupId>
+            <artifactId>org.apache.karaf.features.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.karaf.shell</groupId>
+            <artifactId>org.apache.karaf.shell.core</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <resources>
+            <resource>
+                <directory>${project.basedir}/src/main/resources</directory>
+                <includes>
+                    <include>**/*</include>
+                </includes>
+            </resource>
+            <resource>
+                <directory>${project.basedir}/src/main/resources</directory>
+                <filtering>true</filtering>
+                <includes>
+                    <include>**/*.info</include>
+                </includes>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Karaf-Commands>org.apache.karaf.features.command.*</Karaf-Commands>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/FeaturesCommandSupport.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/FeaturesCommandSupport.java b/features/command/src/main/java/org/apache/karaf/features/command/FeaturesCommandSupport.java
new file mode 100644
index 0000000..076650d
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/FeaturesCommandSupport.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.karaf.features.command;
+
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+
+public abstract class FeaturesCommandSupport implements Action {
+
+    @Reference
+    private FeaturesService featuresService;
+
+    @Override
+    public Object execute() throws Exception {
+        if (featuresService == null) {
+            throw new IllegalStateException("FeaturesService not found");
+        }
+        doExecute(featuresService);
+        return null;
+    }
+
+    protected abstract void doExecute(FeaturesService admin) throws Exception;
+
+    public void setFeaturesService(FeaturesService featuresService) {
+        this.featuresService = featuresService;
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/InfoFeatureCommand.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/InfoFeatureCommand.java b/features/command/src/main/java/org/apache/karaf/features/command/InfoFeatureCommand.java
new file mode 100644
index 0000000..5ad855c
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/InfoFeatureCommand.java
@@ -0,0 +1,290 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.command;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.karaf.features.BundleInfo;
+import org.apache.karaf.features.Conditional;
+import org.apache.karaf.features.ConfigFileInfo;
+import org.apache.karaf.features.Dependency;
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.command.completers.AllFeatureCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "feature", name = "info", description = "Shows information about selected feature.")
+@Service
+public class InfoFeatureCommand extends FeaturesCommandSupport {
+
+    private static final String INDENT = "  ";
+    private static final String FEATURE_CONTENT = "Feature";
+    private static final String CONDITIONAL_CONTENT = "Conditional(%s)";
+
+	@Argument(index = 0, name = "name", description = "The name of the feature", required = true, multiValued = false)
+    @Completion(AllFeatureCompleter.class)
+    private String name;
+
+    @Argument(index = 1, name = "version", description = "The version of the feature", required = false, multiValued = false)
+    private String version;
+
+    @Option(name = "-c", aliases={"--configuration"}, description="Display configuration info", required = false, multiValued = false)
+    private boolean config;
+
+    @Option(name = "-d", aliases={"--dependency"}, description="Display dependencies info", required = false, multiValued = false)
+    private boolean dependency;
+
+    @Option(name = "-b", aliases={"--bundle"}, description="Display bundles info", required = false, multiValued = false)
+    private boolean bundle;
+
+    @Option(name = "--conditional", description="Display conditional info", required = false, multiValued = false)
+    private boolean conditional;
+
+    @Option(name = "-t", aliases={"--tree"}, description="Display feature tree", required = false, multiValued = false)
+    private boolean tree;
+
+    protected void doExecute(FeaturesService admin) throws Exception {
+        Feature feature = null;
+
+        if (version != null && version.length() > 0) {
+            feature = admin.getFeature(name, version);
+        } else {
+            feature = admin.getFeature(name);
+        }
+
+        if (feature == null) {
+            System.out.println("Feature not found");
+            return;
+        }
+
+        // default behavior
+        if (!config && !dependency && !bundle && !conditional) {
+            config = true;
+            dependency = true;
+            bundle = true;
+            conditional = true;
+        }
+
+        System.out.println("Feature " + feature.getName() + " " + feature.getVersion());
+        if (feature.getDescription() != null) {
+        	System.out.println("Description:");
+        	System.out.println(INDENT + feature.getDescription());
+        }
+        
+        if(feature.getDetails() != null) {
+        	System.out.println("Details:");
+        	printWithIndent(feature.getDetails());
+        }
+
+        if (config) {
+            displayConfigInformation(feature, FEATURE_CONTENT);
+            displayConfigFileInformation(feature, FEATURE_CONTENT);
+        }
+
+        if (dependency) {
+            displayDependencyInformation(feature, FEATURE_CONTENT);
+        }
+
+        if (bundle) {
+            displayBundleInformation(feature, FEATURE_CONTENT);
+        }
+
+        if(conditional) {
+           displayConditionalInfo(feature);
+        }
+
+        if (tree) {
+            if (config || dependency || bundle) {
+                System.out.println("\nFeature tree");
+            }
+
+            int unresolved = displayFeatureTree(admin, feature.getName(), feature.getVersion(), "");
+            if (unresolved > 0) {
+                System.out.println("Tree contains " + unresolved + " unresolved dependencies");
+                System.out.println(" * means that node declares dependency but the dependent feature is not available.");
+            }
+        }
+    }
+
+    private void printWithIndent(String details) {
+    	String[] lines = details.split("\r?\n");
+    	for (String line : lines) {
+			System.out.println(INDENT + line);
+		}
+	}
+
+	private void displayBundleInformation(Feature feature, String contentType) {
+        List<BundleInfo> bundleInfos = feature.getBundles();
+        if (bundleInfos.isEmpty()) {
+            System.out.println(contentType + " has no bundles.");
+        } else {
+            System.out.println(contentType + " contains followed bundles:");
+            for (BundleInfo featureBundle : bundleInfos) {
+                int startLevel = featureBundle.getStartLevel();
+                StringBuilder sb = new StringBuilder();
+                sb.append(INDENT).append(featureBundle.getLocation());
+                if(startLevel > 0) {
+                    sb.append(" start-level=").append(startLevel);
+                }
+                System.out.println(sb.toString());
+            }
+        }
+    }
+
+    private void displayDependencyInformation(Feature feature, String contentType) {
+        List<Dependency> dependencies = feature.getDependencies();
+        if (dependencies.isEmpty()) {
+            System.out.println(contentType + " has no dependencies.");
+        } else {
+            System.out.println(contentType + " depends on:");
+            for (Dependency featureDependency : dependencies) {
+                System.out.println(INDENT + featureDependency.getName() + " " + featureDependency.getVersion());
+            }
+        }
+    }
+
+    private void displayConfigInformation(Feature feature, String contentType) {
+        Map<String, Map<String, String>> configurations = feature.getConfigurations();
+        if (configurations.isEmpty()) {
+            System.out.println(contentType + " has no configuration");
+        } else {
+            System.out.println(contentType + " configuration:");
+            for (String name : configurations.keySet()) {
+                System.out.println(INDENT + name);
+            }
+        }
+    }
+    
+    private void displayConfigFileInformation(Feature feature, String contentType) {
+    	List<ConfigFileInfo> configurationFiles = feature.getConfigurationFiles();
+    	if (configurationFiles.isEmpty()) {
+    		System.out.println(contentType + " has no configuration files");
+    	} else {
+    		System.out.println(contentType + " configuration files: ");
+    		for (ConfigFileInfo configFileInfo : configurationFiles) {
+				System.out.println(INDENT + configFileInfo.getFinalname());
+			}
+    	}    	
+    }
+
+    /**
+     * Called originally with featureName and featureVersion that have already been resolved successfully.
+     *
+     * @param admin
+     * @param featureName
+     * @param featureVersion
+     * @param prefix
+     * @return
+     * @throws Exception
+     */
+    private int displayFeatureTree(FeaturesService admin, String featureName, String featureVersion, String prefix) throws Exception {
+        int unresolved = 0;
+
+        Feature resolved = admin.getFeature(featureName, featureVersion);
+        if (resolved != null) {
+            System.out.println(prefix + " " + resolved.getName() + " " + resolved.getVersion());
+        } else {
+            System.out.println(prefix + " " + featureName + " " + featureVersion + " *");
+            unresolved++;
+        }
+
+        if (resolved != null) {
+            if (bundle) {
+                List<String> bundleLocation = new LinkedList<String>();
+                List<BundleInfo> bundles = resolved.getBundles();
+                for (BundleInfo bundleInfo : bundles) {
+                    bundleLocation.add(bundleInfo.getLocation());
+                }
+
+                if (conditional) {
+                    for (Conditional cond : resolved.getConditional()) {
+                        List<String> condition = cond.getCondition();
+                        List<BundleInfo> conditionalBundles = cond.getBundles();
+                        for (BundleInfo bundleInfo : conditionalBundles) {
+                            bundleLocation.add(bundleInfo.getLocation() + "(condition:"+condition+")");
+                        }
+                    }
+                }
+                for (int i = 0, j = bundleLocation.size(); i < j; i++) {
+                    System.out.println(prefix + " " + (i + 1 == j ? "\\" : "+") + " " + bundleLocation.get(i));
+                }
+            }
+            prefix += "   ";
+            List<Dependency> dependencies = resolved.getDependencies();
+            for (int i = 0, j = dependencies.size(); i < j; i++) {
+                Dependency toDisplay =  dependencies.get(i);
+                unresolved += displayFeatureTree(admin, toDisplay.getName(), toDisplay.getVersion(), prefix +1);
+            }
+
+            if (conditional) {
+                for (Conditional cond : resolved.getConditional()) {
+                    List<Dependency> conditionDependencies = cond.getDependencies();
+                    for (int i = 0, j = conditionDependencies.size(); i < j; i++) {
+                        Dependency toDisplay =  dependencies.get(i);
+                        unresolved += displayFeatureTree(admin, toDisplay.getName(), toDisplay.getVersion(), prefix +1);
+                    }
+                }
+            }
+        }
+
+        return unresolved;
+    }
+
+    private void displayConditionalInfo(Feature feature) {
+        List<? extends Conditional> conditionals = feature.getConditional();
+        if (conditionals.isEmpty()) {
+            System.out.println("Feature has no conditionals.");
+        } else {
+            System.out.println("Feature contains followed conditionals:");
+            for (Conditional featureConditional : conditionals) {
+                String conditionDescription = getConditionDescription(featureConditional);
+                Feature wrappedConditional = featureConditional.asFeature(feature.getName(), feature.getVersion());
+                if (config) {
+                    displayConfigInformation(wrappedConditional, String.format(CONDITIONAL_CONTENT, conditionDescription));
+                    displayConfigFileInformation(wrappedConditional, String.format(CONDITIONAL_CONTENT, conditionDescription));
+                }
+
+                if (dependency) {
+                    displayDependencyInformation(wrappedConditional, String.format(CONDITIONAL_CONTENT, conditionDescription));
+                }
+
+                if (bundle) {
+                    displayBundleInformation(wrappedConditional, String.format(CONDITIONAL_CONTENT, conditionDescription));
+                }
+            }
+        }
+    }
+
+    private String getConditionDescription(Conditional cond) {
+        StringBuffer sb = new StringBuffer();
+        for (String dep : cond.getCondition()) {
+            if (sb.length() > 0) {
+                sb.append(" ");
+            }
+            sb.append(dep);
+        }
+        return sb.toString();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/InstallFeatureCommand.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/InstallFeatureCommand.java b/features/command/src/main/java/org/apache/karaf/features/command/InstallFeatureCommand.java
new file mode 100644
index 0000000..b7f8184
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/InstallFeatureCommand.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.command;
+
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.List;
+
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.command.completers.AvailableFeatureCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "feature", name = "install", description = "Installs a feature with the specified name and version.")
+@Service
+public class InstallFeatureCommand extends FeaturesCommandSupport {
+
+    private static String DEFAULT_VERSION = "0.0.0";
+
+    @Argument(index = 0, name = "feature", description = "The name and version of the features to install. A feature id looks like name/version. The version is optional.", required = true, multiValued = true)
+    @Completion(AvailableFeatureCompleter.class)
+    List<String> features;
+
+    @Option(name = "-r", aliases = "--no-auto-refresh", description = "Do not automatically refresh bundles", required = false, multiValued = false)
+    boolean noRefresh;
+
+    @Option(name = "-s", aliases = "--no-auto-start", description = "Do not start the bundles", required = false, multiValued = false)
+    boolean noStart;
+
+    @Option(name = "-v", aliases = "--verbose", description = "Explain what is being done", required = false, multiValued = false)
+    boolean verbose;
+
+    @Option(name = "-t", aliases = "--simulate", description = "Perform a simulation only", required = false, multiValued = false)
+    boolean simulate;
+
+    protected void doExecute(FeaturesService admin) throws Exception {
+        EnumSet<FeaturesService.Option> options = EnumSet.noneOf(FeaturesService.Option.class);
+        if (simulate) {
+            options.add(FeaturesService.Option.Simulate);
+        }
+        if (noStart) {
+            options.add(FeaturesService.Option.NoAutoStartBundles);
+        }
+        if (noRefresh) {
+            options.add(FeaturesService.Option.NoAutoRefreshBundles);
+        }
+        if (verbose) {
+            options.add(FeaturesService.Option.Verbose);
+        }
+        admin.installFeatures(new HashSet<String>(features), options);
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/ListFeatureVersionsCommand.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/ListFeatureVersionsCommand.java b/features/command/src/main/java/org/apache/karaf/features/command/ListFeatureVersionsCommand.java
new file mode 100644
index 0000000..b2c5e42
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/ListFeatureVersionsCommand.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.command;
+
+import java.util.Arrays;
+
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.Repository;
+import org.apache.karaf.features.command.completers.AllFeatureCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.table.ShellTable;
+
+@Command(scope = "feature", name = "version-list", description = "Lists all versions of a feature available from the currently available repositories.")
+@Service
+public class ListFeatureVersionsCommand extends FeaturesCommandSupport {
+
+	@Argument(index = 0, name = "feature", description = "Name of feature.", required = true, multiValued = false)
+    @Completion(AllFeatureCompleter.class)
+	String feature;
+
+    @Option(name = "--no-format", description = "Disable table rendered output", required = false, multiValued = false)
+    boolean noFormat;
+
+    protected void doExecute(FeaturesService admin) throws Exception {
+        ShellTable table = new ShellTable();
+        table.column("Version");
+        table.column("Repository");
+        table.column("Repository URL");
+        table.emptyTableText("No versions available for features '" + feature + "'");
+             
+        for (Repository r : Arrays.asList(admin.listRepositories())) {
+            for (Feature f : r.getFeatures()) {
+
+                if (f.getName().equals(feature)) {
+                    table.addRow().addContent(f.getVersion(), r.getName(), r.getURI());
+                }
+            }
+        }
+
+        table.print(System.out, !noFormat);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/ListFeaturesCommand.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/ListFeaturesCommand.java b/features/command/src/main/java/org/apache/karaf/features/command/ListFeaturesCommand.java
new file mode 100644
index 0000000..e86ff64
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/ListFeaturesCommand.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.command;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.Repository;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.table.ShellTable;
+
+@Command(scope = "feature", name = "list", description = "Lists all existing features available from the defined repositories.")
+@Service
+public class ListFeaturesCommand extends FeaturesCommandSupport {
+
+    @Option(name = "-i", aliases = {"--installed"}, description = "Display a list of all installed features only", required = false, multiValued = false)
+    boolean onlyInstalled;
+
+    @Option(name = "-r", aliases = {"--required"}, description = "Display a list of all required features only", required = false, multiValued = false)
+    boolean onlyRequired;
+
+    @Option(name = "-o", aliases = {"--ordered"}, description = "Display a list using alphabetical order ", required = false, multiValued = false)
+    boolean ordered;
+
+    @Option(name = "--no-format", description = "Disable table rendered output", required = false, multiValued = false)
+    boolean noFormat;
+
+    protected void doExecute(FeaturesService featuresService) throws Exception {
+        boolean needsLegend = false;
+        
+        ShellTable table = new ShellTable();
+        table.column("Name");
+        table.column("Version");
+        table.column("Required");
+        table.column("Installed");
+        table.column("Repository");
+        table.column("Description").maxSize(50);
+        table.emptyTableText(onlyInstalled ? "No features installed" : "No features available");
+
+        List<Repository> repos = Arrays.asList(featuresService.listRepositories());
+        for (Repository r : repos) {
+            List<Feature> features = Arrays.asList(r.getFeatures());
+            if (ordered) {
+                Collections.sort(features, new FeatureComparator());
+            }
+            for (Feature f : features) {
+                if (onlyInstalled && !featuresService.isInstalled(f)) {
+                    // Filter out not installed features if we only want to see the installed ones
+                    continue;
+                }
+                if (onlyRequired && !featuresService.isRequired(f)) {
+                    // Filter out not installed features if we only want to see the installed ones
+                    continue;
+                }
+                table.addRow().addContent(
+                        f.getName(),
+                        f.getVersion(),
+                        featuresService.isRequired(f) ? "x" : "",
+                        featuresService.isInstalled(f) ? "x" : "",
+                        r.getName(),
+                        f.getDescription());
+                if (isInstalledViaDeployDir(r.getName())) {
+                    needsLegend = true;
+                }
+            }
+        }
+
+        table.print(System.out, !noFormat);
+
+        if (needsLegend) {
+            System.out.println("* Installed via deploy directory");
+        }
+
+    }
+
+    private boolean isInstalledViaDeployDir(String st) {
+        return (st == null || st.length() <= 1) ? false : (st.charAt(st.length() - 1) == '*');
+    }
+
+    class FeatureComparator implements Comparator<Feature> {
+        public int compare(Feature o1, Feature o2) {
+            return o1.getName().toLowerCase().compareTo( o2.getName().toLowerCase() );
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/RepoAddCommand.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/RepoAddCommand.java b/features/command/src/main/java/org/apache/karaf/features/command/RepoAddCommand.java
new file mode 100644
index 0000000..16faf42
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/RepoAddCommand.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.karaf.features.command;
+
+import java.net.URI;
+
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.command.completers.AvailableRepoNameCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "feature", name = "repo-add", description = "Add a features repository")
+@Service
+public class RepoAddCommand extends FeaturesCommandSupport {
+
+    @Argument(index = 0, name = "name/url", description = "Shortcut name of the features repository or the full URL", required = true, multiValued = false)
+    @Completion(AvailableRepoNameCompleter.class)
+    private String nameOrUrl;
+    
+    @Argument(index = 1, name = "version", description = "The version of the features repository if using features repository name as first argument. It should be empty if using the URL", required = false, multiValued = false)
+    private String version;
+
+    @Option(name = "-i", aliases = { "--install" }, description = "Install all features contained in the features repository", required = false, multiValued = false)
+    private boolean install;
+
+    @Override
+    protected void doExecute(FeaturesService featuresService) throws Exception {
+        String effectiveVersion = (version == null) ? "LATEST" : version;
+        URI uri = featuresService.getRepositoryUriFor(nameOrUrl, effectiveVersion);
+        if (uri == null) {
+            uri = new URI(nameOrUrl);
+        }
+        System.out.println("Adding feature url " + uri);
+        featuresService.addRepository(uri, install);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/RepoListCommand.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/RepoListCommand.java b/features/command/src/main/java/org/apache/karaf/features/command/RepoListCommand.java
new file mode 100644
index 0000000..55acf79
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/RepoListCommand.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.karaf.features.command;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.Repository;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.MultiException;
+import org.apache.karaf.shell.support.table.ShellTable;
+
+@Command(scope = "feature", name = "repo-list", description = "Displays a list of all defined repositories.")
+@Service
+public class RepoListCommand extends FeaturesCommandSupport {
+
+    @Option(name="-r", description="Reload all feature urls", required = false, multiValued = false)
+    boolean reload;
+
+    @Option(name = "--no-format", description = "Disable table rendered output", required = false, multiValued = false)
+    boolean noFormat;
+    
+    protected void doExecute(FeaturesService featuresService) throws Exception {
+        if (reload) {
+            reloadAllRepos(featuresService);
+        }
+        
+        ShellTable table = new ShellTable();
+        table.column("Repository");
+        table.column("URL");
+        table.emptyTableText("No repositories available");
+
+        Repository[] repos = featuresService.listRepositories();
+     	for (Repository repo : repos) {
+            if (repo != null) {
+     	        table.addRow().addContent(repo.getName(), repo.getURI().toString()); 
+            }
+     	}
+     	table.print(System.out, !noFormat);
+    }
+
+    private void reloadAllRepos(FeaturesService featuresService) throws Exception {
+        System.out.println("Reloading all repositories from their urls");
+        System.out.println();
+        List<Exception> exceptions = new ArrayList<Exception>();
+        for (Repository repo : featuresService.listRepositories()) {
+            try {
+                featuresService.addRepository(repo.getURI());
+            } catch (Exception e) {
+                exceptions.add(e);
+            }
+        }
+        MultiException.throwIf("Unable to reload repositories", exceptions);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/RepoRefreshCommand.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/RepoRefreshCommand.java b/features/command/src/main/java/org/apache/karaf/features/command/RepoRefreshCommand.java
new file mode 100644
index 0000000..8c7ed79
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/RepoRefreshCommand.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.command;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.Repository;
+import org.apache.karaf.features.command.completers.InstalledRepoUriCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+
+@Command(scope = "feature", name = "repo-refresh", description = "Refresh a features repository")
+public class RepoRefreshCommand extends FeaturesCommandSupport {
+    @Argument(index = 0, name = "Feature name or uri", description = "Shortcut name of the feature repository or the full URI", required = false, multiValued = false)
+    @Completion(InstalledRepoUriCompleter.class)
+    private String nameOrUrl;
+    
+    @Argument(index = 1, name = "Feature version", description = "The version of the feature if using the feature name. Should be empty if using the uri", required = false, multiValued = false)
+    private String version;
+
+    @Override
+    protected void doExecute(FeaturesService featuresService) throws Exception {
+        List<URI> uris = new ArrayList<URI>();
+    	if (nameOrUrl != null) {
+    		String effectiveVersion = (version == null) ? "LATEST" : version;
+        	URI uri = featuresService.getRepositoryUriFor(nameOrUrl, effectiveVersion);
+        	if (uri == null) {
+        		uri = new URI(nameOrUrl);
+        	}
+            uris.add(uri);
+    	} else {
+            Repository[] repos = featuresService.listRepositories();
+            for (Repository repo : repos) {
+                uris.add(repo.getURI());
+            }
+    	}
+        for (URI uri : uris) {
+            try {
+                System.out.println("Refreshing feature url " + uri);
+                featuresService.refreshRepository(uri);
+            } catch (Exception e) {
+                System.err.println("Error refreshing " + uri.toString() + ": " + e.getMessage());
+            }
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/RepoRemoveCommand.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/RepoRemoveCommand.java b/features/command/src/main/java/org/apache/karaf/features/command/RepoRemoveCommand.java
new file mode 100644
index 0000000..0710b72
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/RepoRemoveCommand.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.karaf.features.command;
+
+import java.net.URI;
+
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.Repository;
+import org.apache.karaf.features.command.completers.InstalledRepoNameCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "feature", name = "repo-remove", description = "Removes the specified repository features service.")
+@Service
+public class RepoRemoveCommand extends FeaturesCommandSupport {
+
+    @Argument(index = 0, name = "repository", description = "Name or url of the repository to remove.", required = true, multiValued = false)
+    @Completion(InstalledRepoNameCompleter.class)
+    private String repository;
+
+    @Option(name = "-u", aliases = { "--uninstall-all" }, description = "Uninstall all features from the repository", required = false, multiValued = false)
+    private boolean uninstall;
+
+    protected void doExecute(FeaturesService featuresService) throws Exception {
+    	URI uri = null;
+    	for (Repository r : featuresService.listRepositories()) {
+    		if (r.getName() != null && r.getName().equals(repository)) {
+    			uri = r.getURI();
+    			break;
+    		}
+    	}
+
+    	if (uri == null) {
+    	    uri = new URI(repository);
+    	}
+
+    	featuresService.removeRepository(uri, uninstall);
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/UninstallFeatureCommand.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/UninstallFeatureCommand.java b/features/command/src/main/java/org/apache/karaf/features/command/UninstallFeatureCommand.java
new file mode 100644
index 0000000..e62f697
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/UninstallFeatureCommand.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.command;
+
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.List;
+
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.command.completers.RequiredFeatureCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "feature", name = "uninstall", description = "Uninstalls a feature with the specified name and version.")
+@Service
+public class UninstallFeatureCommand extends FeaturesCommandSupport {
+
+    @Argument(index = 0, name = "features", description = "The name and version of the features to uninstall. A feature id looks like name/version. The version is optional.", required = true, multiValued = true)
+    @Completion(RequiredFeatureCompleter.class)
+    List<String> features;
+
+    @Option(name = "-r", aliases = "--no-auto-refresh", description = "Do not automatically refresh bundles", required = false, multiValued = false)
+    boolean noRefresh;
+
+    @Option(name = "-v", aliases = "--verbose", description = "Explain what is being done", required = false, multiValued = false)
+    boolean verbose;
+
+    @Option(name = "-t", aliases = "--simulate", description = "Perform a simulation only", required = false, multiValued = false)
+    boolean simulate;
+
+    protected void doExecute(FeaturesService admin) throws Exception {
+        // iterate in the provided feature
+        EnumSet<FeaturesService.Option> options = EnumSet.noneOf(FeaturesService.Option.class);
+        if (simulate) {
+            options.add(FeaturesService.Option.Simulate);
+        }
+        if (noRefresh) {
+            options.add(FeaturesService.Option.NoAutoRefreshBundles);
+        }
+        if (verbose) {
+            options.add(FeaturesService.Option.Verbose);
+        }
+        admin.uninstallFeatures(new HashSet<String>(features), options);
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/completers/AllFeatureCompleter.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/completers/AllFeatureCompleter.java b/features/command/src/main/java/org/apache/karaf/features/command/completers/AllFeatureCompleter.java
new file mode 100644
index 0000000..7444b95
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/completers/AllFeatureCompleter.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.karaf.features.command.completers;
+
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+/**
+ * {@link org.apache.karaf.shell.console.Completer} for available features.
+ */
+@Service
+public class AllFeatureCompleter extends FeatureCompleterSupport {
+
+    @Override
+    protected boolean acceptsFeature(Feature feature) {
+        return true;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/completers/AvailableFeatureCompleter.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/completers/AvailableFeatureCompleter.java b/features/command/src/main/java/org/apache/karaf/features/command/completers/AvailableFeatureCompleter.java
new file mode 100644
index 0000000..79cd280
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/completers/AvailableFeatureCompleter.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.karaf.features.command.completers;
+
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+/**
+ * {@link org.apache.karaf.shell.console.Completer} for features not installed yet.
+ */
+@Service
+public class AvailableFeatureCompleter extends FeatureCompleterSupport {
+
+    @Override
+    protected boolean acceptsFeature(Feature feature) {
+        return !featuresService.isInstalled(feature);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/completers/AvailableRepoNameCompleter.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/completers/AvailableRepoNameCompleter.java b/features/command/src/main/java/org/apache/karaf/features/command/completers/AvailableRepoNameCompleter.java
new file mode 100644
index 0000000..acefe77
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/completers/AvailableRepoNameCompleter.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.karaf.features.command.completers;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.completers.StringsCompleter;
+
+/**
+ * Shows the list of feature repos that can be installed with their short name
+ */
+@Service
+public class AvailableRepoNameCompleter implements Completer {
+
+    @Reference
+    private FeaturesService featuresService;
+
+    public void setFeaturesService(FeaturesService featuresService) {
+        this.featuresService = featuresService;
+    }
+
+    public int complete(Session session, CommandLine commandLine, final List<String> candidates) {
+        StringsCompleter delegate = new StringsCompleter(Arrays.asList(featuresService.getRepositoryNames()));
+        return delegate.complete(session, commandLine, candidates);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/completers/FeatureCompleterSupport.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/completers/FeatureCompleterSupport.java b/features/command/src/main/java/org/apache/karaf/features/command/completers/FeatureCompleterSupport.java
new file mode 100644
index 0000000..d01e5af
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/completers/FeatureCompleterSupport.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.command.completers;
+
+import java.util.List;
+
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.completers.StringsCompleter;
+
+/**
+ * Base completer for feature commands.
+ */
+public abstract class FeatureCompleterSupport implements Completer {
+
+    /**
+     * Feature service.
+     */
+    @Reference
+    protected FeaturesService featuresService;
+
+    public void setFeaturesService(FeaturesService featuresService) {
+        this.featuresService = featuresService;
+    }
+
+    public int complete(Session session, final CommandLine commandLine, final List<String> candidates) {
+        StringsCompleter delegate = new StringsCompleter();
+        try {
+            for (Feature feature : featuresService.listFeatures()) {
+                if (acceptsFeature(feature)) {
+                    delegate.getStrings().add(feature.getName());
+                }
+            }
+        } catch (Exception e) {
+            // Ignore
+        }
+        return delegate.complete(session, commandLine, candidates);
+    }
+
+    /**
+     * Method for filtering features.
+     *
+     * @param feature The feature.
+     * @return True if feature should be available in completer.
+     */
+    protected abstract boolean acceptsFeature(Feature feature);
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoNameCompleter.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoNameCompleter.java b/features/command/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoNameCompleter.java
new file mode 100644
index 0000000..94e4cf7
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoNameCompleter.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.karaf.features.command.completers;
+
+import java.util.List;
+
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.Repository;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.completers.StringsCompleter;
+
+/**
+ * {@link Completer} for Feature Repository URLs.
+ *
+ * Displays a list of currently installed Feature repositories.
+ *
+ */
+@Service
+public class InstalledRepoNameCompleter implements Completer {
+
+    @Reference
+    private FeaturesService featuresService;
+
+    public void setFeaturesService(FeaturesService featuresService) {
+        this.featuresService = featuresService;
+    }
+
+    public int complete(Session session, final CommandLine commandLine, final List<String> candidates) {
+        StringsCompleter delegate = new StringsCompleter();
+        try {
+            for (Repository repository : featuresService.listRepositories()) {
+                delegate.getStrings().add(repository.getName());
+            }
+        } catch (Exception e) {
+            // Ignore
+        }
+        return delegate.complete(session, commandLine, candidates);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoUriCompleter.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoUriCompleter.java b/features/command/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoUriCompleter.java
new file mode 100644
index 0000000..7a760c2
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoUriCompleter.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.karaf.features.command.completers;
+
+import java.util.List;
+
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.Repository;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.completers.StringsCompleter;
+
+/**
+ * {@link Completer} for Feature Repository URLs.
+ *
+ * Displays a list of currently installed Feature repositories.
+ *
+ */
+
+@Service
+public class InstalledRepoUriCompleter implements Completer {
+
+    @Reference
+    private FeaturesService featuresService;
+
+    public void setFeaturesService(FeaturesService featuresService) {
+        this.featuresService = featuresService;
+    }
+
+    public int complete(Session session, final CommandLine commandLine, final List<String> candidates) {
+        StringsCompleter delegate = new StringsCompleter();
+        try {
+            for (Repository repository : featuresService.listRepositories()) {
+                delegate.getStrings().add(repository.getURI().toString());
+            }
+        } catch (Exception e) {
+            // Ignore
+        }
+        return delegate.complete(session, commandLine, candidates);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/completers/RequiredFeatureCompleter.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/completers/RequiredFeatureCompleter.java b/features/command/src/main/java/org/apache/karaf/features/command/completers/RequiredFeatureCompleter.java
new file mode 100644
index 0000000..a51f75f
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/completers/RequiredFeatureCompleter.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.karaf.features.command.completers;
+
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+/**
+ * {@link org.apache.karaf.shell.console.Completer} for installed features.
+ */
+@Service
+public class RequiredFeatureCompleter extends FeatureCompleterSupport {
+
+    @Override
+    protected boolean acceptsFeature(Feature feature) {
+        return featuresService.isRequired(feature);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/resources/OSGI-INF/bundle.info
----------------------------------------------------------------------
diff --git a/features/command/src/main/resources/OSGI-INF/bundle.info b/features/command/src/main/resources/OSGI-INF/bundle.info
new file mode 100644
index 0000000..8f0598b
--- /dev/null
+++ b/features/command/src/main/resources/OSGI-INF/bundle.info
@@ -0,0 +1,30 @@
+h1. Synopsis
+
+${project.name}
+
+${project.description}
+
+Maven URL:
+[mvn:${project.groupId}/${project.artifactId}/${project.version}]
+
+h1. Description
+
+This bundle provides the Karaf shell commands to manipulate features.
+
+The following commands are available:
+
+* features:addUrl - Adds a list of repository URLs to the features service.
+* features:info- Shows information about selected information.
+* features:install- Installs a feature with the specified name and version.
+* features:list - Lists all existing features available from the defined repositories.
+* features:listVersions- Lists all versions of a feature available from the currently available repositories.
+* features:listRepositories- Displays a list of all defined repositories.
+* features:listUrl- Displays a list of all defined repository URLs.
+* features:refreshUrl- Reloads the list of available features from the repositories.
+* features:removeRepository- Removes the specified repository features service.
+* features:removeUrl- Removes the given list of repository URLs from the features service.
+* features:uninstall- Uninstalls a feature with the specified name and version.
+
+h1. See also
+
+Commands- and Provisioning- sections of the Karaf User Guide.

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/NOTICE
----------------------------------------------------------------------
diff --git a/features/core/NOTICE b/features/core/NOTICE
new file mode 100644
index 0000000..b70f1f9
--- /dev/null
+++ b/features/core/NOTICE
@@ -0,0 +1,71 @@
+Apache Karaf
+Copyright 2010-2014 The Apache Software Foundation
+
+
+I. Included Software
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2010).
+Licensed under the Apache License 2.0.
+
+This product includes software developed at
+OW2 (http://www.ow2.org/).
+Licensed under the BSD License.
+
+This product includes software developed at
+OPS4J (http://www.ops4j.org/).
+Licensed under the Apache License 2.0.
+
+This product includes software developed at
+Eclipse Foundation (http://www.eclipse.org/).
+Licensed under the EPL.
+
+This product includes software written by
+Antony Lesuisse.
+Licensed under Public Domain.
+
+
+II. Used Software
+
+This product uses software developed at
+FUSE Source (http://www.fusesource.org/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+AOP Alliance (http://aopalliance.sourceforge.net/).
+Licensed under the Public Domain.
+
+This product uses software developed at
+Tanuki Software (http://www.tanukisoftware.com/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+Jasypt (http://jasypt.sourceforge.net/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+JLine (http://jline.sourceforge.net).
+Licensed under the BSD License.
+
+This product uses software developed at
+SLF4J (http://www.slf4j.org/).
+Licensed under the MIT License.
+
+This product uses software developed at
+SpringSource (http://www.springsource.org/).
+Licensed under the Apache License 2.0.
+
+This product includes software from http://www.json.org.
+Copyright (c) 2002 JSON.org
+
+
+III. License Summary
+- Apache License 2.0
+- BSD License
+- EPL License
+- MIT License


[08/33] git commit: [KARAF-2852] Merge jms/core and jms/command

Posted by gn...@apache.org.
[KARAF-2852] Merge jms/core and jms/command


Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/0f53437c
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/0f53437c
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/0f53437c

Branch: refs/heads/master
Commit: 0f53437c5c7d7370ceeb2e075f340f3d647bc5a7
Parents: 53996d9
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Fri Apr 11 08:21:15 2014 +0200
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Fri Apr 11 19:20:02 2014 +0200

----------------------------------------------------------------------
 .../enterprise/src/main/feature/feature.xml     |   1 -
 jms/NOTICE                                      |  71 +++++
 jms/command/NOTICE                              |  71 -----
 jms/command/pom.xml                             |  86 ------
 .../apache/karaf/jms/command/BrowseCommand.java | 104 -------
 .../jms/command/ConnectionFactoriesCommand.java |  45 ---
 .../karaf/jms/command/ConsumeCommand.java       |  40 ---
 .../apache/karaf/jms/command/CountCommand.java  |  41 ---
 .../apache/karaf/jms/command/CreateCommand.java |  46 ---
 .../apache/karaf/jms/command/DeleteCommand.java |  40 ---
 .../apache/karaf/jms/command/InfoCommand.java   |  46 ---
 .../karaf/jms/command/JmsCommandSupport.java    |  36 ---
 .../command/JmsConnectionCommandSupport.java    |  39 ---
 .../apache/karaf/jms/command/MoveCommand.java   |  44 ---
 .../apache/karaf/jms/command/QueuesCommand.java |  43 ---
 .../apache/karaf/jms/command/SendCommand.java   |  44 ---
 .../apache/karaf/jms/command/TopicsCommand.java |  43 ---
 .../ConnectionFactoriesFileNameCompleter.java   |  59 ----
 .../ConnectionFactoriesNameCompleter.java       |  59 ----
 .../src/main/resources/OSGI-INF/bundle.info     |  29 --
 jms/core/NOTICE                                 |  71 -----
 jms/core/pom.xml                                | 102 -------
 .../java/org/apache/karaf/jms/JmsMBean.java     | 153 ----------
 .../java/org/apache/karaf/jms/JmsMessage.java   | 164 ----------
 .../java/org/apache/karaf/jms/JmsService.java   | 159 ----------
 .../apache/karaf/jms/internal/JmsConnector.java |  99 ------
 .../apache/karaf/jms/internal/JmsMBeanImpl.java | 155 ----------
 .../karaf/jms/internal/JmsServiceImpl.java      | 300 -------------------
 .../resources/OSGI-INF/blueprint/jms-core.xml   |  41 ---
 .../src/main/resources/OSGI-INF/bundle.info     |  18 --
 .../jms/internal/connectionfactory-activemq.xml |  44 ---
 .../internal/connectionfactory-webspheremq.xml  |  36 ---
 jms/pom.xml                                     |  86 +++++-
 .../java/org/apache/karaf/jms/JmsMBean.java     | 153 ++++++++++
 .../java/org/apache/karaf/jms/JmsMessage.java   | 164 ++++++++++
 .../java/org/apache/karaf/jms/JmsService.java   | 159 ++++++++++
 .../apache/karaf/jms/command/BrowseCommand.java | 104 +++++++
 .../jms/command/ConnectionFactoriesCommand.java |  45 +++
 .../karaf/jms/command/ConsumeCommand.java       |  40 +++
 .../apache/karaf/jms/command/CountCommand.java  |  41 +++
 .../apache/karaf/jms/command/CreateCommand.java |  46 +++
 .../apache/karaf/jms/command/DeleteCommand.java |  40 +++
 .../apache/karaf/jms/command/InfoCommand.java   |  46 +++
 .../karaf/jms/command/JmsCommandSupport.java    |  36 +++
 .../command/JmsConnectionCommandSupport.java    |  39 +++
 .../apache/karaf/jms/command/MoveCommand.java   |  44 +++
 .../apache/karaf/jms/command/QueuesCommand.java |  43 +++
 .../apache/karaf/jms/command/SendCommand.java   |  44 +++
 .../apache/karaf/jms/command/TopicsCommand.java |  43 +++
 .../ConnectionFactoriesFileNameCompleter.java   |  59 ++++
 .../ConnectionFactoriesNameCompleter.java       |  59 ++++
 .../apache/karaf/jms/internal/JmsConnector.java |  99 ++++++
 .../apache/karaf/jms/internal/JmsMBeanImpl.java | 155 ++++++++++
 .../karaf/jms/internal/JmsServiceImpl.java      | 300 +++++++++++++++++++
 .../resources/OSGI-INF/blueprint/jms-core.xml   |  41 +++
 jms/src/main/resources/OSGI-INF/bundle.info     |  18 ++
 .../jms/internal/connectionfactory-activemq.xml |  44 +++
 .../internal/connectionfactory-webspheremq.xml  |  36 +++
 58 files changed, 2047 insertions(+), 2266 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/assemblies/features/enterprise/src/main/feature/feature.xml
----------------------------------------------------------------------
diff --git a/assemblies/features/enterprise/src/main/feature/feature.xml b/assemblies/features/enterprise/src/main/feature/feature.xml
index 0a57038..c68017f 100644
--- a/assemblies/features/enterprise/src/main/feature/feature.xml
+++ b/assemblies/features/enterprise/src/main/feature/feature.xml
@@ -199,7 +199,6 @@
         <feature>aries-blueprint</feature>
         <bundle>mvn:org.apache.geronimo.specs/geronimo-jms_1.1_spec/${geronimo.jms-spec.version}</bundle>
         <bundle>mvn:org.apache.karaf.jms/org.apache.karaf.jms.core/${project.version}</bundle>
-        <bundle>mvn:org.apache.karaf.jms/org.apache.karaf.jms.command/${project.version}</bundle>
     </feature>
 
     <feature name="openwebbeans" description="Apache OpenWebBeans CDI container support" version="${openwebbeans.version}" resolver="(obr)">

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/NOTICE
----------------------------------------------------------------------
diff --git a/jms/NOTICE b/jms/NOTICE
new file mode 100644
index 0000000..b70f1f9
--- /dev/null
+++ b/jms/NOTICE
@@ -0,0 +1,71 @@
+Apache Karaf
+Copyright 2010-2014 The Apache Software Foundation
+
+
+I. Included Software
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2010).
+Licensed under the Apache License 2.0.
+
+This product includes software developed at
+OW2 (http://www.ow2.org/).
+Licensed under the BSD License.
+
+This product includes software developed at
+OPS4J (http://www.ops4j.org/).
+Licensed under the Apache License 2.0.
+
+This product includes software developed at
+Eclipse Foundation (http://www.eclipse.org/).
+Licensed under the EPL.
+
+This product includes software written by
+Antony Lesuisse.
+Licensed under Public Domain.
+
+
+II. Used Software
+
+This product uses software developed at
+FUSE Source (http://www.fusesource.org/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+AOP Alliance (http://aopalliance.sourceforge.net/).
+Licensed under the Public Domain.
+
+This product uses software developed at
+Tanuki Software (http://www.tanukisoftware.com/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+Jasypt (http://jasypt.sourceforge.net/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+JLine (http://jline.sourceforge.net).
+Licensed under the BSD License.
+
+This product uses software developed at
+SLF4J (http://www.slf4j.org/).
+Licensed under the MIT License.
+
+This product uses software developed at
+SpringSource (http://www.springsource.org/).
+Licensed under the Apache License 2.0.
+
+This product includes software from http://www.json.org.
+Copyright (c) 2002 JSON.org
+
+
+III. License Summary
+- Apache License 2.0
+- BSD License
+- EPL License
+- MIT License

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/command/NOTICE
----------------------------------------------------------------------
diff --git a/jms/command/NOTICE b/jms/command/NOTICE
deleted file mode 100644
index b70f1f9..0000000
--- a/jms/command/NOTICE
+++ /dev/null
@@ -1,71 +0,0 @@
-Apache Karaf
-Copyright 2010-2014 The Apache Software Foundation
-
-
-I. Included Software
-
-This product includes software developed at
-The Apache Software Foundation (http://www.apache.org/).
-Licensed under the Apache License 2.0.
-
-This product uses software developed at
-The OSGi Alliance (http://www.osgi.org/).
-Copyright (c) OSGi Alliance (2000, 2010).
-Licensed under the Apache License 2.0.
-
-This product includes software developed at
-OW2 (http://www.ow2.org/).
-Licensed under the BSD License.
-
-This product includes software developed at
-OPS4J (http://www.ops4j.org/).
-Licensed under the Apache License 2.0.
-
-This product includes software developed at
-Eclipse Foundation (http://www.eclipse.org/).
-Licensed under the EPL.
-
-This product includes software written by
-Antony Lesuisse.
-Licensed under Public Domain.
-
-
-II. Used Software
-
-This product uses software developed at
-FUSE Source (http://www.fusesource.org/).
-Licensed under the Apache License 2.0.
-
-This product uses software developed at
-AOP Alliance (http://aopalliance.sourceforge.net/).
-Licensed under the Public Domain.
-
-This product uses software developed at
-Tanuki Software (http://www.tanukisoftware.com/).
-Licensed under the Apache License 2.0.
-
-This product uses software developed at
-Jasypt (http://jasypt.sourceforge.net/).
-Licensed under the Apache License 2.0.
-
-This product uses software developed at
-JLine (http://jline.sourceforge.net).
-Licensed under the BSD License.
-
-This product uses software developed at
-SLF4J (http://www.slf4j.org/).
-Licensed under the MIT License.
-
-This product uses software developed at
-SpringSource (http://www.springsource.org/).
-Licensed under the Apache License 2.0.
-
-This product includes software from http://www.json.org.
-Copyright (c) 2002 JSON.org
-
-
-III. License Summary
-- Apache License 2.0
-- BSD License
-- EPL License
-- MIT License

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/command/pom.xml
----------------------------------------------------------------------
diff --git a/jms/command/pom.xml b/jms/command/pom.xml
deleted file mode 100644
index 55eb54b..0000000
--- a/jms/command/pom.xml
+++ /dev/null
@@ -1,86 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-
-    <!--
-
-        Licensed to the Apache Software Foundation (ASF) under one or more
-        contributor license agreements.  See the NOTICE file distributed with
-        this work for additional information regarding copyright ownership.
-        The ASF licenses this file to You under the Apache License, Version 2.0
-        (the "License"); you may not use this file except in compliance with
-        the License.  You may obtain a copy of the License at
-
-            http://www.apache.org/licenses/LICENSE-2.0
-
-        Unless required by applicable law or agreed to in writing, software
-        distributed under the License is distributed on an "AS IS" BASIS,
-        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-        See the License for the specific language governing permissions and
-        limitations under the License.
-    -->
-
-    <modelVersion>4.0.0</modelVersion>
-
-    <parent>
-        <groupId>org.apache.karaf.jms</groupId>
-        <artifactId>jms</artifactId>
-        <version>4.0.0-SNAPSHOT</version>
-        <relativePath>../pom.xml</relativePath>
-    </parent>
-
-    <artifactId>org.apache.karaf.jms.command</artifactId>
-    <packaging>bundle</packaging>
-    <name>Apache Karaf :: JMS :: Command</name>
-    <description>This bundle provides shell commands to manipulate the JMS server.</description>
-
-    <properties>
-        <appendedResourcesDirectory>${basedir}/../../etc/appended-resources</appendedResourcesDirectory>
-    </properties>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.core</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.karaf.jms</groupId>
-            <artifactId>org.apache.karaf.jms.core</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.karaf.shell</groupId>
-            <artifactId>org.apache.karaf.shell.core</artifactId>
-        </dependency>
-    </dependencies>
-
-    <build>
-        <resources>
-            <resource>
-                <directory>${project.basedir}/src/main/resources</directory>
-                <includes>
-                    <include>**/*</include>
-                </includes>
-            </resource>
-            <resource>
-                <directory>${project.basedir}/src/main/resources</directory>
-                <filtering>true</filtering>
-                <includes>
-                    <include>**/*.info</include>
-                </includes>
-            </resource>
-        </resources>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-bundle-plugin</artifactId>
-                <configuration>
-                    <instructions>
-                        <Export-Package>!*</Export-Package>
-                        <Karaf-Commands>*</Karaf-Commands>
-                    </instructions>
-                </configuration>
-            </plugin>
-        </plugins>
-    </build>
-
-</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/command/src/main/java/org/apache/karaf/jms/command/BrowseCommand.java
----------------------------------------------------------------------
diff --git a/jms/command/src/main/java/org/apache/karaf/jms/command/BrowseCommand.java b/jms/command/src/main/java/org/apache/karaf/jms/command/BrowseCommand.java
deleted file mode 100644
index cb86aa6..0000000
--- a/jms/command/src/main/java/org/apache/karaf/jms/command/BrowseCommand.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jms.command;
-
-import java.util.List;
-
-import org.apache.karaf.jms.JmsMessage;
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.Option;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.karaf.shell.support.table.ShellTable;
-
-@Command(scope = "jms", name = "browse", description = "Browse a JMS queue")
-@Service
-public class BrowseCommand extends JmsConnectionCommandSupport {
-
-    @Argument(index = 1, name = "queue", description = "The JMS queue to browse", required = true, multiValued = false)
-    String queue;
-
-    @Option(name = "-s", aliases = { "--selector" }, description = "The selector to select the messages to browse", required = false, multiValued = false)
-    String selector;
-
-    @Option(name = "-v", aliases = { "--verbose" }, description = "Display JMS properties", required = false, multiValued = false)
-    boolean verbose = false;
-
-    @Override
-    public Object execute() throws Exception {
-
-        ShellTable table = new ShellTable();
-        table.column("Message ID");
-        table.column("Content").maxSize(80);
-        table.column("Charset");
-        table.column("Type");
-        table.column("Correlation ID");
-        table.column("Delivery Mode");
-        table.column("Destination");
-        table.column("Expiration");
-        table.column("Priority");
-        table.column("Redelivered");
-        table.column("ReplyTo");
-        table.column("Timestamp");
-        if (verbose) {
-            table.column("Properties");
-        }
-
-        List<JmsMessage> messages = getJmsService().browse(connectionFactory, queue, selector, username, password);
-        for (JmsMessage message : messages) {
-            if (verbose) {
-                StringBuilder properties = new StringBuilder();
-                for (String property : message.getProperties().keySet()) {
-                    properties.append(property).append("=").append(message.getProperties().get(property)).append("\n");
-                }
-                table.addRow().addContent(
-                        message.getMessageId(),
-                        message.getContent(),
-                        message.getCharset(),
-                        message.getType(),
-                        message.getCorrelationID(),
-                        message.getDeliveryMode(),
-                        message.getDestination(),
-                        message.getExpiration(),
-                        message.getPriority(),
-                        message.isRedelivered(),
-                        message.getReplyTo(),
-                        message.getTimestamp(),
-                        properties.toString());
-            } else {
-                table.addRow().addContent(
-                        message.getMessageId(),
-                        message.getContent(),
-                        message.getCharset(),
-                        message.getType(),
-                        message.getCorrelationID(),
-                        message.getDeliveryMode(),
-                        message.getDestination(),
-                        message.getExpiration(),
-                        message.getPriority(),
-                        message.isRedelivered(),
-                        message.getReplyTo(),
-                        message.getTimestamp());
-            }
-        }
-
-        table.print(System.out);
-
-        return null;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/command/src/main/java/org/apache/karaf/jms/command/ConnectionFactoriesCommand.java
----------------------------------------------------------------------
diff --git a/jms/command/src/main/java/org/apache/karaf/jms/command/ConnectionFactoriesCommand.java b/jms/command/src/main/java/org/apache/karaf/jms/command/ConnectionFactoriesCommand.java
deleted file mode 100644
index b698336..0000000
--- a/jms/command/src/main/java/org/apache/karaf/jms/command/ConnectionFactoriesCommand.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jms.command;
-
-import java.util.List;
-
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.karaf.shell.support.table.ShellTable;
-
-@Command(scope = "jms", name = "connectionfactories", description = "List the JMS connection factories")
-@Service
-public class ConnectionFactoriesCommand extends JmsCommandSupport {
-
-    @Override
-    public Object execute() throws Exception {
-
-        ShellTable table = new ShellTable();
-        table.column("JMS Connection Factory");
-
-        List<String> connectionFactories = getJmsService().connectionFactories();
-        for (String connectionFactory : connectionFactories) {
-            table.addRow().addContent(connectionFactory);
-        }
-
-        table.print(System.out);
-
-        return null;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/command/src/main/java/org/apache/karaf/jms/command/ConsumeCommand.java
----------------------------------------------------------------------
diff --git a/jms/command/src/main/java/org/apache/karaf/jms/command/ConsumeCommand.java b/jms/command/src/main/java/org/apache/karaf/jms/command/ConsumeCommand.java
deleted file mode 100644
index cd8caaf..0000000
--- a/jms/command/src/main/java/org/apache/karaf/jms/command/ConsumeCommand.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jms.command;
-
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.Option;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-
-@Command(scope = "jms", name = "consume", description = "Consume messages from a JMS queue.")
-@Service
-public class ConsumeCommand extends JmsConnectionCommandSupport {
-
-    @Argument(index = 1, name = "queue", description = "The JMS queue where to consume messages", required = true, multiValued = false)
-    String queue;
-
-    @Option(name = "-s", aliases = { "--selector" }, description = "The selector to use to select the messages to consume", required = false, multiValued = false)
-    String selector;
-
-    @Override
-    public Object execute() throws Exception {
-        System.out.println(getJmsService().consume(connectionFactory, queue, selector, username, password) + " message(s) consumed");
-        return null;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/command/src/main/java/org/apache/karaf/jms/command/CountCommand.java
----------------------------------------------------------------------
diff --git a/jms/command/src/main/java/org/apache/karaf/jms/command/CountCommand.java b/jms/command/src/main/java/org/apache/karaf/jms/command/CountCommand.java
deleted file mode 100644
index 576e8dd..0000000
--- a/jms/command/src/main/java/org/apache/karaf/jms/command/CountCommand.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jms.command;
-
-
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.karaf.shell.support.table.ShellTable;
-
-@Command(scope = "jms", name = "count", description = "Count the number of messages on a JMS queue.")
-@Service
-public class CountCommand extends JmsConnectionCommandSupport {
-
-    @Argument(index = 1, name = "queue", description = "The JMS queue name", required = true, multiValued = false)
-    String queue;
-
-    @Override
-    public Object execute() throws Exception {
-        ShellTable table = new ShellTable();
-        table.column("Messages Count");
-        table.addRow().addContent(getJmsService().count(connectionFactory, queue, username, password));
-        table.print(System.out);
-        return null;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/command/src/main/java/org/apache/karaf/jms/command/CreateCommand.java
----------------------------------------------------------------------
diff --git a/jms/command/src/main/java/org/apache/karaf/jms/command/CreateCommand.java b/jms/command/src/main/java/org/apache/karaf/jms/command/CreateCommand.java
deleted file mode 100644
index c2c7eca..0000000
--- a/jms/command/src/main/java/org/apache/karaf/jms/command/CreateCommand.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jms.command;
-
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.Completion;
-import org.apache.karaf.shell.api.action.Option;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.karaf.shell.support.completers.StringsCompleter;
-
-@Command(scope = "jms", name = "create", description = "Create a JMS connection factory.")
-@Service
-public class CreateCommand extends JmsCommandSupport {
-
-    @Argument(index = 0, name = "name", description = "The JMS connection factory name", required = true, multiValued = false)
-    String name;
-
-    @Option(name = "-t", aliases = { "--type" }, description = "The JMS connection factory type (ActiveMQ or WebsphereMQ)", required = false, multiValued = false)
-    @Completion(value = StringsCompleter.class, values = { "activemq", "webspheremq" })
-    String type = "ActiveMQ";
-
-    @Option(name = "--url", description = "URL of the JMS broker. For WebsphereMQ type, the URL is hostname/port/queuemanager/channel", required = false, multiValued = false)
-    String url = "tcp://localhost:61616";
-
-    @Override
-    public Object execute() throws Exception {
-        getJmsService().create(name, type, url);
-        return null;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/command/src/main/java/org/apache/karaf/jms/command/DeleteCommand.java
----------------------------------------------------------------------
diff --git a/jms/command/src/main/java/org/apache/karaf/jms/command/DeleteCommand.java b/jms/command/src/main/java/org/apache/karaf/jms/command/DeleteCommand.java
deleted file mode 100644
index cab3123..0000000
--- a/jms/command/src/main/java/org/apache/karaf/jms/command/DeleteCommand.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jms.command;
-
-
-import org.apache.karaf.jms.command.completers.ConnectionFactoriesFileNameCompleter;
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.Completion;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-
-@Command(scope = "jms", name = "delete", description = "Delete a JMS connection factory")
-@Service
-public class DeleteCommand extends JmsCommandSupport {
-
-    @Argument(index = 0, name = "name", description = "The JMS connection factory name", required = true, multiValued = false)
-    @Completion(ConnectionFactoriesFileNameCompleter.class)
-    String name;
-
-    @Override
-    public Object execute() throws Exception {
-        getJmsService().delete(name);
-        return null;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/command/src/main/java/org/apache/karaf/jms/command/InfoCommand.java
----------------------------------------------------------------------
diff --git a/jms/command/src/main/java/org/apache/karaf/jms/command/InfoCommand.java b/jms/command/src/main/java/org/apache/karaf/jms/command/InfoCommand.java
deleted file mode 100644
index 354db39..0000000
--- a/jms/command/src/main/java/org/apache/karaf/jms/command/InfoCommand.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jms.command;
-
-
-import java.util.Map;
-
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.karaf.shell.support.table.ShellTable;
-
-@Command(scope = "jms", name = "info", description = "Provides details about a JMS connection factory.")
-@Service
-public class InfoCommand extends JmsConnectionCommandSupport {
-
-    @Override
-    public Object execute() throws Exception {
-        ShellTable table = new ShellTable();
-        table.column("Property");
-        table.column("Value");
-
-        Map<String, String> info = getJmsService().info(connectionFactory, username, password);
-        for (String key : info.keySet()) {
-            table.addRow().addContent(key, info.get(key));
-        }
-
-        table.print(System.out);
-
-        return null;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/command/src/main/java/org/apache/karaf/jms/command/JmsCommandSupport.java
----------------------------------------------------------------------
diff --git a/jms/command/src/main/java/org/apache/karaf/jms/command/JmsCommandSupport.java b/jms/command/src/main/java/org/apache/karaf/jms/command/JmsCommandSupport.java
deleted file mode 100644
index 2f5df8f..0000000
--- a/jms/command/src/main/java/org/apache/karaf/jms/command/JmsCommandSupport.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jms.command;
-
-import org.apache.karaf.jms.JmsService;
-import org.apache.karaf.shell.api.action.Action;
-import org.apache.karaf.shell.api.action.lifecycle.Reference;
-
-public abstract class JmsCommandSupport implements Action {
-
-    @Reference
-    private JmsService jmsService;
-
-    public JmsService getJmsService() {
-        return jmsService;
-    }
-
-    public void setJmsService(JmsService jmsService) {
-        this.jmsService = jmsService;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/command/src/main/java/org/apache/karaf/jms/command/JmsConnectionCommandSupport.java
----------------------------------------------------------------------
diff --git a/jms/command/src/main/java/org/apache/karaf/jms/command/JmsConnectionCommandSupport.java b/jms/command/src/main/java/org/apache/karaf/jms/command/JmsConnectionCommandSupport.java
deleted file mode 100644
index 64adfe4..0000000
--- a/jms/command/src/main/java/org/apache/karaf/jms/command/JmsConnectionCommandSupport.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jms.command;
-
-import org.apache.karaf.jms.command.completers.ConnectionFactoriesNameCompleter;
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Completion;
-import org.apache.karaf.shell.api.action.Option;
-
-/**
- * For commands that need a connection factory and authentication information 
- */
-public abstract class JmsConnectionCommandSupport extends JmsCommandSupport {
-
-    @Argument(index = 0, name = "connectionFactory", description = "The JMS connection factory name", required = true, multiValued = false)
-    @Completion(ConnectionFactoriesNameCompleter.class)
-    String connectionFactory;
-
-    @Option(name = "-u", aliases = { "--username" }, description = "Username to connect to the JMS broker", required = false, multiValued = false)
-    String username = "karaf";
-
-    @Option(name = "-p", aliases = { "--password" }, description = "Password to connect to the JMS broker", required = false, multiValued = false)
-    String password = "karaf";
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/command/src/main/java/org/apache/karaf/jms/command/MoveCommand.java
----------------------------------------------------------------------
diff --git a/jms/command/src/main/java/org/apache/karaf/jms/command/MoveCommand.java b/jms/command/src/main/java/org/apache/karaf/jms/command/MoveCommand.java
deleted file mode 100644
index a4c8d12..0000000
--- a/jms/command/src/main/java/org/apache/karaf/jms/command/MoveCommand.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jms.command;
-
-
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.Option;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-
-@Command(scope = "jms", name = "move", description = "Move messages from one JMS queue to another one.")
-@Service
-public class MoveCommand extends JmsConnectionCommandSupport {
-
-    @Argument(index = 1, name = "source", description = "The source JMS queue", required = true, multiValued = false)
-    String source;
-
-    @Argument(index = 2, name = "destination", description = "The destination JMS queue", required = true, multiValued = false)
-    String destination;
-
-    @Option(name = "-s", aliases = { "--selector" }, description = "Selector to move only some messages", required = false, multiValued = false)
-    String selector;
-
-    @Override
-    public Object execute() throws Exception {
-        System.out.println(getJmsService().move(connectionFactory, source, destination, selector, username, password) + " message(s) moved");
-        return null;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/command/src/main/java/org/apache/karaf/jms/command/QueuesCommand.java
----------------------------------------------------------------------
diff --git a/jms/command/src/main/java/org/apache/karaf/jms/command/QueuesCommand.java b/jms/command/src/main/java/org/apache/karaf/jms/command/QueuesCommand.java
deleted file mode 100644
index 7cf1dac..0000000
--- a/jms/command/src/main/java/org/apache/karaf/jms/command/QueuesCommand.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jms.command;
-
-
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.karaf.shell.support.table.ShellTable;
-
-@Command(scope = "jms", name = "queues", description = "List the JMS queues.")
-@Service
-public class QueuesCommand extends JmsConnectionCommandSupport {
-
-    @Override
-    public Object execute() throws Exception {
-        ShellTable table = new ShellTable();
-
-        table.column("JMS Queues");
-
-        for (String queue : getJmsService().queues(connectionFactory, username, password)) {
-            table.addRow().addContent(queue);
-        }
-
-        table.print(System.out);
-
-        return null;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/command/src/main/java/org/apache/karaf/jms/command/SendCommand.java
----------------------------------------------------------------------
diff --git a/jms/command/src/main/java/org/apache/karaf/jms/command/SendCommand.java b/jms/command/src/main/java/org/apache/karaf/jms/command/SendCommand.java
deleted file mode 100644
index 63d3f4a..0000000
--- a/jms/command/src/main/java/org/apache/karaf/jms/command/SendCommand.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jms.command;
-
-
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.Option;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-
-@Command(scope = "jms", name = "send", description = "Send a message to ")
-@Service
-public class SendCommand extends JmsConnectionCommandSupport {
-
-    @Argument(index = 1, name = "queue", description = "The JMS queue name", required = true, multiValued = false)
-    String queue;
-
-    @Argument(index = 2, name = "message", description = "The JMS message content", required = true, multiValued = false)
-    String message;
-
-    @Option(name = "-r", aliases = { "--replyTo" }, description = "Set the message ReplyTo", required = false, multiValued = false)
-    String replyTo;
-
-    @Override
-    public Object execute() throws Exception {
-        getJmsService().send(connectionFactory, queue, message, replyTo, username, password);
-        return null;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/command/src/main/java/org/apache/karaf/jms/command/TopicsCommand.java
----------------------------------------------------------------------
diff --git a/jms/command/src/main/java/org/apache/karaf/jms/command/TopicsCommand.java b/jms/command/src/main/java/org/apache/karaf/jms/command/TopicsCommand.java
deleted file mode 100644
index b583bc4..0000000
--- a/jms/command/src/main/java/org/apache/karaf/jms/command/TopicsCommand.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jms.command;
-
-
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.karaf.shell.support.table.ShellTable;
-
-@Command(scope = "jms", name = "topics", description = "List the JMS topics.")
-@Service
-public class TopicsCommand extends JmsConnectionCommandSupport {
-
-    @Override
-    public Object execute() throws Exception {
-        ShellTable table = new ShellTable();
-
-        table.column("JMS Topics");
-
-        for (String topic : getJmsService().topics(connectionFactory, username, password)) {
-            table.addRow().addContent(topic);
-        }
-
-        table.print(System.out);
-
-        return null;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/command/src/main/java/org/apache/karaf/jms/command/completers/ConnectionFactoriesFileNameCompleter.java
----------------------------------------------------------------------
diff --git a/jms/command/src/main/java/org/apache/karaf/jms/command/completers/ConnectionFactoriesFileNameCompleter.java b/jms/command/src/main/java/org/apache/karaf/jms/command/completers/ConnectionFactoriesFileNameCompleter.java
deleted file mode 100644
index c33ff62..0000000
--- a/jms/command/src/main/java/org/apache/karaf/jms/command/completers/ConnectionFactoriesFileNameCompleter.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jms.command.completers;
-
-import java.util.List;
-
-import org.apache.karaf.jms.JmsService;
-import org.apache.karaf.shell.api.action.lifecycle.Reference;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.karaf.shell.api.console.CommandLine;
-import org.apache.karaf.shell.api.console.Completer;
-import org.apache.karaf.shell.api.console.Session;
-import org.apache.karaf.shell.support.completers.StringsCompleter;
-
-/**
- * Completer on the JMS connection factory file names.
- */
-@Service
-public class ConnectionFactoriesFileNameCompleter implements Completer {
-
-    @Reference
-    private JmsService jmsService;
-
-    @Override
-    public int complete(Session session, CommandLine commandLine, List<String> candidates) {
-        StringsCompleter delegate = new StringsCompleter();
-        try {
-            for (String connectionFactory : jmsService.connectionFactoryFileNames()) {
-                delegate.getStrings().add(connectionFactory.replace("connectionfactory-", "").replace(".xml", ""));
-            }
-        } catch (Exception e) {
-            // nothing to do
-        }
-        return delegate.complete(session, commandLine, candidates);
-    }
-
-    public JmsService getJmsService() {
-        return jmsService;
-    }
-
-    public void setJmsService(JmsService jmsService) {
-        this.jmsService = jmsService;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/command/src/main/java/org/apache/karaf/jms/command/completers/ConnectionFactoriesNameCompleter.java
----------------------------------------------------------------------
diff --git a/jms/command/src/main/java/org/apache/karaf/jms/command/completers/ConnectionFactoriesNameCompleter.java b/jms/command/src/main/java/org/apache/karaf/jms/command/completers/ConnectionFactoriesNameCompleter.java
deleted file mode 100644
index 98f97b3..0000000
--- a/jms/command/src/main/java/org/apache/karaf/jms/command/completers/ConnectionFactoriesNameCompleter.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jms.command.completers;
-
-import java.util.List;
-
-import org.apache.karaf.jms.JmsService;
-import org.apache.karaf.shell.api.action.lifecycle.Reference;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.karaf.shell.api.console.CommandLine;
-import org.apache.karaf.shell.api.console.Completer;
-import org.apache.karaf.shell.api.console.Session;
-import org.apache.karaf.shell.support.completers.StringsCompleter;
-
-/**
- * Completer on the JMS connection factories name.
- */
-@Service
-public class ConnectionFactoriesNameCompleter implements Completer {
-
-    @Reference
-    private JmsService jmsService;
-
-    @Override
-    public int complete(Session session, CommandLine commandLine, List<String> candidates) {
-        StringsCompleter delegate = new StringsCompleter();
-        try {
-            for (String connectionFactory : jmsService.connectionFactories()) {
-                delegate.getStrings().add(connectionFactory);
-            }
-        } catch (Exception e) {
-            // nothing to do
-        }
-        return delegate.complete(session, commandLine, candidates);
-    }
-
-    public JmsService getJmsService() {
-        return jmsService;
-    }
-
-    public void setJmsService(JmsService jmsService) {
-        this.jmsService = jmsService;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/command/src/main/resources/OSGI-INF/bundle.info
----------------------------------------------------------------------
diff --git a/jms/command/src/main/resources/OSGI-INF/bundle.info b/jms/command/src/main/resources/OSGI-INF/bundle.info
deleted file mode 100644
index 8b83f13..0000000
--- a/jms/command/src/main/resources/OSGI-INF/bundle.info
+++ /dev/null
@@ -1,29 +0,0 @@
-h1. Synopsis
-
-${project.name}
-
-${project.description}
-
-Maven URL:
-[mvn:${project.groupId}/${project.artifactId}/${project.version}]
-
-h1. Description
-
-This bundle provides the shell commands to manipulate the JMS service.
-
-The following commands are available:
-
-* jms:create
-* jms:delete
-* jms:connectionfactories
-* jms:info
-* jms:count
-* jms:queues
-* jms:topics
-* jms:send
-* jms:consume
-* jms:move
-
-h1. See also
-
-JMS - section of the Karaf User Guide
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/core/NOTICE
----------------------------------------------------------------------
diff --git a/jms/core/NOTICE b/jms/core/NOTICE
deleted file mode 100644
index b70f1f9..0000000
--- a/jms/core/NOTICE
+++ /dev/null
@@ -1,71 +0,0 @@
-Apache Karaf
-Copyright 2010-2014 The Apache Software Foundation
-
-
-I. Included Software
-
-This product includes software developed at
-The Apache Software Foundation (http://www.apache.org/).
-Licensed under the Apache License 2.0.
-
-This product uses software developed at
-The OSGi Alliance (http://www.osgi.org/).
-Copyright (c) OSGi Alliance (2000, 2010).
-Licensed under the Apache License 2.0.
-
-This product includes software developed at
-OW2 (http://www.ow2.org/).
-Licensed under the BSD License.
-
-This product includes software developed at
-OPS4J (http://www.ops4j.org/).
-Licensed under the Apache License 2.0.
-
-This product includes software developed at
-Eclipse Foundation (http://www.eclipse.org/).
-Licensed under the EPL.
-
-This product includes software written by
-Antony Lesuisse.
-Licensed under Public Domain.
-
-
-II. Used Software
-
-This product uses software developed at
-FUSE Source (http://www.fusesource.org/).
-Licensed under the Apache License 2.0.
-
-This product uses software developed at
-AOP Alliance (http://aopalliance.sourceforge.net/).
-Licensed under the Public Domain.
-
-This product uses software developed at
-Tanuki Software (http://www.tanukisoftware.com/).
-Licensed under the Apache License 2.0.
-
-This product uses software developed at
-Jasypt (http://jasypt.sourceforge.net/).
-Licensed under the Apache License 2.0.
-
-This product uses software developed at
-JLine (http://jline.sourceforge.net).
-Licensed under the BSD License.
-
-This product uses software developed at
-SLF4J (http://www.slf4j.org/).
-Licensed under the MIT License.
-
-This product uses software developed at
-SpringSource (http://www.springsource.org/).
-Licensed under the Apache License 2.0.
-
-This product includes software from http://www.json.org.
-Copyright (c) 2002 JSON.org
-
-
-III. License Summary
-- Apache License 2.0
-- BSD License
-- EPL License
-- MIT License

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/core/pom.xml
----------------------------------------------------------------------
diff --git a/jms/core/pom.xml b/jms/core/pom.xml
deleted file mode 100644
index 720d361..0000000
--- a/jms/core/pom.xml
+++ /dev/null
@@ -1,102 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-
-    <!--
-
-        Licensed to the Apache Software Foundation (ASF) under one or more
-        contributor license agreements.  See the NOTICE file distributed with
-        this work for additional information regarding copyright ownership.
-        The ASF licenses this file to You under the Apache License, Version 2.0
-        (the "License"); you may not use this file except in compliance with
-        the License.  You may obtain a copy of the License at
-
-            http://www.apache.org/licenses/LICENSE-2.0
-
-        Unless required by applicable law or agreed to in writing, software
-        distributed under the License is distributed on an "AS IS" BASIS,
-        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-        See the License for the specific language governing permissions and
-        limitations under the License.
-    -->
-
-    <modelVersion>4.0.0</modelVersion>
-
-    <parent>
-        <groupId>org.apache.karaf.jms</groupId>
-        <artifactId>jms</artifactId>
-        <version>4.0.0-SNAPSHOT</version>
-        <relativePath>../pom.xml</relativePath>
-    </parent>
-
-    <artifactId>org.apache.karaf.jms.core</artifactId>
-    <packaging>bundle</packaging>
-    <name>Apache Karaf :: JMS :: Core</name>
-    <description>This bundle provides core implementation of the JMS service.</description>
-
-    <properties>
-        <appendedResourcesDirectory>${basedir}/../../etc/appended-resources</appendedResourcesDirectory>
-    </properties>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.core</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.geronimo.specs</groupId>
-            <artifactId>geronimo-jms_1.1_spec</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.activemq</groupId>
-            <artifactId>activemq-pool</artifactId>
-            <version>5.9.0</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.karaf</groupId>
-            <artifactId>org.apache.karaf.util</artifactId>
-        </dependency>
-    </dependencies>
-
-    <build>
-        <resources>
-            <resource>
-                <directory>${project.basedir}/src/main/resources</directory>
-                <includes>
-                    <include>**/*</include>
-                </includes>
-            </resource>
-            <resource>
-                <directory>${project.basedir}/src/main/resources</directory>
-                <filtering>true</filtering>
-                <includes>
-                    <include>**/*.info</include>
-                </includes>
-            </resource>
-        </resources>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-bundle-plugin</artifactId>
-                <configuration>
-                    <instructions>
-                        <Export-Package>
-                            org.apache.karaf.jms
-                        </Export-Package>
-                        <Import-Package>
-                            org.apache.activemq*;resolution:=optional,
-                            *
-                        </Import-Package>
-                        <Private-Package>
-                            org.apache.karaf.jms.internal,
-                            org.apache.karaf.util
-                        </Private-Package>
-                    </instructions>
-                </configuration>
-            </plugin>
-        </plugins>
-    </build>
-
-</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/core/src/main/java/org/apache/karaf/jms/JmsMBean.java
----------------------------------------------------------------------
diff --git a/jms/core/src/main/java/org/apache/karaf/jms/JmsMBean.java b/jms/core/src/main/java/org/apache/karaf/jms/JmsMBean.java
deleted file mode 100644
index 8540b86..0000000
--- a/jms/core/src/main/java/org/apache/karaf/jms/JmsMBean.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jms;
-
-import javax.management.MBeanException;
-import javax.management.openmbean.TabularData;
-import java.util.List;
-import java.util.Map;
-
-/**
- * JMS MBean.
- */
-public interface JmsMBean {
-
-    /**
-     * List the JMS connection factories.
-     *
-     * @return the list of the JMS connection factories name.
-     * @throws MBeanException
-     */
-    List<String> getConnectionfactories() throws MBeanException;
-
-    /**
-     * Create a JMS connection factory.
-     *
-     * @param name the JMS connection factory name.
-     * @param type the JMS connection factory type (ActiveMQ or WebsphereMQ).
-     * @param url the JMS connection factory URL. NB: when type is WebsphereMQ, the URL has the format host/port/queuemanager/channel.
-     * @throws MBeanException
-     */
-    void create(String name, String type, String url) throws MBeanException;
-
-    /**
-     * Delete a JMS connection factory.
-     *
-     * @param name the JMS connection factory name.
-     * @throws MBeanException
-     */
-    void delete(String name) throws MBeanException;
-
-    /**
-     * Get details about a JMS connection factory.
-     *
-     * @param connectionFactory the JMS connection factory name.
-     * @param username optional username to connect to the JMS broker.
-     * @param password optional password to connect to the JMS broker.
-     * @return a map (property/value) containing details.
-     * @throws MBeanException
-     */
-    Map<String, String> info(String connectionFactory, String username, String password) throws MBeanException;
-
-    /**
-     * Count the messages on a given JMS queue.
-     *
-     * @param connectionFactory the JMS connection factory name.
-     * @param queue the JMS queue name.
-     * @param username optional username to connect to the JMS broker.
-     * @param password optional password to connect to the JMS broker.
-     * @return
-     * @throws MBeanException
-     */
-    int count(String connectionFactory, String queue, String username, String password) throws MBeanException;
-
-    /**
-     * List the JMS queues.
-     *
-     * @param connectionFactory the JMS connection factory name.
-     * @param username optional username to connect to the JMS broker.
-     * @param password optional password to connect to the JMS broker.
-     * @return the list of JMS queues.
-     * @throws MBeanException
-     */
-    List<String> queues(String connectionFactory, String username, String password) throws MBeanException;
-
-    /**
-     * List the JMS topics.
-     *
-     * @param connectionFactory the JMS connection factory name.
-     * @param username optional username to connect to the JMS broker.
-     * @param password optional password to connect to the JMS broker.
-     * @return the list of JMS topics.
-     * @throws MBeanException
-     */
-    List<String> topics(String connectionFactory, String username, String password) throws MBeanException;
-
-    /**
-     * Browse the messages in a JMS queue.
-     *
-     * @param connectionFactory the JMS connection factory name.
-     * @param queue the JMS queue name.
-     * @param selector a selector to use to browse only certain messages.
-     * @param username optional username to connect to the JMS broker.
-     * @param password optional password to connect to the JMS broker.
-     * @return a tabular data with messages details.
-     * @throws MBeanException
-     */
-    TabularData browse(String connectionFactory, String queue, String selector, String username, String password) throws MBeanException;
-
-    /**
-     * Send a JMS message to given queue.
-     *
-     * @param connectionFactory the JMS connection factory name.
-     * @param queue the JMS queue name.
-     * @param content the message content.
-     * @param replyTo the message ReplyTo.
-     * @param username optional username to connect to the JMS broker.
-     * @param password optional password to connect to the JMS broker.
-     * @throws MBeanException
-     */
-    void send(String connectionFactory, String queue, String content, String replyTo, String username, String password) throws MBeanException;
-
-    /**
-     * Consume JMS messages from a given queue.
-     *
-     * @param connectionFactory the JMS connection factory name.
-     * @param queue the JMS queue name.
-     * @param selector a selector to use to consume only certain messages.
-     * @param username optional username to connect to the JMS broker.
-     * @param password optional password to connect to the JMS broker.
-     * @return the number of messages consumed.
-     * @throws MBeanException
-     */
-    int consume(String connectionFactory, String queue, String selector, String username, String password) throws MBeanException;
-
-    /**
-     * Move JMS messages from one queue to another.
-     *
-     * @param connectionFactory the JMS connection factory name.
-     * @param source the source JMS queue name.
-     * @param destination the destination JMS queue name.
-     * @param selector a selector to move only certain messages.
-     * @param username optional username to connect to the JMS broker.
-     * @param password optional password to connect to the JMS broker.
-     * @return the number of messages moved.
-     * @throws MBeanException
-     */
-    int move(String connectionFactory, String source, String destination, String selector, String username, String password) throws MBeanException;
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/core/src/main/java/org/apache/karaf/jms/JmsMessage.java
----------------------------------------------------------------------
diff --git a/jms/core/src/main/java/org/apache/karaf/jms/JmsMessage.java b/jms/core/src/main/java/org/apache/karaf/jms/JmsMessage.java
deleted file mode 100644
index a85af10..0000000
--- a/jms/core/src/main/java/org/apache/karaf/jms/JmsMessage.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jms;
-
-import javax.jms.*;
-import java.io.UnsupportedEncodingException;
-import java.util.Date;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Describe a JMS message is more human readable way.
- */
-public class JmsMessage {
-
-    private Map<String, Object> properties = new HashMap<String, Object>();
-
-    private String content;
-    private String charset = "UTF-8";
-    private String correlationID;
-    private String deliveryMode;
-    private String destination;
-    private String expiration;
-    private String messageId;
-    private int priority;
-    private boolean redelivered;
-    private String replyTo;
-    private String timestamp;
-    private String type;
-
-    public JmsMessage(Message message) {
-        try {
-            initFromMessage(message);
-        } catch (JMSException e) {
-            throw new RuntimeException(e.getMessage(), e);
-        }
-    }
-
-    public void initFromMessage(Message message) throws JMSException {
-        @SuppressWarnings("unchecked")
-        Enumeration<String> names = message.getPropertyNames();
-        while (names.hasMoreElements()) {
-            String key = names.nextElement();
-            Object value = message.getObjectProperty(key);
-            properties.put(key, value);
-        }
-
-        correlationID = message.getJMSCorrelationID();
-        if (message.getJMSDeliveryMode() == DeliveryMode.NON_PERSISTENT) {
-            deliveryMode = "Non Persistent";
-        } else {
-            deliveryMode = "Persistent";
-        }
-        Destination destinationDest = message.getJMSDestination();
-        if (destinationDest != null) {
-            destination = destinationDest.toString();
-        }
-        if (message.getJMSExpiration() > 0) {
-            expiration = new Date(message.getJMSExpiration()).toString();
-        } else {
-            expiration = "Never";
-        }
-        messageId = message.getJMSMessageID();
-        priority = message.getJMSPriority();
-        redelivered = message.getJMSRedelivered();
-        Destination replyToDest = message.getJMSReplyTo();
-        if (replyToDest != null) {
-            replyTo = replyToDest.toString();
-        }
-        if (message.getJMSTimestamp() > 0) {
-            timestamp = new Date(message.getJMSTimestamp()).toString();
-        } else {
-            timestamp = "";
-        }
-        type = message.getJMSType();
-        content = getMessageContent(message);
-    }
-
-
-    private String getMessageContent(Message message) throws JMSException {
-        if (message instanceof TextMessage) {
-            return ((TextMessage) message).getText();
-        } else if (message instanceof BytesMessage) {
-            BytesMessage bMessage = (BytesMessage) message;
-            long length = bMessage.getBodyLength();
-            byte[] content = new byte[(int) length];
-            bMessage.readBytes(content);
-            try {
-                return new String(content, charset);
-            } catch (UnsupportedEncodingException e) {
-                throw new RuntimeException(e.getMessage(), e);
-            }
-        }
-        return "";
-    }
-
-    public Map<String, Object> getProperties() {
-        return properties;
-    }
-
-    public String getContent() {
-        return content;
-    }
-
-    public String getCharset() {
-        return charset;
-    }
-
-    public String getCorrelationID() {
-        return correlationID;
-    }
-
-    public String getDeliveryMode() {
-        return deliveryMode;
-    }
-
-    public String getDestination() {
-        return destination;
-    }
-
-    public String getExpiration() {
-        return expiration;
-    }
-
-    public String getMessageId() {
-        return messageId;
-    }
-
-    public int getPriority() {
-        return priority;
-    }
-
-    public boolean isRedelivered() {
-        return redelivered;
-    }
-
-    public String getReplyTo() {
-        return replyTo;
-    }
-
-    public String getTimestamp() {
-        return timestamp;
-    }
-
-    public String getType() {
-        return type;
-    }
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/core/src/main/java/org/apache/karaf/jms/JmsService.java
----------------------------------------------------------------------
diff --git a/jms/core/src/main/java/org/apache/karaf/jms/JmsService.java b/jms/core/src/main/java/org/apache/karaf/jms/JmsService.java
deleted file mode 100644
index 8aa970f..0000000
--- a/jms/core/src/main/java/org/apache/karaf/jms/JmsService.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jms;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * JMS Service.
- */
-public interface JmsService {
-
-    /**
-     * List the JMS connection factories.
-     *
-     * @return the list of JMS connection factory names.
-     * @throws Exception
-     */
-    List<String> connectionFactories() throws Exception;
-
-    /**
-     * List the JMS connecion factories file names.
-     *
-     * @return the list of JMS connection factory file names.
-     * @throws Exception
-     */
-    List<String> connectionFactoryFileNames() throws Exception;
-
-    /**
-     * Create a new JMS connection factory.
-     *
-     * @param name the JMS connection factory name.
-     * @param type the JMS connection factory type (ActiveMQ, WebsphereMQ, ...).
-     * @param url the JMS URL to use.
-     * @throws Exception
-     */
-    void create(String name, String type, String url) throws Exception;
-
-    /**
-     * Delete a JMS connection factory.
-     *
-     * @param name the JMS connection factory name.
-     * @throws Exception
-     */
-    void delete(String name) throws Exception;
-
-    /**
-     * Get details about a given JMS connection factory.
-     *
-     * @param connectionFactory the JMS connection factory name.
-     * @param username optional username to connect to the JMS broker.
-     * @param password optional password to connect to the JMS broker.
-     * @return a map (property/value) containing details.
-     * @throws Exception
-     */
-    Map<String, String> info(String connectionFactory, String username, String password) throws Exception;
-
-    /**
-     * Count the number of messages in a JMS queue.
-     *
-     * @param connectionFactory the JMS connection factory name.
-     * @param queue the queue name.
-     * @param username optional username to connect to the JMS broker.
-     * @param password optional password to connect to the JMS broker.
-     * @return the number of messages in a JMS queue.
-     * @throws Exception
-     */
-    int count(String connectionFactory, String queue, String username, String password) throws Exception;
-
-    /**
-     * List the queues.
-     *
-     * @param connectionFactory the JMS connection factory name.
-     * @param username optional username to connect to the JMS broker.
-     * @param password optional password to connect to the JMS broker.
-     * @return the list of queues.
-     * @throws Exception
-     */
-    List<String> queues(String connectionFactory, String username, String password) throws Exception;
-
-    /**
-     * List the topics.
-     *
-     * @param connectionFactory the JMS connection factory name.
-     * @param username optional username to connect to the JMS broker.
-     * @param password optional password to connect to the JMS broker.
-     * @return the list of topics.
-     * @throws Exception
-     */
-    List<String> topics(String connectionFactory, String username, String password) throws Exception;
-
-    /**
-     * Browse a destination.
-     *
-     * @param connectionFactory the JMS connection factory name.
-     * @param queue the queue name.
-     * @param selector the selector.
-     * @param username optional username to connect to the JMS broker.
-     * @param password optional password to connect to the JMS broker.
-     * @return the list of messages.
-     * @throws Exception
-     */
-    List<JmsMessage> browse(String connectionFactory, String queue, String selector, String username, String password) throws Exception;
-
-    /**
-     * Send a message on the given queue.
-     *
-     * @param connectionFactory the JMS connection factory name.
-     * @param queue the queue name.
-     * @param body the message body.
-     * @param replyTo the message replyTo header.
-     * @param username optional username to connect to the JMS broker.
-     * @param password optional password to connect to the JMS broker.
-     * @throws Exception
-     */
-    void send(String connectionFactory, String queue, String body, String replyTo, String username, String password) throws Exception;
-
-    /**
-     * Consume messages from a given destination.
-     *
-     * @param connectionFactory the JMS connection factory name.
-     * @param queue the queue name.
-     * @param selector the messages selector.
-     * @param username optional username to connect to the JMS broker.
-     * @param password optional password to connect to the JMS broker.
-     * @return the number of messages consumed.
-     * @throws Exception
-     */
-    int consume(String connectionFactory, String queue, String selector, String username, String password) throws Exception;
-
-    /**
-     * Move messages from a destination to another.
-     *
-     * @param connectionFactory the JMS connection factory name.
-     * @param sourceQueue the source queue.
-     * @param targetQueue the target queue.
-     * @param selector the messages selector on the source queue.
-     * @param username optional username to connect to the JMS broker.
-     * @param password optional password to connect to the JMS broker.
-     * @return the number of messages moved.
-     * @throws Exception
-     */
-    int move(String connectionFactory, String sourceQueue, String targetQueue, String selector, String username, String password) throws Exception;
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/core/src/main/java/org/apache/karaf/jms/internal/JmsConnector.java
----------------------------------------------------------------------
diff --git a/jms/core/src/main/java/org/apache/karaf/jms/internal/JmsConnector.java b/jms/core/src/main/java/org/apache/karaf/jms/internal/JmsConnector.java
deleted file mode 100644
index ecace89..0000000
--- a/jms/core/src/main/java/org/apache/karaf/jms/internal/JmsConnector.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jms.internal;
-
-import java.io.Closeable;
-import java.io.IOException;
-import java.util.Collection;
-
-import javax.jms.Connection;
-import javax.jms.ConnectionFactory;
-import javax.jms.JMSException;
-import javax.jms.Session;
-
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceReference;
-
-public class JmsConnector implements Closeable {
-    private BundleContext bc;
-    private ServiceReference<ConnectionFactory> reference;
-    private Connection connection;
-    private Session session;
-    private String connectionFactoryName;
-    private String username;
-    private String password;
-
-    public JmsConnector(BundleContext bc, String connectionFactoryName, String username, String password) throws JMSException {
-        this.bc = bc;
-        this.connectionFactoryName = connectionFactoryName;
-        this.username = username;
-        this.password = password;
-    }
-    
-    private ServiceReference<ConnectionFactory> lookupConnectionFactory(String name) {
-        Collection<ServiceReference<ConnectionFactory>> references;
-        try {
-            references = bc.getServiceReferences(ConnectionFactory.class, "(|(osgi.jndi.service.name=" + name + ")(name=" + name + ")(service.id=" + name + "))");
-        } catch (InvalidSyntaxException e) {
-            throw new RuntimeException("Error finding connection factory service " + name, e);
-        }
-        if (references == null || references.size() == 0) {
-            throw new IllegalArgumentException("No JMS connection factory found for " + name);
-        }
-        if (references.size() > 1) {
-            throw new IllegalArgumentException("Multiple JMS connection factories found for " + name);
-        }
-        return references.iterator().next();
-    }
-
-    @Override
-    public void close() throws IOException {
-        if (session != null) {
-            try {
-                session.close();
-            } catch (JMSException e) {
-                // Ignore
-            }
-        }
-        if (connection != null) {
-            try {
-                connection.close();
-            } catch (JMSException e) {
-                // Ignore
-            }
-        }
-        if (reference != null) {
-            bc.ungetService(reference);
-        }
-    }
-
-    public Connection connect() throws JMSException {
-        reference = this.lookupConnectionFactory(connectionFactoryName);
-        ConnectionFactory cf = (ConnectionFactory) bc.getService(reference);
-        connection = cf.createConnection(username, password);
-        connection.start();
-        return connection;
-    }
-
-    public Session createSession() throws JMSException {
-        if (connection == null) {
-            connect();
-        }
-        return session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/core/src/main/java/org/apache/karaf/jms/internal/JmsMBeanImpl.java
----------------------------------------------------------------------
diff --git a/jms/core/src/main/java/org/apache/karaf/jms/internal/JmsMBeanImpl.java b/jms/core/src/main/java/org/apache/karaf/jms/internal/JmsMBeanImpl.java
deleted file mode 100644
index cc46434..0000000
--- a/jms/core/src/main/java/org/apache/karaf/jms/internal/JmsMBeanImpl.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jms.internal;
-
-import org.apache.karaf.jms.JmsMBean;
-import org.apache.karaf.jms.JmsMessage;
-import org.apache.karaf.jms.JmsService;
-
-import javax.management.MBeanException;
-import javax.management.openmbean.*;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Default implementation of the JMS MBean.
- */
-public class JmsMBeanImpl implements JmsMBean {
-
-    private JmsService jmsService;
-
-    @Override
-    public List<String> getConnectionfactories() throws MBeanException {
-        try {
-            return jmsService.connectionFactories();
-        } catch (Throwable t) {
-            throw new MBeanException(null, t.getMessage());
-        }
-    }
-
-    @Override
-    public void create(String name, String type, String url) throws MBeanException {
-        try {
-            jmsService.create(name, type, url);
-        } catch (Throwable t) {
-            throw new MBeanException(null, t.getMessage());
-        }
-    }
-
-    @Override
-    public void delete(String name) throws MBeanException {
-        try {
-            jmsService.delete(name);
-        } catch (Throwable t) {
-            throw new MBeanException(null, t.getMessage());
-        }
-    }
-
-    @Override
-    public Map<String, String> info(String connectionFactory, String username, String password) throws MBeanException {
-        try {
-            return jmsService.info(connectionFactory, username, password);
-        } catch (Throwable t) {
-            throw new MBeanException(null, t.getMessage());
-        }
-    }
-
-    @Override
-    public int count(String connectionFactory, String queue, String username, String password) throws MBeanException {
-        try {
-            return jmsService.count(connectionFactory, queue, username, password);
-        } catch (Throwable t) {
-            throw new MBeanException(null, t.getMessage());
-        }
-    }
-
-    @Override
-    public List<String> queues(String connectionFactory, String username, String password) throws MBeanException {
-        try {
-            return jmsService.queues(connectionFactory, username, password);
-        } catch (Throwable t) {
-            throw new MBeanException(null, t.getMessage());
-        }
-    }
-
-    @Override
-    public List<String> topics(String connectionFactory, String username, String password) throws MBeanException {
-        try {
-            return jmsService.topics(connectionFactory, username, password);
-        } catch (Throwable t) {
-            throw new MBeanException(null, t.getMessage());
-        }
-    }
-
-    @Override
-    public void send(String connectionFactory, String queue, String content, String replyTo, String username, String password) throws MBeanException {
-        try {
-            jmsService.send(connectionFactory, queue, content, replyTo, username, password);
-        } catch (Throwable t) {
-            throw new MBeanException(null, t.getMessage());
-        }
-    }
-
-    @Override
-    public int consume(String connectionFactory, String queue, String selector, String username, String password) throws MBeanException {
-        try {
-            return jmsService.consume(connectionFactory, queue, selector, username, password);
-        } catch (Throwable t) {
-            throw new MBeanException(null, t.getMessage());
-        }
-    }
-
-    @Override
-    public int move(String connectionFactory, String source, String destination, String selector, String username, String password) throws MBeanException {
-        try {
-            return jmsService.move(connectionFactory, source, destination, selector, username, password);
-        } catch (Throwable t) {
-            throw new MBeanException(null, t.getMessage());
-        }
-    }
-
-    @Override
-    public TabularData browse(String connectionFactory, String queue, String selector, String username, String password) throws MBeanException {
-        try {
-            CompositeType type = new CompositeType("message", "JMS Message",
-                    new String[]{ "id", "content", "charset", "type", "correlation", "delivery", "destination", "expiration", "priority", "redelivered", "replyto", "timestamp" },
-                    new String[]{ "Message ID", "Content", "Charset", "Type", "Correlation ID", "Delivery Mode", "Destination", "Expiration Date", "Priority", "Redelivered", "Reply-To", "Timestamp" },
-                    new OpenType[]{ SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, SimpleType.INTEGER, SimpleType.BOOLEAN, SimpleType.STRING, SimpleType.STRING });
-            TabularType tableType = new TabularType("messages", "JMS Messages", type, new String[]{ "id" });
-            TabularData table = new TabularDataSupport(tableType);
-            for (JmsMessage message : getJmsService().browse(connectionFactory, queue, selector, username, password)) {
-                CompositeData data = new CompositeDataSupport(type,
-                        new String[]{ "id", "content", "charset", "type", "correlation", "delivery", "destination", "expiration", "priority", "redelivered", "replyto", "timestamp" },
-                        new Object[]{ message.getMessageId(), message.getContent(), message.getCharset(), message.getType(), message.getCorrelationID(), message.getDeliveryMode(), message.getDestination(), message.getExpiration(), message.getPriority(), message.isRedelivered(), message.getReplyTo(), message.getTimestamp() }
-                        );
-                table.put(data);
-            }
-            return table;
-        } catch (Throwable t) {
-            throw new MBeanException(null, t.getMessage());
-        }
-    }
-
-    public JmsService getJmsService() {
-        return jmsService;
-    }
-
-    public void setJmsService(JmsService jmsService) {
-        this.jmsService = jmsService;
-    }
-
-}


[25/33] Revert "[KARAF-2852] Merge features/core and features/command"

Posted by gn...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/resources/org/apache/karaf/features/karaf-features-1.0.0.xsd
----------------------------------------------------------------------
diff --git a/features/core/src/main/resources/org/apache/karaf/features/karaf-features-1.0.0.xsd b/features/core/src/main/resources/org/apache/karaf/features/karaf-features-1.0.0.xsd
new file mode 100644
index 0000000..9536ba1
--- /dev/null
+++ b/features/core/src/main/resources/org/apache/karaf/features/karaf-features-1.0.0.xsd
@@ -0,0 +1,239 @@
+<?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://karaf.apache.org/xmlns/features/v1.0.0"
+    xmlns:tns="http://karaf.apache.org/xmlns/features/v1.0.0"
+    xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+    <xs:annotation>
+        <xs:documentation><![CDATA[
+Karaf features mechanism. For documentation please visit the
+<a href="http://karaf.apache.org/">Karaf website</a>.
+        ]]></xs:documentation>
+    </xs:annotation>
+
+    <xs:complexType name="features">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Root element of the Feature definition. It contains an optional attribute for
+designating the name of the repository of this feature. The Karaf shell will
+show the repository name when displaying information about the feature.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+            <xs:element name="repository" type="xs:anyURI">
+                <xs:annotation>
+                    <xs:documentation><![CDATA[
+Additional repositories where dependencies are stored.
+                    ]]></xs:documentation>
+                </xs:annotation>
+            </xs:element>
+            <xs:element name="feature" type="tns:feature">
+                <xs:annotation>
+                    <xs:documentation><![CDATA[
+Feature definition.
+                    ]]></xs:documentation>
+                </xs:annotation>
+            </xs:element>
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string" />
+    </xs:complexType>
+
+    <xs:complexType name="feature">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Definition of the Feature.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+            <xs:element name="details" minOccurs="0" type="xs:string">
+                <xs:annotation>
+                    <xs:documentation><![CDATA[
+The help text shown for this feature when using the feature:info console command.
+                    ]]>
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:element>
+            <xs:element name="config" type="tns:config" />
+            <xs:element name="configfile" type="tns:configFile" />
+            <xs:element name="feature" type="tns:dependency" />
+            <xs:element name="bundle" type="tns:bundle" />
+        </xs:choice>
+        <xs:attribute name="name" type="tns:featureName" use="required" />
+        <xs:attribute name="version" type="xs:string" default="0.0.0" />
+        <xs:attribute name="description" type="xs:string" />
+        <xs:attribute name="resolver" type="tns:resolver">
+            <xs:annotation>
+                <xs:documentation><![CDATA[
+Optional alternative resolver to use for determining the list of bundles to install for a given feature.
+                ]]>
+                </xs:documentation>
+            </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="install" type="tns:install">
+            <xs:annotation>
+                <xs:documentation><![CDATA[
+If true, marks that the feature should start automatically when placed in the deploy folder.
+                ]]>
+                </xs:documentation>
+            </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="start-level" type="xs:int">
+             <xs:annotation>
+                <xs:documentation><![CDATA[
+Set this attribute to have an OSGi start level for the bundles in this feature different
+from the default start level defined in Karaf's config.properties.
+                ]]>
+                </xs:documentation>
+             </xs:annotation>
+         </xs:attribute>
+         <xs:attribute name="region" type="xs:string"/>
+    </xs:complexType>
+
+    <xs:complexType name="bundle">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Deployable element to install.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:simpleContent>
+            <xs:extension base="xs:anyURI">
+                <xs:attribute name="start-level" type="xs:int">
+                    <xs:annotation>
+                        <xs:documentation><![CDATA[
+Set this attribute to have an OSGi start level for this bundle different
+from the default start level defined in Karaf's config.properties.
+
+                        ]]>
+                        </xs:documentation>
+                    </xs:annotation>
+                </xs:attribute>
+                <xs:attribute name="start" type="xs:boolean" default="true">
+                    <xs:annotation>
+                        <xs:documentation><![CDATA[
+If false, leaves the bundle in resolved state rather than the default active state.
+                        ]]>
+                        </xs:documentation>
+                    </xs:annotation>
+                </xs:attribute>
+                <xs:attribute name="dependency" type="xs:boolean">
+                    <xs:annotation>
+                        <xs:documentation><![CDATA[
+Mark this bundle as a dependency for the resolver.
+                        ]]>
+                        </xs:documentation>
+                    </xs:annotation>
+                </xs:attribute>
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:complexType name="dependency">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Dependency of feature.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:simpleContent>
+            <xs:extension base="tns:featureName">
+                <xs:attribute name="version" type="xs:string" default="0.0.0" />
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:complexType name="config">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Configuration entries which should be created during feature installation. This
+configuration may be used with OSGi Configuration Admin. The element content is
+read in as a properties file.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:simpleContent>
+            <xs:extension base="xs:string">
+                <xs:attribute name="name" type="xs:string" use="required" />
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:complexType name="configFile">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Additional configuration files which should be created during feature installation.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:simpleContent>
+            <xs:extension base="xs:anyURI">
+                <xs:attribute name="finalname" type="xs:string" use="required">
+                    <xs:annotation>
+                        <xs:documentation><![CDATA[
+The final destination path and name for the configuration file (relative to the KARAF_BASE).
+                        ]]></xs:documentation>
+                    </xs:annotation>
+                </xs:attribute>
+                <xs:attribute name="override" type="xs:boolean">
+                    <xs:annotation>
+                        <xs:documentation><![CDATA[
+If the configFile already exists at the finalname location, whether or not to replace it.
+                        ]]></xs:documentation>
+                    </xs:annotation>
+                </xs:attribute>
+
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:simpleType name="featureName">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Feature name should be non empty string.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:minLength value="1" />
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="resolver">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Resolver to use. Karaf will look for OSGi service which has following properties:
+objectClass: org.apache.karaf.features.Resolver
+name: the value
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:minLength value="1" />
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="install">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Installation mode. Can be either manual or auto. Specifies whether the feature should be automatically installed when
+dropped inside the deploy folder. Note: This attribute doesn't affect feature descriptors that are installed from the
+command line or as part of the org.apache.karaf.features.cfg.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:minLength value="1" />
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:element name="features" type="tns:features" />
+
+</xs:schema>

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/resources/org/apache/karaf/features/karaf-features-1.1.0.xsd
----------------------------------------------------------------------
diff --git a/features/core/src/main/resources/org/apache/karaf/features/karaf-features-1.1.0.xsd b/features/core/src/main/resources/org/apache/karaf/features/karaf-features-1.1.0.xsd
new file mode 100644
index 0000000..7138573
--- /dev/null
+++ b/features/core/src/main/resources/org/apache/karaf/features/karaf-features-1.1.0.xsd
@@ -0,0 +1,237 @@
+<?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://karaf.apache.org/xmlns/features/v1.1.0"
+    xmlns:tns="http://karaf.apache.org/xmlns/features/v1.1.0"
+    xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+    <xs:annotation>
+        <xs:documentation><![CDATA[
+Karaf features mechanism. For documentation please visit the
+<a href="http://karaf.apache.org/">Karaf website</a>.
+        ]]></xs:documentation>
+    </xs:annotation>
+
+    <xs:complexType name="features">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Root element of Feature definition. It contains an required attribute for
+designating from which repository this feature should be loaded. The Karaf
+shell will show the repository name when displaying information about the feature.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+            <xs:element name="repository" type="xs:anyURI">
+                <xs:annotation>
+                    <xs:documentation><![CDATA[
+Additional repositories where dependencies are stored.
+                    ]]></xs:documentation>
+                </xs:annotation>
+            </xs:element>
+            <xs:element name="feature" type="tns:feature">
+                <xs:annotation>
+                    <xs:documentation><![CDATA[
+Feature definition.
+                    ]]></xs:documentation>
+                </xs:annotation>
+            </xs:element>
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string" use="required"/>
+    </xs:complexType>
+
+    <xs:complexType name="feature">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Definition of the Feature.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+            <xs:element name="details" minOccurs="0" type="xs:string">
+                <xs:annotation>
+                    <xs:documentation><![CDATA[
+The help text shown for this feature when using feature:info console command.
+                    ]]>
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:element>
+            <xs:element name="config" type="tns:config" />
+            <xs:element name="configfile" type="tns:configFile" />
+            <xs:element name="feature" type="tns:dependency" />
+            <xs:element name="bundle" type="tns:bundle" />
+        </xs:choice>
+        <xs:attribute name="name" type="tns:featureName" use="required" />
+        <xs:attribute name="version" type="xs:string" default="0.0.0" />
+        <xs:attribute name="description" type="xs:string" />
+        <xs:attribute name="resolver" type="tns:resolver">
+            <xs:annotation>
+                <xs:documentation><![CDATA[
+Optional alternative resolver to use for determining the list of bundles to install for a given feature.
+                ]]>
+                </xs:documentation>
+            </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="install" type="tns:install">
+            <xs:annotation>
+                <xs:documentation><![CDATA[
+Marks if the feaute will be automatically started when thrown to the deploy folder.
+                ]]>
+                </xs:documentation>
+            </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="start-level" type="xs:int">
+             <xs:annotation>
+                <xs:documentation><![CDATA[
+Set this attribute to have an OSGi start level for this feature different
+from the default start level defined in Karaf's config.properties.
+                ]]>
+                </xs:documentation>
+             </xs:annotation>
+         </xs:attribute>
+    </xs:complexType>
+
+    <xs:complexType name="bundle">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Deployable element to install.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:simpleContent>
+            <xs:extension base="xs:anyURI">
+                <xs:attribute name="start-level" type="xs:int">
+                    <xs:annotation>
+                        <xs:documentation><![CDATA[
+Set this attribute to have an OSGi start level for this bundle different
+from the default start level defined in the Karaf's config.properties.
+                        ]]>
+                        </xs:documentation>
+                    </xs:annotation>
+                </xs:attribute>
+                <xs:attribute name="start" type="xs:boolean" default="true">
+                    <xs:annotation>
+                        <xs:documentation><![CDATA[
+If false, leaves bundle in resolved state rather than the default active state.
+                        ]]>
+                        </xs:documentation>
+                    </xs:annotation>
+                </xs:attribute>
+                <xs:attribute name="dependency" type="xs:boolean">
+                    <xs:annotation>
+                        <xs:documentation><![CDATA[
+Mark this bundle as a dependency for the resolver.
+                        ]]>
+                        </xs:documentation>
+                    </xs:annotation>
+                </xs:attribute>
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:complexType name="dependency">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Dependency of feature.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:simpleContent>
+            <xs:extension base="tns:featureName">
+                <xs:attribute name="version" type="xs:string" default="0.0.0" />
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:complexType name="config">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Configuration entries which should be created during feature installation. This
+configuration may be used with OSGi Configuration Admin. The element content is
+read in as a properties file.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:simpleContent>
+            <xs:extension base="xs:string">
+                <xs:attribute name="name" type="xs:string" use="required" />
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:complexType name="configFile">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Additional configuration files which should be created during feature installation.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:simpleContent>
+            <xs:extension base="xs:anyURI">
+                <xs:attribute name="finalname" type="xs:string" use="required">
+                    <xs:annotation>
+                        <xs:documentation><![CDATA[
+The final destination path and name for the configuration file.
+                        ]]></xs:documentation>
+                    </xs:annotation>
+                </xs:attribute>
+                <xs:attribute name="override" type="xs:boolean">
+                    <xs:annotation>
+                        <xs:documentation><![CDATA[
+If the configFile already exists at the finalname location, whether or not to replace it.
+                        ]]></xs:documentation>
+                    </xs:annotation>
+                </xs:attribute>
+
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:simpleType name="featureName">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Feature name should be non empty string.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:minLength value="1" />
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="resolver">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Resolver to use. Karaf will look for OSGi service which have following properties:
+objectClass: org.apache.karaf.features.Resolver
+name: the value
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:minLength value="1" />
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="install">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Installation mode. Can be either manual or auto. Specifies whether the feature should be automatically installed when
+dropped inside the deploy folder. Note: This attribute doesn't affect feature descriptors that are installed from the
+command line or as part of the org.apache.karaf.features.cfg.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:minLength value="1" />
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:element name="features" type="tns:features" />
+
+</xs:schema>

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/resources/org/apache/karaf/features/karaf-features-1.2.0.xsd
----------------------------------------------------------------------
diff --git a/features/core/src/main/resources/org/apache/karaf/features/karaf-features-1.2.0.xsd b/features/core/src/main/resources/org/apache/karaf/features/karaf-features-1.2.0.xsd
new file mode 100644
index 0000000..dbc4bfa
--- /dev/null
+++ b/features/core/src/main/resources/org/apache/karaf/features/karaf-features-1.2.0.xsd
@@ -0,0 +1,254 @@
+<?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://karaf.apache.org/xmlns/features/v1.2.0"
+    xmlns:tns="http://karaf.apache.org/xmlns/features/v1.2.0"
+    xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+    <xs:annotation>
+        <xs:documentation><![CDATA[
+Karaf features mechanism. For documentation please visit the
+<a href="http://karaf.apache.org/">Karaf website</a>.
+        ]]></xs:documentation>
+    </xs:annotation>
+
+    <xs:complexType name="features">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Root element of Feature definition. It contains an required attribute for
+designating from which repository this feature should be loaded. The Karaf
+shell will show the repository name when displaying information about the feature.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+            <xs:element name="repository" type="xs:anyURI">
+                <xs:annotation>
+                    <xs:documentation><![CDATA[
+Additional repositories where dependencies are stored.
+                    ]]></xs:documentation>
+                </xs:annotation>
+            </xs:element>
+            <xs:element name="feature" type="tns:feature">
+                <xs:annotation>
+                    <xs:documentation><![CDATA[
+Feature definition.
+                    ]]></xs:documentation>
+                </xs:annotation>
+            </xs:element>
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string" use="required"/>
+    </xs:complexType>
+
+    <xs:complexType name="feature">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Definition of the Feature.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+            <xs:element name="details" minOccurs="0" type="xs:string">
+                <xs:annotation>
+                    <xs:documentation><![CDATA[
+The help text shown for this feature when using feature:info console command.
+                    ]]>
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:element>
+            <xs:element name="config" type="tns:config" />
+            <xs:element name="configfile" type="tns:configFile" />
+            <xs:element name="feature" type="tns:dependency" />
+            <xs:element name="bundle" type="tns:bundle" />
+            <xs:element name="conditional" type="tns:conditional" />
+        </xs:choice>
+        <xs:attribute name="name" type="tns:featureName" use="required" />
+        <xs:attribute name="version" type="xs:string" default="0.0.0" />
+        <xs:attribute name="description" type="xs:string" />
+        <xs:attribute name="resolver" type="tns:resolver">
+            <xs:annotation>
+                <xs:documentation><![CDATA[
+Optional alternative resolver to use for determining the list of bundles to install for a given feature.
+                ]]>
+                </xs:documentation>
+            </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="install" type="tns:install">
+            <xs:annotation>
+                <xs:documentation><![CDATA[
+Marks if the feaute will be automatically started when thrown to the deploy folder.
+                ]]>
+                </xs:documentation>
+            </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="start-level" type="xs:int">
+             <xs:annotation>
+                <xs:documentation><![CDATA[
+Set this attribute to have an OSGi start level for this feature different
+from the default start level defined in Karaf's config.properties.
+                ]]>
+                </xs:documentation>
+             </xs:annotation>
+         </xs:attribute>
+    </xs:complexType>
+
+    <xs:complexType name="conditional">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Definition of the Conditional.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+            <xs:element name="config" type="tns:config" />
+            <xs:element name="configfile" type="tns:configFile" />
+            <xs:element name="feature" type="tns:dependency" />
+            <xs:element name="bundle" type="tns:bundle" />
+            <xs:element name="condition" type="tns:dependency" minOccurs="0" maxOccurs="1" />
+        </xs:choice>
+    </xs:complexType>
+
+
+    <xs:complexType name="bundle">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Deployable element to install.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:simpleContent>
+            <xs:extension base="xs:anyURI">
+                <xs:attribute name="start-level" type="xs:int">
+                    <xs:annotation>
+                        <xs:documentation><![CDATA[
+Set this attribute to have an OSGi start level for this bundle different
+from the default start level defined in the Karaf's config.properties.
+                        ]]>
+                        </xs:documentation>
+                    </xs:annotation>
+                </xs:attribute>
+                <xs:attribute name="start" type="xs:boolean" default="true">
+                    <xs:annotation>
+                        <xs:documentation><![CDATA[
+If false, leaves bundle in resolved state rather than the default active state.
+                        ]]>
+                        </xs:documentation>
+                    </xs:annotation>
+                </xs:attribute>
+                <xs:attribute name="dependency" type="xs:boolean">
+                    <xs:annotation>
+                        <xs:documentation><![CDATA[
+Mark this bundle as a dependency for the resolver.
+                        ]]>
+                        </xs:documentation>
+                    </xs:annotation>
+                </xs:attribute>
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:complexType name="dependency">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Dependency of feature.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:simpleContent>
+            <xs:extension base="tns:featureName">
+                <xs:attribute name="version" type="xs:string" default="0.0.0" />
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:complexType name="config">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Configuration entries which should be created during feature installation. This
+configuration may be used with OSGi Configuration Admin. The element content is
+read in as a properties file.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:simpleContent>
+            <xs:extension base="xs:string">
+                <xs:attribute name="name" type="xs:string" use="required" />
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:complexType name="configFile">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Additional configuration files which should be created during feature installation.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:simpleContent>
+            <xs:extension base="xs:anyURI">
+                <xs:attribute name="finalname" type="xs:string" use="required">
+                    <xs:annotation>
+                        <xs:documentation><![CDATA[
+The final destination path and name for the configuration file.
+                        ]]></xs:documentation>
+                    </xs:annotation>
+                </xs:attribute>
+                <xs:attribute name="override" type="xs:boolean">
+                    <xs:annotation>
+                        <xs:documentation><![CDATA[
+If the configFile already exists at the finalname location, whether or not to replace it.
+                        ]]></xs:documentation>
+                    </xs:annotation>
+                </xs:attribute>
+
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:simpleType name="featureName">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Feature name should be non empty string.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:minLength value="1" />
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="resolver">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Resolver to use. Karaf will look for OSGi service which have following properties:
+objectClass: org.apache.karaf.features.Resolver
+name: the value
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:minLength value="1" />
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="install">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Installation mode. Can be either manual or auto. Specifies whether the feature should be automatically installed when
+dropped inside the deploy folder. Note: This attribute doesn't affect feature descriptors that are installed from the
+command line or as part of the org.apache.karaf.features.cfg.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:minLength value="1" />
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:element name="features" type="tns:features" />
+
+</xs:schema>

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/resources/org/apache/karaf/features/karaf-features-1.3.0.xsd
----------------------------------------------------------------------
diff --git a/features/core/src/main/resources/org/apache/karaf/features/karaf-features-1.3.0.xsd b/features/core/src/main/resources/org/apache/karaf/features/karaf-features-1.3.0.xsd
new file mode 100644
index 0000000..60ec8d2
--- /dev/null
+++ b/features/core/src/main/resources/org/apache/karaf/features/karaf-features-1.3.0.xsd
@@ -0,0 +1,280 @@
+<?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://karaf.apache.org/xmlns/features/v1.3.0"
+    xmlns:tns="http://karaf.apache.org/xmlns/features/v1.3.0"
+    xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+    <xs:annotation>
+        <xs:documentation><![CDATA[
+Karaf features mechanism. For documentation please visit the
+<a href="http://karaf.apache.org/">Karaf website</a>.
+        ]]></xs:documentation>
+    </xs:annotation>
+
+    <xs:complexType name="features">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Root element of Feature definition. It contains an required attribute for
+designating from which repository this feature should be loaded. The Karaf
+shell will show the repository name when displaying information about the feature.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+            <xs:element name="repository" type="xs:anyURI">
+                <xs:annotation>
+                    <xs:documentation><![CDATA[
+Additional repositories where dependencies are stored.
+                    ]]></xs:documentation>
+                </xs:annotation>
+            </xs:element>
+            <xs:element name="feature" type="tns:feature">
+                <xs:annotation>
+                    <xs:documentation><![CDATA[
+Feature definition.
+                    ]]></xs:documentation>
+                </xs:annotation>
+            </xs:element>
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string" use="required"/>
+    </xs:complexType>
+
+    <xs:complexType name="feature">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Definition of the Feature.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+            <xs:element name="details" minOccurs="0" type="xs:string">
+                <xs:annotation>
+                    <xs:documentation><![CDATA[
+The help text shown for this feature when using feature:info console command.
+                    ]]>
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:element>
+            <xs:element name="config" type="tns:config" />
+            <xs:element name="configfile" type="tns:configFile" />
+            <xs:element name="feature" type="tns:dependency" />
+            <xs:element name="bundle" type="tns:bundle" />
+            <xs:element name="conditional" type="tns:conditional" />
+            <xs:element name="requirement" type="tns:requirement" />
+            <xs:element name="capability" type="tns:capability" />
+        </xs:choice>
+        <xs:attribute name="name" type="tns:featureName" use="required" />
+        <xs:attribute name="version" type="xs:string" default="0.0.0" />
+        <xs:attribute name="description" type="xs:string" />
+        <xs:attribute name="resolver" type="tns:resolver">
+            <xs:annotation>
+                <xs:documentation><![CDATA[
+Optional alternative resolver to use for determining the list of bundles to install for a given feature.
+                ]]>
+                </xs:documentation>
+            </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="install" type="tns:install">
+            <xs:annotation>
+                <xs:documentation><![CDATA[
+Marks if the feaute will be automatically started when thrown to the deploy folder.
+                ]]>
+                </xs:documentation>
+            </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="start-level" type="xs:int">
+             <xs:annotation>
+                <xs:documentation><![CDATA[
+Set this attribute to have an OSGi start level for this feature different
+from the default start level defined in Karaf's config.properties.
+                ]]>
+                </xs:documentation>
+             </xs:annotation>
+         </xs:attribute>
+    </xs:complexType>
+
+    <xs:complexType name="conditional">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Definition of the Conditional.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+            <xs:element name="config" type="tns:config" />
+            <xs:element name="configfile" type="tns:configFile" />
+            <xs:element name="feature" type="tns:dependency" />
+            <xs:element name="bundle" type="tns:bundle" />
+            <xs:element name="condition" type="tns:dependency" minOccurs="0" maxOccurs="1" />
+        </xs:choice>
+    </xs:complexType>
+
+
+    <xs:complexType name="bundle">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Deployable element to install.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:simpleContent>
+            <xs:extension base="xs:anyURI">
+                <xs:attribute name="start-level" type="xs:int">
+                    <xs:annotation>
+                        <xs:documentation><![CDATA[
+Set this attribute to have an OSGi start level for this bundle different
+from the default start level defined in the Karaf's config.properties.
+                        ]]>
+                        </xs:documentation>
+                    </xs:annotation>
+                </xs:attribute>
+                <xs:attribute name="start" type="xs:boolean" default="true">
+                    <xs:annotation>
+                        <xs:documentation><![CDATA[
+If false, leaves bundle in resolved state rather than the default active state.
+                        ]]>
+                        </xs:documentation>
+                    </xs:annotation>
+                </xs:attribute>
+                <xs:attribute name="dependency" type="xs:boolean">
+                    <xs:annotation>
+                        <xs:documentation><![CDATA[
+Mark this bundle as a dependency for the resolver.
+                        ]]>
+                        </xs:documentation>
+                    </xs:annotation>
+                </xs:attribute>
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:complexType name="dependency">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Dependency of feature.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:simpleContent>
+            <xs:extension base="tns:featureName">
+                <xs:attribute name="version" type="xs:string" default="0.0.0" />
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:complexType name="config">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Configuration entries which should be created during feature installation. This
+configuration may be used with OSGi Configuration Admin. The element content is
+read in as a properties file.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:simpleContent>
+            <xs:extension base="xs:string">
+                <xs:attribute name="name" type="xs:string" use="required" />
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:complexType name="configFile">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Additional configuration files which should be created during feature installation.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:simpleContent>
+            <xs:extension base="xs:anyURI">
+                <xs:attribute name="finalname" type="xs:string" use="required">
+                    <xs:annotation>
+                        <xs:documentation><![CDATA[
+The final destination path and name for the configuration file.
+                        ]]></xs:documentation>
+                    </xs:annotation>
+                </xs:attribute>
+                <xs:attribute name="override" type="xs:boolean">
+                    <xs:annotation>
+                        <xs:documentation><![CDATA[
+If the configFile already exists at the finalname location, whether or not to replace it.
+                        ]]></xs:documentation>
+                    </xs:annotation>
+                </xs:attribute>
+
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:complexType name="requirement">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Additional requirements of this feature.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:simpleContent>
+            <xs:extension base="xs:string">
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:complexType name="capability">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Additional capability of this feature.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:simpleContent>
+            <xs:extension base="xs:string">
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:simpleType name="featureName">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Feature name should be non empty string.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:minLength value="1" />
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="resolver">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Resolver to use. Karaf will look for OSGi service which have following properties:
+objectClass: org.apache.karaf.features.Resolver
+name: the value
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:minLength value="1" />
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="install">
+        <xs:annotation>
+            <xs:documentation><![CDATA[
+Installation mode. Can be either manual or auto. Specifies whether the feature should be automatically installed when
+dropped inside the deploy folder. Note: This attribute doesn't affect feature descriptors that are installed from the
+command line or as part of the org.apache.karaf.features.cfg.
+            ]]></xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:minLength value="1" />
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:element name="features" type="tns:features" />
+
+</xs:schema>

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/test/java/org/apache/karaf/features/ConditionalTest.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/ConditionalTest.java b/features/core/src/test/java/org/apache/karaf/features/ConditionalTest.java
new file mode 100644
index 0000000..b103683
--- /dev/null
+++ b/features/core/src/test/java/org/apache/karaf/features/ConditionalTest.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.karaf.features;
+
+import junit.framework.TestCase;
+import org.apache.karaf.features.internal.service.RepositoryImpl;
+
+
+public class ConditionalTest extends TestCase {
+
+    public void testLoad() throws Exception {
+        RepositoryImpl r = new RepositoryImpl(getClass().getResource("internal/service/f06.xml").toURI());
+        // Check repo
+        Feature[] features = r.getFeatures();
+        assertNotNull(features);
+        assertEquals(1, features.length);
+        Feature feature = features[0];
+
+        assertNotNull(feature.getConditional());
+        assertEquals(2,feature.getConditional().size());
+
+        Conditional conditional = feature.getConditional().get(0);
+        assertNotNull(conditional.getCondition());
+        assertEquals(1,conditional.getCondition().size());
+        String dependency = conditional.getCondition().get(0);
+        assertNotNull(dependency);
+        assertEquals("http", dependency);
+        assertNotNull(conditional.getBundles());
+        assertEquals(1, feature.getConditional().get(0).getBundles().size());
+
+        conditional = feature.getConditional().get(1);
+        assertNotNull(conditional.getCondition());
+        assertEquals(1,conditional.getCondition().size());
+        dependency = conditional.getCondition().get(0);
+        assertNotNull(dependency);
+        assertEquals("req:osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(!(version>=1.7)))\"", dependency);
+
+        String wrapperName = "my6/1.5.3-beta-3".replaceAll("[^A-Za-z0-9 ]", "_");
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/test/java/org/apache/karaf/features/FeatureTest.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/FeatureTest.java b/features/core/src/test/java/org/apache/karaf/features/FeatureTest.java
new file mode 100644
index 0000000..b7d4c27
--- /dev/null
+++ b/features/core/src/test/java/org/apache/karaf/features/FeatureTest.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.karaf.features;
+
+import junit.framework.TestCase;
+
+public class FeatureTest extends TestCase {
+	
+	public void testValueOf() {
+		Feature feature = org.apache.karaf.features.internal.model.Feature.valueOf("name" + org.apache.karaf.features.internal.model.Feature.SPLIT_FOR_NAME_AND_VERSION + "version");
+		assertEquals(feature.getName(), "name");
+		assertEquals(feature.getVersion(), "version");
+		feature = org.apache.karaf.features.internal.model.Feature.valueOf("name");
+		assertEquals(feature.getName(), "name");
+		assertEquals(feature.getVersion(), org.apache.karaf.features.internal.model.Feature.DEFAULT_VERSION);
+	}
+	
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/test/java/org/apache/karaf/features/FeaturesServiceTest.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/FeaturesServiceTest.java b/features/core/src/test/java/org/apache/karaf/features/FeaturesServiceTest.java
new file mode 100644
index 0000000..9f7e67b
--- /dev/null
+++ b/features/core/src/test/java/org/apache/karaf/features/FeaturesServiceTest.java
@@ -0,0 +1,430 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features;
+
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.reset;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+import org.apache.karaf.features.internal.service.FeaturesServiceImpl;
+import org.apache.karaf.features.internal.service.StateStorage;
+import org.easymock.EasyMock;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+public class FeaturesServiceTest extends TestBase {
+    private static final String FEATURE_WITH_INVALID_BUNDLE = "<features name='test' xmlns='http://karaf.apache.org/xmlns/features/v1.0.0'>"
+            + "  <feature name='f1'><bundle>%s</bundle><bundle>zfs:unknown</bundle></feature>"
+            + "  <feature name='f2'><bundle>%s</bundle></feature>"
+            + "</features>";
+
+    File dataFile;
+
+    @Before
+    public void setUp() throws IOException {
+        dataFile = File.createTempFile("features", null, null);
+    }
+    
+    private URI createTempRepo(String repoContent, Object ... variables) throws IOException {
+        File tmp = File.createTempFile("karaf", ".feature");
+        PrintWriter pw = new PrintWriter(new FileWriter(tmp));
+        pw.printf(repoContent, variables);
+        pw.close();
+        return tmp.toURI();
+    }
+
+    /*
+       TODO: migrate those tests
+
+    @Test
+    public void testInstallFeature() throws Exception {
+        URI uri = createTempRepo(
+                "<features name='test' xmlns='http://karaf.apache.org/xmlns/features/v1.0.0'>" 
+                + "  <feature name='f1'><bundle start='true'>bundle-f1</bundle></feature>"
+                + "</features>");
+
+        BundleManager bundleManager = EasyMock.createMock(BundleManager.class);
+        Bundle installedBundle = createDummyBundle(12345L, "bundle-f1", headers());
+        FeaturesServiceImpl svc = testAddRepository("bundle-f1", uri, bundleManager, installedBundle);
+        
+        reset(bundleManager);
+        
+        expect(bundleManager.installBundleIfNeeded(eq("bundle-f1"), eq(0), eq((String)null))).andReturn(new BundleInstallerResult(installedBundle, true));
+        expect(bundleManager.getDataFile(EasyMock.anyObject(String.class))).andReturn(dataFile);
+        ignoreRefreshes(bundleManager);
+        replay(bundleManager);
+        svc.installFeature("f1", org.apache.karaf.features.internal.model.Feature.DEFAULT_VERSION, EnumSet.of(FeaturesService.Option.NoAutoRefreshBundles));
+        verify(bundleManager);
+        
+        Feature[] installed = svc.listInstalledFeatures();
+        assertEquals(1, installed.length);
+        assertEquals("f1", installed[0].getName());
+    }
+
+    private FeaturesServiceImpl testAddRepository(String name, URI uri, BundleManager bundleManager,
+            Bundle installedBundle) throws IOException, BundleException, Exception {
+        expect(bundleManager.getDataFile(EasyMock.anyObject(String.class))).andReturn(dataFile);
+        expect(bundleManager.installBundleIfNeeded(eq(name), eq(0), eq((String)null))).andReturn(new BundleInstallerResult(installedBundle, true)).anyTimes();
+
+        replay(bundleManager);
+        FeaturesServiceImpl svc = new FeaturesServiceImpl(bundleManager);
+        svc.addRepository(uri);
+        Repository[] repositories = svc.listRepositories();
+        verify(bundleManager);
+
+        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).getLocation());
+        assertTrue(features[0].getBundles().get(0).isStart());
+        return svc;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testUninstallFeatureWithTwoVersions() throws Exception {
+        URI uri  = createTempRepo("<features name='test' xmlns='http://karaf.apache.org/xmlns/features/v1.0.0'>"
+                + "  <feature name='f1' version='0.1'><bundle>bundle-0.1</bundle></feature>"
+                + "  <feature name='f1' version='0.2'><bundle>bundle-0.1</bundle></feature>" 
+                + "</features>");
+
+        Bundle bundlef101 = createDummyBundle(12345L, "bundle-0.1", headers());
+
+        BundleManager bundleManager = EasyMock.createMock(BundleManager.class);
+        BundleContext bundleContext = EasyMock.createMock(BundleContext.class);
+        expect(bundleManager.getDataFile(EasyMock.anyObject(String.class))).andReturn(dataFile).anyTimes();
+        expect(bundleManager.installBundleIfNeeded("bundle-0.1", 0, null)).andReturn(new BundleInstallerResult(bundlef101, true));
+        expect(bundleManager.installBundleIfNeeded("bundle-0.1", 0, null)).andReturn(new BundleInstallerResult(bundlef101, false));
+        expect(bundleManager.getBundleContext()).andReturn(bundleContext);
+        ignoreRefreshes(bundleManager);
+        bundleManager.uninstall(Collections.EMPTY_LIST, true);
+        EasyMock.expectLastCall().times(2);
+        
+        
+        replay(bundleManager);
+        FeaturesServiceImpl svc = new FeaturesServiceImpl(bundleManager);
+        svc.addRepository(uri);
+
+        try {
+            svc.uninstallFeature("f1");
+            fail("Uninstall should have failed as feature is not installed");
+        } catch (Exception e) {
+            // ok
+        }
+
+        svc.installFeature("f1", "0.1", EnumSet.of(FeaturesService.Option.NoAutoRefreshBundles));
+        svc.installFeature("f1", "0.2", EnumSet.of(FeaturesService.Option.NoAutoRefreshBundles));
+
+        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");
+        verify(bundleManager);
+    }    
+    
+    @Test
+    public void testAddAndRemoveRepository() throws Exception {
+        URI uri = createTempRepo("<features name='test' xmlns='http://karaf.apache.org/xmlns/features/v1.0.0'>"
+                + "  <feature name='f1' version='0.1'><bundle>bundle-f1-0.1</bundle></feature>"
+                + "</features>");
+
+        BundleManager bundleManager = EasyMock.createMock(BundleManager.class);
+        expect(bundleManager.getDataFile(EasyMock.<String>anyObject())).andReturn(dataFile).anyTimes();
+
+        replay(bundleManager);
+        FeaturesServiceImpl svc = new FeaturesServiceImpl(bundleManager);
+        EasyMock.verify(bundleManager);
+
+        svc.addRepository(uri);                                                     
+        svc.removeRepository(uri);
+        verify(bundleManager);
+    }
+
+    // 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
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testInstallFeatureWithDependantFeatures() throws Exception {
+        URI uri = createTempRepo("<features name='test' xmlns='http://karaf.apache.org/xmlns/features/v1.0.0'>"
+                                 + "  <feature name='f1' version='0.1'><feature version='0.1'>f2</feature><bundle>bundle-f1-0.1</bundle></feature>"
+                                 + "  <feature name='f2' version='0.1'><bundle>bundle-f2-0.1</bundle></feature>"
+                                 + "</features>");
+
+        BundleManager bundleManager = EasyMock.createMock(BundleManager.class);
+        BundleContext bundleContext = EasyMock.createMock(BundleContext.class);
+        Bundle bundlef101 = createDummyBundle(12345L, "bundle-f1-0.1", headers());
+        Bundle bundlef201 = createDummyBundle(54321L, "bundle-f2-0.1", headers());
+        expect(bundleManager.getDataFile(EasyMock.<String> anyObject())).andReturn(dataFile).anyTimes();
+        expect(bundleManager.installBundleIfNeeded("bundle-f1-0.1", 0, null))
+            .andReturn(new BundleInstallerResult(bundlef101, true));
+        expect(bundleManager.installBundleIfNeeded("bundle-f2-0.1", 0, null))
+            .andReturn(new BundleInstallerResult(bundlef201, true));
+        expect(bundleManager.getBundleContext()).andReturn(bundleContext).anyTimes();
+        expect(bundleContext.getBundle(12345)).andReturn(bundlef101).anyTimes();
+        ignoreRefreshes(bundleManager);
+        bundleManager.uninstall(Collections.EMPTY_LIST, true);
+       
+        EasyMock.expectLastCall().anyTimes();
+        replay(bundleManager);
+        
+        FeaturesServiceImpl svc = new FeaturesServiceImpl(bundleManager);
+        svc.addRepository(uri);
+        svc.installFeature("f1", "0.1");
+        svc.uninstallFeature("f1", "0.1");
+        verify(bundleManager);
+
+    }
+
+    @SuppressWarnings("unchecked")
+    private BundleManager prepareBundleManagerForInstallUninstall(String bundleUri, String bundlename) throws Exception {
+        BundleManager bundleManager = EasyMock.createMock(BundleManager.class);
+        BundleContext bundleContext = EasyMock.createMock(BundleContext.class);
+        Bundle installedBundle = createDummyBundle(12345L, bundlename, headers());
+        expect(bundleManager.getDataFile(EasyMock.<String>anyObject())).andReturn(dataFile).anyTimes();
+        expect(bundleManager.installBundleIfNeeded(bundleUri, 0, null)).andReturn(new BundleInstallerResult(installedBundle, true));
+        expect(bundleManager.getBundleContext()).andReturn(bundleContext);
+        ignoreRefreshes(bundleManager);
+        bundleManager.uninstall(Collections.EMPTY_LIST, true);
+        EasyMock.expectLastCall().times(2);
+        return bundleManager;
+    }
+
+    @Test
+    public void testInstallFeatureWithDependantFeaturesAndVersionWithoutPreinstall() throws Exception {
+        URI uri = createTempRepo("<features name='test' xmlns='http://karaf.apache.org/xmlns/features/v1.0.0'>"
+                + "  <feature name='f1' version='0.1'><feature version='0.1'>f2</feature></feature>"
+                + "  <feature name='f2' version='0.1'><bundle>bundle-0.1</bundle></feature>"
+                + "  <feature name='f2' version='0.2'><bundle>bundle-0.2</bundle></feature>"
+                + "</features>");
+
+        BundleManager bundleManager = prepareBundleManagerForInstallUninstall("bundle-0.1", "bundle-0.1");
+
+        replay(bundleManager);
+        FeaturesServiceImpl svc = new FeaturesServiceImpl(bundleManager);
+        svc.addRepository(uri);
+        svc.installFeature("f1", "0.1");
+        svc.uninstallFeature("f1", "0.1");
+        svc.uninstallFeature("f2", "0.1");
+        verify(bundleManager);
+    }
+
+    @Test
+    public void testInstallFeatureWithDependantFeaturesAndNoVersionWithoutPreinstall() throws Exception {
+        URI uri = createTempRepo("<features name='test' xmlns='http://karaf.apache.org/xmlns/features/v1.0.0'>"
+                + "  <feature name='f1' version='0.1'><feature>f2</feature></feature>"
+                + "  <feature name='f2' version='0.1'><bundle>bundle-0.1</bundle></feature>"
+                + "  <feature name='f2' version='0.2'><bundle>bundle-0.2</bundle></feature>"
+                + "</features>");
+
+        BundleManager bundleManager = prepareBundleManagerForInstallUninstall("bundle-0.2", "bundle-0.2");
+
+        replay(bundleManager);
+        FeaturesServiceImpl svc = new FeaturesServiceImpl(bundleManager);
+        svc.addRepository(uri);
+        svc.installFeature("f1", "0.1");
+        svc.uninstallFeature("f1", "0.1");
+        svc.uninstallFeature("f2", "0.2");
+        verify(bundleManager);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testInstallFeatureWithDependantFeaturesAndRangeWithoutPreinstall() throws Exception {
+        URI uri = createTempRepo("<features name='test' xmlns='http://karaf.apache.org/xmlns/features/v1.0.0'>"
+                + "  <feature name='f1' version='0.1'><feature version='[0.1,0.3)'>f2</feature></feature>"
+                + "  <feature name='f2' version='0.1'><bundle>bundle-0.1</bundle></feature>"
+                + "  <feature name='f2' version='0.2'><bundle>bundle-0.2</bundle></feature>"
+                + "</features>");
+
+        BundleManager bundleManager = EasyMock.createMock(BundleManager.class);
+        BundleContext bundleContext = EasyMock.createMock(BundleContext.class);
+        Bundle bundleVer02 = createDummyBundle(54321L, "bundleVer02", headers());
+        expect(bundleManager.getDataFile(EasyMock.<String>anyObject())).andReturn(dataFile).anyTimes();
+        expect(bundleManager.installBundleIfNeeded("bundle-0.2", 0, null)).andReturn(new BundleInstallerResult(bundleVer02, true));
+        expect(bundleManager.getBundleContext()).andReturn(bundleContext);
+        ignoreRefreshes(bundleManager);
+        bundleManager.uninstall(Collections.EMPTY_LIST, true);
+
+        EasyMock.expectLastCall().times(2);
+
+        replay(bundleManager);
+        FeaturesServiceImpl svc = new FeaturesServiceImpl(bundleManager);
+        svc.addRepository(uri);
+        svc.installFeature("f1", "0.1");
+        svc.uninstallFeature("f1", "0.1");
+        svc.uninstallFeature("f2", "0.2");
+        verify(bundleManager);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testInstallFeatureWithDependantFeaturesAndRangeWithPreinstall() throws Exception {
+        String bundleVer01Uri = "bundle-0.1";
+        String bundleVer02Uri = "bundle-0.2";
+
+        URI uri = createTempRepo("<features name='test' xmlns='http://karaf.apache.org/xmlns/features/v1.0.0'>"
+                + "<feature name='f1' version='0.1'><feature version='[0.1,0.3)'>f2</feature></feature>"
+                + "  <feature name='f2' version='0.1'><bundle>%s</bundle></feature>"
+                + "  <feature name='f2' version='0.2'><bundle>%s</bundle></feature>"
+                + "</features>", bundleVer01Uri, bundleVer02Uri);
+        
+        BundleContext bundleContext = EasyMock.createMock(BundleContext.class);
+        expect(bundleContext.getBundles()).andReturn(new Bundle[0]);
+        replay(bundleContext);
+
+        FeaturesServiceImpl svc = new FeaturesServiceImpl(null, bundleContext, new Storage(), null, null, null, null);
+        svc.addRepository(uri);
+        svc.installFeature("f2", "0.1");
+        svc.installFeature("f1", "0.1");
+        svc.uninstallFeature("f1", "0.1");
+        svc.uninstallFeature("f2", "0.1");
+
+        verify(bundleContext);
+    }
+    */
+
+    @Test
+    public void testGetFeaturesShouldHandleDifferentVersionPatterns() throws Exception {
+        URI uri = createTempRepo("<features name='test' xmlns='http://karaf.apache.org/xmlns/features/v1.0.0'>"
+                + "  <feature name='f1' version='0.1'><feature version='[0.1,0.3)'>f2</feature></feature>"
+                + "  <feature name='f2' version='0.1'><bundle>bundle1</bundle></feature>"
+                + "  <feature name='f2' version='0.2'><bundle>bundle2</bundle></feature>"
+                + "</features>");
+
+        FeaturesServiceImpl svc = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, null, null, null, null);
+        svc.addRepository(uri);
+
+        assertEquals(feature("f2", "0.2"), svc.getFeature("f2", "[0.1,0.3)"));
+        assertEquals(feature("f2", "0.2"), svc.getFeature("f2", "0.0.0"));
+        assertEquals(feature("f2", "0.2"), svc.getFeature("f2", "0.2"));
+        assertNull(svc.getFeature("f2", "0.3"));
+    }
+
+    @Test
+    public void testInstallBatchFeatureWithFailure() throws Exception {
+        String bundle1Uri = "file:bundle1";
+        String bundle2Uri = "file:bundle2";
+
+        URI uri = createTempRepo(FEATURE_WITH_INVALID_BUNDLE, bundle1Uri, bundle2Uri);
+        
+        BundleContext bundleContext = EasyMock.createMock(BundleContext.class);
+        expect(bundleContext.getBundles()).andReturn(new Bundle[0]);
+        replay(bundleContext);
+
+        FeaturesServiceImpl svc = new FeaturesServiceImpl(null, bundleContext, new Storage(), null, null, null, null, null, null, null);
+        svc.addRepository(uri);
+        try {
+            List<String> features = new ArrayList<String>();
+            for (Feature feature : svc.listFeatures()) {
+                features.add(feature.getId());
+            }
+            Collections.reverse(features);
+            svc.installFeatures(new CopyOnWriteArraySet<String>(features),
+                                EnumSet.noneOf(FeaturesService.Option.class));
+            fail("Call should have thrown an exception");
+        } catch (MalformedURLException e) {
+        }
+        verify(bundleContext);
+    }
+
+    /**
+     * This test checks schema validation of submited uri.
+     */
+    @Test
+    public void testSchemaValidation() throws Exception {
+        URI uri = createTempRepo("<features name='test' xmlns='http://karaf.apache.org/xmlns/features/v1.0.0'>"
+                + "  <featur><bundle>somebundle</bundle></featur></features>");
+
+        FeaturesServiceImpl svc = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, null, null, null, null);
+        try {
+            svc.addRepository(uri);
+            fail("exception expected");
+        } catch (Exception e) {
+            assertTrue(e.getMessage().contains("Unable to validate"));
+        }
+    }
+
+    /**
+     * This test checks feature service behavior with old, non namespaced descriptor.
+     */
+    @Test
+    public void testLoadOldFeatureFile() throws Exception {
+        URI uri = createTempRepo("<features name='test' xmlns='http://karaf.apache.org/xmlns/features/v1.0.0'>"
+                + "  <feature name='f1'><bundle>file:bundle1</bundle><bundle>file:bundle2</bundle></feature>"
+                + "</features>");
+
+        FeaturesServiceImpl svc = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, null, null, null, null);
+        svc.addRepository(uri);
+        Feature feature = svc.getFeature("f1");
+        Assert.assertNotNull("No feature named fi found", feature);        
+        List<BundleInfo> bundles = feature.getBundles();
+        Assert.assertEquals(2, bundles.size());
+    }
+
+    static class Storage extends StateStorage {
+        @Override
+        protected InputStream getInputStream() throws IOException {
+            return null;
+        }
+        @Override
+        protected OutputStream getOutputStream() throws IOException {
+            return null;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/test/java/org/apache/karaf/features/RepositoryTest.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/RepositoryTest.java b/features/core/src/test/java/org/apache/karaf/features/RepositoryTest.java
new file mode 100644
index 0000000..164dc79
--- /dev/null
+++ b/features/core/src/test/java/org/apache/karaf/features/RepositoryTest.java
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features;
+
+import java.net.URI;
+
+import junit.framework.TestCase;
+import org.apache.karaf.features.internal.resolver.FeatureResource;
+import org.apache.karaf.features.internal.service.RepositoryImpl;
+import org.osgi.resource.Resource;
+
+
+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(3, 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).getLocation());
+        assertEquals("b2", features[0].getBundles().get(1).getLocation());
+        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" + org.apache.karaf.features.internal.model.Feature.SPLIT_FOR_NAME_AND_VERSION + org.apache.karaf.features.internal.model.Feature.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).getLocation());
+        assertEquals("f3", features[2].getName());
+        assertNotNull(features[2].getConfigurationFiles());
+        assertEquals(1, features[2].getConfigurationFiles().size());
+        assertEquals("cf1", features[2].getConfigurationFiles().get(0).getFinalname());
+        assertEquals(true, features[2].getConfigurationFiles().get(0).isOverride());
+        assertEquals("cfloc", features[2].getConfigurationFiles().get(0).getLocation());
+    }
+
+    public void testLoadFormattedRepo() throws Exception {
+        RepositoryImpl r = new RepositoryImpl(getClass().getResource("repo2.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(3, 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).getLocation());
+        assertEquals("b2", features[0].getBundles().get(1).getLocation());
+        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" + org.apache.karaf.features.internal.model.Feature.SPLIT_FOR_NAME_AND_VERSION + org.apache.karaf.features.internal.model.Feature.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).getLocation());
+        assertEquals("f3", features[2].getName());
+        assertNotNull(features[2].getConfigurationFiles());
+        assertEquals(1, features[2].getConfigurationFiles().size());
+        assertEquals("cf1", features[2].getConfigurationFiles().get(0).getFinalname());
+        assertEquals(true, features[2].getConfigurationFiles().get(0).isOverride());
+        assertEquals("cfloc", features[2].getConfigurationFiles().get(0).getLocation());
+    }
+
+    public void testLoadRepoWithCapabilitiesAndRequirement() throws Exception {
+        RepositoryImpl r = new RepositoryImpl(getClass().getResource("repo3.xml").toURI());
+        // Check features
+        Feature[] features = r.getFeatures();
+        assertNotNull(features);
+        assertEquals(1, features.length);
+        assertNotNull(features[0]);
+        assertEquals("f1", features[0].getName());
+        assertEquals(1, features[0].getCapabilities().size());
+        assertEquals("cap", features[0].getCapabilities().get(0).getValue().trim());
+        assertEquals(1, features[0].getRequirements().size());
+        assertEquals("req", features[0].getRequirements().get(0).getValue().trim());
+
+        Resource res = FeatureResource.build(features[0], null, null);
+        assertEquals(1, res.getCapabilities("cap").size());
+        assertEquals(1, res.getRequirements("req").size());
+    }
+
+    public void testShowWrongUriInException() throws Exception {
+        String uri = "src/test/resources/org/apache/karaf/shell/features/repo1.xml";
+        RepositoryImpl r = new RepositoryImpl(new URI(uri));
+        try {
+            r.load();
+        } catch (Exception e) {
+            assertTrue(e.getMessage().contains(uri));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/test/java/org/apache/karaf/features/TestBase.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/TestBase.java b/features/core/src/test/java/org/apache/karaf/features/TestBase.java
new file mode 100644
index 0000000..ac8f3d9
--- /dev/null
+++ b/features/core/src/test/java/org/apache/karaf/features/TestBase.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features;
+
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
+
+import org.easymock.EasyMock;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.startlevel.BundleStartLevel;
+
+import static java.util.Arrays.asList;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+
+public class TestBase {
+    public Bundle createDummyBundle(long id, final String symbolicName, Dictionary<String,String> headers) {
+        Bundle bundle = EasyMock.createNiceMock(Bundle.class);
+        
+        // Be aware that this means all bundles are treated as different
+        expect(bundle.compareTo(EasyMock.<Bundle>anyObject())).andReturn(1).anyTimes();
+
+        expect(bundle.getBundleId()).andReturn(id).anyTimes();
+        expect(bundle.getSymbolicName()).andReturn(symbolicName).anyTimes();
+        expect(bundle.getHeaders()).andReturn(headers).anyTimes();
+        BundleStartLevel sl = EasyMock.createMock(BundleStartLevel.class);
+        expect(sl.isPersistentlyStarted()).andReturn(true).anyTimes();
+        expect(bundle.adapt(BundleStartLevel.class)).andReturn(sl).anyTimes();
+        replay(bundle, sl);
+        return bundle;
+    }
+    
+    public Dictionary<String, String> headers(String ... keyAndHeader) {
+        Hashtable<String, String> headersTable = new Hashtable<String, String>();
+        int c=0;
+        while (c < keyAndHeader.length) {
+            String key = keyAndHeader[c++];
+            String value = keyAndHeader[c++];
+            headersTable.put(key, value);
+        }
+        return headersTable;
+    }
+    
+    public Map<String, Map<String, Feature>> features(Feature ... features) {
+        final Map<String, Map<String, Feature>> featuresMap = new HashMap<String, Map<String,Feature>>();
+        for (Feature feature : features) {
+            Map<String, Feature> featureVersion = getOrCreate(featuresMap, feature);
+            featureVersion.put(feature.getVersion(), feature);
+        }
+        return featuresMap;
+    }
+    
+    private Map<String, Feature> getOrCreate(final Map<String, Map<String, Feature>> featuresMap, Feature feature) {
+        Map<String, Feature> featureVersion = featuresMap.get(feature.getName());
+        if (featureVersion == null) {
+            featureVersion = new HashMap<String, Feature>();
+            featuresMap.put(feature.getName(), featureVersion);
+        }
+        return featureVersion;
+    }
+
+    public Feature feature(String name) {
+        return feature(name, null);
+    }
+
+    public Feature feature(String name, String version) {
+        return new org.apache.karaf.features.internal.model.Feature(name, version);
+    }
+    
+    public Set<Bundle> setOf(Bundle ... elements) {
+        return new HashSet<Bundle>(Arrays.asList(elements));
+    }
+    
+    public Set<Long> setOf(Long ... elements) {
+        return new HashSet<Long>(Arrays.asList(elements));
+    }
+    
+    public Set<String> setOf(String ... elements) {
+        return new HashSet<String>(asList(elements));
+    }
+    
+    public Set<Feature> setOf(Feature ... elements) {
+        return new HashSet<Feature>(Arrays.asList(elements));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/test/java/org/apache/karaf/features/internal/service/BootFeaturesInstallerTest.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/internal/service/BootFeaturesInstallerTest.java b/features/core/src/test/java/org/apache/karaf/features/internal/service/BootFeaturesInstallerTest.java
new file mode 100644
index 0000000..31f4f29
--- /dev/null
+++ b/features/core/src/test/java/org/apache/karaf/features/internal/service/BootFeaturesInstallerTest.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.karaf.features.internal.service;
+
+import static java.util.Arrays.asList;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.junit.Assert.fail;
+
+import java.net.URI;
+import java.util.EnumSet;
+
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.FeaturesService.Option;
+import org.apache.karaf.features.TestBase;
+import org.easymock.EasyMock;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class BootFeaturesInstallerTest extends TestBase {
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testParser() {
+        BootFeaturesInstaller installer = new BootFeaturesInstaller(null, null, "", "", false);
+        Assert.assertEquals(asList(setOf("test1", "test2"),setOf("test3")), installer.parseBootFeatures("(test1, test2), test3"));
+        Assert.assertEquals(asList(setOf("test1", "test2", "test3")), installer.parseBootFeatures("test1, test2, test3"));
+    }
+    
+    @Test
+    public void testDefaultBootFeatures() throws Exception  {
+        FeaturesServiceImpl impl = EasyMock.createMock(FeaturesServiceImpl.class);
+
+        impl.installFeatures(setOf("config", "standard", "region"), EnumSet.of(Option.NoFailOnFeatureNotFound));
+        EasyMock.expectLastCall();
+
+        impl.bootDone();
+        EasyMock.expectLastCall();
+
+        replay(impl);
+        BootFeaturesInstaller bootFeatures = new BootFeaturesInstaller(null, impl, "", "config,standard,region", false);
+        bootFeatures.installBootFeatures();
+        EasyMock.verify(impl);        
+    }
+
+    @Test
+    public void testStagedBoot() throws Exception  {
+        FeaturesServiceImpl impl = EasyMock.createStrictMock(FeaturesServiceImpl.class);
+
+        impl.installFeatures(setOf("transaction"), EnumSet.of(Option.NoFailOnFeatureNotFound));
+        EasyMock.expectLastCall();
+        impl.installFeatures(setOf("ssh"), EnumSet.of(Option.NoFailOnFeatureNotFound));
+        EasyMock.expectLastCall();
+
+        impl.bootDone();
+        EasyMock.expectLastCall();
+
+        replay(impl);
+        BootFeaturesInstaller bootFeatures = new BootFeaturesInstaller(null, impl , "", "(transaction), ssh", false);
+        bootFeatures.installBootFeatures();
+        EasyMock.verify(impl);        
+    }
+
+    @Test
+    public void testStartDoesNotFailWithOneInvalidUri() throws Exception {
+        FeaturesServiceImpl impl = EasyMock.createStrictMock(FeaturesServiceImpl.class);
+        impl.addRepository(URI.create("mvn:inexistent/features/1.0/xml/features"));
+        EasyMock.expectLastCall().andThrow(new IllegalArgumentException());
+
+        impl.bootDone();
+        EasyMock.expectLastCall();
+
+        replay(impl);
+        BootFeaturesInstaller bootFeatures = new BootFeaturesInstaller(null, impl, "mvn:inexistent/features/1.0/xml/features", "", false);
+        bootFeatures.installBootFeatures();
+        EasyMock.verify(impl);
+    }
+
+}


[28/33] Revert "[KARAF-2852] Merge features/core and features/command"

Posted by gn...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResourceBuilder.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResourceBuilder.java b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResourceBuilder.java
new file mode 100644
index 0000000..cb2c36a
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResourceBuilder.java
@@ -0,0 +1,1129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.resolver;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.felix.utils.version.VersionRange;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+import org.osgi.framework.namespace.IdentityNamespace;
+import org.osgi.framework.wiring.BundleCapability;
+import org.osgi.framework.wiring.BundleRevision;
+import org.osgi.resource.Capability;
+import org.osgi.resource.Requirement;
+import org.osgi.resource.Resource;
+
+public class ResourceBuilder {
+
+    public static final String RESOLUTION_DYNAMIC = "dynamic";
+
+    public static Resource build(String uri, Map<String, String> headerMap)
+            throws BundleException {
+
+        // Verify that only manifest version 2 is specified.
+        String manifestVersion = getManifestVersion(headerMap);
+        if (manifestVersion == null || !manifestVersion.equals("2")) {
+            throw new BundleException("Unsupported 'Bundle-ManifestVersion' value: " + manifestVersion);
+        }
+
+        //
+        // Parse bundle version.
+        //
+
+        Version bundleVersion = Version.emptyVersion;
+        if (headerMap.get(Constants.BUNDLE_VERSION) != null) {
+            bundleVersion = Version.parseVersion(headerMap.get(Constants.BUNDLE_VERSION));
+        }
+
+        //
+        // Parse bundle symbolic name.
+        //
+
+        String bundleSymbolicName = null;
+        ParsedHeaderClause bundleCap = parseBundleSymbolicName(headerMap);
+        if (bundleCap == null) {
+            throw new BundleException("Bundle manifest must include bundle symbolic name");
+        }
+        bundleSymbolicName = (String) bundleCap.attrs.get(BundleRevision.BUNDLE_NAMESPACE);
+
+        // Now that we have symbolic name and version, create the resource
+        String type = headerMap.get(Constants.FRAGMENT_HOST) == null ? IdentityNamespace.TYPE_BUNDLE : IdentityNamespace.TYPE_FRAGMENT;
+        ResourceImpl resource = new ResourceImpl(bundleSymbolicName, type, bundleVersion);
+        if (uri != null) {
+            Map<String, Object> attrs = new HashMap<String, Object>();
+            attrs.put(UriNamespace.URI_NAMESPACE, uri);
+            resource.addCapability(new CapabilityImpl(resource, UriNamespace.URI_NAMESPACE, Collections.<String, String>emptyMap(), attrs));
+        }
+
+        // Add a bundle and host capability to all
+        // non-fragment bundles. A host capability is the same
+        // as a require capability, but with a different capability
+        // namespace. Bundle capabilities resolve required-bundle
+        // dependencies, while host capabilities resolve fragment-host
+        // dependencies.
+        if (headerMap.get(Constants.FRAGMENT_HOST) == null) {
+            // All non-fragment bundles have bundle capability.
+            resource.addCapability(new CapabilityImpl(resource, BundleRevision.BUNDLE_NAMESPACE, bundleCap.dirs, bundleCap.attrs));
+            // A non-fragment bundle can choose to not have a host capability.
+            String attachment = bundleCap.dirs.get(Constants.FRAGMENT_ATTACHMENT_DIRECTIVE);
+            attachment = (attachment == null) ? Constants.FRAGMENT_ATTACHMENT_RESOLVETIME : attachment;
+            if (!attachment.equalsIgnoreCase(Constants.FRAGMENT_ATTACHMENT_NEVER)) {
+                Map<String, Object> hostAttrs = new HashMap<String, Object>(bundleCap.attrs);
+                Object value = hostAttrs.remove(BundleRevision.BUNDLE_NAMESPACE);
+                hostAttrs.put(BundleRevision.HOST_NAMESPACE, value);
+                resource.addCapability(new CapabilityImpl(
+                        resource, BundleRevision.HOST_NAMESPACE,
+                        bundleCap.dirs,
+                        hostAttrs));
+            }
+        }
+
+        //
+        // Parse Fragment-Host.
+        //
+
+        List<RequirementImpl> hostReqs = parseFragmentHost(resource, headerMap);
+
+        //
+        // Parse Require-Bundle
+        //
+
+        List<ParsedHeaderClause> rbClauses = parseStandardHeader(headerMap.get(Constants.REQUIRE_BUNDLE));
+        rbClauses = normalizeRequireClauses(rbClauses);
+        List<Requirement> rbReqs = convertRequires(rbClauses, resource);
+
+        //
+        // Parse Import-Package.
+        //
+
+        List<ParsedHeaderClause> importClauses = parseStandardHeader(headerMap.get(Constants.IMPORT_PACKAGE));
+        importClauses = normalizeImportClauses(importClauses);
+        List<Requirement> importReqs = convertImports(importClauses, resource);
+
+        //
+        // Parse DynamicImport-Package.
+        //
+
+        List<ParsedHeaderClause> dynamicClauses = parseStandardHeader(headerMap.get(Constants.DYNAMICIMPORT_PACKAGE));
+        dynamicClauses = normalizeDynamicImportClauses(dynamicClauses);
+        List<Requirement> dynamicReqs = convertImports(dynamicClauses, resource);
+
+        //
+        // Parse Require-Capability.
+        //
+
+        List<ParsedHeaderClause> requireClauses = parseStandardHeader(headerMap.get(Constants.REQUIRE_CAPABILITY));
+        requireClauses = normalizeRequireCapabilityClauses(requireClauses);
+        List<Requirement> requireReqs = convertRequireCapabilities(requireClauses, resource);
+
+        //
+        // Parse Export-Package.
+        //
+
+        List<ParsedHeaderClause> exportClauses = parseStandardHeader(headerMap.get(Constants.EXPORT_PACKAGE));
+        exportClauses = normalizeExportClauses(exportClauses, bundleSymbolicName, bundleVersion);
+        List<Capability> exportCaps = convertExports(exportClauses, resource);
+
+        //
+        // Parse Provide-Capability.
+        //
+
+        List<ParsedHeaderClause> provideClauses = parseStandardHeader(headerMap.get(Constants.PROVIDE_CAPABILITY));
+        provideClauses = normalizeProvideCapabilityClauses(provideClauses);
+        List<Capability> provideCaps = convertProvideCapabilities(provideClauses, resource);
+
+        //
+        // Parse Import-Service and Export-Service
+        // if Require-Capability and Provide-Capability are not set for services
+        //
+
+        boolean hasServiceReferenceCapability = false;
+        for (Capability cap : exportCaps) {
+            hasServiceReferenceCapability |= ServiceNamespace.SERVICE_NAMESPACE.equals(cap.getNamespace());
+        }
+        if (!hasServiceReferenceCapability) {
+            List<ParsedHeaderClause> exportServices = parseStandardHeader(headerMap.get(Constants.EXPORT_SERVICE));
+            List<Capability> caps = convertExportService(exportServices, resource);
+            provideCaps.addAll(caps);
+        }
+
+        boolean hasServiceReferenceRequirement = false;
+        for (Requirement req : requireReqs) {
+            hasServiceReferenceRequirement |= ServiceNamespace.SERVICE_NAMESPACE.equals(req.getNamespace());
+        }
+        if (!hasServiceReferenceRequirement) {
+            List<ParsedHeaderClause> importServices = parseStandardHeader(headerMap.get(Constants.IMPORT_SERVICE));
+            List<Requirement> reqs = convertImportService(importServices, resource);
+            requireReqs.addAll(reqs);
+        }
+
+        // Combine all capabilities.
+        resource.addCapabilities(exportCaps);
+        resource.addCapabilities(provideCaps);
+
+        // Combine all requirements.
+        resource.addRequirements(hostReqs);
+        resource.addRequirements(importReqs);
+        resource.addRequirements(rbReqs);
+        resource.addRequirements(requireReqs);
+        resource.addRequirements(dynamicReqs);
+
+        return resource;
+    }
+
+    public static List<Requirement> parseImport(Resource resource, String imports) throws BundleException {
+        List<ParsedHeaderClause> importClauses = parseStandardHeader(imports);
+        importClauses = normalizeImportClauses(importClauses);
+        List<Requirement> importReqs = convertImports(importClauses, resource);
+        return importReqs;
+    }
+
+    public static List<Requirement> parseRequirement(Resource resource, String requirement) throws BundleException {
+        List<ParsedHeaderClause> requireClauses = parseStandardHeader(requirement);
+        requireClauses = normalizeRequireCapabilityClauses(requireClauses);
+        List<Requirement> requireReqs = convertRequireCapabilities(requireClauses, resource);
+        return requireReqs;
+    }
+
+    public static List<Capability> parseExport(Resource resource, String bundleSymbolicName, Version bundleVersion, String exports) throws BundleException {
+        List<ParsedHeaderClause> exportClauses = parseStandardHeader(exports);
+        exportClauses = normalizeExportClauses(exportClauses, bundleSymbolicName, bundleVersion);
+        List<Capability> exportCaps = convertExports(exportClauses, resource);
+        return exportCaps;
+    }
+
+    public static List<Capability> parseCapability(Resource resource, String capability) throws BundleException {
+        List<ParsedHeaderClause> provideClauses = parseStandardHeader(capability);
+        provideClauses = normalizeProvideCapabilityClauses(provideClauses);
+        List<Capability> provideCaps = convertProvideCapabilities(provideClauses, resource);
+        return provideCaps;
+    }
+
+    @SuppressWarnings( "deprecation" )
+    private static List<ParsedHeaderClause> normalizeImportClauses(
+            List<ParsedHeaderClause> clauses)
+            throws BundleException {
+        // Verify that the values are equals if the package specifies
+        // both version and specification-version attributes.
+        Set<String> dupeSet = new HashSet<String>();
+        for (ParsedHeaderClause clause : clauses) {
+            // Check for "version" and "specification-version" attributes
+            // and verify they are the same if both are specified.
+            Object v = clause.attrs.get(Constants.VERSION_ATTRIBUTE);
+            Object sv = clause.attrs.get(Constants.PACKAGE_SPECIFICATION_VERSION);
+            if ((v != null) && (sv != null)) {
+                // Verify they are equal.
+                if (!((String) v).trim().equals(((String) sv).trim())) {
+                    throw new IllegalArgumentException(
+                            "Both version and specification-version are specified, but they are not equal.");
+                }
+            }
+
+            // Ensure that only the "version" attribute is used and convert
+            // it to the VersionRange type.
+            if ((v != null) || (sv != null)) {
+                clause.attrs.remove(Constants.PACKAGE_SPECIFICATION_VERSION);
+                v = (v == null) ? sv : v;
+                clause.attrs.put(Constants.VERSION_ATTRIBUTE, VersionRange.parseVersionRange(v.toString()));
+            }
+
+            // If bundle version is specified, then convert its type to VersionRange.
+            v = clause.attrs.get(Constants.BUNDLE_VERSION_ATTRIBUTE);
+            if (v != null) {
+                clause.attrs.put(Constants.BUNDLE_VERSION_ATTRIBUTE, VersionRange.parseVersionRange(v.toString()));
+            }
+
+            // Verify java.* is not imported, nor any duplicate imports.
+            for (String pkgName : clause.paths) {
+                if (!dupeSet.contains(pkgName)) {
+                    // Verify that java.* packages are not imported.
+                    if (pkgName.startsWith("java.")) {
+                        throw new BundleException("Importing java.* packages not allowed: " + pkgName);
+                    }
+                    // The character "." has no meaning in the OSGi spec except
+                    // when placed on the bundle class path. Some people, however,
+                    // mistakenly think it means the default package when imported
+                    // or exported. This is not correct. It is invalid.
+                    else if (pkgName.equals(".")) {
+                        throw new BundleException("Importing '.' is invalid.");
+                    }
+                    // Make sure a package name was specified.
+                    else if (pkgName.length() == 0) {
+                        throw new BundleException(
+                                "Imported package names cannot be zero length.");
+                    }
+                    dupeSet.add(pkgName);
+                } else {
+                    throw new BundleException("Duplicate import: " + pkgName);
+                }
+            }
+        }
+
+        return clauses;
+    }
+
+    private static List<Capability> convertExportService(List<ParsedHeaderClause> clauses, Resource resource) {
+        List<Capability> capList = new ArrayList<Capability>();
+        for (ParsedHeaderClause clause : clauses) {
+            for (String path : clause.paths) {
+                Map<String, String> dirs = new LinkedHashMap<String, String>();
+                dirs.put(ServiceNamespace.CAPABILITY_EFFECTIVE_DIRECTIVE, ServiceNamespace.EFFECTIVE_ACTIVE);
+                Map<String, Object> attrs = new LinkedHashMap<String, Object>();
+                attrs.put(Constants.OBJECTCLASS, path);
+                attrs.putAll(clause.attrs);
+                capList.add(new CapabilityImpl(
+                                resource,
+                                ServiceNamespace.SERVICE_NAMESPACE,
+                                dirs,
+                                attrs));
+            }
+        }
+        return capList;
+    }
+
+    private static List<Requirement> convertImportService(List<ParsedHeaderClause> clauses, Resource resource) throws BundleException {
+        try {
+            List<Requirement> reqList = new ArrayList<Requirement>();
+            for (ParsedHeaderClause clause : clauses) {
+                for (String path : clause.paths) {
+                    String multiple = clause.dirs.get("multiple");
+                    String avail    = clause.dirs.get("availability");
+                    String filter   = (String) clause.attrs.get("filter");
+                    Map<String, String> dirs = new LinkedHashMap<String, String>();
+                    dirs.put(ServiceNamespace.REQUIREMENT_EFFECTIVE_DIRECTIVE, ServiceNamespace.EFFECTIVE_ACTIVE);
+                    if ("optional".equals(avail)) {
+                        dirs.put(ServiceNamespace.REQUIREMENT_RESOLUTION_DIRECTIVE, ServiceNamespace.RESOLUTION_OPTIONAL);
+                    }
+                    if ("true".equals(multiple)) {
+                        dirs.put(ServiceNamespace.REQUIREMENT_CARDINALITY_DIRECTIVE, ServiceNamespace.CARDINALITY_MULTIPLE);
+                    }
+                    if (filter == null) {
+                        filter = "(" + Constants.OBJECTCLASS + "=" + path + ")";
+                    } else if (!filter.startsWith("(") && !filter.endsWith(")")) {
+                        filter = "(&(" + Constants.OBJECTCLASS + "=" + path + ")(" + filter + "))";
+                    } else {
+                        filter = "(&(" + Constants.OBJECTCLASS + "=" + path + ")" + filter + ")";
+                    }
+                    dirs.put(ServiceNamespace.REQUIREMENT_FILTER_DIRECTIVE, filter);
+                    reqList.add(new RequirementImpl(
+                                    resource,
+                                    ServiceNamespace.SERVICE_NAMESPACE,
+                                    dirs,
+                                    Collections.<String, Object>emptyMap(),
+                                    SimpleFilter.parse(filter)));
+                }
+            }
+            return reqList;
+        } catch (Exception ex) {
+            throw new BundleException("Error creating requirement: " + ex, ex);
+        }
+    }
+
+    private static List<Requirement> convertImports(List<ParsedHeaderClause> clauses, Resource resource) {
+        // Now convert generic header clauses into requirements.
+        List<Requirement> reqList = new ArrayList<Requirement>();
+        for (ParsedHeaderClause clause : clauses) {
+            for (String path : clause.paths) {
+                // Prepend the package name to the array of attributes.
+                Map<String, Object> attrs = clause.attrs;
+                // Note that we use a linked hash map here to ensure the
+                // package attribute is first, which will make indexing
+                // more efficient.
+    // TODO: OSGi R4.3 - This is ordering is kind of hacky.
+                // Prepend the package name to the array of attributes.
+                Map<String, Object> newAttrs = new LinkedHashMap<String, Object>(attrs.size() + 1);
+                // We want this first from an indexing perspective.
+                newAttrs.put(BundleRevision.PACKAGE_NAMESPACE, path);
+                newAttrs.putAll(attrs);
+                // But we need to put it again to make sure it wasn't overwritten.
+                newAttrs.put(BundleRevision.PACKAGE_NAMESPACE, path);
+
+                // Create filter now so we can inject filter directive.
+                SimpleFilter sf = SimpleFilter.convert(newAttrs);
+
+                // Inject filter directive.
+    // TODO: OSGi R4.3 - Can we insert this on demand somehow?
+                Map<String, String> dirs = clause.dirs;
+                Map<String, String> newDirs = new HashMap<String, String>(dirs.size() + 1);
+                newDirs.putAll(dirs);
+                newDirs.put(Constants.FILTER_DIRECTIVE, sf.toString());
+
+                // Create package requirement and add to requirement list.
+                reqList.add(
+                        new RequirementImpl(
+                                resource,
+                                BundleRevision.PACKAGE_NAMESPACE,
+                                newDirs,
+                                Collections.<String, Object>emptyMap(),
+                                sf));
+            }
+        }
+
+        return reqList;
+    }
+
+    @SuppressWarnings( "deprecation" )
+    private static List<ParsedHeaderClause> normalizeDynamicImportClauses(
+            List<ParsedHeaderClause> clauses)
+            throws BundleException {
+        // Verify that the values are equals if the package specifies
+        // both version and specification-version attributes.
+        for (ParsedHeaderClause clause : clauses) {
+            // Add the resolution directive to indicate that these are
+            // dynamic imports.
+            clause.dirs.put(Constants.RESOLUTION_DIRECTIVE, RESOLUTION_DYNAMIC);
+
+            // Check for "version" and "specification-version" attributes
+            // and verify they are the same if both are specified.
+            Object v = clause.attrs.get(Constants.VERSION_ATTRIBUTE);
+            Object sv = clause.attrs.get(Constants.PACKAGE_SPECIFICATION_VERSION);
+            if ((v != null) && (sv != null)) {
+                // Verify they are equal.
+                if (!((String) v).trim().equals(((String) sv).trim())) {
+                    throw new IllegalArgumentException(
+                            "Both version and specification-version are specified, but they are not equal.");
+                }
+            }
+
+            // Ensure that only the "version" attribute is used and convert
+            // it to the VersionRange type.
+            if ((v != null) || (sv != null)) {
+                clause.attrs.remove(Constants.PACKAGE_SPECIFICATION_VERSION);
+                v = (v == null) ? sv : v;
+                clause.attrs.put(Constants.VERSION_ATTRIBUTE, VersionRange.parseVersionRange(v.toString()));
+            }
+
+            // If bundle version is specified, then convert its type to VersionRange.
+            v = clause.attrs.get(Constants.BUNDLE_VERSION_ATTRIBUTE);
+            if (v != null) {
+                clause.attrs.put(Constants.BUNDLE_VERSION_ATTRIBUTE, VersionRange.parseVersionRange(v.toString()));
+            }
+
+            // Dynamic imports can have duplicates, so verify that java.*
+            // packages are not imported.
+            for (String pkgName : clause.paths) {
+                if (pkgName.startsWith("java.")) {
+                    throw new BundleException("Dynamically importing java.* packages not allowed: " + pkgName);
+                } else if (!pkgName.equals("*") && pkgName.endsWith("*") && !pkgName.endsWith(".*")) {
+                    throw new BundleException("Partial package name wild carding is not allowed: " + pkgName);
+                }
+            }
+        }
+
+        return clauses;
+    }
+
+    private static List<ParsedHeaderClause> normalizeRequireCapabilityClauses(
+            List<ParsedHeaderClause> clauses)
+            throws BundleException {
+
+        return clauses;
+    }
+
+    private static List<ParsedHeaderClause> normalizeProvideCapabilityClauses(
+            List<ParsedHeaderClause> clauses)
+            throws BundleException
+    {
+
+        // Convert attributes into specified types.
+        for (ParsedHeaderClause clause : clauses)
+        {
+            for (Map.Entry<String, String> entry : clause.types.entrySet())
+            {
+                String type = entry.getValue();
+                if (!type.equals("String"))
+                {
+                    if (type.equals("Double"))
+                    {
+                        clause.attrs.put(
+                                entry.getKey(),
+                                new Double(clause.attrs.get(entry.getKey()).toString().trim()));
+                    }
+                    else if (type.equals("Version"))
+                    {
+                        clause.attrs.put(
+                                entry.getKey(),
+                                new Version(clause.attrs.get(entry.getKey()).toString().trim()));
+                    }
+                    else if (type.equals("Long"))
+                    {
+                        clause.attrs.put(
+                                entry.getKey(),
+                                new Long(clause.attrs.get(entry.getKey()).toString().trim()));
+                    }
+                    else if (type.startsWith("List"))
+                    {
+                        int startIdx = type.indexOf('<');
+                        int endIdx = type.indexOf('>');
+                        if (((startIdx > 0) && (endIdx <= startIdx))
+                                || ((startIdx < 0) && (endIdx > 0)))
+                        {
+                            throw new BundleException(
+                                    "Invalid Provide-Capability attribute list type for '"
+                                            + entry.getKey()
+                                            + "' : "
+                                            + type);
+                        }
+
+                        String listType = "String";
+                        if (endIdx > startIdx)
+                        {
+                            listType = type.substring(startIdx + 1, endIdx).trim();
+                        }
+
+                        List<String> tokens = parseDelimitedString(
+                                clause.attrs.get(entry.getKey()).toString(), ",", false);
+                        List<Object> values = new ArrayList<Object>(tokens.size());
+                        for (String token : tokens)
+                        {
+                            if (listType.equals("String"))
+                            {
+                                values.add(token);
+                            }
+                            else if (listType.equals("Double"))
+                            {
+                                values.add(new Double(token.trim()));
+                            }
+                            else if (listType.equals("Version"))
+                            {
+                                values.add(new Version(token.trim()));
+                            }
+                            else if (listType.equals("Long"))
+                            {
+                                values.add(new Long(token.trim()));
+                            }
+                            else
+                            {
+                                throw new BundleException(
+                                        "Unknown Provide-Capability attribute list type for '"
+                                                + entry.getKey()
+                                                + "' : "
+                                                + type);
+                            }
+                        }
+                        clause.attrs.put(
+                                entry.getKey(),
+                                values);
+                    }
+                    else
+                    {
+                        throw new BundleException(
+                                "Unknown Provide-Capability attribute type for '"
+                                        + entry.getKey()
+                                        + "' : "
+                                        + type);
+                    }
+                }
+            }
+        }
+
+        return clauses;
+    }
+
+    private static List<Requirement> convertRequireCapabilities(
+            List<ParsedHeaderClause> clauses, Resource resource)
+            throws BundleException {
+        // Now convert generic header clauses into requirements.
+        List<Requirement> reqList = new ArrayList<Requirement>();
+        for (ParsedHeaderClause clause : clauses) {
+            try {
+                String filterStr = clause.dirs.get(Constants.FILTER_DIRECTIVE);
+                SimpleFilter sf = (filterStr != null)
+                        ? SimpleFilter.parse(filterStr)
+                        : new SimpleFilter(null, null, SimpleFilter.MATCH_ALL);
+                for (String path : clause.paths) {
+                    // Create requirement and add to requirement list.
+                    reqList.add(new RequirementImpl(
+                                    resource, path, clause.dirs, clause.attrs, sf));
+                }
+            } catch (Exception ex) {
+                throw new BundleException("Error creating requirement: " + ex, ex);
+            }
+        }
+
+        return reqList;
+    }
+
+    private static List<Capability> convertProvideCapabilities(
+            List<ParsedHeaderClause> clauses, Resource resource)
+            throws BundleException {
+        List<Capability> capList = new ArrayList<Capability>();
+        for (ParsedHeaderClause clause : clauses) {
+            for (String path : clause.paths) {
+                if (path.startsWith("osgi.wiring.")) {
+//                    throw new BundleException("Manifest cannot use Provide-Capability for '" + path + "' namespace.");
+                }
+
+                // Create package capability and add to capability list.
+                capList.add(new CapabilityImpl(resource, path, clause.dirs, clause.attrs));
+            }
+        }
+
+        return capList;
+    }
+
+    @SuppressWarnings( "deprecation" )
+    private static List<ParsedHeaderClause> normalizeExportClauses(
+            List<ParsedHeaderClause> clauses,
+            String bsn, Version bv)
+            throws BundleException {
+        // Verify that "java.*" packages are not exported.
+        for (ParsedHeaderClause clause : clauses) {
+            // Verify that the named package has not already been declared.
+            for (String pkgName : clause.paths) {
+                // Verify that java.* packages are not exported.
+                if (pkgName.startsWith("java.")) {
+                    throw new BundleException("Exporting java.* packages not allowed: " + pkgName);
+                }
+                // The character "." has no meaning in the OSGi spec except
+                // when placed on the bundle class path. Some people, however,
+                // mistakenly think it means the default package when imported
+                // or exported. This is not correct. It is invalid.
+                else if (pkgName.equals(".")) {
+                    throw new BundleException("Exporing '.' is invalid.");
+                }
+                // Make sure a package name was specified.
+                else if (pkgName.length() == 0) {
+                    throw new BundleException("Exported package names cannot be zero length.");
+                }
+            }
+
+            // Check for "version" and "specification-version" attributes
+            // and verify they are the same if both are specified.
+            Object v = clause.attrs.get(Constants.VERSION_ATTRIBUTE);
+            Object sv = clause.attrs.get(Constants.PACKAGE_SPECIFICATION_VERSION);
+            if ((v != null) && (sv != null)) {
+                // Verify they are equal.
+                if (!((String) v).trim().equals(((String) sv).trim())) {
+                    throw new IllegalArgumentException("Both version and specification-version are specified, but they are not equal.");
+                }
+            }
+
+            // Always add the default version if not specified.
+            if ((v == null) && (sv == null)) {
+                v = Version.emptyVersion;
+            }
+
+            // Ensure that only the "version" attribute is used and convert
+            // it to the appropriate type.
+            if ((v != null) || (sv != null)) {
+                // Convert version attribute to type Version.
+                clause.attrs.remove(Constants.PACKAGE_SPECIFICATION_VERSION);
+                v = (v == null) ? sv : v;
+                clause.attrs.put(Constants.VERSION_ATTRIBUTE, Version.parseVersion(v.toString()));
+            }
+
+            // Find symbolic name and version attribute, if present.
+            if (clause.attrs.containsKey(Constants.BUNDLE_VERSION_ATTRIBUTE)
+                    || clause.attrs.containsKey(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE)) {
+                throw new BundleException("Exports must not specify bundle symbolic name or bundle version.");
+            }
+
+            // Now that we know that there are no bundle symbolic name and version
+            // attributes, add them since the spec says they are there implicitly.
+            clause.attrs.put(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE, bsn);
+            clause.attrs.put(Constants.BUNDLE_VERSION_ATTRIBUTE, bv);
+        }
+
+        return clauses;
+    }
+
+    private static List<Capability> convertExports(
+            List<ParsedHeaderClause> clauses, Resource resource) {
+        List<Capability> capList = new ArrayList<Capability>();
+        for (ParsedHeaderClause clause : clauses) {
+            for (String pkgName : clause.paths) {
+                // Prepend the package name to the array of attributes.
+                Map<String, Object> attrs = clause.attrs;
+                Map<String, Object> newAttrs = new HashMap<String, Object>(attrs.size() + 1);
+                newAttrs.putAll(attrs);
+                newAttrs.put(BundleRevision.PACKAGE_NAMESPACE, pkgName);
+
+                // Create package capability and add to capability list.
+                capList.add(new CapabilityImpl(resource, BundleRevision.PACKAGE_NAMESPACE, clause.dirs, newAttrs));
+            }
+        }
+
+        return capList;
+    }
+
+    private static String getManifestVersion(Map<String, String> headerMap) {
+        String manifestVersion = headerMap.get(Constants.BUNDLE_MANIFESTVERSION);
+        return (manifestVersion == null) ? "1" : manifestVersion.trim();
+    }
+
+    private static List<ParsedHeaderClause> calculateImplicitImports(
+            List<BundleCapability> exports, List<ParsedHeaderClause> imports)
+            throws BundleException {
+        List<ParsedHeaderClause> clauseList = new ArrayList<ParsedHeaderClause>();
+
+        // Since all R3 exports imply an import, add a corresponding
+        // requirement for each existing export capability. Do not
+        // duplicate imports.
+        Map<String, String> map = new HashMap<String, String>();
+        // Add existing imports.
+        for (ParsedHeaderClause anImport : imports) {
+            for (int pathIdx = 0; pathIdx < anImport.paths.size(); pathIdx++) {
+                map.put(anImport.paths.get(pathIdx), anImport.paths.get(pathIdx));
+            }
+        }
+        // Add import requirement for each export capability.
+        for (BundleCapability export : exports) {
+            if (map.get(export.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE).toString()) == null) {
+                // Convert Version to VersionRange.
+                Object version = export.getAttributes().get(Constants.VERSION_ATTRIBUTE);
+                ParsedHeaderClause clause = new ParsedHeaderClause();
+                if (version != null) {
+                    clause.attrs.put(Constants.VERSION_ATTRIBUTE, VersionRange.parseVersionRange(version.toString()));
+                }
+                clause.paths.add((String) export.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE));
+                clauseList.add(clause);
+            }
+        }
+
+        return clauseList;
+    }
+
+    private static List<Capability> calculateImplicitUses(
+            List<Capability> exports, List<ParsedHeaderClause> imports)
+            throws BundleException {
+        // Add a "uses" directive onto each export of R3 bundles
+        // that references every other import (which will include
+        // exports, since export implies import); this is
+        // necessary since R3 bundles assumed a single class space,
+        // but R4 allows for multiple class spaces.
+        String usesValue = "";
+        for (ParsedHeaderClause anImport : imports) {
+            for (int pathIdx = 0; pathIdx < anImport.paths.size(); pathIdx++) {
+                usesValue = usesValue
+                        + ((usesValue.length() > 0) ? "," : "")
+                        + anImport.paths.get(pathIdx);
+            }
+        }
+        for (int i = 0; i < exports.size(); i++) {
+            Map<String, String> dirs = new HashMap<String, String>(1);
+            dirs.put(Constants.USES_DIRECTIVE, usesValue);
+            exports.set(i, new CapabilityImpl(
+                    exports.get(i).getResource(),
+                    BundleRevision.PACKAGE_NAMESPACE,
+                    dirs,
+                    exports.get(i).getAttributes()));
+        }
+
+        return exports;
+    }
+
+    private static ParsedHeaderClause parseBundleSymbolicName(Map<String, String> headerMap)
+            throws BundleException {
+        List<ParsedHeaderClause> clauses = parseStandardHeader(headerMap.get(Constants.BUNDLE_SYMBOLICNAME));
+        if (clauses.size() > 0) {
+            if (clauses.size() > 1 || clauses.get(0).paths.size() > 1) {
+                throw new BundleException("Cannot have multiple symbolic names: " + headerMap.get(Constants.BUNDLE_SYMBOLICNAME));
+            }
+
+            // Get bundle version.
+            Version bundleVersion = Version.emptyVersion;
+            if (headerMap.get(Constants.BUNDLE_VERSION) != null) {
+                bundleVersion = Version.parseVersion(headerMap.get(Constants.BUNDLE_VERSION));
+            }
+
+            // Create a require capability and return it.
+            ParsedHeaderClause clause = clauses.get(0);
+            String symName = clause.paths.get(0);
+            clause.attrs.put(BundleRevision.BUNDLE_NAMESPACE, symName);
+            clause.attrs.put(Constants.BUNDLE_VERSION_ATTRIBUTE, bundleVersion);
+            return clause;
+        }
+
+        return null;
+    }
+
+    private static List<RequirementImpl> parseFragmentHost(
+            Resource resource, Map<String, String> headerMap)
+            throws BundleException {
+        List<RequirementImpl> reqs = new ArrayList<RequirementImpl>();
+
+        List<ParsedHeaderClause> clauses = parseStandardHeader(headerMap.get(Constants.FRAGMENT_HOST));
+        if (clauses.size() > 0) {
+            // Make sure that only one fragment host symbolic name is specified.
+            if (clauses.size() > 1 || clauses.get(0).paths.size() > 1) {
+                throw new BundleException("Fragments cannot have multiple hosts: " + headerMap.get(Constants.FRAGMENT_HOST));
+            }
+
+            // If the bundle-version attribute is specified, then convert
+            // it to the proper type.
+            Object value = clauses.get(0).attrs.get(Constants.BUNDLE_VERSION_ATTRIBUTE);
+            value = (value == null) ? "0.0.0" : value;
+            clauses.get(0).attrs.put(Constants.BUNDLE_VERSION_ATTRIBUTE, VersionRange.parseVersionRange(value.toString()));
+
+            // Note that we use a linked hash map here to ensure the
+            // host symbolic name is first, which will make indexing
+            // more efficient.
+    // TODO: OSGi R4.3 - This is ordering is kind of hacky.
+            // Prepend the host symbolic name to the map of attributes.
+            Map<String, Object> attrs = clauses.get(0).attrs;
+            Map<String, Object> newAttrs = new LinkedHashMap<String, Object>(attrs.size() + 1);
+            // We want this first from an indexing perspective.
+            newAttrs.put(BundleRevision.HOST_NAMESPACE, clauses.get(0).paths.get(0));
+            newAttrs.putAll(attrs);
+            // But we need to put it again to make sure it wasn't overwritten.
+            newAttrs.put(BundleRevision.HOST_NAMESPACE, clauses.get(0).paths.get(0));
+
+            // Create filter now so we can inject filter directive.
+            SimpleFilter sf = SimpleFilter.convert(newAttrs);
+
+            // Inject filter directive.
+    // TODO: OSGi R4.3 - Can we insert this on demand somehow?
+            Map<String, String> dirs = clauses.get(0).dirs;
+            Map<String, String> newDirs = new HashMap<String, String>(dirs.size() + 1);
+            newDirs.putAll(dirs);
+            newDirs.put(Constants.FILTER_DIRECTIVE, sf.toString());
+
+            reqs.add(new RequirementImpl(
+                    resource, BundleRevision.HOST_NAMESPACE,
+                    newDirs,
+                    newAttrs));
+        }
+
+        return reqs;
+    }
+
+    private static List<ParsedHeaderClause> normalizeRequireClauses(List<ParsedHeaderClause> clauses) {
+        // Convert bundle version attribute to VersionRange type.
+        for (ParsedHeaderClause clause : clauses) {
+            Object value = clause.attrs.get(Constants.BUNDLE_VERSION_ATTRIBUTE);
+            if (value != null) {
+                clause.attrs.put(Constants.BUNDLE_VERSION_ATTRIBUTE, VersionRange.parseVersionRange(value.toString()));
+            }
+        }
+
+        return clauses;
+    }
+
+    private static List<Requirement> convertRequires(List<ParsedHeaderClause> clauses, Resource resource) {
+        List<Requirement> reqList = new ArrayList<Requirement>();
+        for (ParsedHeaderClause clause : clauses) {
+            for (String path : clause.paths) {
+                // Prepend the bundle symbolic name to the array of attributes.
+                Map<String, Object> attrs = clause.attrs;
+                // Note that we use a linked hash map here to ensure the
+                // symbolic name attribute is first, which will make indexing
+                // more efficient.
+    // TODO: OSGi R4.3 - This is ordering is kind of hacky.
+                // Prepend the symbolic name to the array of attributes.
+                Map<String, Object> newAttrs = new LinkedHashMap<String, Object>(attrs.size() + 1);
+                // We want this first from an indexing perspective.
+                newAttrs.put(BundleRevision.BUNDLE_NAMESPACE, path);
+                newAttrs.putAll(attrs);
+                // But we need to put it again to make sure it wasn't overwritten.
+                newAttrs.put(BundleRevision.BUNDLE_NAMESPACE, path);
+
+                // Create filter now so we can inject filter directive.
+                SimpleFilter sf = SimpleFilter.convert(newAttrs);
+
+                // Inject filter directive.
+    // TODO: OSGi R4.3 - Can we insert this on demand somehow?
+                Map<String, String> dirs = clause.dirs;
+                Map<String, String> newDirs = new HashMap<String, String>(dirs.size() + 1);
+                newDirs.putAll(dirs);
+                newDirs.put(Constants.FILTER_DIRECTIVE, sf.toString());
+
+                // Create package requirement and add to requirement list.
+                reqList.add(new RequirementImpl(resource, BundleRevision.BUNDLE_NAMESPACE, newDirs, newAttrs));
+            }
+        }
+
+        return reqList;
+    }
+
+    private static final char EOF = (char) -1;
+
+    private static char charAt(int pos, String headers, int length)
+    {
+        if (pos >= length)
+        {
+            return EOF;
+        }
+        return headers.charAt(pos);
+    }
+
+    private static final int CLAUSE_START = 0;
+    private static final int PARAMETER_START = 1;
+    private static final int KEY = 2;
+    private static final int DIRECTIVE_OR_TYPEDATTRIBUTE = 4;
+    private static final int ARGUMENT = 8;
+    private static final int VALUE = 16;
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    private static List<ParsedHeaderClause> parseStandardHeader(String header)
+    {
+        List<ParsedHeaderClause> clauses = new ArrayList<ParsedHeaderClause>();
+        if (header == null)
+        {
+            return clauses;
+        }
+        ParsedHeaderClause clause = null;
+        String key = null;
+        Map targetMap = null;
+        int state = CLAUSE_START;
+        int currentPosition = 0;
+        int startPosition = 0;
+        int length = header.length();
+        boolean quoted = false;
+        boolean escaped = false;
+
+        char currentChar = EOF;
+        do
+        {
+            currentChar = charAt(currentPosition, header, length);
+            switch (state)
+            {
+                case CLAUSE_START:
+                    clause = new ParsedHeaderClause();
+                    clauses.add(clause);
+                    state = PARAMETER_START;
+                case PARAMETER_START:
+                    startPosition = currentPosition;
+                    state = KEY;
+                case KEY:
+                    switch (currentChar)
+                    {
+                        case ':':
+                        case '=':
+                            key = header.substring(startPosition, currentPosition).trim();
+                            startPosition = currentPosition + 1;
+                            targetMap = clause.attrs;
+                            state = currentChar == ':' ? DIRECTIVE_OR_TYPEDATTRIBUTE : ARGUMENT;
+                            break;
+                        case EOF:
+                        case ',':
+                        case ';':
+                            clause.paths.add(header.substring(startPosition, currentPosition).trim());
+                            state = currentChar == ',' ? CLAUSE_START : PARAMETER_START;
+                            break;
+                        default:
+                            break;
+                    }
+                    currentPosition++;
+                    break;
+                case DIRECTIVE_OR_TYPEDATTRIBUTE:
+                    switch(currentChar)
+                    {
+                        case '=':
+                            if (startPosition != currentPosition)
+                            {
+                                clause.types.put(key, header.substring(startPosition, currentPosition).trim());
+                            }
+                            else
+                            {
+                                targetMap = clause.dirs;
+                            }
+                            state = ARGUMENT;
+                            startPosition = currentPosition + 1;
+                            break;
+                        default:
+                            break;
+                    }
+                    currentPosition++;
+                    break;
+                case ARGUMENT:
+                    if (currentChar == '\"')
+                    {
+                        quoted = true;
+                        currentPosition++;
+                    }
+                    else
+                    {
+                        quoted = false;
+                    }
+                    if (!Character.isWhitespace(currentChar)) {
+                        state = VALUE;
+                    }
+                    else {
+                        currentPosition++;
+                    }
+                    break;
+                case VALUE:
+                    if (escaped)
+                    {
+                        escaped = false;
+                    }
+                    else
+                    {
+                        if (currentChar == '\\' )
+                        {
+                            escaped = true;
+                        }
+                        else if (quoted && currentChar == '\"')
+                        {
+                            quoted = false;
+                        }
+                        else if (!quoted)
+                        {
+                            String value = null;
+                            switch(currentChar)
+                            {
+                                case EOF:
+                                case ';':
+                                case ',':
+                                    value = header.substring(startPosition, currentPosition).trim();
+                                    if (value.startsWith("\"") && value.endsWith("\""))
+                                    {
+                                        value = value.substring(1, value.length() - 1);
+                                    }
+                                    if (targetMap.put(key, value) != null)
+                                    {
+                                        throw new IllegalArgumentException(
+                                                "Duplicate '" + key + "' in: " + header);
+                                    }
+                                    state = currentChar == ';' ? PARAMETER_START : CLAUSE_START;
+                                    break;
+                                default:
+                                    break;
+                            }
+                        }
+                    }
+                    currentPosition++;
+                    break;
+                default:
+                    break;
+            }
+        } while ( currentChar != EOF);
+
+        if (state > PARAMETER_START)
+        {
+            throw new IllegalArgumentException("Unable to parse header: " + header);
+        }
+        return clauses;
+    }
+
+    public static List<String> parseDelimitedString(String value, String delim)
+    {
+        return parseDelimitedString(value, delim, true);
+    }
+
+    /**
+     * Parses delimited string and returns an array containing the tokens. This
+     * parser obeys quotes, so the delimiter character will be ignored if it is
+     * inside of a quote. This method assumes that the quote character is not
+     * included in the set of delimiter characters.
+     * @param value the delimited string to parse.
+     * @param delim the characters delimiting the tokens.
+     * @return a list of string or an empty list if there are none.
+     **/
+    public static List<String> parseDelimitedString(String value, String delim, boolean trim)
+    {
+        if (value == null)
+        {
+            value = "";
+        }
+
+        List<String> list = new ArrayList();
+
+        int CHAR = 1;
+        int DELIMITER = 2;
+        int STARTQUOTE = 4;
+        int ENDQUOTE = 8;
+
+        StringBuffer sb = new StringBuffer();
+
+        int expecting = (CHAR | DELIMITER | STARTQUOTE);
+
+        boolean isEscaped = false;
+        for (int i = 0; i < value.length(); i++)
+        {
+            char c = value.charAt(i);
+
+            boolean isDelimiter = (delim.indexOf(c) >= 0);
+
+            if (!isEscaped && (c == '\\'))
+            {
+                isEscaped = true;
+                continue;
+            }
+
+            if (isEscaped)
+            {
+                sb.append(c);
+            }
+            else if (isDelimiter && ((expecting & DELIMITER) > 0))
+            {
+                if (trim)
+                {
+                    list.add(sb.toString().trim());
+                }
+                else
+                {
+                    list.add(sb.toString());
+                }
+                sb.delete(0, sb.length());
+                expecting = (CHAR | DELIMITER | STARTQUOTE);
+            }
+            else if ((c == '"') && ((expecting & STARTQUOTE) > 0))
+            {
+                sb.append(c);
+                expecting = CHAR | ENDQUOTE;
+            }
+            else if ((c == '"') && ((expecting & ENDQUOTE) > 0))
+            {
+                sb.append(c);
+                expecting = (CHAR | STARTQUOTE | DELIMITER);
+            }
+            else if ((expecting & CHAR) > 0)
+            {
+                sb.append(c);
+            }
+            else
+            {
+                throw new IllegalArgumentException("Invalid delimited string: " + value);
+            }
+
+            isEscaped = false;
+        }
+
+        if (sb.length() > 0)
+        {
+            if (trim)
+            {
+                list.add(sb.toString().trim());
+            }
+            else
+            {
+                list.add(sb.toString());
+            }
+        }
+
+        return list;
+    }
+
+
+    static class ParsedHeaderClause {
+        public final List<String> paths = new ArrayList<String>();
+        public final Map<String, String> dirs = new LinkedHashMap<String, String>();
+        public final Map<String, Object> attrs = new LinkedHashMap<String, Object>();
+        public final Map<String, String> types = new LinkedHashMap<String, String>();
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResourceImpl.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResourceImpl.java b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResourceImpl.java
new file mode 100644
index 0000000..18e0dc3
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResourceImpl.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.karaf.features.internal.resolver;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.osgi.framework.Version;
+import org.osgi.framework.namespace.IdentityNamespace;
+import org.osgi.resource.Capability;
+import org.osgi.resource.Requirement;
+import org.osgi.resource.Resource;
+
+/**
+ */
+public class ResourceImpl implements Resource {
+
+    private final List<Capability> m_caps;
+    private final List<Requirement> m_reqs;
+
+    public ResourceImpl(String name, Version version) {
+        this(name, IdentityNamespace.TYPE_BUNDLE, version);
+    }
+
+    public ResourceImpl(String name, String type, Version version)
+    {
+        m_caps = new ArrayList<Capability>();
+        m_caps.add(0, new IdentityCapability(this, name, type, version));
+        m_reqs = new ArrayList<Requirement>();
+    }
+
+    public void addCapability(Capability capability) {
+        assert capability.getResource() == this;
+        m_caps.add(capability);
+    }
+
+    public void addCapabilities(Iterable<? extends Capability> capabilities) {
+        for (Capability cap : capabilities) {
+            addCapability(cap);
+        }
+    }
+
+    public void addRequirement(Requirement requirement) {
+        assert requirement.getResource() == this;
+        m_reqs.add(requirement);
+    }
+
+    public void addRequirements(Iterable<? extends Requirement> requirements) {
+        for (Requirement req : requirements) {
+            addRequirement(req);
+        }
+    }
+
+    public List<Capability> getCapabilities(String namespace)
+    {
+        List<Capability> result = m_caps;
+        if (namespace != null)
+        {
+            result = new ArrayList<Capability>();
+            for (Capability cap : m_caps)
+            {
+                if (cap.getNamespace().equals(namespace))
+                {
+                    result.add(cap);
+                }
+            }
+        }
+        return result;
+    }
+
+    public List<Requirement> getRequirements(String namespace)
+    {
+        List<Requirement> result = m_reqs;
+        if (namespace != null)
+        {
+            result = new ArrayList<Requirement>();
+            for (Requirement req : m_reqs)
+            {
+                if (req.getNamespace().equals(namespace))
+                {
+                    result.add(req);
+                }
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public String toString()
+    {
+        Capability cap = getCapabilities(IdentityNamespace.IDENTITY_NAMESPACE).get(0);
+        return cap.getAttributes().get(IdentityNamespace.IDENTITY_NAMESPACE) + "/"
+                + cap.getAttributes().get(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ServiceNamespace.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ServiceNamespace.java b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ServiceNamespace.java
new file mode 100644
index 0000000..4fe3bf8
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ServiceNamespace.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.karaf.features.internal.resolver;
+
+import org.osgi.resource.Namespace;
+
+/**
+ */
+public final class ServiceNamespace extends Namespace {
+
+    public static final String SERVICE_NAMESPACE = "service-reference";
+
+    private ServiceNamespace() {
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/resolver/SimpleFilter.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/SimpleFilter.java b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/SimpleFilter.java
new file mode 100644
index 0000000..ae10441
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/SimpleFilter.java
@@ -0,0 +1,649 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.resolver;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.felix.utils.version.VersionRange;
+
+public class SimpleFilter
+{
+    public static final int MATCH_ALL = 0;
+    public static final int AND = 1;
+    public static final int OR = 2;
+    public static final int NOT = 3;
+    public static final int EQ = 4;
+    public static final int LTE = 5;
+    public static final int GTE = 6;
+    public static final int SUBSTRING = 7;
+    public static final int PRESENT = 8;
+    public static final int APPROX = 9;
+
+    private final String m_name;
+    private final Object m_value;
+    private final int m_op;
+
+    public SimpleFilter(String attr, Object value, int op)
+    {
+        m_name = attr;
+        m_value = value;
+        m_op = op;
+    }
+
+    public String getName()
+    {
+        return m_name;
+    }
+
+    public Object getValue()
+    {
+        return m_value;
+    }
+
+    public int getOperation()
+    {
+        return m_op;
+    }
+
+    public String toString()
+    {
+        String s = null;
+        switch (m_op)
+        {
+            case AND:
+                s = "(&" + toString((List) m_value) + ")";
+                break;
+            case OR:
+                s = "(|" + toString((List) m_value) + ")";
+                break;
+            case NOT:
+                s = "(!" + toString((List) m_value) + ")";
+                break;
+            case EQ:
+                s = "(" + m_name + "=" + toEncodedString(m_value) + ")";
+                break;
+            case LTE:
+                s = "(" + m_name + "<=" + toEncodedString(m_value) + ")";
+                break;
+            case GTE:
+                s = "(" + m_name + ">=" + toEncodedString(m_value) + ")";
+                break;
+            case SUBSTRING:
+                s = "(" + m_name + "=" + unparseSubstring((List<String>) m_value) + ")";
+                break;
+            case PRESENT:
+                s = "(" + m_name + "=*)";
+                break;
+            case APPROX:
+                s = "(" + m_name + "~=" + toEncodedString(m_value) + ")";
+                break;
+            case MATCH_ALL:
+                s = "(*)";
+                break;
+        }
+        return s;
+    }
+
+    private static String toString(List list)
+    {
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0; i < list.size(); i++)
+        {
+            sb.append(list.get(i).toString());
+        }
+        return sb.toString();
+    }
+
+    private static String toDecodedString(String s, int startIdx, int endIdx)
+    {
+        StringBuffer sb = new StringBuffer(endIdx - startIdx);
+        boolean escaped = false;
+        for (int i = 0; i < (endIdx - startIdx); i++)
+        {
+            char c = s.charAt(startIdx + i);
+            if (!escaped && (c == '\\'))
+            {
+                escaped = true;
+            }
+            else
+            {
+                escaped = false;
+                sb.append(c);
+            }
+        }
+
+        return sb.toString();
+    }
+
+    private static String toEncodedString(Object o)
+    {
+        if (o instanceof String)
+        {
+            String s = (String) o;
+            StringBuffer sb = new StringBuffer();
+            for (int i = 0; i < s.length(); i++)
+            {
+                char c = s.charAt(i);
+                if ((c == '\\') || (c == '(') || (c == ')') || (c == '*'))
+                {
+                    sb.append('\\');
+                }
+                sb.append(c);
+            }
+
+            o = sb.toString();
+        }
+
+        return o.toString();
+    }
+
+    public static SimpleFilter parse(String filter)
+    {
+        int idx = skipWhitespace(filter, 0);
+
+        if ((filter == null) || (filter.length() == 0) || (idx >= filter.length()))
+        {
+            throw new IllegalArgumentException("Null or empty filter.");
+        }
+        else if (filter.charAt(idx) != '(')
+        {
+            throw new IllegalArgumentException("Missing opening parenthesis: " + filter);
+        }
+
+        SimpleFilter sf = null;
+        List stack = new ArrayList();
+        boolean isEscaped = false;
+        while (idx < filter.length())
+        {
+            if (sf != null)
+            {
+                throw new IllegalArgumentException(
+                        "Only one top-level operation allowed: " + filter);
+            }
+
+            if (!isEscaped && (filter.charAt(idx) == '('))
+            {
+                // Skip paren and following whitespace.
+                idx = skipWhitespace(filter, idx + 1);
+
+                if (filter.charAt(idx) == '&')
+                {
+                    int peek = skipWhitespace(filter, idx + 1);
+                    if (filter.charAt(peek) == '(')
+                    {
+                        idx = peek - 1;
+                        stack.add(0, new SimpleFilter(null, new ArrayList(), SimpleFilter.AND));
+                    }
+                    else
+                    {
+                        stack.add(0, new Integer(idx));
+                    }
+                }
+                else if (filter.charAt(idx) == '|')
+                {
+                    int peek = skipWhitespace(filter, idx + 1);
+                    if (filter.charAt(peek) == '(')
+                    {
+                        idx = peek - 1;
+                        stack.add(0, new SimpleFilter(null, new ArrayList(), SimpleFilter.OR));
+                    }
+                    else
+                    {
+                        stack.add(0, new Integer(idx));
+                    }
+                }
+                else if (filter.charAt(idx) == '!')
+                {
+                    int peek = skipWhitespace(filter, idx + 1);
+                    if (filter.charAt(peek) == '(')
+                    {
+                        idx = peek - 1;
+                        stack.add(0, new SimpleFilter(null, new ArrayList(), SimpleFilter.NOT));
+                    }
+                    else
+                    {
+                        stack.add(0, new Integer(idx));
+                    }
+                }
+                else
+                {
+                    stack.add(0, new Integer(idx));
+                }
+            }
+            else if (!isEscaped && (filter.charAt(idx) == ')'))
+            {
+                Object top = stack.remove(0);
+                if (top instanceof SimpleFilter)
+                {
+                    if (!stack.isEmpty() && (stack.get(0) instanceof SimpleFilter))
+                    {
+                        ((List) ((SimpleFilter) stack.get(0)).m_value).add(top);
+                    }
+                    else
+                    {
+                        sf = (SimpleFilter) top;
+                    }
+                }
+                else if (!stack.isEmpty() && (stack.get(0) instanceof SimpleFilter))
+                {
+                    ((List) ((SimpleFilter) stack.get(0)).m_value).add(
+                            SimpleFilter.subfilter(filter, ((Integer) top).intValue(), idx));
+                }
+                else
+                {
+                    sf = SimpleFilter.subfilter(filter, ((Integer) top).intValue(), idx);
+                }
+            }
+            else if (!isEscaped && (filter.charAt(idx) == '\\'))
+            {
+                isEscaped = true;
+            }
+            else
+            {
+                isEscaped = false;
+            }
+
+            idx = skipWhitespace(filter, idx + 1);
+        }
+
+        if (sf == null)
+        {
+            throw new IllegalArgumentException("Missing closing parenthesis: " + filter);
+        }
+
+        return sf;
+    }
+
+    private static SimpleFilter subfilter(String filter, int startIdx, int endIdx)
+    {
+        final String opChars = "=<>~";
+
+        // Determine the ending index of the attribute name.
+        int attrEndIdx = startIdx;
+        for (int i = 0; i < (endIdx - startIdx); i++)
+        {
+            char c = filter.charAt(startIdx + i);
+            if (opChars.indexOf(c) >= 0)
+            {
+                break;
+            }
+            else if (!Character.isWhitespace(c))
+            {
+                attrEndIdx = startIdx + i + 1;
+            }
+        }
+        if (attrEndIdx == startIdx)
+        {
+            throw new IllegalArgumentException(
+                    "Missing attribute name: " + filter.substring(startIdx, endIdx));
+        }
+        String attr = filter.substring(startIdx, attrEndIdx);
+
+        // Skip the attribute name and any following whitespace.
+        startIdx = skipWhitespace(filter, attrEndIdx);
+
+        // Determine the operator type.
+        int op = -1;
+        switch (filter.charAt(startIdx))
+        {
+            case '=':
+                op = EQ;
+                startIdx++;
+                break;
+            case '<':
+                if (filter.charAt(startIdx + 1) != '=')
+                {
+                    throw new IllegalArgumentException(
+                            "Unknown operator: " + filter.substring(startIdx, endIdx));
+                }
+                op = LTE;
+                startIdx += 2;
+                break;
+            case '>':
+                if (filter.charAt(startIdx + 1) != '=')
+                {
+                    throw new IllegalArgumentException(
+                            "Unknown operator: " + filter.substring(startIdx, endIdx));
+                }
+                op = GTE;
+                startIdx += 2;
+                break;
+            case '~':
+                if (filter.charAt(startIdx + 1) != '=')
+                {
+                    throw new IllegalArgumentException(
+                            "Unknown operator: " + filter.substring(startIdx, endIdx));
+                }
+                op = APPROX;
+                startIdx += 2;
+                break;
+            default:
+                throw new IllegalArgumentException(
+                        "Unknown operator: " + filter.substring(startIdx, endIdx));
+        }
+
+        // Parse value.
+        Object value = toDecodedString(filter, startIdx, endIdx);
+
+        // Check if the equality comparison is actually a substring
+        // or present operation.
+        if (op == EQ)
+        {
+            String valueStr = filter.substring(startIdx, endIdx);
+            List<String> values = parseSubstring(valueStr);
+            if ((values.size() == 2)
+                    && (values.get(0).length() == 0)
+                    && (values.get(1).length() == 0))
+            {
+                op = PRESENT;
+            }
+            else if (values.size() > 1)
+            {
+                op = SUBSTRING;
+                value = values;
+            }
+        }
+
+        return new SimpleFilter(attr, value, op);
+    }
+
+    public static List<String> parseSubstring(String value)
+    {
+        List<String> pieces = new ArrayList();
+        StringBuffer ss = new StringBuffer();
+        // int kind = SIMPLE; // assume until proven otherwise
+        boolean wasStar = false; // indicates last piece was a star
+        boolean leftstar = false; // track if the initial piece is a star
+        boolean rightstar = false; // track if the final piece is a star
+
+        int idx = 0;
+
+        // We assume (sub)strings can contain leading and trailing blanks
+        boolean escaped = false;
+        loop:   for (;;)
+        {
+            if (idx >= value.length())
+            {
+                if (wasStar)
+                {
+                    // insert last piece as "" to handle trailing star
+                    rightstar = true;
+                }
+                else
+                {
+                    pieces.add(ss.toString());
+                    // accumulate the last piece
+                    // note that in the case of
+                    // (cn=); this might be
+                    // the string "" (!=null)
+                }
+                ss.setLength(0);
+                break loop;
+            }
+
+            // Read the next character and account for escapes.
+            char c = value.charAt(idx++);
+            if (!escaped && (c == '*'))
+            {
+                // If we have successive '*' characters, then we can
+                // effectively collapse them by ignoring succeeding ones.
+                if (!wasStar)
+                {
+                    if (ss.length() > 0)
+                    {
+                        pieces.add(ss.toString()); // accumulate the pieces
+                        // between '*' occurrences
+                    }
+                    ss.setLength(0);
+                    // if this is a leading star, then track it
+                    if (pieces.isEmpty())
+                    {
+                        leftstar = true;
+                    }
+                    wasStar = true;
+                }
+            }
+            else if (!escaped && (c == '\\'))
+            {
+                escaped = true;
+            }
+            else
+            {
+                escaped = false;
+                wasStar = false;
+                ss.append(c);
+            }
+        }
+        if (leftstar || rightstar || pieces.size() > 1)
+        {
+            // insert leading and/or trailing "" to anchor ends
+            if (rightstar)
+            {
+                pieces.add("");
+            }
+            if (leftstar)
+            {
+                pieces.add(0, "");
+            }
+        }
+        return pieces;
+    }
+
+    public static String unparseSubstring(List<String> pieces)
+    {
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0; i < pieces.size(); i++)
+        {
+            if (i > 0)
+            {
+                sb.append("*");
+            }
+            sb.append(toEncodedString(pieces.get(i)));
+        }
+        return sb.toString();
+    }
+
+    public static boolean compareSubstring(List<String> pieces, String s)
+    {
+        // Walk the pieces to match the string
+        // There are implicit stars between each piece,
+        // and the first and last pieces might be "" to anchor the match.
+        // assert (pieces.length > 1)
+        // minimal case is <string>*<string>
+
+        boolean result = true;
+        int len = pieces.size();
+
+        // Special case, if there is only one piece, then
+        // we must perform an equality test.
+        if (len == 1)
+        {
+            return s.equals(pieces.get(0));
+        }
+
+        // Otherwise, check whether the pieces match
+        // the specified string.
+
+        int index = 0;
+
+        loop:   for (int i = 0; i < len; i++)
+        {
+            String piece = pieces.get(i);
+
+            // If this is the first piece, then make sure the
+            // string starts with it.
+            if (i == 0)
+            {
+                if (!s.startsWith(piece))
+                {
+                    result = false;
+                    break loop;
+                }
+            }
+
+            // If this is the last piece, then make sure the
+            // string ends with it.
+            if (i == (len - 1))
+            {
+                if (s.endsWith(piece) && (s.length() >= (index + piece.length())))
+                {
+                    result = true;
+                }
+                else
+                {
+                    result = false;
+                }
+                break loop;
+            }
+
+            // If this is neither the first or last piece, then
+            // make sure the string contains it.
+            if ((i > 0) && (i < (len - 1)))
+            {
+                index = s.indexOf(piece, index);
+                if (index < 0)
+                {
+                    result = false;
+                    break loop;
+                }
+            }
+
+            // Move string index beyond the matching piece.
+            index += piece.length();
+        }
+
+        return result;
+    }
+
+    private static int skipWhitespace(String s, int startIdx)
+    {
+        int len = s.length();
+        while ((startIdx < len) && Character.isWhitespace(s.charAt(startIdx)))
+        {
+            startIdx++;
+        }
+        return startIdx;
+    }
+
+    /**
+     * Converts a attribute map to a filter. The filter is created by iterating
+     * over the map's entry set. If ordering of attributes is important (e.g.,
+     * for hitting attribute indices), then the map's entry set should iterate
+     * in the desired order. Equality testing is assumed for all attribute types
+     * other than version ranges, which are handled appropriated. If the attribute
+     * map is empty, then a filter that matches anything is returned.
+     * @param attrs Map of attributes to convert to a filter.
+     * @return A filter corresponding to the attributes.
+     */
+    public static SimpleFilter convert(Map<String, Object> attrs)
+    {
+        // Rather than building a filter string to be parsed into a SimpleFilter,
+        // we will just create the parsed SimpleFilter directly.
+
+        List<SimpleFilter> filters = new ArrayList<SimpleFilter>();
+
+        for (Entry<String, Object> entry : attrs.entrySet())
+        {
+            if (entry.getValue() instanceof VersionRange)
+            {
+                VersionRange vr = (VersionRange) entry.getValue();
+                if (!vr.isOpenFloor())
+                {
+                    filters.add(
+                            new SimpleFilter(
+                                    entry.getKey(),
+                                    vr.getFloor().toString(),
+                                    SimpleFilter.GTE));
+                }
+                else
+                {
+                    SimpleFilter not =
+                            new SimpleFilter(null, new ArrayList(), SimpleFilter.NOT);
+                    ((List) not.getValue()).add(
+                            new SimpleFilter(
+                                    entry.getKey(),
+                                    vr.getFloor().toString(),
+                                    SimpleFilter.LTE));
+                    filters.add(not);
+                }
+
+                if (vr.getCeiling() != null)
+                {
+                    if (!vr.isOpenCeiling())
+                    {
+                        filters.add(
+                                new SimpleFilter(
+                                        entry.getKey(),
+                                        vr.getCeiling().toString(),
+                                        SimpleFilter.LTE));
+                    }
+                    else
+                    {
+                        SimpleFilter not =
+                                new SimpleFilter(null, new ArrayList(), SimpleFilter.NOT);
+                        ((List) not.getValue()).add(
+                                new SimpleFilter(
+                                        entry.getKey(),
+                                        vr.getCeiling().toString(),
+                                        SimpleFilter.GTE));
+                        filters.add(not);
+                    }
+                }
+            }
+            else
+            {
+                List<String> values = SimpleFilter.parseSubstring(entry.getValue().toString());
+                if (values.size() > 1)
+                {
+                    filters.add(
+                            new SimpleFilter(
+                                    entry.getKey(),
+                                    values,
+                                    SimpleFilter.SUBSTRING));
+                }
+                else
+                {
+                    filters.add(
+                            new SimpleFilter(
+                                    entry.getKey(),
+                                    values.get(0),
+                                    SimpleFilter.EQ));
+                }
+            }
+        }
+
+        SimpleFilter sf = null;
+
+        if (filters.size() == 1)
+        {
+            sf = filters.get(0);
+        }
+        else if (attrs.size() > 1)
+        {
+            sf = new SimpleFilter(null, filters, SimpleFilter.AND);
+        }
+        else if (filters.isEmpty())
+        {
+            sf = new SimpleFilter(null, null, SimpleFilter.MATCH_ALL);
+        }
+
+        return sf;
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/resolver/Slf4jResolverLog.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/Slf4jResolverLog.java b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/Slf4jResolverLog.java
new file mode 100644
index 0000000..2f4a1f3
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/Slf4jResolverLog.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.karaf.features.internal.resolver;
+
+import org.slf4j.Logger;
+
+/**
+ */
+public class Slf4jResolverLog extends org.apache.felix.resolver.Logger {
+
+    private final Logger logger;
+
+    public Slf4jResolverLog(Logger logger) {
+        super(LOG_DEBUG);
+        this.logger = logger;
+    }
+
+    @Override
+    protected void doLog(int level, String msg, Throwable throwable) {
+        switch (level) {
+            case LOG_ERROR:
+                logger.error(msg, throwable);
+                break;
+            case LOG_WARNING:
+                logger.warn(msg, throwable);
+                break;
+            case LOG_INFO:
+                logger.info(msg, throwable);
+                break;
+            case LOG_DEBUG:
+                logger.debug(msg, throwable);
+                break;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/resolver/UriNamespace.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/UriNamespace.java b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/UriNamespace.java
new file mode 100644
index 0000000..b5158bf
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/UriNamespace.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.karaf.features.internal.resolver;
+
+import java.util.List;
+
+import org.osgi.resource.Capability;
+import org.osgi.resource.Namespace;
+import org.osgi.resource.Resource;
+
+/**
+ */
+public final class UriNamespace extends Namespace {
+
+    public static final String URI_NAMESPACE = "karaf.uri";
+
+    public static String getUri(Resource resource)
+    {
+        List<Capability> caps = resource.getCapabilities(null);
+        for (Capability cap : caps)
+        {
+            if (cap.getNamespace().equals(UriNamespace.URI_NAMESPACE))
+            {
+                return cap.getAttributes().get(UriNamespace.URI_NAMESPACE).toString();
+            }
+        }
+        return null;
+    }
+
+
+    private UriNamespace() {
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/service/Artifact.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/Artifact.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/Artifact.java
new file mode 100644
index 0000000..44e9a7c
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/Artifact.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.karaf.features.internal.service;
+
+import java.net.URI;
+
+/**
+ * Simple abstraction of a maven artifact to avoid external deps
+ */
+public class Artifact {
+    String groupId;
+    String artifactId;
+    String version;
+    String extension;
+    String classifier;
+    
+    public Artifact(String coords) {
+        String[] coordsAr = coords.split(":");
+        if (coordsAr.length != 5) {
+            throw new IllegalArgumentException("Maven URL " + coords + " is malformed or not complete");
+        }
+        this.groupId = coordsAr[0];
+        this.artifactId = coordsAr[1];
+        this.version = coordsAr[4];
+        this.extension = coordsAr[2];
+        this.classifier = coordsAr[3];
+    }
+    
+    public Artifact(String coords, String version) {
+        this(coords);
+        this.version = version;
+    }
+    
+    public URI getMavenUrl(String version) {
+        String uriSt = "mvn:" + this.groupId + "/" + this.artifactId + "/" + version + "/" + this.extension + "/" + this.classifier;
+        try {
+            return new URI(uriSt);
+        } catch (Exception e) {
+            return null;
+        }
+    }
+}


[22/33] Revert "[KARAF-2852] Merge features/core and features/command"

Posted by gn...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/deployment/Downloader.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/deployment/Downloader.java b/features/src/main/java/org/apache/karaf/features/internal/deployment/Downloader.java
deleted file mode 100644
index 2d5dd98..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/deployment/Downloader.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.deployment;
-
-import java.net.MalformedURLException;
-
-import org.apache.karaf.features.internal.util.MultiException;
-
-public interface Downloader {
-
-    void await() throws InterruptedException, MultiException;
-
-    void download(String location, DownloadCallback downloadCallback) throws MalformedURLException;
-
-    interface DownloadCallback {
-
-        void downloaded(StreamProvider provider) throws Exception;
-
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/deployment/StreamProvider.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/deployment/StreamProvider.java b/features/src/main/java/org/apache/karaf/features/internal/deployment/StreamProvider.java
deleted file mode 100644
index 60a3dfc..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/deployment/StreamProvider.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.deployment;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-public interface StreamProvider {
-
-    InputStream open() throws IOException;
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/management/FeaturesServiceMBeanImpl.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/management/FeaturesServiceMBeanImpl.java b/features/src/main/java/org/apache/karaf/features/internal/management/FeaturesServiceMBeanImpl.java
deleted file mode 100644
index b1a5865..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/management/FeaturesServiceMBeanImpl.java
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.karaf.features.internal.management;
-
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.EnumSet;
-import java.util.Hashtable;
-import java.util.List;
-
-import javax.management.MBeanNotificationInfo;
-import javax.management.MBeanRegistration;
-import javax.management.MBeanServer;
-import javax.management.NotCompliantMBeanException;
-import javax.management.Notification;
-import javax.management.ObjectName;
-import javax.management.openmbean.TabularData;
-
-import org.apache.karaf.features.*;
-import org.apache.karaf.features.management.FeaturesServiceMBean;
-import org.apache.karaf.features.management.codec.JmxFeature;
-import org.apache.karaf.features.management.codec.JmxFeatureEvent;
-import org.apache.karaf.features.management.codec.JmxRepository;
-import org.apache.karaf.features.management.codec.JmxRepositoryEvent;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceRegistration;
-
-/**
- * Implementation of {@link FeaturesServiceMBean}.
- */
-public class FeaturesServiceMBeanImpl extends StandardEmitterMBean implements
-        MBeanRegistration, FeaturesServiceMBean {
-
-    private ServiceRegistration<FeaturesListener> registration;
-
-    private BundleContext bundleContext;
-
-    private ObjectName objectName;
-
-    private volatile long sequenceNumber = 0;
-
-    private org.apache.karaf.features.FeaturesService featuresService;
-
-    public FeaturesServiceMBeanImpl() throws NotCompliantMBeanException {
-        super(FeaturesServiceMBean.class);
-    }
-
-    public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception {
-        objectName = name;
-        return name;
-    }
-
-    public void postRegister(Boolean registrationDone) {
-        registration = bundleContext.registerService(FeaturesListener.class,
-                getFeaturesListener(), new Hashtable<String, String>());
-    }
-
-    public void preDeregister() throws Exception {
-        registration.unregister();
-    }
-
-    public void postDeregister() {
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public TabularData getFeatures() throws Exception {
-        try {
-            List<Feature> allFeatures = Arrays.asList(featuresService.listFeatures());
-            List<Feature> insFeatures = Arrays.asList(featuresService.listInstalledFeatures());
-            ArrayList<JmxFeature> features = new ArrayList<JmxFeature>();
-            for (Feature feature : allFeatures) {
-                try {
-                    features.add(new JmxFeature(feature, insFeatures.contains(feature)));
-                } catch (Throwable t) {
-                    t.printStackTrace();
-                }
-            }
-            TabularData table = JmxFeature.tableFrom(features);
-            return table;
-        } catch (Throwable t) {
-            t.printStackTrace();
-            return null;
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public TabularData getRepositories() throws Exception {
-        try {
-            List<Repository> allRepositories = Arrays.asList(featuresService.listRepositories());
-            ArrayList<JmxRepository> repositories = new ArrayList<JmxRepository>();
-            for (Repository repository : allRepositories) {
-                try {
-                    repositories.add(new JmxRepository(repository));
-                } catch (Throwable t) {
-                    t.printStackTrace();
-                }
-            }
-            TabularData table = JmxRepository.tableFrom(repositories);
-            return table;
-        } catch (Throwable t) {
-            t.printStackTrace();
-            return null;
-        }
-    }
-
-    public void addRepository(String uri) throws Exception {
-        featuresService.addRepository(new URI(uri));
-    }
-
-    public void addRepository(String uri, boolean install) throws Exception {
-        featuresService.addRepository(new URI(uri), install);
-    }
-
-    public void removeRepository(String uri) throws Exception {
-        featuresService.removeRepository(new URI(uri));
-    }
-
-    public void removeRepository(String uri, boolean uninstall) throws Exception {
-        featuresService.removeRepository(new URI(uri), uninstall);
-    }
-
-    public void installFeature(String name) throws Exception {
-        featuresService.installFeature(name);
-    }
-
-    public void installFeature(String name, boolean noRefresh) throws Exception {
-        EnumSet<org.apache.karaf.features.FeaturesService.Option> options = EnumSet.noneOf(org.apache.karaf.features.FeaturesService.Option.class);
-        if (noRefresh) {
-            options.add(org.apache.karaf.features.FeaturesService.Option.NoAutoRefreshBundles);
-        }
-        featuresService.installFeature(name, options);
-    }
-
-    public void installFeature(String name, boolean noRefresh, boolean noStart) throws Exception {
-        EnumSet<org.apache.karaf.features.FeaturesService.Option> options = EnumSet.noneOf(org.apache.karaf.features.FeaturesService.Option.class);
-        if (noRefresh) {
-            options.add(org.apache.karaf.features.FeaturesService.Option.NoAutoRefreshBundles);
-        }
-        if (noStart) {
-            options.add(org.apache.karaf.features.FeaturesService.Option.NoAutoStartBundles);
-        }
-        featuresService.installFeature(name, options);
-    }
-
-    public void installFeature(String name, String version) throws Exception {
-        featuresService.installFeature(name, version);
-    }
-
-    public void installFeature(String name, String version, boolean noRefresh) throws Exception {
-        EnumSet<org.apache.karaf.features.FeaturesService.Option> options = EnumSet.noneOf(org.apache.karaf.features.FeaturesService.Option.class);
-        if (noRefresh) {
-            options.add(org.apache.karaf.features.FeaturesService.Option.NoAutoRefreshBundles);
-        }
-        featuresService.installFeature(name, version, options);
-    }
-
-    public void installFeature(String name, String version, boolean noRefresh, boolean noStart) throws Exception {
-        EnumSet<org.apache.karaf.features.FeaturesService.Option> options = EnumSet.noneOf(org.apache.karaf.features.FeaturesService.Option.class);
-        if (noRefresh) {
-            options.add(org.apache.karaf.features.FeaturesService.Option.NoAutoRefreshBundles);
-        }
-        if (noStart) {
-            options.add(org.apache.karaf.features.FeaturesService.Option.NoAutoStartBundles);
-        }
-        featuresService.installFeature(name, version, options);
-    }
-
-    public TabularData infoFeature(String name) throws Exception {
-        try {
-            Feature feature = featuresService.getFeature(name);
-            return infoFeature(feature);
-        } catch (Throwable t) {
-            t.printStackTrace();
-            return null;
-        }
-    }
-
-    public TabularData infoFeature(String name, String version) throws Exception {
-        try {
-            Feature feature = featuresService.getFeature(name, version);
-            return infoFeature(feature);
-        } catch (Throwable t) {
-            t.printStackTrace();
-            return null;
-        }
-    }
-
-    private TabularData infoFeature(Feature feature) throws Exception {
-        JmxFeature jmxFeature = null;
-        if (featuresService.isInstalled(feature)) {
-            jmxFeature = new JmxFeature(feature, true);
-        } else {
-            jmxFeature = new JmxFeature(feature, false);
-        }
-        ArrayList<JmxFeature> features = new ArrayList<JmxFeature>();
-        features.add(jmxFeature);
-        TabularData table = JmxFeature.tableFrom(features);
-        return table;
-    }
-
-    public void uninstallFeature(String name) throws Exception {
-        featuresService.uninstallFeature(name);
-    }
-
-    public void uninstallFeature(String name, boolean noRefresh) throws Exception {
-        EnumSet<org.apache.karaf.features.FeaturesService.Option> options = EnumSet.noneOf(org.apache.karaf.features.FeaturesService.Option.class);
-        if (noRefresh) {
-            options.add(org.apache.karaf.features.FeaturesService.Option.NoAutoRefreshBundles);
-        }
-        featuresService.uninstallFeature(name, options);
-    }
-
-    public void uninstallFeature(String name, String version) throws Exception {
-        featuresService.uninstallFeature(name, version);
-    }
-
-    public void uninstallFeature(String name, String version, boolean noRefresh) throws Exception {
-        EnumSet<org.apache.karaf.features.FeaturesService.Option> options = EnumSet.noneOf(org.apache.karaf.features.FeaturesService.Option.class);
-        if (noRefresh) {
-            options.add(org.apache.karaf.features.FeaturesService.Option.NoAutoRefreshBundles);
-        }
-        featuresService.uninstallFeature(name, version, options);
-    }
-
-    public void setBundleContext(BundleContext bundleContext) {
-        this.bundleContext = bundleContext;
-    }
-
-    public void setFeaturesService(org.apache.karaf.features.FeaturesService featuresService) {
-        this.featuresService = featuresService;
-    }
-
-    public FeaturesListener getFeaturesListener() {
-        return new FeaturesListener() {
-            public void featureEvent(FeatureEvent event) {
-                if (!event.isReplay()) {
-                    Notification notification = new Notification(FEATURE_EVENT_TYPE, objectName, sequenceNumber++);
-                    notification.setUserData(new JmxFeatureEvent(event).asCompositeData());
-                    sendNotification(notification);
-                }
-            }
-
-            public void repositoryEvent(RepositoryEvent event) {
-                if (!event.isReplay()) {
-                    Notification notification = new Notification(REPOSITORY_EVENT_TYPE, objectName, sequenceNumber++);
-                    notification.setUserData(new JmxRepositoryEvent(event).asCompositeData());
-                    sendNotification(notification);
-                }
-            }
-
-            public boolean equals(Object o) {
-                if (this == o) {
-                    return true;
-                }
-                return o.equals(this);
-            }
-
-        };
-    }
-
-    public MBeanNotificationInfo[] getNotificationInfo() {
-        return getBroadcastInfo();
-    }
-
-    private static MBeanNotificationInfo[] getBroadcastInfo() {
-        String type = Notification.class.getCanonicalName();
-        MBeanNotificationInfo info1 = new MBeanNotificationInfo(new String[]{FEATURE_EVENT_EVENT_TYPE},
-                type, "Some features notification");
-        MBeanNotificationInfo info2 = new MBeanNotificationInfo(new String[]{REPOSITORY_EVENT_EVENT_TYPE},
-                type, "Some repository notification");
-        return new MBeanNotificationInfo[]{info1, info2};
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/management/StandardEmitterMBean.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/management/StandardEmitterMBean.java b/features/src/main/java/org/apache/karaf/features/internal/management/StandardEmitterMBean.java
deleted file mode 100644
index 13a4b6c..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/management/StandardEmitterMBean.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.karaf.features.internal.management;
-
-import javax.management.*;
-
-public class StandardEmitterMBean extends StandardMBean implements NotificationEmitter {
-
-    private final NotificationBroadcasterSupport emitter;
-
-    @SuppressWarnings("rawtypes")
-	public StandardEmitterMBean(Class mbeanInterface) throws NotCompliantMBeanException {
-        super(mbeanInterface);
-        this.emitter = new NotificationBroadcasterSupport() {
-            @Override
-            public MBeanNotificationInfo[] getNotificationInfo() {
-                return StandardEmitterMBean.this.getNotificationInfo();
-            }
-        };
-    }
-
-    public void sendNotification(Notification notification) {
-        emitter.sendNotification(notification);
-    }
-
-
-    public void removeNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws ListenerNotFoundException {
-        emitter.removeNotificationListener(listener, filter, handback);
-    }
-
-    public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws IllegalArgumentException {
-        emitter.addNotificationListener(listener, filter, handback);
-    }
-
-    public void removeNotificationListener(NotificationListener listener) throws ListenerNotFoundException {
-        emitter.removeNotificationListener(listener);
-    }
-
-    public MBeanNotificationInfo[] getNotificationInfo() {
-        return new MBeanNotificationInfo[0];
-    }
-
-    @Override
-    public MBeanInfo getMBeanInfo() {
-        MBeanInfo mbeanInfo = super.getMBeanInfo();
-        if (mbeanInfo != null) {
-            MBeanNotificationInfo[] notificationInfo = getNotificationInfo();
-            mbeanInfo = new MBeanInfo(mbeanInfo.getClassName(), mbeanInfo.getDescription(), mbeanInfo.getAttributes(),
-                    mbeanInfo.getConstructors(), mbeanInfo.getOperations(), notificationInfo);
-        }
-        return mbeanInfo;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/model/Bundle.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/model/Bundle.java b/features/src/main/java/org/apache/karaf/features/internal/model/Bundle.java
deleted file mode 100644
index 7eebbe5..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/model/Bundle.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-
-package org.apache.karaf.features.internal.model;
-
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlSchemaType;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.XmlValue;
-import org.apache.karaf.features.BundleInfo;
-
-
-/**
- * 
- * Deployable element to install.
- *             
- * 
- * <p>Java class for bundle complex type.
- * 
- * <p>The following schema fragment specifies the expected content contained within this class.
- * 
- * <pre>
- * &lt;complexType name="bundle">
- *   &lt;simpleContent>
- *     &lt;extension base="&lt;http://www.w3.org/2001/XMLSchema>anyURI">
- *       &lt;attribute name="start-level" type="{http://www.w3.org/2001/XMLSchema}int" />
- *       &lt;attribute name="start" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *       &lt;attribute name="dependency" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *     &lt;/extension>
- *   &lt;/simpleContent>
- * &lt;/complexType>
- * </pre>
- * 
- * 
- */
-@XmlAccessorType(XmlAccessType.FIELD)
-@XmlType(name = "bundle", propOrder = {
-    "value"
-})
-public class Bundle implements BundleInfo {
-
-    @XmlValue
-    @XmlSchemaType(name = "anyURI")
-    protected String value;
-    @XmlAttribute(name = "start-level")
-    protected Integer startLevel;
-    @XmlAttribute
-    protected Boolean start;// = true;
-    @XmlAttribute
-    protected Boolean dependency;
-
-
-    public Bundle() {
-    }
-
-    public Bundle(String value) {
-        this.value = value;
-    }
-
-    /**
-     * Gets the value of the value property.
-     * 
-     * @return
-     *     possible object is
-     *     {@link String }
-     *     
-     */
-    public String getLocation() {
-        return value;
-    }
-
-    /**
-     * Sets the value of the value property.
-     * 
-     * @param value
-     *     allowed object is
-     *     {@link String }
-     *     
-     */
-    public void setLocation(String value) {
-        this.value = value;
-    }
-
-    /**
-     * Gets the value of the startLevel property.
-     * 
-     * @return
-     *     possible object is
-     *     {@link Integer }
-     *     
-     */
-    public int getStartLevel() {
-        return startLevel == null? 0: startLevel;
-    }
-
-    /**
-     * Sets the value of the startLevel property.
-     * 
-     * @param value
-     *     allowed object is
-     *     {@link Integer }
-     *     
-     */
-    public void setStartLevel(Integer value) {
-        this.startLevel = value;
-    }
-
-    /**
-     * Gets the value of the start property.
-     * 
-     * @return
-     *     possible object is
-     *     {@link Boolean }
-     *     
-     */
-    public boolean isStart() {
-        return start == null? true: start;
-    }
-
-    /**
-     * Sets the value of the start property.
-     * 
-     * @param value
-     *     allowed object is
-     *     {@link Boolean }
-     *     
-     */
-    public void setStart(Boolean value) {
-        this.start = value;
-    }
-
-    /**
-     * Gets the value of the dependency property.
-     * 
-     * @return
-     *     possible object is
-     *     {@link Boolean }
-     *     
-     */
-    public boolean isDependency() {
-        return dependency == null? false: dependency;
-    }
-
-    /**
-     * Sets the value of the dependency property.
-     * 
-     * @param value
-     *     allowed object is
-     *     {@link Boolean }
-     *     
-     */
-    public void setDependency(Boolean value) {
-        this.dependency = value;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        Bundle bundle = (Bundle) o;
-
-        if (dependency != bundle.dependency) return false;
-        if (start != bundle.start) return false;
-        if (startLevel != bundle.startLevel) return false;
-        if (value != null ? !value.equals(bundle.value) : bundle.value != null) return false;
-
-        return true;
-    }
-
-    @Override
-    public int hashCode() {
-        int result = value != null ? value.hashCode() : 0;
-        result = 31 * result + getStartLevel();
-        result = 31 * result + (isStart() ? 1 : 0);
-        result = 31 * result + (isDependency() ? 1 : 0);
-        return result;
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/model/Capability.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/model/Capability.java b/features/src/main/java/org/apache/karaf/features/internal/model/Capability.java
deleted file mode 100644
index ef60454..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/model/Capability.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-
-package org.apache.karaf.features.internal.model;
-
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.XmlValue;
-
-import org.apache.karaf.features.BundleInfo;
-
-
-/**
- * 
- * Additional capability for a feature.
- *             
- * 
- * <p>Java class for bundle complex type.
- * 
- * <p>The following schema fragment specifies the expected content contained within this class.
- * 
- * <pre>
- * &lt;complexType name="capability">
- *   &lt;simpleContent>
- *     &lt;extension base="&lt;http://www.w3.org/2001/XMLSchema>string">
- *     &lt;/extension>
- *   &lt;/simpleContent>
- * &lt;/complexType>
- * </pre>
- * 
- * 
- */
-@XmlAccessorType(XmlAccessType.FIELD)
-@XmlType(name = "capability", propOrder = {
-    "value"
-})
-public class Capability implements org.apache.karaf.features.Capability {
-
-    @XmlValue
-    protected String value;
-
-
-    public Capability() {
-    }
-
-    public Capability(String value) {
-        this.value = value;
-    }
-
-    public String getValue() {
-        return value;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        Capability bundle = (Capability) o;
-
-        if (value != null ? !value.equals(bundle.value) : bundle.value != null) return false;
-
-        return true;
-    }
-
-    @Override
-    public int hashCode() {
-        int result = value != null ? value.hashCode() : 0;
-        return result;
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/model/Conditional.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/model/Conditional.java b/features/src/main/java/org/apache/karaf/features/internal/model/Conditional.java
deleted file mode 100644
index ed0e8ff..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/model/Conditional.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.model;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlType;
-import org.apache.karaf.features.Feature;
-
-@XmlAccessorType(XmlAccessType.FIELD)
-@XmlType(name = "conditional", propOrder = {
-        "condition",
-        "config",
-        "configfile",
-        "feature",
-        "bundle"
-})
-public class Conditional extends Content implements org.apache.karaf.features.Conditional {
-
-    @XmlElement(name = "condition")
-    protected List<String> condition;
-
-    public List<String> getCondition() {
-        if (condition == null) {
-            this.condition = new ArrayList<String>();
-        }
-        return condition;
-    }
-
-    @Override
-    public Feature asFeature(String name, String version) {
-        String conditionName = name + "-condition-" + getConditionId().replaceAll("[^A-Za-z0-9 ]", "_");
-        org.apache.karaf.features.internal.model.Feature f = new org.apache.karaf.features.internal.model.Feature(conditionName, version);
-        f.getBundle().addAll(getBundle());
-        f.getConfig().addAll(getConfig());
-        f.getConfigfile().addAll(getConfigfile());
-        f.getFeature().addAll(getFeature());
-        return f;
-    }
-
-    private String getConditionId() {
-        StringBuffer sb = new StringBuffer();
-        for (String cond : getCondition()) {
-            if (sb.length() > 0) {
-                sb.append("_");
-            }
-            sb.append(cond);
-        }
-        return sb.toString();
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/model/Config.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/model/Config.java b/features/src/main/java/org/apache/karaf/features/internal/model/Config.java
deleted file mode 100644
index a2c6674..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/model/Config.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.karaf.features.internal.model;
-
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.XmlValue;
-
-
-/**
- * 
- * Configuration entries which should be created during feature installation. This
- * configuration may be used with OSGi Configuration Admin.
- *             
- * 
- * <p>Java class for config complex type.
- * 
- * <p>The following schema fragment specifies the expected content contained within this class.
- * 
- * <pre>
- * &lt;complexType name="config">
- *   &lt;simpleContent>
- *     &lt;extension base="&lt;http://www.w3.org/2001/XMLSchema>string">
- *       &lt;attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
- *     &lt;/extension>
- *   &lt;/simpleContent>
- * &lt;/complexType>
- * </pre>
- * 
- * 
- */
-@XmlAccessorType(XmlAccessType.FIELD)
-@XmlType(name = "config", propOrder = {
-    "value"
-})
-public class Config {
-
-    @XmlValue
-    protected String value;
-    @XmlAttribute(required = true)
-    protected String name;
-
-    /**
-     * Gets the value of the value property.
-     * 
-     * @return
-     *     possible object is
-     *     {@link String }
-     *     
-     */
-    public String getValue() {
-        return value;
-    }
-
-    /**
-     * Sets the value of the value property.
-     * 
-     * @param value
-     *     allowed object is
-     *     {@link String }
-     *     
-     */
-    public void setValue(String value) {
-        this.value = value;
-    }
-
-    /**
-     * Gets the value of the name property.
-     * 
-     * @return
-     *     possible object is
-     *     {@link String }
-     *     
-     */
-    public String getName() {
-        return name;
-    }
-
-    /**
-     * Sets the value of the name property.
-     * 
-     * @param value
-     *     allowed object is
-     *     {@link String }
-     *     
-     */
-    public void setName(String value) {
-        this.name = value;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/model/ConfigFile.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/model/ConfigFile.java b/features/src/main/java/org/apache/karaf/features/internal/model/ConfigFile.java
deleted file mode 100644
index e5d9d94..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/model/ConfigFile.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.karaf.features.internal.model;
-
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.XmlValue;
-import org.apache.karaf.features.ConfigFileInfo;
-
-
-/**
- * 
- * Additional configuration files which should be created during feature installation.
- *             
- * 
- * <p>Java class for configFile complex type.
- * 
- * <p>The following schema fragment specifies the expected content contained within this class.
- * 
- * <pre>
- * &lt;complexType name="configFile">
- *   &lt;simpleContent>
- *     &lt;extension base="&lt;http://www.w3.org/2001/XMLSchema>string">
- *       &lt;attribute name="finalname" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
- *       &lt;attribute name="override" type="{http://www.w3.org/2001/XMLSchema}boolean" />
- *     &lt;/extension>
- *   &lt;/simpleContent>
- * &lt;/complexType>
- * </pre>
- * 
- * 
- */
-@XmlAccessorType(XmlAccessType.FIELD)
-@XmlType(name = "configFile", propOrder = {
-    "value"
-})
-public class ConfigFile implements ConfigFileInfo {
-
-    @XmlValue
-    protected String value;
-    @XmlAttribute(required = true)
-    protected String finalname;
-    @XmlAttribute
-    protected Boolean override;
-
-    /**
-     * Gets the value of the value property.
-     * 
-     * @return
-     *     possible object is
-     *     {@link String }
-     *     
-     */
-    public String getLocation() {
-        return value;
-    }
-
-    /**
-     * Sets the value of the value property.
-     * 
-     * @param value
-     *     allowed object is
-     *     {@link String }
-     *     
-     */
-    public void setLocation(String value) {
-        this.value = value;
-    }
-
-    /**
-     * Gets the value of the finalname property.
-     * 
-     * @return
-     *     possible object is
-     *     {@link String }
-     *     
-     */
-    public String getFinalname() {
-        return finalname;
-    }
-
-    /**
-     * Sets the value of the finalname property.
-     * 
-     * @param value
-     *     allowed object is
-     *     {@link String }
-     *     
-     */
-    public void setFinalname(String value) {
-    	this.finalname = value;
-    }
-
-    /**
-     * Gets the value of the override property.
-     * 
-     * @return
-     *     possible object is
-     *     {@link Boolean }
-     *     
-     */
-    public boolean isOverride() {
-        return override == null? false: override;
-    }
-
-    /**
-     * Sets the value of the override property.
-     * 
-     * @param value
-     *     allowed object is
-     *     {@link Boolean }
-     *     
-     */
-    public void setOverride(Boolean value) {
-    	this.override = value;
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/model/Content.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/model/Content.java b/features/src/main/java/org/apache/karaf/features/internal/model/Content.java
deleted file mode 100644
index 756e4c1..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/model/Content.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.model;
-
-import java.io.IOException;
-import java.io.StringReader;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.HashMap;
-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.bind.annotation.XmlTransient;
-import org.apache.karaf.features.BundleInfo;
-import org.apache.karaf.features.ConfigFileInfo;
-
-@XmlTransient
-public class Content {
-
-    protected List<Config> config;
-    protected List<ConfigFile> configfile;
-    protected List<Dependency> feature;
-    protected List<Bundle> bundle;
-
-    /**
-     * Gets the value of the config property.
-     * <p/>
-     * <p/>
-     * This accessor method returns a reference to the live list,
-     * not a snapshot. Therefore any modification you make to the
-     * returned list will be present inside the JAXB object.
-     * This is why there is not a <CODE>set</CODE> method for the config property.
-     * <p/>
-     * <p/>
-     * For example, to add a new item, do as follows:
-     * <pre>
-     *    getConfig().add(newItem);
-     * </pre>
-     * <p/>
-     * <p/>
-     * <p/>
-     * Objects of the following type(s) are allowed in the list
-     * {@link Config }
-     */
-    public List<Config> getConfig() {
-        if (config == null) {
-            config = new ArrayList<Config>();
-        }
-        return this.config;
-    }
-
-    /**
-     * Gets the value of the configfile property.
-     * <p/>
-     * <p/>
-     * This accessor method returns a reference to the live list,
-     * not a snapshot. Therefore any modification you make to the
-     * returned list will be present inside the JAXB object.
-     * This is why there is not a <CODE>set</CODE> method for the configfile property.
-     * <p/>
-     * <p/>
-     * For example, to add a new item, do as follows:
-     * <pre>
-     *    getConfigfile().add(newItem);
-     * </pre>
-     * <p/>
-     * <p/>
-     * <p/>
-     * Objects of the following type(s) are allowed in the list
-     * {@link ConfigFile }
-     */
-    public List<ConfigFile> getConfigfile() {
-        if (configfile == null) {
-            configfile = new ArrayList<ConfigFile>();
-        }
-        return this.configfile;
-    }
-
-    /**
-     * Gets the value of the feature property.
-     * <p/>
-     * <p/>
-     * This accessor method returns a reference to the live list,
-     * not a snapshot. Therefore any modification you make to the
-     * returned list will be present inside the JAXB object.
-     * This is why there is not a <CODE>set</CODE> method for the feature property.
-     * <p/>
-     * <p/>
-     * For example, to add a new item, do as follows:
-     * <pre>
-     *    getFeature().add(newItem);
-     * </pre>
-     * <p/>
-     * <p/>
-     * <p/>
-     * Objects of the following type(s) are allowed in the list
-     * {@link Dependency }
-     */
-    public List<Dependency> getFeature() {
-        if (feature == null) {
-            feature = new ArrayList<Dependency>();
-        }
-        return this.feature;
-    }
-
-    /**
-     * Gets the value of the bundle property.
-     * <p/>
-     * <p/>
-     * This accessor method returns a reference to the live list,
-     * not a snapshot. Therefore any modification you make to the
-     * returned list will be present inside the JAXB object.
-     * This is why there is not a <CODE>set</CODE> method for the bundle property.
-     * <p/>
-     * <p/>
-     * For example, to add a new item, do as follows:
-     * <pre>
-     *    getBundle().add(newItem);
-     * </pre>
-     * <p/>
-     * <p/>
-     * <p/>
-     * Objects of the following type(s) are allowed in the list
-     * {@link Bundle }
-     */
-    public List<Bundle> getBundle() {
-        if (bundle == null) {
-            bundle = new ArrayList<Bundle>();
-        }
-        return this.bundle;
-    }
-
-    public List<org.apache.karaf.features.Dependency> getDependencies() {
-        return Collections.<org.apache.karaf.features.Dependency>unmodifiableList(getFeature());
-    }
-
-    public List<BundleInfo> getBundles() {
-        return Collections.<BundleInfo>unmodifiableList(getBundle());
-    }
-
-    public Map<String, Map<String, String>> getConfigurations() {
-        Map<String, Map<String, String>> result = new HashMap<String, Map<String, String>>();
-        for (Config config : getConfig()) {
-            String name = config.getName();
-            StringReader propStream = new StringReader(config.getValue());
-            Properties props = new Properties();
-            try {
-                props.load(propStream);
-            } catch (IOException e) {
-                //ignore??
-            }
-            interpolation(props);
-            Map<String, String> propMap = new HashMap<String, String>();
-            for (Map.Entry<Object, Object> entry : props.entrySet()) {
-                propMap.put((String) entry.getKey(), (String) entry.getValue());
-            }
-            result.put(name, propMap);
-        }
-        return result;
-    }
-
-    public List<ConfigFileInfo> getConfigurationFiles() {
-        return Collections.<ConfigFileInfo>unmodifiableList(getConfigfile());
-    }
-
-    @SuppressWarnings("rawtypes")
-	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);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/model/Dependency.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/model/Dependency.java b/features/src/main/java/org/apache/karaf/features/internal/model/Dependency.java
deleted file mode 100644
index 9c92a93..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/model/Dependency.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-
-package org.apache.karaf.features.internal.model;
-
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.XmlValue;
-
-
-/**
- * 
- * Dependency of feature.
- *             
- * 
- * <p>Java class for dependency complex type.
- * 
- * <p>The following schema fragment specifies the expected content contained within this class.
- * 
- * <pre>
- * &lt;complexType name="dependency">
- *   &lt;simpleContent>
- *     &lt;extension base="&lt;http://karaf.apache.org/xmlns/features/v1.0.0>featureName">
- *       &lt;attribute name="version" type="{http://www.w3.org/2001/XMLSchema}string" default="0.0.0" />
- *     &lt;/extension>
- *   &lt;/simpleContent>
- * &lt;/complexType>
- * </pre>
- * 
- * 
- */
-@XmlAccessorType(XmlAccessType.FIELD)
-@XmlType(name = "dependency", propOrder = {
-    "value"
-})
-public class Dependency implements org.apache.karaf.features.Dependency {
-
-    @XmlValue
-    protected String value;
-    @XmlAttribute
-    protected String version;
-
-    /**
-     * 
-     * Feature name should be non empty string.
-     *             
-     * 
-     * @return
-     *     possible object is
-     *     {@link String }
-     *     
-     */
-    public String getName() {
-        return value;
-    }
-
-    /**
-     * Sets the value of the value property.
-     * 
-     * @param value
-     *     allowed object is
-     *     {@link String }
-     *     
-     */
-    public void setName(String value) {
-        this.value = value;
-    }
-
-    /**
-     * Gets the value of the version property.
-     * 
-     * @return
-     *     possible object is
-     *     {@link String }
-     *     
-     */
-    public String getVersion() {
-        if (version == null) {
-            return "0.0.0";
-        } else {
-            return version;
-        }
-    }
-
-    /**
-     * Sets the value of the version property.
-     * 
-     * @param value
-     *     allowed object is
-     *     {@link String }
-     *     
-     */
-    public void setVersion(String value) {
-        this.version = value;
-    }
-
-    public String toString() {
-    	String ret = getName() + Feature.SPLIT_FOR_NAME_AND_VERSION + getVersion();
-    	return ret;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/model/Feature.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/model/Feature.java b/features/src/main/java/org/apache/karaf/features/internal/model/Feature.java
deleted file mode 100644
index 46580da..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/model/Feature.java
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.karaf.features.internal.model;
-
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.List;
-import java.util.Properties;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlType;
-
-
-/**
- * 
- * Definition of the Feature.
- *             
- * 
- * <p>Java class for feature complex type.
- * 
- * <p>The following schema fragment specifies the expected content contained within this class.
- * 
- * <pre>
- * &lt;complexType name="feature">
- *   &lt;complexContent>
- *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       &lt;sequence>
- *         &lt;element name="details" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
- *         &lt;element name="config" type="{http://karaf.apache.org/xmlns/features/v1.0.0}config" maxOccurs="unbounded" minOccurs="0"/>
- *         &lt;element name="configfile" type="{http://karaf.apache.org/xmlns/features/v1.0.0}configFile" maxOccurs="unbounded" minOccurs="0"/>
- *         &lt;element name="feature" type="{http://karaf.apache.org/xmlns/features/v1.0.0}dependency" maxOccurs="unbounded" minOccurs="0"/>
- *         &lt;element name="bundle" type="{http://karaf.apache.org/xmlns/features/v1.0.0}bundle" maxOccurs="unbounded" minOccurs="0"/>
- *         &lt;element name="conditional" type="{http://karaf.apache.org/xmlns/features/v1.0.0}conditional" maxOccurs="unbounded" minOccurs="0"/>
- *         &lt;element name="capability" type="{http://karaf.apache.org/xmlns/features/v1.0.0}capability" maxOccurs="unbounded" minOccurs="0"/>
- *         &lt;element name="requirement" type="{http://karaf.apache.org/xmlns/features/v1.0.0}requirement" maxOccurs="unbounded" minOccurs="0"/>
- *       &lt;/sequence>
- *       &lt;attribute name="name" use="required" type="{http://karaf.apache.org/xmlns/features/v1.0.0}featureName" />
- *       &lt;attribute name="version" type="{http://www.w3.org/2001/XMLSchema}string" default="0.0.0" />
- *       &lt;attribute name="description" type="{http://www.w3.org/2001/XMLSchema}string" />
- *       &lt;attribute name="resolver" type="{http://karaf.apache.org/xmlns/features/v1.0.0}resolver" />
- *     &lt;/restriction>
- *   &lt;/complexContent>
- * &lt;/complexType>
- * </pre>
- * 
- * 
- */
-@XmlAccessorType(XmlAccessType.FIELD)
-@XmlType(name = "feature", propOrder = {
-    "details",
-    "config",
-    "configfile",
-    "feature",
-    "bundle",
-    "conditional",
-    "capability",
-    "requirement"
-})
-public class Feature extends Content implements org.apache.karaf.features.Feature {
-    public static String SPLIT_FOR_NAME_AND_VERSION = "/";
-    public static String DEFAULT_VERSION = "0.0.0";
-
-
-    protected String details;
-    @XmlAttribute(required = true)
-    protected String name;
-    @XmlAttribute
-    protected String version;
-    @XmlAttribute
-    protected String description;
-    @XmlAttribute
-    protected String resolver;
-    @XmlAttribute
-    protected String install;
-    @XmlAttribute(name = "start-level")
-    protected Integer startLevel;
-    @XmlAttribute
-    protected String region;
-    protected List<Conditional> conditional;
-    protected List<Capability> capability;
-    protected List<Requirement> requirement;
-
-    public Feature() {
-    }
-
-    public Feature(String name) {
-        this.name = name;
-    }
-
-    public Feature(String name, String version) {
-        this.name = name;
-        this.version = version;
-    }
-
-
-    public static org.apache.karaf.features.Feature valueOf(String str) {
-    	if (str.contains(SPLIT_FOR_NAME_AND_VERSION)) {
-    		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 Feature(strName, strVersion);
-    	} else {
-    		return new Feature(str);
-    	}
-
-
-    }
-
-
-    public String getId() {
-        return getName() + SPLIT_FOR_NAME_AND_VERSION + getVersion();
-    }
-
-    /**
-     * Gets the value of the name property.
-     * 
-     * @return
-     *     possible object is
-     *     {@link String }
-     *     
-     */
-    public String getName() {
-        return name;
-    }
-
-    /**
-     * Sets the value of the name property.
-     * 
-     * @param value
-     *     allowed object is
-     *     {@link String }
-     *     
-     */
-    public void setName(String value) {
-        this.name = value;
-    }
-
-    /**
-     * Gets the value of the version property.
-     * 
-     * @return
-     *     possible object is
-     *     {@link String }
-     *     
-     */
-    public String getVersion() {
-        if (version == null) {
-            return DEFAULT_VERSION;
-        } else {
-            return version;
-        }
-    }
-
-    /**
-     * Sets the value of the version property.
-     * 
-     * @param value
-     *     allowed object is
-     *     {@link String }
-     *     
-     */
-    public void setVersion(String value) {
-        this.version = value;
-    }
-
-    /**
-     * Since version has a default value ("0.0.0"), returns
-     * whether or not the version has been set.
-     */
-    public boolean hasVersion() {
-        return this.version != null;
-    }
-
-    /**
-     * Gets the value of the description property.
-     * 
-     * @return
-     *     possible object is
-     *     {@link String }
-     *     
-     */
-    public String getDescription() {
-        return description;
-    }
-
-    /**
-     * Sets the value of the description property.
-     * 
-     * @param value
-     *     allowed object is
-     *     {@link String }
-     *     
-     */
-    public void setDescription(String value) {
-        this.description = value;
-    }
-
-    public String getDetails() {
-        return details;
-    }
-
-    public void setDetails(String details) {
-        this.details = details;
-    }
-
-    /**
-     * Gets the value of the resolver property.
-     * 
-     * @return
-     *     possible object is
-     *     {@link String }
-     *     
-     */
-    public String getResolver() {
-        return resolver;
-    }
-
-    public String getInstall() {
-        return install;
-    }
-
-    public void setInstall(String install) {
-        this.install = install;
-    }
-
-    /**
-     * Sets the value of the resolver property.
-     * 
-     * @param value
-     *     allowed object is
-     *     {@link String }
-     *     
-     */
-    public void setResolver(String value) {
-        this.resolver = value;
-    }
-    
-    /**
-     * Gets the value of the startLevel property.
-     * 
-     * @return
-     *     possible object is
-     *     {@link Integer }
-     *     
-     */
-    public int getStartLevel() {
-        return startLevel == null? 0: startLevel;
-    }
-
-    /**
-     * Sets the value of the startLevel property.
-     * 
-     * @param value
-     *     allowed object is
-     *     {@link Integer }
-     *     
-     */
-    public void setStartLevel(Integer value) {
-        this.startLevel = value;
-    }
-
-
-    public String getRegion() {
-        return region;
-    }
-
-    public void setRegion(String region) {
-        this.region = region;
-    }
-
-    /**
-     * Gets the value of the conditional property.
-     * <p/>
-     * <p/>
-     * This accessor method returns a reference to the live list,
-     * not a snapshot. Therefore any modification you make to the
-     * returned list will be present inside the JAXB object.
-     * This is why there is not a <CODE>set</CODE> method for the feature property.
-     * <p/>
-     * <p/>
-     * For example, to add a new item, do as follows:
-     * <pre>
-     *    getConditionals().add(newItem);
-     * </pre>
-     * <p/>
-     * <p/>
-     * <p/>
-     * Objects of the following type(s) are allowed in the list
-     * {@link Conditional }
-     */
-    public List<Conditional> getConditional() {
-        if (conditional == null) {
-            conditional = new ArrayList<Conditional>();
-        }
-        return this.conditional;
-    }
-
-    public List<Capability> getCapabilities() {
-        if (capability == null) {
-            capability = new ArrayList<Capability>();
-        }
-        return this.capability;
-    }
-
-    public List<Requirement> getRequirements() {
-        if (requirement == null) {
-            requirement = new ArrayList<Requirement>();
-        }
-        return this.requirement;
-    }
-
-    public String toString() {
-    	return getId();
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        Feature feature = (Feature) o;
-
-        if (name != null ? !name.equals(feature.name) : feature.name != null) return false;
-        if (version != null ? !version.equals(feature.version) : feature.version != null) return false;
-
-        return true;
-    }
-
-    @Override
-    public int hashCode() {
-        int result = name != null ? name.hashCode() : 0;
-        result = 31 * result + (version != null ? version.hashCode() : 0);
-        return result;
-    }
-
-    @SuppressWarnings("rawtypes")
-	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);
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/model/Features.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/model/Features.java b/features/src/main/java/org/apache/karaf/features/internal/model/Features.java
deleted file mode 100644
index e116f31..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/model/Features.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.karaf.features.internal.model;
-
-import java.util.ArrayList;
-import java.util.List;
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlSchemaType;
-import javax.xml.bind.annotation.XmlType;
-
-
-/**
- * 
- * Root element of Feature definition. It contains optional attribute which allow
- * name of repository. This name will be used in shell to display source repository
- * of given feature.
- *             
- * 
- * <p>Java class for featuresRoot complex type.
- * 
- * <p>The following schema fragment specifies the expected content contained within this class.
- * 
- * <pre>
- * &lt;complexType name="features">
- *   &lt;complexContent>
- *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       &lt;sequence>
- *         &lt;element name="repository" type="{http://www.w3.org/2001/XMLSchema}anyURI" maxOccurs="unbounded" minOccurs="0"/>
- *         &lt;element name="feature" type="{http://karaf.apache.org/xmlns/features/v1.0.0}feature" maxOccurs="unbounded" minOccurs="0"/>
- *       &lt;/sequence>
- *       &lt;attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
- *     &lt;/restriction>
- *   &lt;/complexContent>
- * &lt;/complexType>
- * </pre>
- * 
- * 
- */
-@XmlRootElement(name = "features")
-@XmlAccessorType(XmlAccessType.FIELD)
-@XmlType(name = "features", propOrder = {
-    "repository",
-    "feature"
-})
-public class Features {
-
-    @XmlSchemaType(name = "anyURI")
-    protected List<String> repository;
-    protected List<Feature> feature;
-    @XmlAttribute
-    protected String name;
-
-    /**
-     * Gets the value of the repository property.
-     * 
-     * <p>
-     * This accessor method returns a reference to the live list,
-     * not a snapshot. Therefore any modification you make to the
-     * returned list will be present inside the JAXB object.
-     * This is why there is not a <CODE>set</CODE> method for the repository property.
-     * 
-     * <p>
-     * For example, to add a new item, do as follows:
-     * <pre>
-     *    getRepository().add(newItem);
-     * </pre>
-     * 
-     * 
-     * <p>
-     * Objects of the following type(s) are allowed in the list
-     * {@link String }
-     * 
-     * 
-     */
-    public List<String> getRepository() {
-        if (repository == null) {
-            repository = new ArrayList<String>();
-        }
-        return this.repository;
-    }
-
-    /**
-     * Gets the value of the feature property.
-     * 
-     * <p>
-     * This accessor method returns a reference to the live list,
-     * not a snapshot. Therefore any modification you make to the
-     * returned list will be present inside the JAXB object.
-     * This is why there is not a <CODE>set</CODE> method for the feature property.
-     * 
-     * <p>
-     * For example, to add a new item, do as follows:
-     * <pre>
-     *    getFeature().add(newItem);
-     * </pre>
-     * 
-     * 
-     * <p>
-     * Objects of the following type(s) are allowed in the list
-     * {@link Feature }
-     * 
-     * 
-     */
-    public List<Feature> getFeature() {
-        if (feature == null) {
-            feature = new ArrayList<Feature>();
-        }
-        return this.feature;
-    }
-
-    /**
-     * Gets the value of the name property.
-     * 
-     * @return
-     *     possible object is
-     *     {@link String }
-     *     
-     */
-    public String getName() {
-        return name;
-    }
-
-    /**
-     * Sets the value of the name property.
-     * 
-     * @param value
-     *     allowed object is
-     *     {@link String }
-     *     
-     */
-    public void setName(String value) {
-        this.name = value;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java b/features/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java
deleted file mode 100644
index 2036452..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.karaf.features.internal.model;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.Writer;
-import java.net.URL;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import javax.xml.XMLConstants;
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBException;
-import javax.xml.bind.Marshaller;
-import javax.xml.bind.Unmarshaller;
-import javax.xml.namespace.QName;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.sax.SAXSource;
-import javax.xml.transform.stream.StreamSource;
-import javax.xml.validation.Schema;
-import javax.xml.validation.SchemaFactory;
-
-import org.apache.karaf.features.FeaturesNamespaces;
-import org.apache.karaf.util.XmlUtils;
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-import org.xml.sax.Attributes;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.XMLFilter;
-import org.xml.sax.XMLReader;
-import org.xml.sax.helpers.XMLFilterImpl;
-
-public class JaxbUtil {
-
-    private static final JAXBContext FEATURES_CONTEXT;
-    static {
-        try {
-            FEATURES_CONTEXT = JAXBContext.newInstance(Features.class);
-        } catch (JAXBException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    public static void marshal(Features features, OutputStream out) throws JAXBException {
-        Marshaller marshaller = FEATURES_CONTEXT.createMarshaller();
-
-        marshaller.setProperty("jaxb.formatted.output", true);
-
-        marshaller.marshal(features, out);
-    }
-
-    public static void marshal(Features features, Writer out) throws JAXBException {
-        Marshaller marshaller = FEATURES_CONTEXT.createMarshaller();
-
-        marshaller.setProperty("jaxb.formatted.output", true);
-
-        marshaller.marshal(features, out);
-    }
-
-
-    /**
-     * Read in a Features from the input stream.
-     *
-     * @param uri      uri to read
-     * @param validate whether to validate the input.
-     * @return a Features read from the input stream
-     */
-    public static Features unmarshal(String uri, boolean validate) {
-        if (validate) {
-            return unmarshalValidate(uri, null);
-        } else {
-            return unmarshalNoValidate(uri, null);
-        }
-    }
-
-    public static Features unmarshal(String uri, InputStream stream, boolean validate) {
-        if (validate) {
-            return unmarshalValidate(uri, stream);
-        } else {
-            return unmarshalNoValidate(uri, stream);
-        }
-    }
-
-    private static Features unmarshalValidate(String uri, InputStream stream) {
-        try {
-            Document doc;
-            if (stream != null) {
-                doc = XmlUtils.parse(stream);
-                doc.setDocumentURI(uri);
-            } else {
-                doc = XmlUtils.parse(uri);
-            }
-
-            Schema schema = getSchema(doc.getDocumentElement().getNamespaceURI());
-            try {
-                schema.newValidator().validate(new DOMSource(doc));
-            } catch (SAXException e) {
-                throw new IllegalArgumentException("Unable to validate " + uri, e);
-            }
-
-            fixDom(doc, doc.getDocumentElement());
-            Unmarshaller unmarshaller = FEATURES_CONTEXT.createUnmarshaller();
-            return (Features) unmarshaller.unmarshal(new DOMSource(doc));
-
-
-        } catch (RuntimeException e) {
-            throw e;
-        } catch (Exception e) {
-            throw new RuntimeException("Unable to load " + uri, e);
-        }
-    }
-
-    private static Map<String, Schema> schemas = new ConcurrentHashMap<String, Schema>();
-    private static Schema getSchema(String namespace) throws SAXException {
-        Schema schema = schemas.get(namespace);
-        if (schema == null) {
-            String schemaLocation;
-            if (FeaturesNamespaces.URI_1_0_0.equals(namespace)) {
-                schemaLocation = "/org/apache/karaf/features/karaf-features-1.0.0.xsd";
-            } else if (FeaturesNamespaces.URI_1_1_0.equals(namespace)) {
-                schemaLocation = "/org/apache/karaf/features/karaf-features-1.1.0.xsd";
-            } else if (FeaturesNamespaces.URI_1_2_0.equals(namespace)) {
-                schemaLocation = "/org/apache/karaf/features/karaf-features-1.2.0.xsd";
-            } else if (FeaturesNamespaces.URI_1_3_0.equals(namespace)) {
-                schemaLocation = "/org/apache/karaf/features/karaf-features-1.3.0.xsd";
-            } else {
-                throw new IllegalArgumentException("Unsupported namespace: " + namespace);
-            }
-
-            SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
-            // root element has namespace - we can use schema validation
-            URL url = JaxbUtil.class.getResource(schemaLocation);
-            if (url == null) {
-                throw new IllegalStateException("Could not find resource: " + schemaLocation);
-            }
-            schema = factory.newSchema(new StreamSource(url.toExternalForm()));
-            schemas.put(namespace, schema);
-        }
-        return schema;
-    }
-
-
-    private static void fixDom(Document doc, Node node) {
-        if (node.getNamespaceURI() != null && !FeaturesNamespaces.URI_CURRENT.equals(node.getNamespaceURI())) {
-            doc.renameNode(node, FeaturesNamespaces.URI_CURRENT, node.getLocalName());
-        }
-        NodeList children = node.getChildNodes();
-        for (int i = 0; i < children.getLength(); i++) {
-            fixDom(doc, children.item(i));
-        }
-    }
-
-    private static Features unmarshalNoValidate(String uri, InputStream stream) {
-        try {
-            Unmarshaller unmarshaller = FEATURES_CONTEXT.createUnmarshaller();
-            XMLFilter xmlFilter = new NoSourceAndNamespaceFilter(XmlUtils.xmlReader());
-            xmlFilter.setContentHandler(unmarshaller.getUnmarshallerHandler());
-
-
-            InputSource is = new InputSource(uri);
-            if (stream != null) {
-                is.setByteStream(stream);
-            }
-            SAXSource source = new SAXSource(xmlFilter, new InputSource(uri));
-            return (Features) unmarshaller.unmarshal(source);
-
-        } catch (RuntimeException e) {
-            throw e;
-        } catch (Exception e) {
-            throw new RuntimeException("Unable to load " + uri, e);
-        }
-    }
-
-    /**
-     * Provides an empty inputsource for the entity resolver.
-     * Converts all elements to the features namespace to make old feature files
-     * compatible to the new format
-     */
-    public static class NoSourceAndNamespaceFilter extends XMLFilterImpl {        
-        private static final InputSource EMPTY_INPUT_SOURCE = new InputSource(new ByteArrayInputStream(new byte[0]));
-
-        public NoSourceAndNamespaceFilter(XMLReader xmlReader) {
-            super(xmlReader);
-        }
-
-        @Override
-        public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
-            return EMPTY_INPUT_SOURCE;
-        }
-
-        @Override
-        public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
-            super.startElement(FeaturesNamespaces.URI_CURRENT, localName, qName, atts);
-        }
-
-        @Override
-        public void endElement(String uri, String localName, String qName) throws SAXException {
-            super.endElement(FeaturesNamespaces.URI_CURRENT, localName, qName);
-        }
-    }
-
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/model/ObjectFactory.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/model/ObjectFactory.java b/features/src/main/java/org/apache/karaf/features/internal/model/ObjectFactory.java
deleted file mode 100644
index 96fbb0f..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/model/ObjectFactory.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.karaf.features.internal.model;
-
-import javax.xml.bind.JAXBElement;
-import javax.xml.bind.annotation.XmlElementDecl;
-import javax.xml.bind.annotation.XmlRegistry;
-import javax.xml.namespace.QName;
-
-
-/**
- * This object contains factory methods for each 
- * Java content interface and Java element interface 
- * generated in the org.apache.karaf.features.wrapper package.
- * <p>An ObjectFactory allows you to programatically 
- * construct new instances of the Java representation 
- * for XML content. The Java representation of XML 
- * content can consist of schema derived interfaces 
- * and classes representing the binding of schema 
- * type definitions, element declarations and model 
- * groups.  Factory methods for each of these are 
- * provided in this class.
- * 
- */
-@XmlRegistry
-public class ObjectFactory {
-
-    private final static QName _Features_QNAME = new QName("http://karaf.apache.org/xmlns/features/v1.0.0", "features");
-
-    /**
-     * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: org.apache.karaf.features.wrapper
-     * 
-     */
-    public ObjectFactory() {
-    }
-
-    /**
-     * Create an instance of {@link ConfigFile }
-     * 
-     */
-    public ConfigFile createConfigFile() {
-        return new ConfigFile();
-    }
-
-    /**
-     * Create an instance of {@link Dependency }
-     * 
-     */
-    public Dependency createDependency() {
-        return new Dependency();
-    }
-
-    /**
-     * Create an instance of {@link Bundle }
-     * 
-     */
-    public Bundle createBundle() {
-        return new Bundle();
-    }
-
-    /**
-     * Create an instance of {@link Features }
-     * 
-     */
-    public Features createFeaturesRoot() {
-        return new Features();
-    }
-
-    /**
-     * Create an instance of {@link Config }
-     * 
-     */
-    public Config createConfig() {
-        return new Config();
-    }
-
-    /**
-     * Create an instance of {@link Feature }
-     * 
-     */
-    public Feature createFeature() {
-        return new Feature();
-    }
-
-    /**
-     * Create an instance of {@link JAXBElement }{@code <}{@link Features }{@code >}}
-     * 
-     */
-    @XmlElementDecl(namespace = "http://karaf.apache.org/xmlns/features/v1.0.0", name = "features")
-    public JAXBElement<Features> createFeatures(Features value) {
-        return new JAXBElement<Features>(_Features_QNAME, Features.class, null, value);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/model/Requirement.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/model/Requirement.java b/features/src/main/java/org/apache/karaf/features/internal/model/Requirement.java
deleted file mode 100644
index f7b5775..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/model/Requirement.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-
-package org.apache.karaf.features.internal.model;
-
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.XmlValue;
-
-
-/**
- * 
- * Additional requirement for a feature.
- *             
- * 
- * <p>Java class for bundle complex type.
- * 
- * <p>The following schema fragment specifies the expected content contained within this class.
- * 
- * <pre>
- * &lt;complexType name="capability">
- *   &lt;simpleContent>
- *     &lt;extension base="&lt;http://www.w3.org/2001/XMLSchema>string">
- *     &lt;/extension>
- *   &lt;/simpleContent>
- * &lt;/complexType>
- * </pre>
- * 
- * 
- */
-@XmlAccessorType(XmlAccessType.FIELD)
-@XmlType(name = "requirement", propOrder = {
-    "value"
-})
-public class Requirement implements org.apache.karaf.features.Requirement {
-
-    @XmlValue
-    protected String value;
-
-
-    public Requirement() {
-    }
-
-    public Requirement(String value) {
-        this.value = value;
-    }
-
-    public String getValue() {
-        return value;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        Requirement bundle = (Requirement) o;
-
-        if (value != null ? !value.equals(bundle.value) : bundle.value != null) return false;
-
-        return true;
-    }
-
-    @Override
-    public int hashCode() {
-        int result = value != null ? value.hashCode() : 0;
-        return result;
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/model/package-info.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/model/package-info.java b/features/src/main/java/org/apache/karaf/features/internal/model/package-info.java
deleted file mode 100644
index c86a58c..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/model/package-info.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-@javax.xml.bind.annotation.XmlSchema(namespace = org.apache.karaf.features.FeaturesNamespaces.URI_CURRENT, elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
-package org.apache.karaf.features.internal.model;


[20/33] Revert "[KARAF-2852] Merge features/core and features/command"

Posted by gn...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/resolver/ResolveContextImpl.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/resolver/ResolveContextImpl.java b/features/src/main/java/org/apache/karaf/features/internal/resolver/ResolveContextImpl.java
deleted file mode 100644
index e2ff793..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/resolver/ResolveContextImpl.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.resolver;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.osgi.framework.Constants;
-import org.osgi.resource.Capability;
-import org.osgi.resource.Requirement;
-import org.osgi.resource.Resource;
-import org.osgi.resource.Wiring;
-import org.osgi.service.repository.Repository;
-import org.osgi.service.resolver.HostedCapability;
-import org.osgi.service.resolver.ResolveContext;
-
-/**
-*/
-public class ResolveContextImpl extends ResolveContext {
-
-    private final Set<Resource> mandatory;
-    private final Set<Resource> optional;
-    private final Repository repository;
-    private final Map<Resource, Wiring> wirings;
-    private final boolean resolveOptional;
-
-    private final CandidateComparator candidateComparator = new CandidateComparator();
-
-    public ResolveContextImpl(Set<Resource> mandatory,
-                              Set<Resource> optional,
-                              Repository repository,
-                              boolean resolveOptional) {
-        this.mandatory = mandatory;
-        this.optional = optional;
-        this.repository = repository;
-        this.wirings = new HashMap<Resource, Wiring>();
-        this.resolveOptional = resolveOptional;
-    }
-
-    @Override
-    public Collection<Resource> getMandatoryResources() {
-        return mandatory;
-    }
-
-    @Override
-    public Collection<Resource> getOptionalResources() {
-        return optional;
-    }
-
-    @Override
-    public List<Capability> findProviders(Requirement requirement) {
-        List<Capability> caps = new ArrayList<Capability>();
-        Map<Requirement, Collection<Capability>> resMap =
-                repository.findProviders(Collections.singleton(requirement));
-        Collection<Capability> res = resMap != null ? resMap.get(requirement) : null;
-        if (res != null) {
-            caps.addAll(res);
-        }
-        Collections.sort(caps, candidateComparator);
-        return caps;
-    }
-    @Override
-    public int insertHostedCapability(List capabilities, HostedCapability hostedCapability) {
-        for (int i=0; i < capabilities.size(); i++) {
-            Capability cap = (Capability) capabilities.get(i);
-            if (candidateComparator.compare(hostedCapability, cap) <= 0) {
-                capabilities.add(i, hostedCapability);
-                return i;
-            }
-        }
-        capabilities.add(hostedCapability);
-        return capabilities.size() - 1;
-    }
-    @Override
-    public boolean isEffective(Requirement requirement) {
-        return resolveOptional ||
-                !Constants.RESOLUTION_OPTIONAL.equals(requirement.getDirectives().get(Constants.RESOLUTION_DIRECTIVE));
-    }
-    @Override
-    public Map<Resource, Wiring> getWirings() {
-        return wirings;
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/resolver/ResourceBuilder.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/resolver/ResourceBuilder.java b/features/src/main/java/org/apache/karaf/features/internal/resolver/ResourceBuilder.java
deleted file mode 100644
index cb2c36a..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/resolver/ResourceBuilder.java
+++ /dev/null
@@ -1,1129 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.resolver;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.felix.utils.version.VersionRange;
-import org.osgi.framework.BundleException;
-import org.osgi.framework.Constants;
-import org.osgi.framework.Version;
-import org.osgi.framework.namespace.IdentityNamespace;
-import org.osgi.framework.wiring.BundleCapability;
-import org.osgi.framework.wiring.BundleRevision;
-import org.osgi.resource.Capability;
-import org.osgi.resource.Requirement;
-import org.osgi.resource.Resource;
-
-public class ResourceBuilder {
-
-    public static final String RESOLUTION_DYNAMIC = "dynamic";
-
-    public static Resource build(String uri, Map<String, String> headerMap)
-            throws BundleException {
-
-        // Verify that only manifest version 2 is specified.
-        String manifestVersion = getManifestVersion(headerMap);
-        if (manifestVersion == null || !manifestVersion.equals("2")) {
-            throw new BundleException("Unsupported 'Bundle-ManifestVersion' value: " + manifestVersion);
-        }
-
-        //
-        // Parse bundle version.
-        //
-
-        Version bundleVersion = Version.emptyVersion;
-        if (headerMap.get(Constants.BUNDLE_VERSION) != null) {
-            bundleVersion = Version.parseVersion(headerMap.get(Constants.BUNDLE_VERSION));
-        }
-
-        //
-        // Parse bundle symbolic name.
-        //
-
-        String bundleSymbolicName = null;
-        ParsedHeaderClause bundleCap = parseBundleSymbolicName(headerMap);
-        if (bundleCap == null) {
-            throw new BundleException("Bundle manifest must include bundle symbolic name");
-        }
-        bundleSymbolicName = (String) bundleCap.attrs.get(BundleRevision.BUNDLE_NAMESPACE);
-
-        // Now that we have symbolic name and version, create the resource
-        String type = headerMap.get(Constants.FRAGMENT_HOST) == null ? IdentityNamespace.TYPE_BUNDLE : IdentityNamespace.TYPE_FRAGMENT;
-        ResourceImpl resource = new ResourceImpl(bundleSymbolicName, type, bundleVersion);
-        if (uri != null) {
-            Map<String, Object> attrs = new HashMap<String, Object>();
-            attrs.put(UriNamespace.URI_NAMESPACE, uri);
-            resource.addCapability(new CapabilityImpl(resource, UriNamespace.URI_NAMESPACE, Collections.<String, String>emptyMap(), attrs));
-        }
-
-        // Add a bundle and host capability to all
-        // non-fragment bundles. A host capability is the same
-        // as a require capability, but with a different capability
-        // namespace. Bundle capabilities resolve required-bundle
-        // dependencies, while host capabilities resolve fragment-host
-        // dependencies.
-        if (headerMap.get(Constants.FRAGMENT_HOST) == null) {
-            // All non-fragment bundles have bundle capability.
-            resource.addCapability(new CapabilityImpl(resource, BundleRevision.BUNDLE_NAMESPACE, bundleCap.dirs, bundleCap.attrs));
-            // A non-fragment bundle can choose to not have a host capability.
-            String attachment = bundleCap.dirs.get(Constants.FRAGMENT_ATTACHMENT_DIRECTIVE);
-            attachment = (attachment == null) ? Constants.FRAGMENT_ATTACHMENT_RESOLVETIME : attachment;
-            if (!attachment.equalsIgnoreCase(Constants.FRAGMENT_ATTACHMENT_NEVER)) {
-                Map<String, Object> hostAttrs = new HashMap<String, Object>(bundleCap.attrs);
-                Object value = hostAttrs.remove(BundleRevision.BUNDLE_NAMESPACE);
-                hostAttrs.put(BundleRevision.HOST_NAMESPACE, value);
-                resource.addCapability(new CapabilityImpl(
-                        resource, BundleRevision.HOST_NAMESPACE,
-                        bundleCap.dirs,
-                        hostAttrs));
-            }
-        }
-
-        //
-        // Parse Fragment-Host.
-        //
-
-        List<RequirementImpl> hostReqs = parseFragmentHost(resource, headerMap);
-
-        //
-        // Parse Require-Bundle
-        //
-
-        List<ParsedHeaderClause> rbClauses = parseStandardHeader(headerMap.get(Constants.REQUIRE_BUNDLE));
-        rbClauses = normalizeRequireClauses(rbClauses);
-        List<Requirement> rbReqs = convertRequires(rbClauses, resource);
-
-        //
-        // Parse Import-Package.
-        //
-
-        List<ParsedHeaderClause> importClauses = parseStandardHeader(headerMap.get(Constants.IMPORT_PACKAGE));
-        importClauses = normalizeImportClauses(importClauses);
-        List<Requirement> importReqs = convertImports(importClauses, resource);
-
-        //
-        // Parse DynamicImport-Package.
-        //
-
-        List<ParsedHeaderClause> dynamicClauses = parseStandardHeader(headerMap.get(Constants.DYNAMICIMPORT_PACKAGE));
-        dynamicClauses = normalizeDynamicImportClauses(dynamicClauses);
-        List<Requirement> dynamicReqs = convertImports(dynamicClauses, resource);
-
-        //
-        // Parse Require-Capability.
-        //
-
-        List<ParsedHeaderClause> requireClauses = parseStandardHeader(headerMap.get(Constants.REQUIRE_CAPABILITY));
-        requireClauses = normalizeRequireCapabilityClauses(requireClauses);
-        List<Requirement> requireReqs = convertRequireCapabilities(requireClauses, resource);
-
-        //
-        // Parse Export-Package.
-        //
-
-        List<ParsedHeaderClause> exportClauses = parseStandardHeader(headerMap.get(Constants.EXPORT_PACKAGE));
-        exportClauses = normalizeExportClauses(exportClauses, bundleSymbolicName, bundleVersion);
-        List<Capability> exportCaps = convertExports(exportClauses, resource);
-
-        //
-        // Parse Provide-Capability.
-        //
-
-        List<ParsedHeaderClause> provideClauses = parseStandardHeader(headerMap.get(Constants.PROVIDE_CAPABILITY));
-        provideClauses = normalizeProvideCapabilityClauses(provideClauses);
-        List<Capability> provideCaps = convertProvideCapabilities(provideClauses, resource);
-
-        //
-        // Parse Import-Service and Export-Service
-        // if Require-Capability and Provide-Capability are not set for services
-        //
-
-        boolean hasServiceReferenceCapability = false;
-        for (Capability cap : exportCaps) {
-            hasServiceReferenceCapability |= ServiceNamespace.SERVICE_NAMESPACE.equals(cap.getNamespace());
-        }
-        if (!hasServiceReferenceCapability) {
-            List<ParsedHeaderClause> exportServices = parseStandardHeader(headerMap.get(Constants.EXPORT_SERVICE));
-            List<Capability> caps = convertExportService(exportServices, resource);
-            provideCaps.addAll(caps);
-        }
-
-        boolean hasServiceReferenceRequirement = false;
-        for (Requirement req : requireReqs) {
-            hasServiceReferenceRequirement |= ServiceNamespace.SERVICE_NAMESPACE.equals(req.getNamespace());
-        }
-        if (!hasServiceReferenceRequirement) {
-            List<ParsedHeaderClause> importServices = parseStandardHeader(headerMap.get(Constants.IMPORT_SERVICE));
-            List<Requirement> reqs = convertImportService(importServices, resource);
-            requireReqs.addAll(reqs);
-        }
-
-        // Combine all capabilities.
-        resource.addCapabilities(exportCaps);
-        resource.addCapabilities(provideCaps);
-
-        // Combine all requirements.
-        resource.addRequirements(hostReqs);
-        resource.addRequirements(importReqs);
-        resource.addRequirements(rbReqs);
-        resource.addRequirements(requireReqs);
-        resource.addRequirements(dynamicReqs);
-
-        return resource;
-    }
-
-    public static List<Requirement> parseImport(Resource resource, String imports) throws BundleException {
-        List<ParsedHeaderClause> importClauses = parseStandardHeader(imports);
-        importClauses = normalizeImportClauses(importClauses);
-        List<Requirement> importReqs = convertImports(importClauses, resource);
-        return importReqs;
-    }
-
-    public static List<Requirement> parseRequirement(Resource resource, String requirement) throws BundleException {
-        List<ParsedHeaderClause> requireClauses = parseStandardHeader(requirement);
-        requireClauses = normalizeRequireCapabilityClauses(requireClauses);
-        List<Requirement> requireReqs = convertRequireCapabilities(requireClauses, resource);
-        return requireReqs;
-    }
-
-    public static List<Capability> parseExport(Resource resource, String bundleSymbolicName, Version bundleVersion, String exports) throws BundleException {
-        List<ParsedHeaderClause> exportClauses = parseStandardHeader(exports);
-        exportClauses = normalizeExportClauses(exportClauses, bundleSymbolicName, bundleVersion);
-        List<Capability> exportCaps = convertExports(exportClauses, resource);
-        return exportCaps;
-    }
-
-    public static List<Capability> parseCapability(Resource resource, String capability) throws BundleException {
-        List<ParsedHeaderClause> provideClauses = parseStandardHeader(capability);
-        provideClauses = normalizeProvideCapabilityClauses(provideClauses);
-        List<Capability> provideCaps = convertProvideCapabilities(provideClauses, resource);
-        return provideCaps;
-    }
-
-    @SuppressWarnings( "deprecation" )
-    private static List<ParsedHeaderClause> normalizeImportClauses(
-            List<ParsedHeaderClause> clauses)
-            throws BundleException {
-        // Verify that the values are equals if the package specifies
-        // both version and specification-version attributes.
-        Set<String> dupeSet = new HashSet<String>();
-        for (ParsedHeaderClause clause : clauses) {
-            // Check for "version" and "specification-version" attributes
-            // and verify they are the same if both are specified.
-            Object v = clause.attrs.get(Constants.VERSION_ATTRIBUTE);
-            Object sv = clause.attrs.get(Constants.PACKAGE_SPECIFICATION_VERSION);
-            if ((v != null) && (sv != null)) {
-                // Verify they are equal.
-                if (!((String) v).trim().equals(((String) sv).trim())) {
-                    throw new IllegalArgumentException(
-                            "Both version and specification-version are specified, but they are not equal.");
-                }
-            }
-
-            // Ensure that only the "version" attribute is used and convert
-            // it to the VersionRange type.
-            if ((v != null) || (sv != null)) {
-                clause.attrs.remove(Constants.PACKAGE_SPECIFICATION_VERSION);
-                v = (v == null) ? sv : v;
-                clause.attrs.put(Constants.VERSION_ATTRIBUTE, VersionRange.parseVersionRange(v.toString()));
-            }
-
-            // If bundle version is specified, then convert its type to VersionRange.
-            v = clause.attrs.get(Constants.BUNDLE_VERSION_ATTRIBUTE);
-            if (v != null) {
-                clause.attrs.put(Constants.BUNDLE_VERSION_ATTRIBUTE, VersionRange.parseVersionRange(v.toString()));
-            }
-
-            // Verify java.* is not imported, nor any duplicate imports.
-            for (String pkgName : clause.paths) {
-                if (!dupeSet.contains(pkgName)) {
-                    // Verify that java.* packages are not imported.
-                    if (pkgName.startsWith("java.")) {
-                        throw new BundleException("Importing java.* packages not allowed: " + pkgName);
-                    }
-                    // The character "." has no meaning in the OSGi spec except
-                    // when placed on the bundle class path. Some people, however,
-                    // mistakenly think it means the default package when imported
-                    // or exported. This is not correct. It is invalid.
-                    else if (pkgName.equals(".")) {
-                        throw new BundleException("Importing '.' is invalid.");
-                    }
-                    // Make sure a package name was specified.
-                    else if (pkgName.length() == 0) {
-                        throw new BundleException(
-                                "Imported package names cannot be zero length.");
-                    }
-                    dupeSet.add(pkgName);
-                } else {
-                    throw new BundleException("Duplicate import: " + pkgName);
-                }
-            }
-        }
-
-        return clauses;
-    }
-
-    private static List<Capability> convertExportService(List<ParsedHeaderClause> clauses, Resource resource) {
-        List<Capability> capList = new ArrayList<Capability>();
-        for (ParsedHeaderClause clause : clauses) {
-            for (String path : clause.paths) {
-                Map<String, String> dirs = new LinkedHashMap<String, String>();
-                dirs.put(ServiceNamespace.CAPABILITY_EFFECTIVE_DIRECTIVE, ServiceNamespace.EFFECTIVE_ACTIVE);
-                Map<String, Object> attrs = new LinkedHashMap<String, Object>();
-                attrs.put(Constants.OBJECTCLASS, path);
-                attrs.putAll(clause.attrs);
-                capList.add(new CapabilityImpl(
-                                resource,
-                                ServiceNamespace.SERVICE_NAMESPACE,
-                                dirs,
-                                attrs));
-            }
-        }
-        return capList;
-    }
-
-    private static List<Requirement> convertImportService(List<ParsedHeaderClause> clauses, Resource resource) throws BundleException {
-        try {
-            List<Requirement> reqList = new ArrayList<Requirement>();
-            for (ParsedHeaderClause clause : clauses) {
-                for (String path : clause.paths) {
-                    String multiple = clause.dirs.get("multiple");
-                    String avail    = clause.dirs.get("availability");
-                    String filter   = (String) clause.attrs.get("filter");
-                    Map<String, String> dirs = new LinkedHashMap<String, String>();
-                    dirs.put(ServiceNamespace.REQUIREMENT_EFFECTIVE_DIRECTIVE, ServiceNamespace.EFFECTIVE_ACTIVE);
-                    if ("optional".equals(avail)) {
-                        dirs.put(ServiceNamespace.REQUIREMENT_RESOLUTION_DIRECTIVE, ServiceNamespace.RESOLUTION_OPTIONAL);
-                    }
-                    if ("true".equals(multiple)) {
-                        dirs.put(ServiceNamespace.REQUIREMENT_CARDINALITY_DIRECTIVE, ServiceNamespace.CARDINALITY_MULTIPLE);
-                    }
-                    if (filter == null) {
-                        filter = "(" + Constants.OBJECTCLASS + "=" + path + ")";
-                    } else if (!filter.startsWith("(") && !filter.endsWith(")")) {
-                        filter = "(&(" + Constants.OBJECTCLASS + "=" + path + ")(" + filter + "))";
-                    } else {
-                        filter = "(&(" + Constants.OBJECTCLASS + "=" + path + ")" + filter + ")";
-                    }
-                    dirs.put(ServiceNamespace.REQUIREMENT_FILTER_DIRECTIVE, filter);
-                    reqList.add(new RequirementImpl(
-                                    resource,
-                                    ServiceNamespace.SERVICE_NAMESPACE,
-                                    dirs,
-                                    Collections.<String, Object>emptyMap(),
-                                    SimpleFilter.parse(filter)));
-                }
-            }
-            return reqList;
-        } catch (Exception ex) {
-            throw new BundleException("Error creating requirement: " + ex, ex);
-        }
-    }
-
-    private static List<Requirement> convertImports(List<ParsedHeaderClause> clauses, Resource resource) {
-        // Now convert generic header clauses into requirements.
-        List<Requirement> reqList = new ArrayList<Requirement>();
-        for (ParsedHeaderClause clause : clauses) {
-            for (String path : clause.paths) {
-                // Prepend the package name to the array of attributes.
-                Map<String, Object> attrs = clause.attrs;
-                // Note that we use a linked hash map here to ensure the
-                // package attribute is first, which will make indexing
-                // more efficient.
-    // TODO: OSGi R4.3 - This is ordering is kind of hacky.
-                // Prepend the package name to the array of attributes.
-                Map<String, Object> newAttrs = new LinkedHashMap<String, Object>(attrs.size() + 1);
-                // We want this first from an indexing perspective.
-                newAttrs.put(BundleRevision.PACKAGE_NAMESPACE, path);
-                newAttrs.putAll(attrs);
-                // But we need to put it again to make sure it wasn't overwritten.
-                newAttrs.put(BundleRevision.PACKAGE_NAMESPACE, path);
-
-                // Create filter now so we can inject filter directive.
-                SimpleFilter sf = SimpleFilter.convert(newAttrs);
-
-                // Inject filter directive.
-    // TODO: OSGi R4.3 - Can we insert this on demand somehow?
-                Map<String, String> dirs = clause.dirs;
-                Map<String, String> newDirs = new HashMap<String, String>(dirs.size() + 1);
-                newDirs.putAll(dirs);
-                newDirs.put(Constants.FILTER_DIRECTIVE, sf.toString());
-
-                // Create package requirement and add to requirement list.
-                reqList.add(
-                        new RequirementImpl(
-                                resource,
-                                BundleRevision.PACKAGE_NAMESPACE,
-                                newDirs,
-                                Collections.<String, Object>emptyMap(),
-                                sf));
-            }
-        }
-
-        return reqList;
-    }
-
-    @SuppressWarnings( "deprecation" )
-    private static List<ParsedHeaderClause> normalizeDynamicImportClauses(
-            List<ParsedHeaderClause> clauses)
-            throws BundleException {
-        // Verify that the values are equals if the package specifies
-        // both version and specification-version attributes.
-        for (ParsedHeaderClause clause : clauses) {
-            // Add the resolution directive to indicate that these are
-            // dynamic imports.
-            clause.dirs.put(Constants.RESOLUTION_DIRECTIVE, RESOLUTION_DYNAMIC);
-
-            // Check for "version" and "specification-version" attributes
-            // and verify they are the same if both are specified.
-            Object v = clause.attrs.get(Constants.VERSION_ATTRIBUTE);
-            Object sv = clause.attrs.get(Constants.PACKAGE_SPECIFICATION_VERSION);
-            if ((v != null) && (sv != null)) {
-                // Verify they are equal.
-                if (!((String) v).trim().equals(((String) sv).trim())) {
-                    throw new IllegalArgumentException(
-                            "Both version and specification-version are specified, but they are not equal.");
-                }
-            }
-
-            // Ensure that only the "version" attribute is used and convert
-            // it to the VersionRange type.
-            if ((v != null) || (sv != null)) {
-                clause.attrs.remove(Constants.PACKAGE_SPECIFICATION_VERSION);
-                v = (v == null) ? sv : v;
-                clause.attrs.put(Constants.VERSION_ATTRIBUTE, VersionRange.parseVersionRange(v.toString()));
-            }
-
-            // If bundle version is specified, then convert its type to VersionRange.
-            v = clause.attrs.get(Constants.BUNDLE_VERSION_ATTRIBUTE);
-            if (v != null) {
-                clause.attrs.put(Constants.BUNDLE_VERSION_ATTRIBUTE, VersionRange.parseVersionRange(v.toString()));
-            }
-
-            // Dynamic imports can have duplicates, so verify that java.*
-            // packages are not imported.
-            for (String pkgName : clause.paths) {
-                if (pkgName.startsWith("java.")) {
-                    throw new BundleException("Dynamically importing java.* packages not allowed: " + pkgName);
-                } else if (!pkgName.equals("*") && pkgName.endsWith("*") && !pkgName.endsWith(".*")) {
-                    throw new BundleException("Partial package name wild carding is not allowed: " + pkgName);
-                }
-            }
-        }
-
-        return clauses;
-    }
-
-    private static List<ParsedHeaderClause> normalizeRequireCapabilityClauses(
-            List<ParsedHeaderClause> clauses)
-            throws BundleException {
-
-        return clauses;
-    }
-
-    private static List<ParsedHeaderClause> normalizeProvideCapabilityClauses(
-            List<ParsedHeaderClause> clauses)
-            throws BundleException
-    {
-
-        // Convert attributes into specified types.
-        for (ParsedHeaderClause clause : clauses)
-        {
-            for (Map.Entry<String, String> entry : clause.types.entrySet())
-            {
-                String type = entry.getValue();
-                if (!type.equals("String"))
-                {
-                    if (type.equals("Double"))
-                    {
-                        clause.attrs.put(
-                                entry.getKey(),
-                                new Double(clause.attrs.get(entry.getKey()).toString().trim()));
-                    }
-                    else if (type.equals("Version"))
-                    {
-                        clause.attrs.put(
-                                entry.getKey(),
-                                new Version(clause.attrs.get(entry.getKey()).toString().trim()));
-                    }
-                    else if (type.equals("Long"))
-                    {
-                        clause.attrs.put(
-                                entry.getKey(),
-                                new Long(clause.attrs.get(entry.getKey()).toString().trim()));
-                    }
-                    else if (type.startsWith("List"))
-                    {
-                        int startIdx = type.indexOf('<');
-                        int endIdx = type.indexOf('>');
-                        if (((startIdx > 0) && (endIdx <= startIdx))
-                                || ((startIdx < 0) && (endIdx > 0)))
-                        {
-                            throw new BundleException(
-                                    "Invalid Provide-Capability attribute list type for '"
-                                            + entry.getKey()
-                                            + "' : "
-                                            + type);
-                        }
-
-                        String listType = "String";
-                        if (endIdx > startIdx)
-                        {
-                            listType = type.substring(startIdx + 1, endIdx).trim();
-                        }
-
-                        List<String> tokens = parseDelimitedString(
-                                clause.attrs.get(entry.getKey()).toString(), ",", false);
-                        List<Object> values = new ArrayList<Object>(tokens.size());
-                        for (String token : tokens)
-                        {
-                            if (listType.equals("String"))
-                            {
-                                values.add(token);
-                            }
-                            else if (listType.equals("Double"))
-                            {
-                                values.add(new Double(token.trim()));
-                            }
-                            else if (listType.equals("Version"))
-                            {
-                                values.add(new Version(token.trim()));
-                            }
-                            else if (listType.equals("Long"))
-                            {
-                                values.add(new Long(token.trim()));
-                            }
-                            else
-                            {
-                                throw new BundleException(
-                                        "Unknown Provide-Capability attribute list type for '"
-                                                + entry.getKey()
-                                                + "' : "
-                                                + type);
-                            }
-                        }
-                        clause.attrs.put(
-                                entry.getKey(),
-                                values);
-                    }
-                    else
-                    {
-                        throw new BundleException(
-                                "Unknown Provide-Capability attribute type for '"
-                                        + entry.getKey()
-                                        + "' : "
-                                        + type);
-                    }
-                }
-            }
-        }
-
-        return clauses;
-    }
-
-    private static List<Requirement> convertRequireCapabilities(
-            List<ParsedHeaderClause> clauses, Resource resource)
-            throws BundleException {
-        // Now convert generic header clauses into requirements.
-        List<Requirement> reqList = new ArrayList<Requirement>();
-        for (ParsedHeaderClause clause : clauses) {
-            try {
-                String filterStr = clause.dirs.get(Constants.FILTER_DIRECTIVE);
-                SimpleFilter sf = (filterStr != null)
-                        ? SimpleFilter.parse(filterStr)
-                        : new SimpleFilter(null, null, SimpleFilter.MATCH_ALL);
-                for (String path : clause.paths) {
-                    // Create requirement and add to requirement list.
-                    reqList.add(new RequirementImpl(
-                                    resource, path, clause.dirs, clause.attrs, sf));
-                }
-            } catch (Exception ex) {
-                throw new BundleException("Error creating requirement: " + ex, ex);
-            }
-        }
-
-        return reqList;
-    }
-
-    private static List<Capability> convertProvideCapabilities(
-            List<ParsedHeaderClause> clauses, Resource resource)
-            throws BundleException {
-        List<Capability> capList = new ArrayList<Capability>();
-        for (ParsedHeaderClause clause : clauses) {
-            for (String path : clause.paths) {
-                if (path.startsWith("osgi.wiring.")) {
-//                    throw new BundleException("Manifest cannot use Provide-Capability for '" + path + "' namespace.");
-                }
-
-                // Create package capability and add to capability list.
-                capList.add(new CapabilityImpl(resource, path, clause.dirs, clause.attrs));
-            }
-        }
-
-        return capList;
-    }
-
-    @SuppressWarnings( "deprecation" )
-    private static List<ParsedHeaderClause> normalizeExportClauses(
-            List<ParsedHeaderClause> clauses,
-            String bsn, Version bv)
-            throws BundleException {
-        // Verify that "java.*" packages are not exported.
-        for (ParsedHeaderClause clause : clauses) {
-            // Verify that the named package has not already been declared.
-            for (String pkgName : clause.paths) {
-                // Verify that java.* packages are not exported.
-                if (pkgName.startsWith("java.")) {
-                    throw new BundleException("Exporting java.* packages not allowed: " + pkgName);
-                }
-                // The character "." has no meaning in the OSGi spec except
-                // when placed on the bundle class path. Some people, however,
-                // mistakenly think it means the default package when imported
-                // or exported. This is not correct. It is invalid.
-                else if (pkgName.equals(".")) {
-                    throw new BundleException("Exporing '.' is invalid.");
-                }
-                // Make sure a package name was specified.
-                else if (pkgName.length() == 0) {
-                    throw new BundleException("Exported package names cannot be zero length.");
-                }
-            }
-
-            // Check for "version" and "specification-version" attributes
-            // and verify they are the same if both are specified.
-            Object v = clause.attrs.get(Constants.VERSION_ATTRIBUTE);
-            Object sv = clause.attrs.get(Constants.PACKAGE_SPECIFICATION_VERSION);
-            if ((v != null) && (sv != null)) {
-                // Verify they are equal.
-                if (!((String) v).trim().equals(((String) sv).trim())) {
-                    throw new IllegalArgumentException("Both version and specification-version are specified, but they are not equal.");
-                }
-            }
-
-            // Always add the default version if not specified.
-            if ((v == null) && (sv == null)) {
-                v = Version.emptyVersion;
-            }
-
-            // Ensure that only the "version" attribute is used and convert
-            // it to the appropriate type.
-            if ((v != null) || (sv != null)) {
-                // Convert version attribute to type Version.
-                clause.attrs.remove(Constants.PACKAGE_SPECIFICATION_VERSION);
-                v = (v == null) ? sv : v;
-                clause.attrs.put(Constants.VERSION_ATTRIBUTE, Version.parseVersion(v.toString()));
-            }
-
-            // Find symbolic name and version attribute, if present.
-            if (clause.attrs.containsKey(Constants.BUNDLE_VERSION_ATTRIBUTE)
-                    || clause.attrs.containsKey(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE)) {
-                throw new BundleException("Exports must not specify bundle symbolic name or bundle version.");
-            }
-
-            // Now that we know that there are no bundle symbolic name and version
-            // attributes, add them since the spec says they are there implicitly.
-            clause.attrs.put(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE, bsn);
-            clause.attrs.put(Constants.BUNDLE_VERSION_ATTRIBUTE, bv);
-        }
-
-        return clauses;
-    }
-
-    private static List<Capability> convertExports(
-            List<ParsedHeaderClause> clauses, Resource resource) {
-        List<Capability> capList = new ArrayList<Capability>();
-        for (ParsedHeaderClause clause : clauses) {
-            for (String pkgName : clause.paths) {
-                // Prepend the package name to the array of attributes.
-                Map<String, Object> attrs = clause.attrs;
-                Map<String, Object> newAttrs = new HashMap<String, Object>(attrs.size() + 1);
-                newAttrs.putAll(attrs);
-                newAttrs.put(BundleRevision.PACKAGE_NAMESPACE, pkgName);
-
-                // Create package capability and add to capability list.
-                capList.add(new CapabilityImpl(resource, BundleRevision.PACKAGE_NAMESPACE, clause.dirs, newAttrs));
-            }
-        }
-
-        return capList;
-    }
-
-    private static String getManifestVersion(Map<String, String> headerMap) {
-        String manifestVersion = headerMap.get(Constants.BUNDLE_MANIFESTVERSION);
-        return (manifestVersion == null) ? "1" : manifestVersion.trim();
-    }
-
-    private static List<ParsedHeaderClause> calculateImplicitImports(
-            List<BundleCapability> exports, List<ParsedHeaderClause> imports)
-            throws BundleException {
-        List<ParsedHeaderClause> clauseList = new ArrayList<ParsedHeaderClause>();
-
-        // Since all R3 exports imply an import, add a corresponding
-        // requirement for each existing export capability. Do not
-        // duplicate imports.
-        Map<String, String> map = new HashMap<String, String>();
-        // Add existing imports.
-        for (ParsedHeaderClause anImport : imports) {
-            for (int pathIdx = 0; pathIdx < anImport.paths.size(); pathIdx++) {
-                map.put(anImport.paths.get(pathIdx), anImport.paths.get(pathIdx));
-            }
-        }
-        // Add import requirement for each export capability.
-        for (BundleCapability export : exports) {
-            if (map.get(export.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE).toString()) == null) {
-                // Convert Version to VersionRange.
-                Object version = export.getAttributes().get(Constants.VERSION_ATTRIBUTE);
-                ParsedHeaderClause clause = new ParsedHeaderClause();
-                if (version != null) {
-                    clause.attrs.put(Constants.VERSION_ATTRIBUTE, VersionRange.parseVersionRange(version.toString()));
-                }
-                clause.paths.add((String) export.getAttributes().get(BundleRevision.PACKAGE_NAMESPACE));
-                clauseList.add(clause);
-            }
-        }
-
-        return clauseList;
-    }
-
-    private static List<Capability> calculateImplicitUses(
-            List<Capability> exports, List<ParsedHeaderClause> imports)
-            throws BundleException {
-        // Add a "uses" directive onto each export of R3 bundles
-        // that references every other import (which will include
-        // exports, since export implies import); this is
-        // necessary since R3 bundles assumed a single class space,
-        // but R4 allows for multiple class spaces.
-        String usesValue = "";
-        for (ParsedHeaderClause anImport : imports) {
-            for (int pathIdx = 0; pathIdx < anImport.paths.size(); pathIdx++) {
-                usesValue = usesValue
-                        + ((usesValue.length() > 0) ? "," : "")
-                        + anImport.paths.get(pathIdx);
-            }
-        }
-        for (int i = 0; i < exports.size(); i++) {
-            Map<String, String> dirs = new HashMap<String, String>(1);
-            dirs.put(Constants.USES_DIRECTIVE, usesValue);
-            exports.set(i, new CapabilityImpl(
-                    exports.get(i).getResource(),
-                    BundleRevision.PACKAGE_NAMESPACE,
-                    dirs,
-                    exports.get(i).getAttributes()));
-        }
-
-        return exports;
-    }
-
-    private static ParsedHeaderClause parseBundleSymbolicName(Map<String, String> headerMap)
-            throws BundleException {
-        List<ParsedHeaderClause> clauses = parseStandardHeader(headerMap.get(Constants.BUNDLE_SYMBOLICNAME));
-        if (clauses.size() > 0) {
-            if (clauses.size() > 1 || clauses.get(0).paths.size() > 1) {
-                throw new BundleException("Cannot have multiple symbolic names: " + headerMap.get(Constants.BUNDLE_SYMBOLICNAME));
-            }
-
-            // Get bundle version.
-            Version bundleVersion = Version.emptyVersion;
-            if (headerMap.get(Constants.BUNDLE_VERSION) != null) {
-                bundleVersion = Version.parseVersion(headerMap.get(Constants.BUNDLE_VERSION));
-            }
-
-            // Create a require capability and return it.
-            ParsedHeaderClause clause = clauses.get(0);
-            String symName = clause.paths.get(0);
-            clause.attrs.put(BundleRevision.BUNDLE_NAMESPACE, symName);
-            clause.attrs.put(Constants.BUNDLE_VERSION_ATTRIBUTE, bundleVersion);
-            return clause;
-        }
-
-        return null;
-    }
-
-    private static List<RequirementImpl> parseFragmentHost(
-            Resource resource, Map<String, String> headerMap)
-            throws BundleException {
-        List<RequirementImpl> reqs = new ArrayList<RequirementImpl>();
-
-        List<ParsedHeaderClause> clauses = parseStandardHeader(headerMap.get(Constants.FRAGMENT_HOST));
-        if (clauses.size() > 0) {
-            // Make sure that only one fragment host symbolic name is specified.
-            if (clauses.size() > 1 || clauses.get(0).paths.size() > 1) {
-                throw new BundleException("Fragments cannot have multiple hosts: " + headerMap.get(Constants.FRAGMENT_HOST));
-            }
-
-            // If the bundle-version attribute is specified, then convert
-            // it to the proper type.
-            Object value = clauses.get(0).attrs.get(Constants.BUNDLE_VERSION_ATTRIBUTE);
-            value = (value == null) ? "0.0.0" : value;
-            clauses.get(0).attrs.put(Constants.BUNDLE_VERSION_ATTRIBUTE, VersionRange.parseVersionRange(value.toString()));
-
-            // Note that we use a linked hash map here to ensure the
-            // host symbolic name is first, which will make indexing
-            // more efficient.
-    // TODO: OSGi R4.3 - This is ordering is kind of hacky.
-            // Prepend the host symbolic name to the map of attributes.
-            Map<String, Object> attrs = clauses.get(0).attrs;
-            Map<String, Object> newAttrs = new LinkedHashMap<String, Object>(attrs.size() + 1);
-            // We want this first from an indexing perspective.
-            newAttrs.put(BundleRevision.HOST_NAMESPACE, clauses.get(0).paths.get(0));
-            newAttrs.putAll(attrs);
-            // But we need to put it again to make sure it wasn't overwritten.
-            newAttrs.put(BundleRevision.HOST_NAMESPACE, clauses.get(0).paths.get(0));
-
-            // Create filter now so we can inject filter directive.
-            SimpleFilter sf = SimpleFilter.convert(newAttrs);
-
-            // Inject filter directive.
-    // TODO: OSGi R4.3 - Can we insert this on demand somehow?
-            Map<String, String> dirs = clauses.get(0).dirs;
-            Map<String, String> newDirs = new HashMap<String, String>(dirs.size() + 1);
-            newDirs.putAll(dirs);
-            newDirs.put(Constants.FILTER_DIRECTIVE, sf.toString());
-
-            reqs.add(new RequirementImpl(
-                    resource, BundleRevision.HOST_NAMESPACE,
-                    newDirs,
-                    newAttrs));
-        }
-
-        return reqs;
-    }
-
-    private static List<ParsedHeaderClause> normalizeRequireClauses(List<ParsedHeaderClause> clauses) {
-        // Convert bundle version attribute to VersionRange type.
-        for (ParsedHeaderClause clause : clauses) {
-            Object value = clause.attrs.get(Constants.BUNDLE_VERSION_ATTRIBUTE);
-            if (value != null) {
-                clause.attrs.put(Constants.BUNDLE_VERSION_ATTRIBUTE, VersionRange.parseVersionRange(value.toString()));
-            }
-        }
-
-        return clauses;
-    }
-
-    private static List<Requirement> convertRequires(List<ParsedHeaderClause> clauses, Resource resource) {
-        List<Requirement> reqList = new ArrayList<Requirement>();
-        for (ParsedHeaderClause clause : clauses) {
-            for (String path : clause.paths) {
-                // Prepend the bundle symbolic name to the array of attributes.
-                Map<String, Object> attrs = clause.attrs;
-                // Note that we use a linked hash map here to ensure the
-                // symbolic name attribute is first, which will make indexing
-                // more efficient.
-    // TODO: OSGi R4.3 - This is ordering is kind of hacky.
-                // Prepend the symbolic name to the array of attributes.
-                Map<String, Object> newAttrs = new LinkedHashMap<String, Object>(attrs.size() + 1);
-                // We want this first from an indexing perspective.
-                newAttrs.put(BundleRevision.BUNDLE_NAMESPACE, path);
-                newAttrs.putAll(attrs);
-                // But we need to put it again to make sure it wasn't overwritten.
-                newAttrs.put(BundleRevision.BUNDLE_NAMESPACE, path);
-
-                // Create filter now so we can inject filter directive.
-                SimpleFilter sf = SimpleFilter.convert(newAttrs);
-
-                // Inject filter directive.
-    // TODO: OSGi R4.3 - Can we insert this on demand somehow?
-                Map<String, String> dirs = clause.dirs;
-                Map<String, String> newDirs = new HashMap<String, String>(dirs.size() + 1);
-                newDirs.putAll(dirs);
-                newDirs.put(Constants.FILTER_DIRECTIVE, sf.toString());
-
-                // Create package requirement and add to requirement list.
-                reqList.add(new RequirementImpl(resource, BundleRevision.BUNDLE_NAMESPACE, newDirs, newAttrs));
-            }
-        }
-
-        return reqList;
-    }
-
-    private static final char EOF = (char) -1;
-
-    private static char charAt(int pos, String headers, int length)
-    {
-        if (pos >= length)
-        {
-            return EOF;
-        }
-        return headers.charAt(pos);
-    }
-
-    private static final int CLAUSE_START = 0;
-    private static final int PARAMETER_START = 1;
-    private static final int KEY = 2;
-    private static final int DIRECTIVE_OR_TYPEDATTRIBUTE = 4;
-    private static final int ARGUMENT = 8;
-    private static final int VALUE = 16;
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    private static List<ParsedHeaderClause> parseStandardHeader(String header)
-    {
-        List<ParsedHeaderClause> clauses = new ArrayList<ParsedHeaderClause>();
-        if (header == null)
-        {
-            return clauses;
-        }
-        ParsedHeaderClause clause = null;
-        String key = null;
-        Map targetMap = null;
-        int state = CLAUSE_START;
-        int currentPosition = 0;
-        int startPosition = 0;
-        int length = header.length();
-        boolean quoted = false;
-        boolean escaped = false;
-
-        char currentChar = EOF;
-        do
-        {
-            currentChar = charAt(currentPosition, header, length);
-            switch (state)
-            {
-                case CLAUSE_START:
-                    clause = new ParsedHeaderClause();
-                    clauses.add(clause);
-                    state = PARAMETER_START;
-                case PARAMETER_START:
-                    startPosition = currentPosition;
-                    state = KEY;
-                case KEY:
-                    switch (currentChar)
-                    {
-                        case ':':
-                        case '=':
-                            key = header.substring(startPosition, currentPosition).trim();
-                            startPosition = currentPosition + 1;
-                            targetMap = clause.attrs;
-                            state = currentChar == ':' ? DIRECTIVE_OR_TYPEDATTRIBUTE : ARGUMENT;
-                            break;
-                        case EOF:
-                        case ',':
-                        case ';':
-                            clause.paths.add(header.substring(startPosition, currentPosition).trim());
-                            state = currentChar == ',' ? CLAUSE_START : PARAMETER_START;
-                            break;
-                        default:
-                            break;
-                    }
-                    currentPosition++;
-                    break;
-                case DIRECTIVE_OR_TYPEDATTRIBUTE:
-                    switch(currentChar)
-                    {
-                        case '=':
-                            if (startPosition != currentPosition)
-                            {
-                                clause.types.put(key, header.substring(startPosition, currentPosition).trim());
-                            }
-                            else
-                            {
-                                targetMap = clause.dirs;
-                            }
-                            state = ARGUMENT;
-                            startPosition = currentPosition + 1;
-                            break;
-                        default:
-                            break;
-                    }
-                    currentPosition++;
-                    break;
-                case ARGUMENT:
-                    if (currentChar == '\"')
-                    {
-                        quoted = true;
-                        currentPosition++;
-                    }
-                    else
-                    {
-                        quoted = false;
-                    }
-                    if (!Character.isWhitespace(currentChar)) {
-                        state = VALUE;
-                    }
-                    else {
-                        currentPosition++;
-                    }
-                    break;
-                case VALUE:
-                    if (escaped)
-                    {
-                        escaped = false;
-                    }
-                    else
-                    {
-                        if (currentChar == '\\' )
-                        {
-                            escaped = true;
-                        }
-                        else if (quoted && currentChar == '\"')
-                        {
-                            quoted = false;
-                        }
-                        else if (!quoted)
-                        {
-                            String value = null;
-                            switch(currentChar)
-                            {
-                                case EOF:
-                                case ';':
-                                case ',':
-                                    value = header.substring(startPosition, currentPosition).trim();
-                                    if (value.startsWith("\"") && value.endsWith("\""))
-                                    {
-                                        value = value.substring(1, value.length() - 1);
-                                    }
-                                    if (targetMap.put(key, value) != null)
-                                    {
-                                        throw new IllegalArgumentException(
-                                                "Duplicate '" + key + "' in: " + header);
-                                    }
-                                    state = currentChar == ';' ? PARAMETER_START : CLAUSE_START;
-                                    break;
-                                default:
-                                    break;
-                            }
-                        }
-                    }
-                    currentPosition++;
-                    break;
-                default:
-                    break;
-            }
-        } while ( currentChar != EOF);
-
-        if (state > PARAMETER_START)
-        {
-            throw new IllegalArgumentException("Unable to parse header: " + header);
-        }
-        return clauses;
-    }
-
-    public static List<String> parseDelimitedString(String value, String delim)
-    {
-        return parseDelimitedString(value, delim, true);
-    }
-
-    /**
-     * Parses delimited string and returns an array containing the tokens. This
-     * parser obeys quotes, so the delimiter character will be ignored if it is
-     * inside of a quote. This method assumes that the quote character is not
-     * included in the set of delimiter characters.
-     * @param value the delimited string to parse.
-     * @param delim the characters delimiting the tokens.
-     * @return a list of string or an empty list if there are none.
-     **/
-    public static List<String> parseDelimitedString(String value, String delim, boolean trim)
-    {
-        if (value == null)
-        {
-            value = "";
-        }
-
-        List<String> list = new ArrayList();
-
-        int CHAR = 1;
-        int DELIMITER = 2;
-        int STARTQUOTE = 4;
-        int ENDQUOTE = 8;
-
-        StringBuffer sb = new StringBuffer();
-
-        int expecting = (CHAR | DELIMITER | STARTQUOTE);
-
-        boolean isEscaped = false;
-        for (int i = 0; i < value.length(); i++)
-        {
-            char c = value.charAt(i);
-
-            boolean isDelimiter = (delim.indexOf(c) >= 0);
-
-            if (!isEscaped && (c == '\\'))
-            {
-                isEscaped = true;
-                continue;
-            }
-
-            if (isEscaped)
-            {
-                sb.append(c);
-            }
-            else if (isDelimiter && ((expecting & DELIMITER) > 0))
-            {
-                if (trim)
-                {
-                    list.add(sb.toString().trim());
-                }
-                else
-                {
-                    list.add(sb.toString());
-                }
-                sb.delete(0, sb.length());
-                expecting = (CHAR | DELIMITER | STARTQUOTE);
-            }
-            else if ((c == '"') && ((expecting & STARTQUOTE) > 0))
-            {
-                sb.append(c);
-                expecting = CHAR | ENDQUOTE;
-            }
-            else if ((c == '"') && ((expecting & ENDQUOTE) > 0))
-            {
-                sb.append(c);
-                expecting = (CHAR | STARTQUOTE | DELIMITER);
-            }
-            else if ((expecting & CHAR) > 0)
-            {
-                sb.append(c);
-            }
-            else
-            {
-                throw new IllegalArgumentException("Invalid delimited string: " + value);
-            }
-
-            isEscaped = false;
-        }
-
-        if (sb.length() > 0)
-        {
-            if (trim)
-            {
-                list.add(sb.toString().trim());
-            }
-            else
-            {
-                list.add(sb.toString());
-            }
-        }
-
-        return list;
-    }
-
-
-    static class ParsedHeaderClause {
-        public final List<String> paths = new ArrayList<String>();
-        public final Map<String, String> dirs = new LinkedHashMap<String, String>();
-        public final Map<String, Object> attrs = new LinkedHashMap<String, Object>();
-        public final Map<String, String> types = new LinkedHashMap<String, String>();
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/resolver/ResourceImpl.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/resolver/ResourceImpl.java b/features/src/main/java/org/apache/karaf/features/internal/resolver/ResourceImpl.java
deleted file mode 100644
index 18e0dc3..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/resolver/ResourceImpl.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.resolver;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.osgi.framework.Version;
-import org.osgi.framework.namespace.IdentityNamespace;
-import org.osgi.resource.Capability;
-import org.osgi.resource.Requirement;
-import org.osgi.resource.Resource;
-
-/**
- */
-public class ResourceImpl implements Resource {
-
-    private final List<Capability> m_caps;
-    private final List<Requirement> m_reqs;
-
-    public ResourceImpl(String name, Version version) {
-        this(name, IdentityNamespace.TYPE_BUNDLE, version);
-    }
-
-    public ResourceImpl(String name, String type, Version version)
-    {
-        m_caps = new ArrayList<Capability>();
-        m_caps.add(0, new IdentityCapability(this, name, type, version));
-        m_reqs = new ArrayList<Requirement>();
-    }
-
-    public void addCapability(Capability capability) {
-        assert capability.getResource() == this;
-        m_caps.add(capability);
-    }
-
-    public void addCapabilities(Iterable<? extends Capability> capabilities) {
-        for (Capability cap : capabilities) {
-            addCapability(cap);
-        }
-    }
-
-    public void addRequirement(Requirement requirement) {
-        assert requirement.getResource() == this;
-        m_reqs.add(requirement);
-    }
-
-    public void addRequirements(Iterable<? extends Requirement> requirements) {
-        for (Requirement req : requirements) {
-            addRequirement(req);
-        }
-    }
-
-    public List<Capability> getCapabilities(String namespace)
-    {
-        List<Capability> result = m_caps;
-        if (namespace != null)
-        {
-            result = new ArrayList<Capability>();
-            for (Capability cap : m_caps)
-            {
-                if (cap.getNamespace().equals(namespace))
-                {
-                    result.add(cap);
-                }
-            }
-        }
-        return result;
-    }
-
-    public List<Requirement> getRequirements(String namespace)
-    {
-        List<Requirement> result = m_reqs;
-        if (namespace != null)
-        {
-            result = new ArrayList<Requirement>();
-            for (Requirement req : m_reqs)
-            {
-                if (req.getNamespace().equals(namespace))
-                {
-                    result.add(req);
-                }
-            }
-        }
-        return result;
-    }
-
-    @Override
-    public String toString()
-    {
-        Capability cap = getCapabilities(IdentityNamespace.IDENTITY_NAMESPACE).get(0);
-        return cap.getAttributes().get(IdentityNamespace.IDENTITY_NAMESPACE) + "/"
-                + cap.getAttributes().get(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/resolver/ServiceNamespace.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/resolver/ServiceNamespace.java b/features/src/main/java/org/apache/karaf/features/internal/resolver/ServiceNamespace.java
deleted file mode 100644
index 4fe3bf8..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/resolver/ServiceNamespace.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.resolver;
-
-import org.osgi.resource.Namespace;
-
-/**
- */
-public final class ServiceNamespace extends Namespace {
-
-    public static final String SERVICE_NAMESPACE = "service-reference";
-
-    private ServiceNamespace() {
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/resolver/SimpleFilter.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/resolver/SimpleFilter.java b/features/src/main/java/org/apache/karaf/features/internal/resolver/SimpleFilter.java
deleted file mode 100644
index ae10441..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/resolver/SimpleFilter.java
+++ /dev/null
@@ -1,649 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.resolver;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import org.apache.felix.utils.version.VersionRange;
-
-public class SimpleFilter
-{
-    public static final int MATCH_ALL = 0;
-    public static final int AND = 1;
-    public static final int OR = 2;
-    public static final int NOT = 3;
-    public static final int EQ = 4;
-    public static final int LTE = 5;
-    public static final int GTE = 6;
-    public static final int SUBSTRING = 7;
-    public static final int PRESENT = 8;
-    public static final int APPROX = 9;
-
-    private final String m_name;
-    private final Object m_value;
-    private final int m_op;
-
-    public SimpleFilter(String attr, Object value, int op)
-    {
-        m_name = attr;
-        m_value = value;
-        m_op = op;
-    }
-
-    public String getName()
-    {
-        return m_name;
-    }
-
-    public Object getValue()
-    {
-        return m_value;
-    }
-
-    public int getOperation()
-    {
-        return m_op;
-    }
-
-    public String toString()
-    {
-        String s = null;
-        switch (m_op)
-        {
-            case AND:
-                s = "(&" + toString((List) m_value) + ")";
-                break;
-            case OR:
-                s = "(|" + toString((List) m_value) + ")";
-                break;
-            case NOT:
-                s = "(!" + toString((List) m_value) + ")";
-                break;
-            case EQ:
-                s = "(" + m_name + "=" + toEncodedString(m_value) + ")";
-                break;
-            case LTE:
-                s = "(" + m_name + "<=" + toEncodedString(m_value) + ")";
-                break;
-            case GTE:
-                s = "(" + m_name + ">=" + toEncodedString(m_value) + ")";
-                break;
-            case SUBSTRING:
-                s = "(" + m_name + "=" + unparseSubstring((List<String>) m_value) + ")";
-                break;
-            case PRESENT:
-                s = "(" + m_name + "=*)";
-                break;
-            case APPROX:
-                s = "(" + m_name + "~=" + toEncodedString(m_value) + ")";
-                break;
-            case MATCH_ALL:
-                s = "(*)";
-                break;
-        }
-        return s;
-    }
-
-    private static String toString(List list)
-    {
-        StringBuffer sb = new StringBuffer();
-        for (int i = 0; i < list.size(); i++)
-        {
-            sb.append(list.get(i).toString());
-        }
-        return sb.toString();
-    }
-
-    private static String toDecodedString(String s, int startIdx, int endIdx)
-    {
-        StringBuffer sb = new StringBuffer(endIdx - startIdx);
-        boolean escaped = false;
-        for (int i = 0; i < (endIdx - startIdx); i++)
-        {
-            char c = s.charAt(startIdx + i);
-            if (!escaped && (c == '\\'))
-            {
-                escaped = true;
-            }
-            else
-            {
-                escaped = false;
-                sb.append(c);
-            }
-        }
-
-        return sb.toString();
-    }
-
-    private static String toEncodedString(Object o)
-    {
-        if (o instanceof String)
-        {
-            String s = (String) o;
-            StringBuffer sb = new StringBuffer();
-            for (int i = 0; i < s.length(); i++)
-            {
-                char c = s.charAt(i);
-                if ((c == '\\') || (c == '(') || (c == ')') || (c == '*'))
-                {
-                    sb.append('\\');
-                }
-                sb.append(c);
-            }
-
-            o = sb.toString();
-        }
-
-        return o.toString();
-    }
-
-    public static SimpleFilter parse(String filter)
-    {
-        int idx = skipWhitespace(filter, 0);
-
-        if ((filter == null) || (filter.length() == 0) || (idx >= filter.length()))
-        {
-            throw new IllegalArgumentException("Null or empty filter.");
-        }
-        else if (filter.charAt(idx) != '(')
-        {
-            throw new IllegalArgumentException("Missing opening parenthesis: " + filter);
-        }
-
-        SimpleFilter sf = null;
-        List stack = new ArrayList();
-        boolean isEscaped = false;
-        while (idx < filter.length())
-        {
-            if (sf != null)
-            {
-                throw new IllegalArgumentException(
-                        "Only one top-level operation allowed: " + filter);
-            }
-
-            if (!isEscaped && (filter.charAt(idx) == '('))
-            {
-                // Skip paren and following whitespace.
-                idx = skipWhitespace(filter, idx + 1);
-
-                if (filter.charAt(idx) == '&')
-                {
-                    int peek = skipWhitespace(filter, idx + 1);
-                    if (filter.charAt(peek) == '(')
-                    {
-                        idx = peek - 1;
-                        stack.add(0, new SimpleFilter(null, new ArrayList(), SimpleFilter.AND));
-                    }
-                    else
-                    {
-                        stack.add(0, new Integer(idx));
-                    }
-                }
-                else if (filter.charAt(idx) == '|')
-                {
-                    int peek = skipWhitespace(filter, idx + 1);
-                    if (filter.charAt(peek) == '(')
-                    {
-                        idx = peek - 1;
-                        stack.add(0, new SimpleFilter(null, new ArrayList(), SimpleFilter.OR));
-                    }
-                    else
-                    {
-                        stack.add(0, new Integer(idx));
-                    }
-                }
-                else if (filter.charAt(idx) == '!')
-                {
-                    int peek = skipWhitespace(filter, idx + 1);
-                    if (filter.charAt(peek) == '(')
-                    {
-                        idx = peek - 1;
-                        stack.add(0, new SimpleFilter(null, new ArrayList(), SimpleFilter.NOT));
-                    }
-                    else
-                    {
-                        stack.add(0, new Integer(idx));
-                    }
-                }
-                else
-                {
-                    stack.add(0, new Integer(idx));
-                }
-            }
-            else if (!isEscaped && (filter.charAt(idx) == ')'))
-            {
-                Object top = stack.remove(0);
-                if (top instanceof SimpleFilter)
-                {
-                    if (!stack.isEmpty() && (stack.get(0) instanceof SimpleFilter))
-                    {
-                        ((List) ((SimpleFilter) stack.get(0)).m_value).add(top);
-                    }
-                    else
-                    {
-                        sf = (SimpleFilter) top;
-                    }
-                }
-                else if (!stack.isEmpty() && (stack.get(0) instanceof SimpleFilter))
-                {
-                    ((List) ((SimpleFilter) stack.get(0)).m_value).add(
-                            SimpleFilter.subfilter(filter, ((Integer) top).intValue(), idx));
-                }
-                else
-                {
-                    sf = SimpleFilter.subfilter(filter, ((Integer) top).intValue(), idx);
-                }
-            }
-            else if (!isEscaped && (filter.charAt(idx) == '\\'))
-            {
-                isEscaped = true;
-            }
-            else
-            {
-                isEscaped = false;
-            }
-
-            idx = skipWhitespace(filter, idx + 1);
-        }
-
-        if (sf == null)
-        {
-            throw new IllegalArgumentException("Missing closing parenthesis: " + filter);
-        }
-
-        return sf;
-    }
-
-    private static SimpleFilter subfilter(String filter, int startIdx, int endIdx)
-    {
-        final String opChars = "=<>~";
-
-        // Determine the ending index of the attribute name.
-        int attrEndIdx = startIdx;
-        for (int i = 0; i < (endIdx - startIdx); i++)
-        {
-            char c = filter.charAt(startIdx + i);
-            if (opChars.indexOf(c) >= 0)
-            {
-                break;
-            }
-            else if (!Character.isWhitespace(c))
-            {
-                attrEndIdx = startIdx + i + 1;
-            }
-        }
-        if (attrEndIdx == startIdx)
-        {
-            throw new IllegalArgumentException(
-                    "Missing attribute name: " + filter.substring(startIdx, endIdx));
-        }
-        String attr = filter.substring(startIdx, attrEndIdx);
-
-        // Skip the attribute name and any following whitespace.
-        startIdx = skipWhitespace(filter, attrEndIdx);
-
-        // Determine the operator type.
-        int op = -1;
-        switch (filter.charAt(startIdx))
-        {
-            case '=':
-                op = EQ;
-                startIdx++;
-                break;
-            case '<':
-                if (filter.charAt(startIdx + 1) != '=')
-                {
-                    throw new IllegalArgumentException(
-                            "Unknown operator: " + filter.substring(startIdx, endIdx));
-                }
-                op = LTE;
-                startIdx += 2;
-                break;
-            case '>':
-                if (filter.charAt(startIdx + 1) != '=')
-                {
-                    throw new IllegalArgumentException(
-                            "Unknown operator: " + filter.substring(startIdx, endIdx));
-                }
-                op = GTE;
-                startIdx += 2;
-                break;
-            case '~':
-                if (filter.charAt(startIdx + 1) != '=')
-                {
-                    throw new IllegalArgumentException(
-                            "Unknown operator: " + filter.substring(startIdx, endIdx));
-                }
-                op = APPROX;
-                startIdx += 2;
-                break;
-            default:
-                throw new IllegalArgumentException(
-                        "Unknown operator: " + filter.substring(startIdx, endIdx));
-        }
-
-        // Parse value.
-        Object value = toDecodedString(filter, startIdx, endIdx);
-
-        // Check if the equality comparison is actually a substring
-        // or present operation.
-        if (op == EQ)
-        {
-            String valueStr = filter.substring(startIdx, endIdx);
-            List<String> values = parseSubstring(valueStr);
-            if ((values.size() == 2)
-                    && (values.get(0).length() == 0)
-                    && (values.get(1).length() == 0))
-            {
-                op = PRESENT;
-            }
-            else if (values.size() > 1)
-            {
-                op = SUBSTRING;
-                value = values;
-            }
-        }
-
-        return new SimpleFilter(attr, value, op);
-    }
-
-    public static List<String> parseSubstring(String value)
-    {
-        List<String> pieces = new ArrayList();
-        StringBuffer ss = new StringBuffer();
-        // int kind = SIMPLE; // assume until proven otherwise
-        boolean wasStar = false; // indicates last piece was a star
-        boolean leftstar = false; // track if the initial piece is a star
-        boolean rightstar = false; // track if the final piece is a star
-
-        int idx = 0;
-
-        // We assume (sub)strings can contain leading and trailing blanks
-        boolean escaped = false;
-        loop:   for (;;)
-        {
-            if (idx >= value.length())
-            {
-                if (wasStar)
-                {
-                    // insert last piece as "" to handle trailing star
-                    rightstar = true;
-                }
-                else
-                {
-                    pieces.add(ss.toString());
-                    // accumulate the last piece
-                    // note that in the case of
-                    // (cn=); this might be
-                    // the string "" (!=null)
-                }
-                ss.setLength(0);
-                break loop;
-            }
-
-            // Read the next character and account for escapes.
-            char c = value.charAt(idx++);
-            if (!escaped && (c == '*'))
-            {
-                // If we have successive '*' characters, then we can
-                // effectively collapse them by ignoring succeeding ones.
-                if (!wasStar)
-                {
-                    if (ss.length() > 0)
-                    {
-                        pieces.add(ss.toString()); // accumulate the pieces
-                        // between '*' occurrences
-                    }
-                    ss.setLength(0);
-                    // if this is a leading star, then track it
-                    if (pieces.isEmpty())
-                    {
-                        leftstar = true;
-                    }
-                    wasStar = true;
-                }
-            }
-            else if (!escaped && (c == '\\'))
-            {
-                escaped = true;
-            }
-            else
-            {
-                escaped = false;
-                wasStar = false;
-                ss.append(c);
-            }
-        }
-        if (leftstar || rightstar || pieces.size() > 1)
-        {
-            // insert leading and/or trailing "" to anchor ends
-            if (rightstar)
-            {
-                pieces.add("");
-            }
-            if (leftstar)
-            {
-                pieces.add(0, "");
-            }
-        }
-        return pieces;
-    }
-
-    public static String unparseSubstring(List<String> pieces)
-    {
-        StringBuffer sb = new StringBuffer();
-        for (int i = 0; i < pieces.size(); i++)
-        {
-            if (i > 0)
-            {
-                sb.append("*");
-            }
-            sb.append(toEncodedString(pieces.get(i)));
-        }
-        return sb.toString();
-    }
-
-    public static boolean compareSubstring(List<String> pieces, String s)
-    {
-        // Walk the pieces to match the string
-        // There are implicit stars between each piece,
-        // and the first and last pieces might be "" to anchor the match.
-        // assert (pieces.length > 1)
-        // minimal case is <string>*<string>
-
-        boolean result = true;
-        int len = pieces.size();
-
-        // Special case, if there is only one piece, then
-        // we must perform an equality test.
-        if (len == 1)
-        {
-            return s.equals(pieces.get(0));
-        }
-
-        // Otherwise, check whether the pieces match
-        // the specified string.
-
-        int index = 0;
-
-        loop:   for (int i = 0; i < len; i++)
-        {
-            String piece = pieces.get(i);
-
-            // If this is the first piece, then make sure the
-            // string starts with it.
-            if (i == 0)
-            {
-                if (!s.startsWith(piece))
-                {
-                    result = false;
-                    break loop;
-                }
-            }
-
-            // If this is the last piece, then make sure the
-            // string ends with it.
-            if (i == (len - 1))
-            {
-                if (s.endsWith(piece) && (s.length() >= (index + piece.length())))
-                {
-                    result = true;
-                }
-                else
-                {
-                    result = false;
-                }
-                break loop;
-            }
-
-            // If this is neither the first or last piece, then
-            // make sure the string contains it.
-            if ((i > 0) && (i < (len - 1)))
-            {
-                index = s.indexOf(piece, index);
-                if (index < 0)
-                {
-                    result = false;
-                    break loop;
-                }
-            }
-
-            // Move string index beyond the matching piece.
-            index += piece.length();
-        }
-
-        return result;
-    }
-
-    private static int skipWhitespace(String s, int startIdx)
-    {
-        int len = s.length();
-        while ((startIdx < len) && Character.isWhitespace(s.charAt(startIdx)))
-        {
-            startIdx++;
-        }
-        return startIdx;
-    }
-
-    /**
-     * Converts a attribute map to a filter. The filter is created by iterating
-     * over the map's entry set. If ordering of attributes is important (e.g.,
-     * for hitting attribute indices), then the map's entry set should iterate
-     * in the desired order. Equality testing is assumed for all attribute types
-     * other than version ranges, which are handled appropriated. If the attribute
-     * map is empty, then a filter that matches anything is returned.
-     * @param attrs Map of attributes to convert to a filter.
-     * @return A filter corresponding to the attributes.
-     */
-    public static SimpleFilter convert(Map<String, Object> attrs)
-    {
-        // Rather than building a filter string to be parsed into a SimpleFilter,
-        // we will just create the parsed SimpleFilter directly.
-
-        List<SimpleFilter> filters = new ArrayList<SimpleFilter>();
-
-        for (Entry<String, Object> entry : attrs.entrySet())
-        {
-            if (entry.getValue() instanceof VersionRange)
-            {
-                VersionRange vr = (VersionRange) entry.getValue();
-                if (!vr.isOpenFloor())
-                {
-                    filters.add(
-                            new SimpleFilter(
-                                    entry.getKey(),
-                                    vr.getFloor().toString(),
-                                    SimpleFilter.GTE));
-                }
-                else
-                {
-                    SimpleFilter not =
-                            new SimpleFilter(null, new ArrayList(), SimpleFilter.NOT);
-                    ((List) not.getValue()).add(
-                            new SimpleFilter(
-                                    entry.getKey(),
-                                    vr.getFloor().toString(),
-                                    SimpleFilter.LTE));
-                    filters.add(not);
-                }
-
-                if (vr.getCeiling() != null)
-                {
-                    if (!vr.isOpenCeiling())
-                    {
-                        filters.add(
-                                new SimpleFilter(
-                                        entry.getKey(),
-                                        vr.getCeiling().toString(),
-                                        SimpleFilter.LTE));
-                    }
-                    else
-                    {
-                        SimpleFilter not =
-                                new SimpleFilter(null, new ArrayList(), SimpleFilter.NOT);
-                        ((List) not.getValue()).add(
-                                new SimpleFilter(
-                                        entry.getKey(),
-                                        vr.getCeiling().toString(),
-                                        SimpleFilter.GTE));
-                        filters.add(not);
-                    }
-                }
-            }
-            else
-            {
-                List<String> values = SimpleFilter.parseSubstring(entry.getValue().toString());
-                if (values.size() > 1)
-                {
-                    filters.add(
-                            new SimpleFilter(
-                                    entry.getKey(),
-                                    values,
-                                    SimpleFilter.SUBSTRING));
-                }
-                else
-                {
-                    filters.add(
-                            new SimpleFilter(
-                                    entry.getKey(),
-                                    values.get(0),
-                                    SimpleFilter.EQ));
-                }
-            }
-        }
-
-        SimpleFilter sf = null;
-
-        if (filters.size() == 1)
-        {
-            sf = filters.get(0);
-        }
-        else if (attrs.size() > 1)
-        {
-            sf = new SimpleFilter(null, filters, SimpleFilter.AND);
-        }
-        else if (filters.isEmpty())
-        {
-            sf = new SimpleFilter(null, null, SimpleFilter.MATCH_ALL);
-        }
-
-        return sf;
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/resolver/Slf4jResolverLog.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/resolver/Slf4jResolverLog.java b/features/src/main/java/org/apache/karaf/features/internal/resolver/Slf4jResolverLog.java
deleted file mode 100644
index 2f4a1f3..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/resolver/Slf4jResolverLog.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.resolver;
-
-import org.slf4j.Logger;
-
-/**
- */
-public class Slf4jResolverLog extends org.apache.felix.resolver.Logger {
-
-    private final Logger logger;
-
-    public Slf4jResolverLog(Logger logger) {
-        super(LOG_DEBUG);
-        this.logger = logger;
-    }
-
-    @Override
-    protected void doLog(int level, String msg, Throwable throwable) {
-        switch (level) {
-            case LOG_ERROR:
-                logger.error(msg, throwable);
-                break;
-            case LOG_WARNING:
-                logger.warn(msg, throwable);
-                break;
-            case LOG_INFO:
-                logger.info(msg, throwable);
-                break;
-            case LOG_DEBUG:
-                logger.debug(msg, throwable);
-                break;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/resolver/UriNamespace.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/resolver/UriNamespace.java b/features/src/main/java/org/apache/karaf/features/internal/resolver/UriNamespace.java
deleted file mode 100644
index b5158bf..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/resolver/UriNamespace.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.resolver;
-
-import java.util.List;
-
-import org.osgi.resource.Capability;
-import org.osgi.resource.Namespace;
-import org.osgi.resource.Resource;
-
-/**
- */
-public final class UriNamespace extends Namespace {
-
-    public static final String URI_NAMESPACE = "karaf.uri";
-
-    public static String getUri(Resource resource)
-    {
-        List<Capability> caps = resource.getCapabilities(null);
-        for (Capability cap : caps)
-        {
-            if (cap.getNamespace().equals(UriNamespace.URI_NAMESPACE))
-            {
-                return cap.getAttributes().get(UriNamespace.URI_NAMESPACE).toString();
-            }
-        }
-        return null;
-    }
-
-
-    private UriNamespace() {
-    }
-}


[13/33] git commit: [KARAF-2888] Refactor repository validation so that we use a single pass, cache the created Schema

Posted by gn...@apache.org.
[KARAF-2888] Refactor repository validation so that we use a single pass, cache the created Schema


Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/1306af5f
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/1306af5f
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/1306af5f

Branch: refs/heads/master
Commit: 1306af5f222e8bf8925d0e42b0062ec3d367c1d3
Parents: a9b763f
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Fri Apr 11 11:14:16 2014 +0200
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Fri Apr 11 19:20:03 2014 +0200

----------------------------------------------------------------------
 features/pom.xml                                |   4 +
 .../org/apache/karaf/features/Repository.java   |   3 +-
 .../karaf/features/internal/model/JaxbUtil.java | 149 ++++++++++++++-----
 .../internal/service/BootFeaturesInstaller.java |   2 +-
 .../internal/service/FeatureValidationUtil.java |  80 +---------
 .../internal/service/FeaturesServiceImpl.java   |   4 +-
 .../internal/service/RepositoryImpl.java        |  15 +-
 .../service/FeaturesValidationTest.java         |  49 +++++-
 .../karaf/tooling/features/CreateKarMojo.java   |  23 ++-
 .../features/GenerateDescriptorMojo.java        |   9 +-
 .../karaf/tooling/features/InstallKarsMojo.java |   9 +-
 .../features/GenerateDescriptorMojoTest.java    |   9 +-
 .../java/org/apache/karaf/util/XmlUtils.java    |  64 +++++---
 13 files changed, 231 insertions(+), 189 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/1306af5f/features/pom.xml
----------------------------------------------------------------------
diff --git a/features/pom.xml b/features/pom.xml
index 5013057..d722ada 100644
--- a/features/pom.xml
+++ b/features/pom.xml
@@ -129,12 +129,16 @@
                             org.apache.felix.resolver,
                             org.apache.felix.utils.version,
                             org.apache.felix.utils.manifest,
+                            org.apache.karaf.util,
                             org.apache.karaf.util.collections,
                             org.apache.karaf.util.json,
                             org.apache.karaf.util.tracker,
                             org.osgi.service.resolver,
                             org.osgi.service.repository
                         </Private-Package>
+                        <Embed-Dependency>
+                            org.apache.karaf.util;inline="org/apache/karaf/util/XmlUtils*.class"
+                        </Embed-Dependency>
                         <Bundle-Activator>
                             org.apache.karaf.features.internal.osgi.Activator
                         </Bundle-Activator>

http://git-wip-us.apache.org/repos/asf/karaf/blob/1306af5f/features/src/main/java/org/apache/karaf/features/Repository.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/Repository.java b/features/src/main/java/org/apache/karaf/features/Repository.java
index 6ee96da..3ea12ec 100644
--- a/features/src/main/java/org/apache/karaf/features/Repository.java
+++ b/features/src/main/java/org/apache/karaf/features/Repository.java
@@ -16,6 +16,7 @@
  */
 package org.apache.karaf.features;
 
+import java.io.IOException;
 import java.net.URI;
 
 /**
@@ -23,7 +24,7 @@ import java.net.URI;
  */
 public interface Repository {
 
-    String getName();
+    String getName() throws IOException;
 
     URI getURI();
 

http://git-wip-us.apache.org/repos/asf/karaf/blob/1306af5f/features/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java b/features/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java
index 39c057a..2036452 100644
--- a/features/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java
+++ b/features/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java
@@ -23,19 +23,27 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.Writer;
+import java.net.URL;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.xml.XMLConstants;
 import javax.xml.bind.JAXBContext;
 import javax.xml.bind.JAXBException;
 import javax.xml.bind.Marshaller;
 import javax.xml.bind.Unmarshaller;
-import javax.xml.bind.ValidationEvent;
-import javax.xml.bind.ValidationEventHandler;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-import javax.xml.stream.XMLInputFactory;
+import javax.xml.namespace.QName;
+import javax.xml.transform.dom.DOMSource;
 import javax.xml.transform.sax.SAXSource;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
 
 import org.apache.karaf.features.FeaturesNamespaces;
+import org.apache.karaf.util.XmlUtils;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
 import org.xml.sax.Attributes;
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
@@ -45,7 +53,6 @@ import org.xml.sax.helpers.XMLFilterImpl;
 
 public class JaxbUtil {
 
-    public static final XMLInputFactory XMLINPUT_FACTORY = XMLInputFactory.newInstance();
     private static final JAXBContext FEATURES_CONTEXT;
     static {
         try {
@@ -75,45 +82,113 @@ public class JaxbUtil {
     /**
      * Read in a Features from the input stream.
      *
-     * @param in       input stream to read
+     * @param uri      uri to read
      * @param validate whether to validate the input.
      * @return a Features read from the input stream
-     * @throws ParserConfigurationException is the SAX parser can not be configured
-     * @throws SAXException                 if there is an xml problem
-     * @throws JAXBException                if the xml cannot be marshalled into a T.
      */
-    public static Features unmarshal(InputStream in, boolean validate) {
-        InputSource inputSource = new InputSource(in);
+    public static Features unmarshal(String uri, boolean validate) {
+        if (validate) {
+            return unmarshalValidate(uri, null);
+        } else {
+            return unmarshalNoValidate(uri, null);
+        }
+    }
+
+    public static Features unmarshal(String uri, InputStream stream, boolean validate) {
+        if (validate) {
+            return unmarshalValidate(uri, stream);
+        } else {
+            return unmarshalNoValidate(uri, stream);
+        }
+    }
 
-        SAXParserFactory factory = SAXParserFactory.newInstance();
-        factory.setNamespaceAware(true);
-        factory.setValidating(validate);
-        SAXParser parser;
+    private static Features unmarshalValidate(String uri, InputStream stream) {
         try {
-            parser = factory.newSAXParser();
-        
-
-        Unmarshaller unmarshaller = FEATURES_CONTEXT.createUnmarshaller();
-        unmarshaller.setEventHandler(new ValidationEventHandler() {
-            public boolean handleEvent(ValidationEvent validationEvent) {
-                System.out.println(validationEvent);
-                return false;
+            Document doc;
+            if (stream != null) {
+                doc = XmlUtils.parse(stream);
+                doc.setDocumentURI(uri);
+            } else {
+                doc = XmlUtils.parse(uri);
             }
-        });
 
-        XMLFilter xmlFilter = new NoSourceAndNamespaceFilter(parser.getXMLReader());
-        xmlFilter.setContentHandler(unmarshaller.getUnmarshallerHandler());
+            Schema schema = getSchema(doc.getDocumentElement().getNamespaceURI());
+            try {
+                schema.newValidator().validate(new DOMSource(doc));
+            } catch (SAXException e) {
+                throw new IllegalArgumentException("Unable to validate " + uri, e);
+            }
 
-        SAXSource source = new SAXSource(xmlFilter, inputSource);
+            fixDom(doc, doc.getDocumentElement());
+            Unmarshaller unmarshaller = FEATURES_CONTEXT.createUnmarshaller();
+            return (Features) unmarshaller.unmarshal(new DOMSource(doc));
 
-        return (Features)unmarshaller.unmarshal(source);
-        
-        } catch (ParserConfigurationException e) {
-            throw new RuntimeException(e);
-        } catch (JAXBException e) {
-            throw new RuntimeException(e);
-        } catch (SAXException e) {
-            throw new RuntimeException(e);
+
+        } catch (RuntimeException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new RuntimeException("Unable to load " + uri, e);
+        }
+    }
+
+    private static Map<String, Schema> schemas = new ConcurrentHashMap<String, Schema>();
+    private static Schema getSchema(String namespace) throws SAXException {
+        Schema schema = schemas.get(namespace);
+        if (schema == null) {
+            String schemaLocation;
+            if (FeaturesNamespaces.URI_1_0_0.equals(namespace)) {
+                schemaLocation = "/org/apache/karaf/features/karaf-features-1.0.0.xsd";
+            } else if (FeaturesNamespaces.URI_1_1_0.equals(namespace)) {
+                schemaLocation = "/org/apache/karaf/features/karaf-features-1.1.0.xsd";
+            } else if (FeaturesNamespaces.URI_1_2_0.equals(namespace)) {
+                schemaLocation = "/org/apache/karaf/features/karaf-features-1.2.0.xsd";
+            } else if (FeaturesNamespaces.URI_1_3_0.equals(namespace)) {
+                schemaLocation = "/org/apache/karaf/features/karaf-features-1.3.0.xsd";
+            } else {
+                throw new IllegalArgumentException("Unsupported namespace: " + namespace);
+            }
+
+            SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+            // root element has namespace - we can use schema validation
+            URL url = JaxbUtil.class.getResource(schemaLocation);
+            if (url == null) {
+                throw new IllegalStateException("Could not find resource: " + schemaLocation);
+            }
+            schema = factory.newSchema(new StreamSource(url.toExternalForm()));
+            schemas.put(namespace, schema);
+        }
+        return schema;
+    }
+
+
+    private static void fixDom(Document doc, Node node) {
+        if (node.getNamespaceURI() != null && !FeaturesNamespaces.URI_CURRENT.equals(node.getNamespaceURI())) {
+            doc.renameNode(node, FeaturesNamespaces.URI_CURRENT, node.getLocalName());
+        }
+        NodeList children = node.getChildNodes();
+        for (int i = 0; i < children.getLength(); i++) {
+            fixDom(doc, children.item(i));
+        }
+    }
+
+    private static Features unmarshalNoValidate(String uri, InputStream stream) {
+        try {
+            Unmarshaller unmarshaller = FEATURES_CONTEXT.createUnmarshaller();
+            XMLFilter xmlFilter = new NoSourceAndNamespaceFilter(XmlUtils.xmlReader());
+            xmlFilter.setContentHandler(unmarshaller.getUnmarshallerHandler());
+
+
+            InputSource is = new InputSource(uri);
+            if (stream != null) {
+                is.setByteStream(stream);
+            }
+            SAXSource source = new SAXSource(xmlFilter, new InputSource(uri));
+            return (Features) unmarshaller.unmarshal(source);
+
+        } catch (RuntimeException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new RuntimeException("Unable to load " + uri, e);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/karaf/blob/1306af5f/features/src/main/java/org/apache/karaf/features/internal/service/BootFeaturesInstaller.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/service/BootFeaturesInstaller.java b/features/src/main/java/org/apache/karaf/features/internal/service/BootFeaturesInstaller.java
index eaa9ba0..5b362b8 100644
--- a/features/src/main/java/org/apache/karaf/features/internal/service/BootFeaturesInstaller.java
+++ b/features/src/main/java/org/apache/karaf/features/internal/service/BootFeaturesInstaller.java
@@ -89,7 +89,7 @@ public class BootFeaturesInstaller {
                     try {
                         featuresService.addRepository(URI.create(repo));
                     } catch (Exception e) {
-                        LOGGER.error("Error installing boot feature repository " + repo);
+                        LOGGER.error("Error installing boot feature repository " + repo, e);
                     }
                 }
             }

http://git-wip-us.apache.org/repos/asf/karaf/blob/1306af5f/features/src/main/java/org/apache/karaf/features/internal/service/FeatureValidationUtil.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/service/FeatureValidationUtil.java b/features/src/main/java/org/apache/karaf/features/internal/service/FeatureValidationUtil.java
index 8fb161e..6903dc0 100644
--- a/features/src/main/java/org/apache/karaf/features/internal/service/FeatureValidationUtil.java
+++ b/features/src/main/java/org/apache/karaf/features/internal/service/FeatureValidationUtil.java
@@ -15,38 +15,15 @@
  */
 package org.apache.karaf.features.internal.service;
 
-import java.io.IOException;
-import java.io.InputStream;
 import java.net.URI;
-import java.net.URLConnection;
 
-import javax.xml.XMLConstants;
-import javax.xml.namespace.QName;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamSource;
-import javax.xml.validation.Schema;
-import javax.xml.validation.SchemaFactory;
-import javax.xml.validation.Validator;
-
-import org.apache.karaf.features.FeaturesNamespaces;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.w3c.dom.Document;
-import org.xml.sax.SAXException;
+import org.apache.karaf.features.internal.model.JaxbUtil;
 
 /**
  * Utility class which fires XML Schema validation.
  */
 public class FeatureValidationUtil {
 
-    public static final QName FEATURES_0_0 = new QName("features");
-    public static final QName FEATURES_1_0 = new QName("http://karaf.apache.org/xmlns/features/v1.0.0", "features");
-    public static final QName FEATURES_1_1 = new QName("http://karaf.apache.org/xmlns/features/v1.1.0", "features");
-    public static final QName FEATURES_1_2 = new QName("http://karaf.apache.org/xmlns/features/v1.2.0", "features");
-    private static final Logger LOGGER = LoggerFactory.getLogger(FeatureValidationUtil.class);
-
     /**
      * Runs schema validation.
      * 
@@ -54,60 +31,7 @@ public class FeatureValidationUtil {
      * @throws Exception When validation fails.
      */
     public static void validate(URI uri) throws Exception {
-        Document doc = load(uri);
-
-        QName name = new QName(doc.getDocumentElement().getNamespaceURI(), doc.getDocumentElement().getLocalName());
-
-        if (FeaturesNamespaces.FEATURES_0_0_0.equals(name)) {
-            LOGGER.warn("Old style feature file without namespace found (URI: {}). This format is deprecated and support for it will soon be removed", uri);
-            return;
-        } else if (FeaturesNamespaces.FEATURES_1_0_0.equals(name)) {
-            validate(doc, "/org/apache/karaf/features/karaf-features-1.0.0.xsd");
-        } else if (FeaturesNamespaces.FEATURES_1_1_0.equals(name)) {
-            validate(doc, "/org/apache/karaf/features/karaf-features-1.1.0.xsd");
-        } else if (FeaturesNamespaces.FEATURES_1_2_0.equals(name)) {
-            validate(doc, "/org/apache/karaf/features/karaf-features-1.2.0.xsd");
-        } else if (FeaturesNamespaces.FEATURES_1_3_0.equals(name)) {
-            validate(doc, "/org/apache/karaf/features/karaf-features-1.3.0.xsd");
-        }
-        else {
-            throw new IllegalArgumentException("Unrecognized root element: " + name);
-        }
-    }
-
-    private static Document load(URI uri) throws IOException, SAXException, ParserConfigurationException {
-        InputStream stream = null;
-        try {
-            URLConnection conn;
-            try {
-                conn = uri.toURL().openConnection();
-            } catch (IllegalArgumentException e) {
-                throw new IllegalArgumentException("invalid URI: " + uri, e);
-            }
-            conn.setDefaultUseCaches(false);
-            stream = conn.getInputStream();
-            // load document and check the root element for namespace declaration
-            DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
-            dFactory.setNamespaceAware(true);
-            return dFactory.newDocumentBuilder().parse(stream);
-        } finally {
-            if (stream != null) {
-                stream.close();
-            }
-        }
-    }
-
-    private static void validate(Document doc, String schemaLocation) throws SAXException {
-        SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
-        // root element has namespace - we can use schema validation
-        Schema schema = factory.newSchema(new StreamSource(FeatureValidationUtil.class.getResourceAsStream(schemaLocation)));
-        // create schema by reading it from an XSD file:
-        Validator validator = schema.newValidator();
-        try {
-            validator.validate(new DOMSource(doc));
-        } catch (Exception e) {
-            throw new IllegalArgumentException("Unable to validate " + doc.getDocumentURI(), e);
-        }
+        JaxbUtil.unmarshal(uri.toASCIIString(), true);
     }
 
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/1306af5f/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java b/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
index 0bd1e67..65223d5 100644
--- a/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
+++ b/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
@@ -281,10 +281,8 @@ public class FeaturesServiceImpl implements FeaturesService {
     //
 
     public Repository loadRepository(URI uri) throws Exception {
-        // TODO: merge validation and loading by loading the DOM, validating, unmarshalling
-        FeatureValidationUtil.validate(uri);
         RepositoryImpl repo = new RepositoryImpl(uri);
-        repo.load();
+        repo.load(true);
         return repo;
     }
 

http://git-wip-us.apache.org/repos/asf/karaf/blob/1306af5f/features/src/main/java/org/apache/karaf/features/internal/service/RepositoryImpl.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/service/RepositoryImpl.java b/features/src/main/java/org/apache/karaf/features/internal/service/RepositoryImpl.java
index 4bf1502..56e5102 100644
--- a/features/src/main/java/org/apache/karaf/features/internal/service/RepositoryImpl.java
+++ b/features/src/main/java/org/apache/karaf/features/internal/service/RepositoryImpl.java
@@ -42,13 +42,8 @@ public class RepositoryImpl implements Repository {
         return uri;
     }
 
-    public String getName() {
-        // TODO: catching this exception is ugly
-        try {
-            load();
-        } catch (IOException e) {
-            throw new RuntimeException("Unable to load repository", e);
-        }
+    public String getName() throws IOException {
+        load();
         return features.getName();
     }
 
@@ -70,6 +65,10 @@ public class RepositoryImpl implements Repository {
 
 
     public void load() throws IOException {
+        load(false);
+    }
+
+    public void load(boolean validate) throws IOException {
         if (features == null) {
             try {
                 InputStream inputStream = uri.toURL().openStream();
@@ -83,7 +82,7 @@ public class RepositoryImpl implements Repository {
     				}
     			};
                 try {
-                    features = JaxbUtil.unmarshal(inputStream, false);
+                    features = JaxbUtil.unmarshal(uri.toASCIIString(), inputStream, validate);
                 } finally {
                     inputStream.close();
                 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/1306af5f/features/src/test/java/org/apache/karaf/features/internal/service/FeaturesValidationTest.java
----------------------------------------------------------------------
diff --git a/features/src/test/java/org/apache/karaf/features/internal/service/FeaturesValidationTest.java b/features/src/test/java/org/apache/karaf/features/internal/service/FeaturesValidationTest.java
index f3ca2e6..9e33ee3 100644
--- a/features/src/test/java/org/apache/karaf/features/internal/service/FeaturesValidationTest.java
+++ b/features/src/test/java/org/apache/karaf/features/internal/service/FeaturesValidationTest.java
@@ -16,20 +16,29 @@
  */
 package org.apache.karaf.features.internal.service;
 
+import java.io.InputStream;
+import java.net.URL;
+
+import org.apache.karaf.features.Repository;
+import org.apache.karaf.features.internal.model.Features;
+import org.apache.karaf.features.internal.model.JaxbUtil;
 import org.junit.Test;
 
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
 
 public class FeaturesValidationTest {
 
     @Test
-    public void testNoNs() throws Exception {
-        FeatureValidationUtil.validate(getClass().getResource("f01.xml").toURI());
+    public void testNs10() throws Exception {
+        FeatureValidationUtil.validate(getClass().getResource("f02.xml").toURI());
     }
 
     @Test
-    public void testNs10() throws Exception {
-        FeatureValidationUtil.validate(getClass().getResource("f02.xml").toURI());
+    public void testNs10Unmarshall() throws Exception {
+        URL url = getClass().getResource("f02.xml");
+        Features features = JaxbUtil.unmarshal(url.toExternalForm(), true);
+        assertNotNull(features);
     }
 
     @Test
@@ -38,13 +47,22 @@ public class FeaturesValidationTest {
     }
 
     @Test
+    public void testNs10NoNameUnmarshall() throws Exception {
+        URL url = getClass().getResource("f03.xml");
+        Features features = JaxbUtil.unmarshal(url.toExternalForm(), true);
+        assertNotNull(features);
+    }
+
+    @Test
     public void testNs11() throws Exception {
         FeatureValidationUtil.validate(getClass().getResource("f04.xml").toURI());
     }
 
     @Test
-    public void testNs12() throws Exception {
-        FeatureValidationUtil.validate(getClass().getResource("f06.xml").toURI());
+    public void testNs11Unmarshall() throws Exception {
+        URL url = getClass().getResource("f04.xml");
+        Features features = JaxbUtil.unmarshal(url.toExternalForm(), true);
+        assertNotNull(features);
     }
 
     @Test
@@ -58,8 +76,27 @@ public class FeaturesValidationTest {
     }
 
     @Test
+    public void testNs12() throws Exception {
+        FeatureValidationUtil.validate(getClass().getResource("f06.xml").toURI());
+    }
+
+    @Test
+    public void testNs12Unmarshall() throws Exception {
+        URL url = getClass().getResource("f06.xml");
+        Features features = JaxbUtil.unmarshal(url.toExternalForm(), true);
+        assertNotNull(features);
+    }
+
+    @Test
     public void testNs13() throws Exception {
         FeatureValidationUtil.validate(getClass().getResource("f07.xml").toURI());
     }
 
+    @Test
+    public void testNs13Unmarshall() throws Exception {
+        URL url = getClass().getResource("f07.xml");
+        Features features = JaxbUtil.unmarshal(url.toExternalForm(), true);
+        assertNotNull(features);
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/1306af5f/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/CreateKarMojo.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/CreateKarMojo.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/CreateKarMojo.java
index c30f7c0..71ff485 100644
--- a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/CreateKarMojo.java
+++ b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/CreateKarMojo.java
@@ -212,23 +212,18 @@ public class CreateKarMojo extends MojoSupport {
     private List<Artifact> readResources(File featuresFile) throws MojoExecutionException {
         List<Artifact> resources = new ArrayList<Artifact>();
         try {
-            InputStream in = new FileInputStream(featuresFile);
-            try {
-                Features features = JaxbUtil.unmarshal(in, false);
-                for (Feature feature : features.getFeature()) {
-                    for (BundleInfo bundle : feature.getBundles()) {
-                        if (ignoreDependencyFlag || (!ignoreDependencyFlag && !bundle.isDependency())) {
-                            resources.add(resourceToArtifact(bundle.getLocation(), false));
-                        }
-                    }
-                    for (ConfigFileInfo configFile : feature.getConfigurationFiles()) {
-                        resources.add(resourceToArtifact(configFile.getLocation(), false));
+            Features features = JaxbUtil.unmarshal(featuresFile.toURI().toASCIIString(), false);
+            for (Feature feature : features.getFeature()) {
+                for (BundleInfo bundle : feature.getBundles()) {
+                    if (ignoreDependencyFlag || (!ignoreDependencyFlag && !bundle.isDependency())) {
+                        resources.add(resourceToArtifact(bundle.getLocation(), false));
                     }
                 }
-                return resources;
-            } finally {
-                in.close();
+                for (ConfigFileInfo configFile : feature.getConfigurationFiles()) {
+                    resources.add(resourceToArtifact(configFile.getLocation(), false));
+                }
             }
+            return resources;
         } catch (MojoExecutionException e) {
             throw e;
         } catch (Exception e) {

http://git-wip-us.apache.org/repos/asf/karaf/blob/1306af5f/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/GenerateDescriptorMojo.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/GenerateDescriptorMojo.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/GenerateDescriptorMojo.java
index 1aff2c6..3cdae4a 100644
--- a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/GenerateDescriptorMojo.java
+++ b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/GenerateDescriptorMojo.java
@@ -401,14 +401,7 @@ public class GenerateDescriptorMojo extends AbstractLogEnabled implements Mojo {
     }
 
     private Features readFeaturesFile(File featuresFile) throws XMLStreamException, JAXBException, IOException {
-        Features features;
-        InputStream in = new FileInputStream(featuresFile);
-        try {
-            features = JaxbUtil.unmarshal(in, false);
-        } finally {
-            in.close();
-        }
-        return features;
+        return JaxbUtil.unmarshal(featuresFile.toURI().toASCIIString(), false);
     }
 
     public void setLog(Log log) {

http://git-wip-us.apache.org/repos/asf/karaf/blob/1306af5f/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/InstallKarsMojo.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/InstallKarsMojo.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/InstallKarsMojo.java
index c1a6c5f..f58ca37 100644
--- a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/InstallKarsMojo.java
+++ b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/InstallKarsMojo.java
@@ -425,14 +425,7 @@ public class InstallKarsMojo extends MojoSupport {
             } else {
                 repoFile = new File(uri);
             }
-            InputStream in = new FileInputStream(repoFile);
-            Features features;
-            try {
-                features = JaxbUtil.unmarshal(in, false);
-            } finally {
-                in.close();
-            }
-            return features;
+            return JaxbUtil.unmarshal(repoFile.toURI().toASCIIString(), false);
         }
 
         public void installFeature(org.apache.karaf.features.Feature feature) throws Exception {

http://git-wip-us.apache.org/repos/asf/karaf/blob/1306af5f/tooling/karaf-maven-plugin/src/test/java/org/apache/karaf/tooling/features/GenerateDescriptorMojoTest.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/test/java/org/apache/karaf/tooling/features/GenerateDescriptorMojoTest.java b/tooling/karaf-maven-plugin/src/test/java/org/apache/karaf/tooling/features/GenerateDescriptorMojoTest.java
index 4b12fda..0eecbd0 100644
--- a/tooling/karaf-maven-plugin/src/test/java/org/apache/karaf/tooling/features/GenerateDescriptorMojoTest.java
+++ b/tooling/karaf-maven-plugin/src/test/java/org/apache/karaf/tooling/features/GenerateDescriptorMojoTest.java
@@ -23,6 +23,7 @@ import static org.junit.Assert.*;
 
 import java.io.ByteArrayOutputStream;
 import java.io.InputStream;
+import java.net.URL;
 import java.util.List;
 
 import javax.xml.bind.JAXBException;
@@ -41,9 +42,9 @@ public class GenerateDescriptorMojoTest {
     @Test
     public void testReadXml100() throws JAXBException, SAXException, ParserConfigurationException, XMLStreamException {
 
-        InputStream in = getClass().getClassLoader().getResourceAsStream("input-features-1.0.0.xml");
+        URL url = getClass().getClassLoader().getResource("input-features-1.0.0.xml");
 
-        Features featuresRoot = JaxbUtil.unmarshal(in, false);
+        Features featuresRoot = JaxbUtil.unmarshal(url.toExternalForm(), false);
 
         assertEquals(featuresRoot.getRepository().size(), 1);
 
@@ -61,9 +62,9 @@ public class GenerateDescriptorMojoTest {
     @Test
     public void testReadXml1() throws Exception {
 
-        InputStream in = getClass().getClassLoader().getResourceAsStream("input-features-1.1.0.xml");
+        URL url = getClass().getClassLoader().getResource("input-features-1.1.0.xml");
 
-        Features featuresRoot = JaxbUtil.unmarshal(in, false);
+        Features featuresRoot = JaxbUtil.unmarshal(url.toExternalForm(), false);
 
         List<Feature> featuresList = featuresRoot.getFeature();
 

http://git-wip-us.apache.org/repos/asf/karaf/blob/1306af5f/util/src/main/java/org/apache/karaf/util/XmlUtils.java
----------------------------------------------------------------------
diff --git a/util/src/main/java/org/apache/karaf/util/XmlUtils.java b/util/src/main/java/org/apache/karaf/util/XmlUtils.java
index cbcb593..adfc2e6 100644
--- a/util/src/main/java/org/apache/karaf/util/XmlUtils.java
+++ b/util/src/main/java/org/apache/karaf/util/XmlUtils.java
@@ -16,17 +16,25 @@
  */
 package org.apache.karaf.util;
 
-import com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl;
-import org.w3c.dom.Document;
-import org.xml.sax.ErrorHandler;
-import org.xml.sax.SAXException;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
 
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.*;
-import java.io.File;
-import java.io.IOException;
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+
+import org.w3c.dom.Document;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
 
 /**
  * Utils class to manipulate XML document in a thread safe way.
@@ -35,6 +43,7 @@ public class XmlUtils {
 
     private static final ThreadLocal<DocumentBuilderFactory> DOCUMENT_BUILDER_FACTORY = new ThreadLocal<DocumentBuilderFactory>();
     private static final ThreadLocal<TransformerFactory> TRANSFORMER_FACTORY = new ThreadLocal<TransformerFactory>();
+    private static final ThreadLocal<SAXParserFactory> SAX_PARSER_FACTORY = new ThreadLocal<SAXParserFactory>();
 
     public static Document parse(String uri) throws TransformerException, IOException, SAXException, ParserConfigurationException {
         DocumentBuilder db = documentBuilder();
@@ -45,6 +54,15 @@ public class XmlUtils {
         }
     }
 
+    public static Document parse(InputStream stream) throws TransformerException, IOException, SAXException, ParserConfigurationException {
+        DocumentBuilder db = documentBuilder();
+        try {
+            return db.parse(stream);
+        } finally {
+            db.reset();
+        }
+    }
+
     public static Document parse(File f) throws TransformerException, IOException, SAXException, ParserConfigurationException {
         DocumentBuilder db = documentBuilder();
         try {
@@ -82,36 +100,40 @@ public class XmlUtils {
         }
     }
 
-    private static DocumentBuilder documentBuilder() throws ParserConfigurationException {
-        DocumentBuilderFactory dbf;
-        if (DOCUMENT_BUILDER_FACTORY.get() == null) {
+    public static XMLReader xmlReader() throws ParserConfigurationException, SAXException {
+        SAXParserFactory spf = SAX_PARSER_FACTORY.get();
+        if (spf == null) {
+            spf = SAXParserFactory.newInstance();
+            spf.setNamespaceAware(true);
+            SAX_PARSER_FACTORY.set(spf);
+        }
+        return spf.newSAXParser().getXMLReader();
+    }
+
+    public static DocumentBuilder documentBuilder() throws ParserConfigurationException {
+        DocumentBuilderFactory dbf = DOCUMENT_BUILDER_FACTORY.get();
+        if (dbf == null) {
             dbf = DocumentBuilderFactory.newInstance();
             dbf.setNamespaceAware(true);
             DOCUMENT_BUILDER_FACTORY.set(dbf);
-        } else {
-            dbf = DOCUMENT_BUILDER_FACTORY.get();
         }
         return dbf.newDocumentBuilder();
     }
 
-    private static Transformer transformer() throws TransformerConfigurationException {
-        TransformerFactory tf;
-        if (TRANSFORMER_FACTORY.get() == null) {
+    public static Transformer transformer() throws TransformerConfigurationException {
+        TransformerFactory tf = TRANSFORMER_FACTORY.get();
+        if (tf == null) {
             tf = TransformerFactory.newInstance();
             TRANSFORMER_FACTORY.set(tf);
-        } else {
-            tf = TRANSFORMER_FACTORY.get();
         }
         return tf.newTransformer();
     }
 
     private static Transformer transformer(Source xsltSource) throws TransformerConfigurationException {
-        TransformerFactory tf;
-        if (TRANSFORMER_FACTORY.get() == null) {
+        TransformerFactory tf = TRANSFORMER_FACTORY.get();
+        if (tf == null) {
             tf = TransformerFactory.newInstance();
             TRANSFORMER_FACTORY.set(tf);
-        } else {
-            tf = TRANSFORMER_FACTORY.get();
         }
         return tf.newTransformer(xsltSource);
     }


[15/33] git commit: [KARAF-2901] Add an option to show bundle version in bundle:tree-show

Posted by gn...@apache.org.
[KARAF-2901] Add an option to show bundle version in bundle:tree-show


Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/6727c1b7
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/6727c1b7
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/6727c1b7

Branch: refs/heads/master
Commit: 6727c1b74a83006c9c2aac98ecfb6daf5d4be928
Parents: edd82fd
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Fri Apr 11 19:17:49 2014 +0200
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Fri Apr 11 19:20:04 2014 +0200

----------------------------------------------------------------------
 .../karaf/bundle/command/ShowBundleTree.java      | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/6727c1b7/bundle/core/src/main/java/org/apache/karaf/bundle/command/ShowBundleTree.java
----------------------------------------------------------------------
diff --git a/bundle/core/src/main/java/org/apache/karaf/bundle/command/ShowBundleTree.java b/bundle/core/src/main/java/org/apache/karaf/bundle/command/ShowBundleTree.java
index a83ce39..f6f3d48 100644
--- a/bundle/core/src/main/java/org/apache/karaf/bundle/command/ShowBundleTree.java
+++ b/bundle/core/src/main/java/org/apache/karaf/bundle/command/ShowBundleTree.java
@@ -30,6 +30,7 @@ import org.apache.felix.utils.version.VersionTable;
 import org.apache.karaf.bundle.command.bundletree.Node;
 import org.apache.karaf.bundle.command.bundletree.Tree;
 import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
 import org.apache.karaf.shell.api.action.lifecycle.Service;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.Constants;
@@ -52,6 +53,10 @@ import static java.lang.String.format;
 public class ShowBundleTree extends BundleCommand {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(ShowBundleTree.class);
+
+    @Option(name = "-v", aliases = { "--version" }, description = "Show bundle versions")
+    private boolean versions;
+
     private Tree<Bundle> tree;
 
     public ShowBundleTree() {
@@ -104,9 +109,16 @@ public class ShowBundleTree extends BundleCommand {
         tree.write(System.out, new Tree.Converter<Bundle>() {
 
             public String toString(Node<Bundle> node) {
-                return String.format("%s [%s]",
-                                     node.getValue().getSymbolicName(),
-                                     node.getValue().getBundleId());
+                if (versions) {
+                    return String.format("%s / [%s] [%s]",
+                            node.getValue().getSymbolicName(),
+                            node.getValue().getVersion().toString(),
+                            node.getValue().getBundleId());
+                } else {
+                    return String.format("%s [%s]",
+                            node.getValue().getSymbolicName(),
+                            node.getValue().getBundleId());
+                }
             }
         });
     }


[06/33] [KARAF-2852] Merge jms/core and jms/command

Posted by gn...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/src/main/java/org/apache/karaf/jms/internal/JmsMBeanImpl.java
----------------------------------------------------------------------
diff --git a/jms/src/main/java/org/apache/karaf/jms/internal/JmsMBeanImpl.java b/jms/src/main/java/org/apache/karaf/jms/internal/JmsMBeanImpl.java
new file mode 100644
index 0000000..cc46434
--- /dev/null
+++ b/jms/src/main/java/org/apache/karaf/jms/internal/JmsMBeanImpl.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.karaf.jms.internal;
+
+import org.apache.karaf.jms.JmsMBean;
+import org.apache.karaf.jms.JmsMessage;
+import org.apache.karaf.jms.JmsService;
+
+import javax.management.MBeanException;
+import javax.management.openmbean.*;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Default implementation of the JMS MBean.
+ */
+public class JmsMBeanImpl implements JmsMBean {
+
+    private JmsService jmsService;
+
+    @Override
+    public List<String> getConnectionfactories() throws MBeanException {
+        try {
+            return jmsService.connectionFactories();
+        } catch (Throwable t) {
+            throw new MBeanException(null, t.getMessage());
+        }
+    }
+
+    @Override
+    public void create(String name, String type, String url) throws MBeanException {
+        try {
+            jmsService.create(name, type, url);
+        } catch (Throwable t) {
+            throw new MBeanException(null, t.getMessage());
+        }
+    }
+
+    @Override
+    public void delete(String name) throws MBeanException {
+        try {
+            jmsService.delete(name);
+        } catch (Throwable t) {
+            throw new MBeanException(null, t.getMessage());
+        }
+    }
+
+    @Override
+    public Map<String, String> info(String connectionFactory, String username, String password) throws MBeanException {
+        try {
+            return jmsService.info(connectionFactory, username, password);
+        } catch (Throwable t) {
+            throw new MBeanException(null, t.getMessage());
+        }
+    }
+
+    @Override
+    public int count(String connectionFactory, String queue, String username, String password) throws MBeanException {
+        try {
+            return jmsService.count(connectionFactory, queue, username, password);
+        } catch (Throwable t) {
+            throw new MBeanException(null, t.getMessage());
+        }
+    }
+
+    @Override
+    public List<String> queues(String connectionFactory, String username, String password) throws MBeanException {
+        try {
+            return jmsService.queues(connectionFactory, username, password);
+        } catch (Throwable t) {
+            throw new MBeanException(null, t.getMessage());
+        }
+    }
+
+    @Override
+    public List<String> topics(String connectionFactory, String username, String password) throws MBeanException {
+        try {
+            return jmsService.topics(connectionFactory, username, password);
+        } catch (Throwable t) {
+            throw new MBeanException(null, t.getMessage());
+        }
+    }
+
+    @Override
+    public void send(String connectionFactory, String queue, String content, String replyTo, String username, String password) throws MBeanException {
+        try {
+            jmsService.send(connectionFactory, queue, content, replyTo, username, password);
+        } catch (Throwable t) {
+            throw new MBeanException(null, t.getMessage());
+        }
+    }
+
+    @Override
+    public int consume(String connectionFactory, String queue, String selector, String username, String password) throws MBeanException {
+        try {
+            return jmsService.consume(connectionFactory, queue, selector, username, password);
+        } catch (Throwable t) {
+            throw new MBeanException(null, t.getMessage());
+        }
+    }
+
+    @Override
+    public int move(String connectionFactory, String source, String destination, String selector, String username, String password) throws MBeanException {
+        try {
+            return jmsService.move(connectionFactory, source, destination, selector, username, password);
+        } catch (Throwable t) {
+            throw new MBeanException(null, t.getMessage());
+        }
+    }
+
+    @Override
+    public TabularData browse(String connectionFactory, String queue, String selector, String username, String password) throws MBeanException {
+        try {
+            CompositeType type = new CompositeType("message", "JMS Message",
+                    new String[]{ "id", "content", "charset", "type", "correlation", "delivery", "destination", "expiration", "priority", "redelivered", "replyto", "timestamp" },
+                    new String[]{ "Message ID", "Content", "Charset", "Type", "Correlation ID", "Delivery Mode", "Destination", "Expiration Date", "Priority", "Redelivered", "Reply-To", "Timestamp" },
+                    new OpenType[]{ SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, SimpleType.INTEGER, SimpleType.BOOLEAN, SimpleType.STRING, SimpleType.STRING });
+            TabularType tableType = new TabularType("messages", "JMS Messages", type, new String[]{ "id" });
+            TabularData table = new TabularDataSupport(tableType);
+            for (JmsMessage message : getJmsService().browse(connectionFactory, queue, selector, username, password)) {
+                CompositeData data = new CompositeDataSupport(type,
+                        new String[]{ "id", "content", "charset", "type", "correlation", "delivery", "destination", "expiration", "priority", "redelivered", "replyto", "timestamp" },
+                        new Object[]{ message.getMessageId(), message.getContent(), message.getCharset(), message.getType(), message.getCorrelationID(), message.getDeliveryMode(), message.getDestination(), message.getExpiration(), message.getPriority(), message.isRedelivered(), message.getReplyTo(), message.getTimestamp() }
+                        );
+                table.put(data);
+            }
+            return table;
+        } catch (Throwable t) {
+            throw new MBeanException(null, t.getMessage());
+        }
+    }
+
+    public JmsService getJmsService() {
+        return jmsService;
+    }
+
+    public void setJmsService(JmsService jmsService) {
+        this.jmsService = jmsService;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/src/main/java/org/apache/karaf/jms/internal/JmsServiceImpl.java
----------------------------------------------------------------------
diff --git a/jms/src/main/java/org/apache/karaf/jms/internal/JmsServiceImpl.java b/jms/src/main/java/org/apache/karaf/jms/internal/JmsServiceImpl.java
new file mode 100644
index 0000000..fe4b43d
--- /dev/null
+++ b/jms/src/main/java/org/apache/karaf/jms/internal/JmsServiceImpl.java
@@ -0,0 +1,300 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.jms.internal;
+
+import org.apache.activemq.ActiveMQConnection;
+import org.apache.activemq.advisory.DestinationSource;
+import org.apache.activemq.command.ActiveMQQueue;
+import org.apache.activemq.command.ActiveMQTopic;
+import org.apache.activemq.pool.PooledConnection;
+import org.apache.karaf.jms.JmsMessage;
+import org.apache.karaf.jms.JmsService;
+import org.apache.karaf.util.TemplateUtils;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+import javax.jms.*;
+
+import java.io.*;
+import java.lang.IllegalStateException;
+import java.util.*;
+
+/**
+ * Default implementation of the JMS Service.
+ */
+public class JmsServiceImpl implements JmsService {
+
+    private BundleContext bundleContext;
+    private File deployFolder;
+    
+    public JmsServiceImpl() {
+        File karafBase = new File(System.getProperty("karaf.base"));
+        deployFolder = new File(karafBase, "deploy");
+    }
+
+    @Override
+    public void create(String name, String type, String url) throws Exception {
+        if (!type.equalsIgnoreCase("activemq") && !type.equalsIgnoreCase("webspheremq")) {
+            throw new IllegalArgumentException("JMS connection factory type not known");
+        }
+
+        File outFile = getConnectionFactoryFile(name);
+        String template;
+        HashMap<String, String> properties = new HashMap<String, String>();
+        properties.put("name", name);
+
+        if (type.equalsIgnoreCase("activemq")) {
+            // activemq
+            properties.put("url", url);
+            template = "connectionfactory-activemq.xml";
+        } else {
+            // webspheremq
+            String[] splitted = url.split("/");
+            if (splitted.length != 4) {
+                throw new IllegalStateException("WebsphereMQ URI should be in the following format: host/port/queuemanager/channel");
+            }
+            
+            properties.put("host", splitted[0]);
+            properties.put("port", splitted[1]);
+            properties.put("queuemanager", splitted[2]);
+            properties.put("channel", splitted[3]);
+            template = "connectionfactory-webspheremq.xml";
+        }
+        InputStream is = this.getClass().getResourceAsStream(template);
+        if (is == null) {
+            throw new IllegalArgumentException("Template resource " + template + " doesn't exist");
+        }
+        TemplateUtils.createFromTemplate(outFile, is, properties);
+    }
+
+    private File getConnectionFactoryFile(String name) {
+        return new File(deployFolder, "connectionfactory-" + name + ".xml");
+    }
+
+    @Override
+    public void delete(String name) throws Exception {
+        File connectionFactoryFile = getConnectionFactoryFile(name);
+        if (!connectionFactoryFile.exists()) {
+            throw new IllegalStateException("The JMS connection factory file " + connectionFactoryFile.getPath() + " doesn't exist");
+        }
+        connectionFactoryFile.delete();
+    }
+
+    @SuppressWarnings("rawtypes")
+    @Override
+    public List<String> connectionFactories() throws Exception {
+        List<String> connectionFactories = new ArrayList<String>();
+        ServiceReference[] references = bundleContext.getServiceReferences(ConnectionFactory.class.getName(), null);
+        if (references != null) {
+            for (ServiceReference reference : references) {
+                if (reference.getProperty("osgi.jndi.service.name") != null) {
+                    connectionFactories.add((String) reference.getProperty("osgi.jndi.service.name"));
+                } else if (reference.getProperty("name") != null) {
+                    connectionFactories.add((String) reference.getProperty("name"));
+                } else {
+                    connectionFactories.add(reference.getProperty(Constants.SERVICE_ID).toString());
+                }
+            }
+        }
+        return connectionFactories;
+    }
+
+    @Override
+    public List<String> connectionFactoryFileNames() throws Exception {
+        String[] connectionFactoryFileNames = deployFolder.list(new FilenameFilter() {
+
+            @Override
+            public boolean accept(File dir, String name) {
+                return name.startsWith("connectionfactory-") && name.endsWith(".xml");
+            }
+        });
+
+        return Arrays.asList(connectionFactoryFileNames);
+    }
+
+    @Override
+    public Map<String, String> info(String connectionFactory, String username, String password) throws IOException, JMSException {
+        JmsConnector connector = new JmsConnector(bundleContext, connectionFactory, username, password);
+        try {
+            ConnectionMetaData metaData = connector.connect().getMetaData();
+            Map<String, String> map = new HashMap<String, String>();
+            map.put("product", metaData.getJMSProviderName());
+            map.put("version", metaData.getProviderVersion());
+            return map;
+        } finally {
+            connector.close();
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public int count(String connectionFactory, final String destination, String username, String password) throws IOException, JMSException {
+        JmsConnector connector = new JmsConnector(bundleContext, connectionFactory, username, password);
+        try  {
+            Session session = connector.createSession();
+            QueueBrowser browser = session.createBrowser(session.createQueue(destination));
+            Enumeration<Message> enumeration = browser.getEnumeration();
+            int count = 0;
+            while (enumeration.hasMoreElements()) {
+                enumeration.nextElement();
+                count++;
+            }
+            browser.close();
+            return count;
+        } finally {
+            connector.close();
+        }
+    }
+
+    private DestinationSource getDestinationSource(Connection connection) throws JMSException {
+        if (connection instanceof PooledConnection) {
+            connection = ((PooledConnection) connection).getConnection();
+        }
+        if (connection instanceof ActiveMQConnection) {
+            return ((ActiveMQConnection) connection).getDestinationSource();
+        } else {
+            return null;
+        }
+    }
+    
+    @Override
+    public List<String> queues(String connectionFactory, String username, String password) throws JMSException, IOException {
+        JmsConnector connector = new JmsConnector(bundleContext, connectionFactory, username, password);
+        try {
+            List<String> queues = new ArrayList<String>();
+            DestinationSource destinationSource = getDestinationSource(connector.connect());
+            if (destinationSource != null) {
+                Set<ActiveMQQueue> activeMQQueues = destinationSource.getQueues();
+                for (ActiveMQQueue activeMQQueue : activeMQQueues) {
+                    queues.add(activeMQQueue.getQueueName());
+                }
+            }
+            return queues;
+        } finally {
+            connector.close();
+        }
+    }
+
+    @Override
+    public List<String> topics(String connectionFactory, String username, String password) throws IOException, JMSException {
+        JmsConnector connector = new JmsConnector(bundleContext, connectionFactory, username, password);
+        try {
+            DestinationSource destinationSource = getDestinationSource(connector.connect());
+            List<String> topics = new ArrayList<String>();
+            if (destinationSource != null) {
+                Set<ActiveMQTopic> activeMQTopics = destinationSource.getTopics();
+                for (ActiveMQTopic activeMQTopic : activeMQTopics) {
+                    topics.add(activeMQTopic.getTopicName());
+                }
+            }
+            return topics;
+        } finally {
+            connector.close();
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public List<JmsMessage> browse(String connectionFactory, final String queue, final String filter,
+                                   String username, String password) throws JMSException, IOException {
+        JmsConnector connector = new JmsConnector(bundleContext, connectionFactory, username, password);
+        try {
+            List<JmsMessage> messages = new ArrayList<JmsMessage>();
+            Session session = connector.createSession();
+            QueueBrowser browser = session.createBrowser(session.createQueue(queue), filter);
+            Enumeration<Message> enumeration = browser.getEnumeration();
+            while (enumeration.hasMoreElements()) {
+                Message message = enumeration.nextElement();
+
+                messages.add(new JmsMessage(message));
+            }
+            browser.close();
+            return messages;
+        } finally {
+            connector.close();
+        }
+    }
+
+    @Override
+    public void send(String connectionFactory, final String queue, final String body, final String replyTo,
+                     String username, String password) throws IOException, JMSException {
+        JmsConnector connector = new JmsConnector(bundleContext, connectionFactory, username, password);
+        try {
+            Session session = connector.createSession();
+            Message message = session.createTextMessage(body);
+            if (replyTo != null) {
+                message.setJMSReplyTo(session.createQueue(replyTo));
+            }
+            MessageProducer producer = session.createProducer(session.createQueue(queue));
+            producer.send(message);
+            producer.close();
+        } finally {
+            connector.close();
+        }
+    }
+
+    @Override
+    public int consume(String connectionFactory, final String queue, final String selector, String username,
+                       String password) throws Exception {
+        JmsConnector connector = new JmsConnector(bundleContext, connectionFactory, username, password);
+        try {
+            int count = 0;
+            Session session = connector.createSession();
+            MessageConsumer consumer = session.createConsumer(session.createQueue(queue), selector);
+            Message message;
+            do {
+                message = consumer.receive(5000L);
+                if (message != null) {
+                    count++;
+                }
+            } while (message != null);
+            return count;
+        } finally {
+            connector.close();
+        }
+    }
+
+    @Override
+    public int move(String connectionFactory, final String sourceQueue, final String targetQueue,
+                    final String selector, String username, String password) throws IOException, JMSException {
+        JmsConnector connector = new JmsConnector(bundleContext, connectionFactory, username, password);
+        try {
+            int count = 0;
+            Session session = connector.createSession();
+            MessageConsumer consumer = session.createConsumer(session.createQueue(sourceQueue), selector);
+            Message message;
+            do {
+                message = consumer.receive(5000L);
+                if (message != null) {
+                    MessageProducer producer = session.createProducer(session.createQueue(targetQueue));
+                    producer.send(message);
+                    count++;
+                }
+            } while (message != null);
+            consumer.close();
+            return count;
+        } finally {
+            connector.close();
+        }
+    }
+
+    public void setBundleContext(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/src/main/resources/OSGI-INF/blueprint/jms-core.xml
----------------------------------------------------------------------
diff --git a/jms/src/main/resources/OSGI-INF/blueprint/jms-core.xml b/jms/src/main/resources/OSGI-INF/blueprint/jms-core.xml
new file mode 100644
index 0000000..7dd8070
--- /dev/null
+++ b/jms/src/main/resources/OSGI-INF/blueprint/jms-core.xml
@@ -0,0 +1,41 @@
+<?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.
+    -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+           xmlns:ext="http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.0.0"
+           default-activation="lazy">
+
+    <ext:property-placeholder placeholder-prefix="$[" placeholder-suffix="]"/>
+
+    <bean id="jmsService" class="org.apache.karaf.jms.internal.JmsServiceImpl">
+        <property name="bundleContext" ref="blueprintBundleContext"/>
+    </bean>
+
+    <service ref="jmsService" interface="org.apache.karaf.jms.JmsService" />
+
+    <!-- Management -->
+    <bean id="jmsMBeanImpl" class="org.apache.karaf.jms.internal.JmsMBeanImpl">
+        <property name="jmsService" ref="jmsService"/>
+    </bean>
+
+    <service ref="jmsMBeanImpl" auto-export="interfaces">
+        <service-properties>
+            <entry key="jmx.objectname" value="org.apache.karaf:type=jms,name=$[karaf.name]"/>
+        </service-properties>
+    </service>
+
+</blueprint>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/src/main/resources/OSGI-INF/bundle.info
----------------------------------------------------------------------
diff --git a/jms/src/main/resources/OSGI-INF/bundle.info b/jms/src/main/resources/OSGI-INF/bundle.info
new file mode 100644
index 0000000..1aeb646
--- /dev/null
+++ b/jms/src/main/resources/OSGI-INF/bundle.info
@@ -0,0 +1,18 @@
+h1. Synopsis
+
+${project.name}
+
+${project.description}
+
+Maven URL:
+[mvn:${project.groupId}/${project.artifactId}/${project.version}]
+
+h1. Description
+
+This bundle is the core implementation of the JMS service support.
+
+The JMS service allows you to create connection factories, and send/browse/consume messages.
+
+h1. See also
+
+JMS - section of the Karaf User Guide

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/src/main/resources/org/apache/karaf/jms/internal/connectionfactory-activemq.xml
----------------------------------------------------------------------
diff --git a/jms/src/main/resources/org/apache/karaf/jms/internal/connectionfactory-activemq.xml b/jms/src/main/resources/org/apache/karaf/jms/internal/connectionfactory-activemq.xml
new file mode 100644
index 0000000..f0aabbd
--- /dev/null
+++ b/jms/src/main/resources/org/apache/karaf/jms/internal/connectionfactory-activemq.xml
@@ -0,0 +1,44 @@
+<?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.
+    -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+
+    <bean id="activemqConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
+        <property name="brokerURL" value="${url}" />
+    </bean>
+
+    <bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory">
+        <property name="maxConnections" value="8" />
+        <property name="connectionFactory" ref="activemqConnectionFactory" />
+    </bean>
+
+    <bean id="resourceManager" class="org.apache.activemq.pool.ActiveMQResourceManager" init-method="recoverResource">
+        <property name="transactionManager" ref="transactionManager" />
+        <property name="connectionFactory" ref="activemqConnectionFactory" />
+        <property name="resourceName" value="activemq.localhost" />
+    </bean>
+
+    <reference id="transactionManager" interface="javax.transaction.TransactionManager" />
+
+    <service ref="pooledConnectionFactory" interface="javax.jms.ConnectionFactory">
+        <service-properties>
+            <entry key="name" value="${name}" />
+            <entry key="osgi.jndi.service.name" value="jms/${name}" />
+        </service-properties>
+    </service>
+
+</blueprint>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/src/main/resources/org/apache/karaf/jms/internal/connectionfactory-webspheremq.xml
----------------------------------------------------------------------
diff --git a/jms/src/main/resources/org/apache/karaf/jms/internal/connectionfactory-webspheremq.xml b/jms/src/main/resources/org/apache/karaf/jms/internal/connectionfactory-webspheremq.xml
new file mode 100644
index 0000000..3123f49
--- /dev/null
+++ b/jms/src/main/resources/org/apache/karaf/jms/internal/connectionfactory-webspheremq.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.
+    -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+
+    <bean id="wmqConnectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory">
+        <property name="transportType" value="1" />
+        <property name="hostName" value="${hostname}" />
+        <property name="port" value="${port}" />
+        <property name="queueManager" value="${queuemanager}" />
+        <property name="channel" value="${channel}" />
+        <property name="useConnectionPooling" value="true" />
+    </bean>
+
+    <service ref="wmqConnectionFactory" interface="javax.jms.ConnectionFactory">
+        <service-properties>
+            <entry key="name" value="${name}"/>
+            <entry key="osgi.jndi.service.name" value="jms/${name}"/>
+        </service-properties>
+    </service>
+
+</blueprint>
\ No newline at end of file


[11/33] git commit: [KARAF-2900] Allow generic requirements as condition to features

Posted by gn...@apache.org.
[KARAF-2900] Allow generic requirements as condition to features


Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/f2669e1d
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/f2669e1d
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/f2669e1d

Branch: refs/heads/master
Commit: f2669e1d709da292b679307f523a771769129e8b
Parents: fc37f55
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Fri Apr 11 17:04:09 2014 +0200
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Fri Apr 11 19:20:03 2014 +0200

----------------------------------------------------------------------
 .../standard/src/main/feature/feature.xml       |  5 +++-
 .../org/apache/karaf/features/Conditional.java  |  2 +-
 .../features/command/InfoFeatureCommand.java    | 10 +++----
 .../internal/deployment/DeploymentBuilder.java  | 30 ++++++++++++++++----
 .../features/internal/model/Conditional.java    | 14 ++++-----
 .../internal/resolver/FeatureResource.java      | 16 +++++++++--
 .../internal/service/FeaturesServiceImpl.java   |  2 +-
 .../apache/karaf/features/ConditionalTest.java  | 13 +++++++--
 .../karaf/features/internal/service/f06.xml     |  4 +++
 9 files changed, 69 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/f2669e1d/assemblies/features/standard/src/main/feature/feature.xml
----------------------------------------------------------------------
diff --git a/assemblies/features/standard/src/main/feature/feature.xml b/assemblies/features/standard/src/main/feature/feature.xml
index 4d06455..86f8270 100644
--- a/assemblies/features/standard/src/main/feature/feature.xml
+++ b/assemblies/features/standard/src/main/feature/feature.xml
@@ -222,7 +222,10 @@
         </config>
         <feature>shell</feature>
         <feature>jaas</feature>
-        <bundle start="true" start-level="30">mvn:org.apache.mina/mina-core/${mina.version}</bundle>
+        <conditional>
+            <condition>req:osgi.ee;filter:="(&amp;(osgi.ee=JavaSE)(!(version>=1.7)))"</condition>
+            <bundle start="true" start-level="30">mvn:org.apache.mina/mina-core/${mina.version}</bundle>
+        </conditional>
         <bundle start="true" start-level="30">mvn:org.apache.sshd/sshd-core/${sshd.version}</bundle>
         <bundle start="true" start-level="30">mvn:org.apache.karaf.shell/org.apache.karaf.shell.ssh/${project.version}</bundle>
     </feature>

http://git-wip-us.apache.org/repos/asf/karaf/blob/f2669e1d/features/src/main/java/org/apache/karaf/features/Conditional.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/Conditional.java b/features/src/main/java/org/apache/karaf/features/Conditional.java
index c0e4d59..fdc9261 100644
--- a/features/src/main/java/org/apache/karaf/features/Conditional.java
+++ b/features/src/main/java/org/apache/karaf/features/Conditional.java
@@ -21,7 +21,7 @@ import java.util.Map;
 
 public interface Conditional {
 
-    List<? extends Dependency> getCondition();
+    List<String> getCondition();
 
     List<Dependency> getDependencies();
 

http://git-wip-us.apache.org/repos/asf/karaf/blob/f2669e1d/features/src/main/java/org/apache/karaf/features/command/InfoFeatureCommand.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/command/InfoFeatureCommand.java b/features/src/main/java/org/apache/karaf/features/command/InfoFeatureCommand.java
index 7084a6e..5ad855c 100644
--- a/features/src/main/java/org/apache/karaf/features/command/InfoFeatureCommand.java
+++ b/features/src/main/java/org/apache/karaf/features/command/InfoFeatureCommand.java
@@ -219,7 +219,7 @@ public class InfoFeatureCommand extends FeaturesCommandSupport {
 
                 if (conditional) {
                     for (Conditional cond : resolved.getConditional()) {
-                        List<? extends Dependency> condition = cond.getCondition();
+                        List<String> condition = cond.getCondition();
                         List<BundleInfo> conditionalBundles = cond.getBundles();
                         for (BundleInfo bundleInfo : conditionalBundles) {
                             bundleLocation.add(bundleInfo.getLocation() + "(condition:"+condition+")");
@@ -278,13 +278,11 @@ public class InfoFeatureCommand extends FeaturesCommandSupport {
 
     private String getConditionDescription(Conditional cond) {
         StringBuffer sb = new StringBuffer();
-        Iterator<? extends Dependency> di = cond.getCondition().iterator();
-        while (di.hasNext()) {
-            Dependency dep = di.next();
-            sb.append(dep.getName()).append("/").append(dep.getVersion());
-            if (di.hasNext()) {
+        for (String dep : cond.getCondition()) {
+            if (sb.length() > 0) {
                 sb.append(" ");
             }
+            sb.append(dep);
         }
         return sb.toString();
     }

http://git-wip-us.apache.org/repos/asf/karaf/blob/f2669e1d/features/src/main/java/org/apache/karaf/features/internal/deployment/DeploymentBuilder.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/deployment/DeploymentBuilder.java b/features/src/main/java/org/apache/karaf/features/internal/deployment/DeploymentBuilder.java
index 00a91c4..c3ac2b7 100644
--- a/features/src/main/java/org/apache/karaf/features/internal/deployment/DeploymentBuilder.java
+++ b/features/src/main/java/org/apache/karaf/features/internal/deployment/DeploymentBuilder.java
@@ -158,8 +158,7 @@ public class DeploymentBuilder {
         return resources;
     }
 
-    public Map<Resource, List<Wire>> resolve(List<Resource> systemBundles,
-                                        boolean resolveOptionalImports) throws ResolutionException {
+    public Map<Resource, List<Wire>> resolve(List<Resource> systemBundles) throws ResolutionException {
         // Resolve
         for (int i = 0; i < systemBundles.size(); i++) {
             resources.put("system-bundle-" + i, systemBundles.get(i));
@@ -172,11 +171,32 @@ public class DeploymentBuilder {
         ResolverImpl resolver = new ResolverImpl(new Slf4jResolverLog(LOGGER));
         ResolveContext context = new ResolveContextImpl(
                 Collections.<Resource>singleton(requirements),
-                this.optionals,
+                Collections.<Resource>emptySet(),
                 new AggregateRepository(repos),
-                resolveOptionalImports);
+                false);
+        Map<Resource, List<Wire>> best = resolver.resolve(context);
 
-        return resolver.resolve(context);
+        // TODO: we actually need to use multiple passes for conditionals
+        // TODO: but it may be optimized by passing the old wiring instead
+        // TODO: of computing everything again
+        Set<Resource> resources = new HashSet<Resource>();
+        resources.add(requirements);
+        for (Resource optional : optionals) {
+            try {
+                Set<Resource> newSet = new HashSet<Resource>(resources);
+                newSet.add(optional);
+                context = new ResolveContextImpl(
+                        newSet,
+                        Collections.<Resource>emptySet(),
+                        new AggregateRepository(repos),
+                        false);
+                best = resolver.resolve(context);
+                resources = newSet;
+            } catch (ResolutionException e) {
+                // Ignore this resource
+            }
+        }
+        return best;
     }
 
     public void requireFeature(String feature) throws IOException {

http://git-wip-us.apache.org/repos/asf/karaf/blob/f2669e1d/features/src/main/java/org/apache/karaf/features/internal/model/Conditional.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/model/Conditional.java b/features/src/main/java/org/apache/karaf/features/internal/model/Conditional.java
index 5bc0b95..ed0e8ff 100644
--- a/features/src/main/java/org/apache/karaf/features/internal/model/Conditional.java
+++ b/features/src/main/java/org/apache/karaf/features/internal/model/Conditional.java
@@ -36,11 +36,11 @@ import org.apache.karaf.features.Feature;
 public class Conditional extends Content implements org.apache.karaf.features.Conditional {
 
     @XmlElement(name = "condition")
-    protected List<Dependency> condition;
+    protected List<String> condition;
 
-    public List<Dependency> getCondition() {
+    public List<String> getCondition() {
         if (condition == null) {
-            this.condition = new ArrayList<Dependency>();
+            this.condition = new ArrayList<String>();
         }
         return condition;
     }
@@ -58,13 +58,11 @@ public class Conditional extends Content implements org.apache.karaf.features.Co
 
     private String getConditionId() {
         StringBuffer sb = new StringBuffer();
-        Iterator<Dependency> di = getCondition().iterator();
-        while (di.hasNext()) {
-            Dependency dependency = di.next();
-            sb.append(dependency.getName() + "_" + dependency.getVersion());
-            if (di.hasNext()) {
+        for (String cond : getCondition()) {
+            if (sb.length() > 0) {
                 sb.append("_");
             }
+            sb.append(cond);
         }
         return sb.toString();
     }

http://git-wip-us.apache.org/repos/asf/karaf/blob/f2669e1d/features/src/main/java/org/apache/karaf/features/internal/resolver/FeatureResource.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/resolver/FeatureResource.java b/features/src/main/java/org/apache/karaf/features/internal/resolver/FeatureResource.java
index 88f08ae..e3b0101 100644
--- a/features/src/main/java/org/apache/karaf/features/internal/resolver/FeatureResource.java
+++ b/features/src/main/java/org/apache/karaf/features/internal/resolver/FeatureResource.java
@@ -44,8 +44,20 @@ public class FeatureResource extends ResourceImpl {
     public static Resource build(Feature feature, Conditional conditional, String featureRange, Map<String, Resource> locToRes) throws BundleException {
         Feature fcond = conditional.asFeature(feature.getName(), feature.getVersion());
         FeatureResource resource = (FeatureResource) build(fcond, featureRange, locToRes);
-        for (Dependency dep : conditional.getCondition()) {
-            addDependency(resource, dep, featureRange);
+        for (String cond : conditional.getCondition()) {
+            if (cond.startsWith("req:")) {
+                cond = cond.substring("req:".length());
+                List<Requirement> reqs = ResourceBuilder.parseRequirement(resource, cond);
+                resource.addRequirements(reqs);
+            } else {
+                org.apache.karaf.features.internal.model.Dependency dep = new org.apache.karaf.features.internal.model.Dependency();
+                String[] p = cond.split("/");
+                dep.setName(p[0]);
+                if (p.length > 1) {
+                    dep.setVersion(p[1]);
+                }
+                addDependency(resource, dep, featureRange);
+            }
         }
         org.apache.karaf.features.internal.model.Dependency dep = new org.apache.karaf.features.internal.model.Dependency();
         dep.setName(feature.getName());

http://git-wip-us.apache.org/repos/asf/karaf/blob/f2669e1d/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java b/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
index 7008ef6..0243dc0 100644
--- a/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
+++ b/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
@@ -790,7 +790,7 @@ public class FeaturesServiceImpl implements FeaturesService {
                          Collections.<String>emptySet(),
                          overrides,
                          Collections.<String>emptySet());
-        Map<Resource, List<Wire>> resolution = builder.resolve(systemBundles, true);
+        Map<Resource, List<Wire>> resolution = builder.resolve(systemBundles);
         Collection<Resource> allResources = resolution.keySet();
         Map<String, StreamProvider> providers = builder.getProviders();
 

http://git-wip-us.apache.org/repos/asf/karaf/blob/f2669e1d/features/src/test/java/org/apache/karaf/features/ConditionalTest.java
----------------------------------------------------------------------
diff --git a/features/src/test/java/org/apache/karaf/features/ConditionalTest.java b/features/src/test/java/org/apache/karaf/features/ConditionalTest.java
index d5e7e46..b103683 100644
--- a/features/src/test/java/org/apache/karaf/features/ConditionalTest.java
+++ b/features/src/test/java/org/apache/karaf/features/ConditionalTest.java
@@ -31,17 +31,24 @@ public class ConditionalTest extends TestCase {
         Feature feature = features[0];
 
         assertNotNull(feature.getConditional());
-        assertEquals(1,feature.getConditional().size());
+        assertEquals(2,feature.getConditional().size());
 
         Conditional conditional = feature.getConditional().get(0);
         assertNotNull(conditional.getCondition());
         assertEquals(1,conditional.getCondition().size());
-        Dependency dependency = conditional.getCondition().get(0);
+        String dependency = conditional.getCondition().get(0);
         assertNotNull(dependency);
-        assertEquals(dependency.getName(),"http");
+        assertEquals("http", dependency);
         assertNotNull(conditional.getBundles());
         assertEquals(1, feature.getConditional().get(0).getBundles().size());
 
+        conditional = feature.getConditional().get(1);
+        assertNotNull(conditional.getCondition());
+        assertEquals(1,conditional.getCondition().size());
+        dependency = conditional.getCondition().get(0);
+        assertNotNull(dependency);
+        assertEquals("req:osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(!(version>=1.7)))\"", dependency);
+
         String wrapperName = "my6/1.5.3-beta-3".replaceAll("[^A-Za-z0-9 ]", "_");
     }
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/f2669e1d/features/src/test/resources/org/apache/karaf/features/internal/service/f06.xml
----------------------------------------------------------------------
diff --git a/features/src/test/resources/org/apache/karaf/features/internal/service/f06.xml b/features/src/test/resources/org/apache/karaf/features/internal/service/f06.xml
index 496cbdb..51e78f1 100644
--- a/features/src/test/resources/org/apache/karaf/features/internal/service/f06.xml
+++ b/features/src/test/resources/org/apache/karaf/features/internal/service/f06.xml
@@ -27,6 +27,10 @@
             <condition>http</condition>
             <bundle>mvn:org.springframework/spring-web/2.5.6.SEC02</bundle>
         </conditional>
+        <conditional>
+            <condition>req:osgi.ee;filter:="(&amp;(osgi.ee=JavaSE)(!(version>=1.7)))"</condition>
+            <bundle start="true" start-level="30">mvn:org.apache.mina/mina-core/${mina.version}</bundle>
+        </conditional>
     </feature>
 </features>
 


[27/33] Revert "[KARAF-2852] Merge features/core and features/command"

Posted by gn...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/service/BootFeaturesInstaller.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/BootFeaturesInstaller.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/BootFeaturesInstaller.java
new file mode 100644
index 0000000..93827bf
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/BootFeaturesInstaller.java
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.service;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.karaf.features.BootFinished;
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.FeaturesService;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class BootFeaturesInstaller {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(BootFeaturesInstaller.class);
+
+    public static String VERSION_PREFIX = "version=";
+
+    private final FeaturesServiceImpl featuresService;
+    private final BundleContext bundleContext;
+    private final String repositories;
+    private final String features;
+    private final boolean asynchronous;
+
+    /**
+     *
+     * @param features list of boot features separated by comma. Optionally contains ;version=x.x.x to specify a specific feature version
+     */
+    public BootFeaturesInstaller(BundleContext bundleContext,
+                                 FeaturesServiceImpl featuresService,
+                                 String repositories,
+                                 String features,
+                                 boolean asynchronous) {
+        this.bundleContext = bundleContext;
+        this.featuresService = featuresService;
+        this.repositories = repositories;
+        this.features = features;
+        this.asynchronous = asynchronous;
+    }
+
+    /**
+     * Install boot features
+     */
+    public void start() {
+        if (featuresService.isBootDone()) {
+            publishBootFinished();
+            return;
+        }
+        if (asynchronous) {
+            new Thread("Initial Features Provisioning") {
+                public void run() {
+                    installBootFeatures();
+                }
+            }.start();
+        } else {
+            installBootFeatures();
+        }
+    }
+
+    protected void installBootFeatures() {
+        try {
+            for (String repo : repositories.split(",")) {
+                repo = repo.trim();
+                if (!repo.isEmpty()) {
+                    try {
+                        featuresService.addRepository(URI.create(repo));
+                    } catch (Exception e) {
+                        LOGGER.error("Error installing boot feature repository " + repo, e);
+                    }
+                }
+            }
+
+            List<Set<String>> stagedFeatures = parseBootFeatures(features);
+            for (Set<String> features : stagedFeatures) {
+                featuresService.installFeatures(features, EnumSet.of(FeaturesService.Option.NoFailOnFeatureNotFound));
+            }
+            featuresService.bootDone();
+            publishBootFinished();
+        } catch (Exception e) {
+            // Special handling in case the bundle has been refreshed.
+            // In such a case, simply exits without logging any exception
+            // as the restart should cause the feature service to finish
+            // the work.
+            if (e instanceof IllegalStateException) {
+                try {
+                    bundleContext.getBundle();
+                } catch (IllegalStateException ies) {
+                    return;
+                }
+            }
+            LOGGER.error("Error installing boot features", e);
+        }
+    }
+
+    /**
+     *
+     * @param featureSt either feature name or <featurename>;version=<version>
+     * @return feature matching the feature string
+     * @throws Exception
+     */
+    private Feature getFeature(String featureSt) throws Exception {
+        String[] parts = featureSt.trim().split(";");
+        String featureName = parts[0];
+        String featureVersion = null;
+        for (String part : parts) {
+            // if the part starts with "version=" it contains the version info
+            if (part.startsWith(VERSION_PREFIX)) {
+                featureVersion = part.substring(VERSION_PREFIX.length());
+            }
+        }
+        if (featureVersion == null) {
+            // no version specified - use default version
+            featureVersion = org.apache.karaf.features.internal.model.Feature.DEFAULT_VERSION;
+        }
+        return featuresService.getFeature(featureName, featureVersion);
+    }
+
+    protected List<Set<String>> parseBootFeatures(String bootFeatures) {
+        Pattern pattern = Pattern.compile("(\\((.+))\\),|.+");
+        Matcher matcher = pattern.matcher(bootFeatures);
+        List<Set<String>> result = new ArrayList<Set<String>>();
+        while (matcher.find()) {
+            String group = matcher.group(2) != null ? matcher.group(2) : matcher.group();
+            result.add(parseFeatureList(group));
+        }
+        return result;
+    }
+
+    protected Set<String> parseFeatureList(String group) {
+        HashSet<String> features = new HashSet<String>();
+        for (String feature : Arrays.asList(group.trim().split("\\s*,\\s*"))) {
+            if (feature.length() > 0) {
+                features.add(feature);
+            }
+        }
+        return features;
+    }
+
+    private void publishBootFinished() {
+        if (bundleContext != null) {
+            BootFinished bootFinished = new BootFinished() {};
+            bundleContext.registerService(BootFinished.class, bootFinished, new Hashtable<String, String>());
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/service/EventAdminListener.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/EventAdminListener.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/EventAdminListener.java
new file mode 100644
index 0000000..b6eaae5
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/EventAdminListener.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.service;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.karaf.features.EventConstants;
+import org.apache.karaf.features.FeatureEvent;
+import org.apache.karaf.features.FeaturesListener;
+import org.apache.karaf.features.RepositoryEvent;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * A listener to publish events to EventAdmin
+ */
+public class EventAdminListener implements FeaturesListener {
+
+    private final ServiceTracker<EventAdmin, EventAdmin> tracker;
+
+    public EventAdminListener(BundleContext context) {
+        tracker = new ServiceTracker<EventAdmin, EventAdmin>(context, EventAdmin.class.getName(), null);
+        tracker.open();
+    }
+
+    public void featureEvent(FeatureEvent event) {
+        EventAdmin eventAdmin = tracker.getService();
+        if (eventAdmin == null) {
+            return;
+        }
+        Dictionary<String, Object> props = new Hashtable<String, Object>();
+        props.put(EventConstants.TYPE, event.getType());
+        props.put(EventConstants.EVENT, event);
+        props.put(EventConstants.TIMESTAMP, System.currentTimeMillis());
+        props.put(EventConstants.FEATURE_NAME, event.getFeature().getName());
+        props.put(EventConstants.FEATURE_VERSION, event.getFeature().getVersion());
+        String topic;
+        switch (event.getType()) {
+            case FeatureInstalled:
+                topic = EventConstants.TOPIC_FEATURES_INSTALLED;
+                break;
+            case FeatureUninstalled:
+                topic = EventConstants.TOPIC_FEATURES_UNINSTALLED;
+                break;
+            default:
+                throw new IllegalStateException("Unknown features event type: " + event.getType());
+        }
+        eventAdmin.postEvent(new Event(topic, props));
+    }
+
+    public void repositoryEvent(RepositoryEvent event) {
+        EventAdmin eventAdmin = tracker.getService();
+        if (eventAdmin == null) {
+            return;
+        }
+        Dictionary<String, Object> props = new Hashtable<String, Object>();
+        props.put(EventConstants.TYPE, event.getType());
+        props.put(EventConstants.EVENT, event);
+        props.put(EventConstants.TIMESTAMP, System.currentTimeMillis());
+        props.put(EventConstants.REPOSITORY_URI, event.getRepository().getURI().toString());
+        String topic;
+        switch (event.getType()) {
+            case RepositoryAdded:
+                topic = EventConstants.TOPIC_REPOSITORY_ADDED;
+                break;
+            case RepositoryRemoved:
+                topic = EventConstants.TOPIC_REPOSITORY_REMOVED;
+                break;
+            default:
+                throw new IllegalStateException("Unknown repository event type: " + event.getType());
+        }
+        eventAdmin.postEvent(new Event(topic, props));
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/service/FeatureConfigInstaller.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/FeatureConfigInstaller.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/FeatureConfigInstaller.java
new file mode 100644
index 0000000..0e9038d
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/FeatureConfigInstaller.java
@@ -0,0 +1,167 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.service;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.karaf.features.ConfigFileInfo;
+import org.apache.karaf.features.Feature;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FeatureConfigInstaller {
+	private static final Logger LOGGER = LoggerFactory.getLogger(FeaturesServiceImpl.class);
+    private static final String CONFIG_KEY = "org.apache.karaf.features.configKey";
+
+    private final ConfigurationAdmin configAdmin;
+    
+    public FeatureConfigInstaller(ConfigurationAdmin configAdmin) {
+		this.configAdmin = configAdmin;
+	}
+
+    private 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};
+        }
+    }
+
+    private Configuration createConfiguration(ConfigurationAdmin configurationAdmin,
+                                                String pid, String factoryPid) throws IOException, InvalidSyntaxException {
+        if (factoryPid != null) {
+            return configurationAdmin.createFactoryConfiguration(factoryPid, null);
+        } else {
+            return configurationAdmin.getConfiguration(pid, null);
+        }
+    }
+
+    private Configuration findExistingConfiguration(ConfigurationAdmin configurationAdmin,
+                                                      String pid, String factoryPid) throws IOException, InvalidSyntaxException {
+        String filter;
+        if (factoryPid == null) {
+            filter = "(" + Constants.SERVICE_PID + "=" + pid + ")";
+        } else {
+            String key = createConfigurationKey(pid, factoryPid);
+            filter = "(" + CONFIG_KEY + "=" + key + ")";
+        }
+        Configuration[] configurations = configurationAdmin.listConfigurations(filter);
+        if (configurations != null && configurations.length > 0) {
+            return configurations[0];
+        }
+        return null;
+    }
+
+    void installFeatureConfigs(Feature feature) throws IOException, InvalidSyntaxException {
+        for (String config : feature.getConfigurations().keySet()) {
+            Dictionary<String,String> props = new Hashtable<String, String>(feature.getConfigurations().get(config));
+            String[] pid = parsePid(config);
+            Configuration cfg = findExistingConfiguration(configAdmin, pid[0], pid[1]);
+            if (cfg == null) {
+                cfg = createConfiguration(configAdmin, pid[0], pid[1]);
+                String key = createConfigurationKey(pid[0], pid[1]);
+                props.put(CONFIG_KEY, key);
+                if (cfg.getBundleLocation() != null) {
+                    cfg.setBundleLocation(null);
+                }
+                cfg.update(props);
+            }
+        }
+        for (ConfigFileInfo configFile : feature.getConfigurationFiles()) {
+            installConfigurationFile(configFile.getLocation(), configFile.getFinalname(), configFile.isOverride());
+        }
+    }
+
+    private String createConfigurationKey(String pid, String factoryPid) {
+        return factoryPid == null ? pid : pid + "-" + factoryPid;
+    }
+
+    private void installConfigurationFile(String fileLocation, String finalname, boolean override) throws IOException {
+    	String basePath = System.getProperty("karaf.base");
+    	
+    	if (finalname.contains("${")) {
+    		//remove any placeholder or variable part, this is not valid.
+    		int marker = finalname.indexOf("}");
+    		finalname = finalname.substring(marker+1);
+    	}
+    	
+    	finalname = basePath + File.separator + finalname;
+    	
+    	File file = new File(finalname); 
+    	if (file.exists()) {
+            if (!override) {
+                LOGGER.debug("Configuration file {} already exist, don't override it", finalname);
+                return;
+            } else {
+                LOGGER.info("Configuration file {} already exist, overriding it", finalname);
+            }
+    	} else {
+            LOGGER.info("Creating configuration file {}", finalname);
+        }
+
+        InputStream is = null;
+        FileOutputStream fop = null;
+        try {
+            is = new BufferedInputStream(new URL(fileLocation).openStream());
+
+            if (!file.exists()) {
+                File parentFile = file.getParentFile();
+                if (parentFile != null)
+                    parentFile.mkdirs();
+                file.createNewFile();
+            }
+
+            fop = new FileOutputStream(file);
+        
+            int bytesRead;
+            byte[] buffer = new byte[1024];
+            
+            while ((bytesRead = is.read(buffer)) != -1) {
+                fop.write(buffer, 0, bytesRead);
+            }
+        } catch (RuntimeException e) {
+            LOGGER.error(e.getMessage());
+            throw e;
+        } catch (MalformedURLException e) {
+        	LOGGER.error(e.getMessage());
+            throw e;
+		} finally {
+			if (is != null)
+				is.close();
+            if (fop != null) {
+			    fop.flush();
+			    fop.close();
+            }
+		}
+            
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/service/FeatureFinder.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/FeatureFinder.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/FeatureFinder.java
new file mode 100644
index 0000000..d6defe0
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/FeatureFinder.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.karaf.features.internal.service;
+
+import java.net.URI;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+
+public class FeatureFinder implements ManagedService {
+
+    final Map<String, String> nameToArtifactMap = new HashMap<String, String>();
+
+    public String[] getNames() {
+        synchronized (nameToArtifactMap) {
+            Set<String> strings = nameToArtifactMap.keySet();
+            return strings.toArray(new String[strings.size()]);
+        }
+    }
+
+    public URI getUriFor(String name, String version) {
+        String coords;
+        synchronized (nameToArtifactMap) {
+            coords = nameToArtifactMap.get(name);
+        }
+        if (coords == null) {
+            return null;
+        }
+        Artifact artifact = new Artifact(coords);
+        return artifact.getMavenUrl(version);
+    }
+
+    @SuppressWarnings("rawtypes")
+    public void updated(Dictionary properties) throws ConfigurationException {
+        synchronized (nameToArtifactMap) {
+            if (properties != null) {
+                nameToArtifactMap.clear();
+                Enumeration keys = properties.keys();
+                while (keys.hasMoreElements()) {
+                    String key = (String) keys.nextElement();
+                    if (!"felix.fileinstall.filename".equals(key) && !"service.pid".equals(key)) {
+                        nameToArtifactMap.put(key, (String) properties.get(key));
+                    }
+                }
+            }
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/service/FeatureValidationUtil.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/FeatureValidationUtil.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/FeatureValidationUtil.java
new file mode 100644
index 0000000..6903dc0
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/FeatureValidationUtil.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.karaf.features.internal.service;
+
+import java.net.URI;
+
+import org.apache.karaf.features.internal.model.JaxbUtil;
+
+/**
+ * Utility class which fires XML Schema validation.
+ */
+public class FeatureValidationUtil {
+
+    /**
+     * Runs schema validation.
+     * 
+     * @param uri Uri to validate.
+     * @throws Exception When validation fails.
+     */
+    public static void validate(URI uri) throws Exception {
+        JaxbUtil.unmarshal(uri.toASCIIString(), true);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
new file mode 100644
index 0000000..0243dc0
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
@@ -0,0 +1,1416 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.service;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import org.apache.felix.utils.version.VersionRange;
+import org.apache.felix.utils.version.VersionTable;
+import org.apache.karaf.features.BundleInfo;
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.FeatureEvent;
+import org.apache.karaf.features.FeaturesListener;
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.Repository;
+import org.apache.karaf.features.RepositoryEvent;
+import org.apache.karaf.features.internal.deployment.DeploymentBuilder;
+import org.apache.karaf.features.internal.deployment.StreamProvider;
+import org.apache.karaf.features.internal.resolver.FeatureNamespace;
+import org.apache.karaf.features.internal.resolver.UriNamespace;
+import org.apache.karaf.features.internal.util.ChecksumUtils;
+import org.apache.karaf.features.internal.util.Macro;
+import org.apache.karaf.features.internal.util.MultiException;
+import org.apache.karaf.util.collections.CopyOnWriteArrayIdentityList;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.FrameworkEvent;
+import org.osgi.framework.FrameworkListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.Version;
+import org.osgi.framework.startlevel.BundleStartLevel;
+import org.osgi.framework.wiring.BundleRevision;
+import org.osgi.framework.wiring.BundleWire;
+import org.osgi.framework.wiring.BundleWiring;
+import org.osgi.framework.wiring.FrameworkWiring;
+import org.osgi.resource.Resource;
+import org.osgi.resource.Wire;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.felix.resolver.Util.getSymbolicName;
+import static org.apache.felix.resolver.Util.getVersion;
+
+/**
+ *
+ */
+public class FeaturesServiceImpl implements FeaturesService {
+
+    public static final String UPDATE_SNAPSHOTS_NONE = "none";
+    public static final String UPDATE_SNAPSHOTS_CRC = "crc";
+    public static final String UPDATE_SNAPSHOTS_ALWAYS = "always";
+    public static final String DEFAULT_UPDATE_SNAPSHOTS = UPDATE_SNAPSHOTS_CRC;
+
+    public static final String DEFAULT_FEATURE_RESOLUTION_RANGE = "${range;[====,====]}";
+    public static final String DEFAULT_BUNDLE_UPDATE_RANGE = "${range;[==,=+)}";
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(FeaturesServiceImpl.class);
+    private static final String SNAPSHOT = "SNAPSHOT";
+    private static final String MAVEN = "mvn:";
+
+    /**
+     * Our bundle.
+     * We use it to check bundle operations affecting our own bundle.
+     */
+    private final Bundle bundle;
+
+    /**
+     * The system bundle context.
+     * For all bundles related operations, we use the system bundle context
+     * to allow this bundle to be stopped and still allow the deployment to
+     * take place.
+     */
+    private final BundleContext systemBundleContext;
+    /**
+     * Used to load and save the {@link State} of this service.
+     */
+    private final StateStorage storage;
+    private final FeatureFinder featureFinder;
+    private final EventAdminListener eventAdminListener;
+    private final FeatureConfigInstaller configInstaller;
+    private final String overrides;
+    /**
+     * Range to use when a version is specified on a feature dependency.
+     * The default is {@link FeaturesServiceImpl#DEFAULT_FEATURE_RESOLUTION_RANGE}
+     */
+    private final String featureResolutionRange;
+    /**
+     * Range to use when verifying if a bundle should be updated or
+     * new bundle installed.
+     * The default is {@link FeaturesServiceImpl#DEFAULT_BUNDLE_UPDATE_RANGE}
+     */
+    private final String bundleUpdateRange;
+    /**
+     * Use CRC to check snapshot bundles and update them if changed.
+     * Either:
+     *   - none : never update snapshots
+     *   - always : always update snapshots
+     *   - crc : use CRC to detect changes
+     */
+    private final String updateSnaphots;
+
+    private final List<FeaturesListener> listeners = new CopyOnWriteArrayIdentityList<FeaturesListener>();
+
+    // Synchronized on lock
+    private final Object lock = new Object();
+    private final State state = new State();
+    private final Map<String, Repository> repositoryCache = new HashMap<String, Repository>();
+    private Map<String, Map<String, Feature>> featureCache;
+
+
+    public FeaturesServiceImpl(Bundle bundle,
+                               BundleContext systemBundleContext,
+                               StateStorage storage,
+                               FeatureFinder featureFinder,
+                               EventAdminListener eventAdminListener,
+                               FeatureConfigInstaller configInstaller,
+                               String overrides,
+                               String featureResolutionRange,
+                               String bundleUpdateRange,
+                               String updateSnaphots) {
+        this.bundle = bundle;
+        this.systemBundleContext = systemBundleContext;
+        this.storage = storage;
+        this.featureFinder = featureFinder;
+        this.eventAdminListener = eventAdminListener;
+        this.configInstaller = configInstaller;
+        this.overrides = overrides;
+        this.featureResolutionRange = featureResolutionRange;
+        this.bundleUpdateRange = bundleUpdateRange;
+        this.updateSnaphots = updateSnaphots;
+        loadState();
+    }
+
+    //
+    // State support
+    //
+
+    protected void loadState() {
+        try {
+            synchronized (lock) {
+                storage.load(state);
+            }
+        } catch (IOException e) {
+            LOGGER.warn("Error loading FeaturesService state", e);
+        }
+    }
+
+    protected void saveState() {
+        try {
+            synchronized (lock) {
+                // Make sure we don't store bundle checksums if
+                // it has been disabled through configadmin
+                // so that we don't keep out-of-date checksums.
+                if (!UPDATE_SNAPSHOTS_CRC.equalsIgnoreCase(updateSnaphots)) {
+                    state.bundleChecksums.clear();
+                }
+                storage.save(state);
+            }
+        } catch (IOException e) {
+            LOGGER.warn("Error saving FeaturesService state", e);
+        }
+    }
+
+    boolean isBootDone() {
+        synchronized (lock) {
+            return state.bootDone.get();
+        }
+    }
+
+    void bootDone() {
+        synchronized (lock) {
+            state.bootDone.set(true);
+            saveState();
+        }
+    }
+
+    //
+    // Listeners support
+    //
+
+    public void registerListener(FeaturesListener listener) {
+        listeners.add(listener);
+        try {
+            Set<String> repositories = new TreeSet<String>();
+            Set<String> installedFeatures = new TreeSet<String>();
+            synchronized (lock) {
+                repositories.addAll(state.repositories);
+                installedFeatures.addAll(state.installedFeatures);
+            }
+            for (String uri : repositories) {
+                Repository repository = new RepositoryImpl(URI.create(uri));
+                listener.repositoryEvent(new RepositoryEvent(repository, RepositoryEvent.EventType.RepositoryAdded, true));
+            }
+            for (String id : installedFeatures) {
+                Feature feature = org.apache.karaf.features.internal.model.Feature.valueOf(id);
+                listener.featureEvent(new FeatureEvent(feature, FeatureEvent.EventType.FeatureInstalled, true));
+            }
+        } catch (Exception e) {
+            LOGGER.error("Error notifying listener about the current state", e);
+        }
+    }
+
+    public void unregisterListener(FeaturesListener listener) {
+        listeners.remove(listener);
+    }
+
+    protected void callListeners(FeatureEvent event) {
+        if (eventAdminListener != null) {
+            eventAdminListener.featureEvent(event);
+        }
+        for (FeaturesListener listener : listeners) {
+            listener.featureEvent(event);
+        }
+    }
+
+    protected void callListeners(RepositoryEvent event) {
+        if (eventAdminListener != null) {
+            eventAdminListener.repositoryEvent(event);
+        }
+        for (FeaturesListener listener : listeners) {
+            listener.repositoryEvent(event);
+        }
+    }
+
+    //
+    // Feature Finder support
+    //
+
+    @Override
+    public URI getRepositoryUriFor(String name, String version) {
+        return featureFinder.getUriFor(name, version);
+    }
+
+    @Override
+    public String[] getRepositoryNames() {
+        return featureFinder.getNames();
+    }
+
+
+    //
+    // Repositories support
+    //
+
+    public Repository loadRepository(URI uri) throws Exception {
+        RepositoryImpl repo = new RepositoryImpl(uri);
+        repo.load(true);
+        return repo;
+    }
+
+    @Override
+    public void validateRepository(URI uri) throws Exception {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void addRepository(URI uri) throws Exception {
+        addRepository(uri, false);
+    }
+
+    @Override
+    public void addRepository(URI uri, boolean install) throws Exception {
+        if (install) {
+            // TODO: implement
+            throw new UnsupportedOperationException();
+        }
+        Repository repository = loadRepository(uri);
+        synchronized (lock) {
+            // Clean cache
+            repositoryCache.put(uri.toString(), repository);
+            featureCache = null;
+            // Add repo
+            if (!state.repositories.add(uri.toString())) {
+                return;
+            }
+            saveState();
+        }
+        callListeners(new RepositoryEvent(repository, RepositoryEvent.EventType.RepositoryAdded, false));
+    }
+
+    @Override
+    public void removeRepository(URI uri) throws Exception {
+        removeRepository(uri, true);
+    }
+
+    @Override
+    public void removeRepository(URI uri, boolean uninstall) throws Exception {
+        // TODO: check we don't have any feature installed from this repository
+        Repository repo;
+        synchronized (lock) {
+            // Remove repo
+            if (!state.repositories.remove(uri.toString())) {
+                return;
+            }
+            // Clean cache
+            featureCache = null;
+            repo = repositoryCache.get(uri.toString());
+            List<String> toRemove = new ArrayList<String>();
+            toRemove.add(uri.toString());
+            while (!toRemove.isEmpty()) {
+                Repository rep = repositoryCache.remove(toRemove.remove(0));
+                if (rep != null) {
+                    for (URI u : rep.getRepositories()) {
+                        toRemove.add(u.toString());
+                    }
+                }
+            }
+            saveState();
+        }
+        if (repo == null) {
+            repo = new RepositoryImpl(uri);
+        }
+        callListeners(new RepositoryEvent(repo, RepositoryEvent.EventType.RepositoryRemoved, false));
+    }
+
+    @Override
+    public void restoreRepository(URI uri) throws Exception {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void refreshRepository(URI uri) throws Exception {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Repository[] listRepositories() throws Exception {
+        // Make sure the cache is loaded
+        getFeatures();
+        synchronized (lock) {
+            return repositoryCache.values().toArray(new Repository[repositoryCache.size()]);
+        }
+    }
+
+    @Override
+    public Repository[] listRequiredRepositories() throws Exception {
+        // Make sure the cache is loaded
+        getFeatures();
+        synchronized (lock) {
+            List<Repository> repos = new ArrayList<Repository>();
+            for (Map.Entry<String, Repository> entry : repositoryCache.entrySet()) {
+                if (state.repositories.contains(entry.getKey())) {
+                    repos.add(entry.getValue());
+                }
+            }
+            return repos.toArray(new Repository[repos.size()]);
+        }
+    }
+
+    @Override
+    public Repository getRepository(String name) throws Exception {
+        // Make sure the cache is loaded
+        getFeatures();
+        synchronized (lock) {
+            for (Repository repo : this.repositoryCache.values()) {
+                if (name.equals(repo.getName())) {
+                    return repo;
+                }
+            }
+            return null;
+        }
+    }
+
+    //
+    // Features support
+    //
+
+    public Feature getFeature(String name) throws Exception {
+        return getFeature(name, null);
+    }
+
+    public Feature getFeature(String name, String version) throws Exception {
+        Map<String, Feature> versions = getFeatures().get(name);
+        return getFeatureMatching(versions, version);
+    }
+
+    protected Feature getFeatureMatching(Map<String, Feature> versions, String version) {
+        if (version != null) {
+            version = version.trim();
+            if (version.equals(org.apache.karaf.features.internal.model.Feature.DEFAULT_VERSION)) {
+                version = "";
+            }
+        } else {
+            version = "";
+        }
+        if (versions == null || versions.isEmpty()) {
+            return null;
+        } else {
+            Feature feature = version.isEmpty() ? null : versions.get(version);
+            if (feature == null) {
+                // Compute version range. If an version has been given, assume exact range
+                VersionRange versionRange = version.isEmpty() ?
+                        new VersionRange(Version.emptyVersion) :
+                        new VersionRange(version, true, true);
+                Version latest = Version.emptyVersion;
+                for (String available : versions.keySet()) {
+                    Version availableVersion = VersionTable.getVersion(available);
+                    if (availableVersion.compareTo(latest) >= 0 && versionRange.contains(availableVersion)) {
+                        feature = versions.get(available);
+                        latest = availableVersion;
+                    }
+                }
+            }
+            return feature;
+        }
+    }
+
+    public Feature[] listFeatures() throws Exception {
+        Set<Feature> features = new HashSet<Feature>();
+        for (Map<String, Feature> featureWithDifferentVersion : getFeatures().values()) {
+            for (Feature f : featureWithDifferentVersion.values()) {
+                features.add(f);
+            }
+        }
+        return features.toArray(new Feature[features.size()]);
+    }
+
+    protected Map<String, Map<String, Feature>> getFeatures() throws Exception {
+        List<String> uris;
+        synchronized (lock) {
+            if (featureCache != null) {
+                return featureCache;
+            }
+            uris = new ArrayList<String>(state.repositories);
+        }
+        //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
+        List<String> toLoad = new ArrayList<String>(uris);
+        while (!toLoad.isEmpty()) {
+            String uri = toLoad.remove(0);
+            Repository repo;
+            synchronized (lock) {
+                repo = repositoryCache.get(uri);
+            }
+            if (repo == null) {
+                RepositoryImpl rep = new RepositoryImpl(URI.create(uri));
+                rep.load();
+                repo = rep;
+                synchronized (lock) {
+                    repositoryCache.put(uri, repo);
+                }
+            }
+            for (URI u : repo.getRepositories()) {
+                toLoad.add(u.toString());
+            }
+        }
+        List<Repository> repos;
+        synchronized (lock) {
+            repos = new ArrayList<Repository>(repositoryCache.values());
+        }
+        // * then load all features
+        for (Repository repo : repos) {
+            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);
+                }
+            }
+        }
+        synchronized (lock) {
+            if (uris.size() == state.repositories.size() &&
+                    state.repositories.containsAll(uris)) {
+                featureCache = map;
+            }
+        }
+        return map;
+    }
+
+    //
+    // Installed features
+    //
+
+    @Override
+    public Feature[] listInstalledFeatures() throws Exception {
+        Set<Feature> features = new HashSet<Feature>();
+        Map<String, Map<String, Feature>> allFeatures = getFeatures();
+        synchronized (lock) {
+            for (Map<String, Feature> featureWithDifferentVersion : allFeatures.values()) {
+                for (Feature f : featureWithDifferentVersion.values()) {
+                    if (isInstalled(f)) {
+                        features.add(f);
+                    }
+                }
+            }
+        }
+        return features.toArray(new Feature[features.size()]);
+    }
+
+    @Override
+    public Feature[] listRequiredFeatures() throws Exception {
+        Set<Feature> features = new HashSet<Feature>();
+        Map<String, Map<String, Feature>> allFeatures = getFeatures();
+        synchronized (lock) {
+            for (Map<String, Feature> featureWithDifferentVersion : allFeatures.values()) {
+                for (Feature f : featureWithDifferentVersion.values()) {
+                    if (isRequired(f)) {
+                        features.add(f);
+                    }
+                }
+            }
+        }
+        return features.toArray(new Feature[features.size()]);
+    }
+
+
+    @Override
+    public boolean isInstalled(Feature f) {
+        String id = normalize(f.getId());
+        synchronized (lock) {
+            return state.installedFeatures.contains(id);
+        }
+    }
+
+    @Override
+    public boolean isRequired(Feature f) {
+        String id = normalize(f.getId());
+        synchronized (lock) {
+            return state.features.contains(id);
+        }
+    }
+
+    //
+    // Installation and uninstallation of features
+    //
+
+    public void installFeature(String name) throws Exception {
+        installFeature(name, EnumSet.noneOf(Option.class));
+    }
+
+    public void installFeature(String name, String version) throws Exception {
+        installFeature(version != null ? name + "/" + version : name, EnumSet.noneOf(Option.class));
+    }
+
+    public void installFeature(String name, EnumSet<Option> options) throws Exception {
+        installFeatures(Collections.singleton(name), options);
+    }
+
+    public void installFeature(String name, String version, EnumSet<Option> options) throws Exception {
+        installFeature(version != null ? name + "/" + version : name, options);
+    }
+
+    public void installFeature(Feature feature, EnumSet<Option> options) throws Exception {
+        installFeature(feature.getId());
+    }
+
+    @Override
+    public void uninstallFeature(String name, String version) throws Exception {
+        uninstallFeature(version != null ? name + "/" + version : name);
+    }
+
+    @Override
+    public void uninstallFeature(String name, String version, EnumSet<Option> options) throws Exception {
+        uninstallFeature(version != null ? name + "/" + version : name, options);
+    }
+
+    @Override
+    public void uninstallFeature(String name) throws Exception {
+        uninstallFeature(name, EnumSet.noneOf(Option.class));
+    }
+
+    @Override
+    public void uninstallFeature(String name, EnumSet<Option> options) throws Exception {
+        uninstallFeatures(Collections.singleton(name), options);
+    }
+
+
+    //
+    //
+    //
+    //   RESOLUTION
+    //
+    //
+    //
+
+
+
+
+
+
+    public void installFeatures(Set<String> features, EnumSet<Option> options) throws Exception {
+        Set<String> required;
+        Set<String> installed;
+        Set<Long> managed;
+        synchronized (lock) {
+            required = new HashSet<String>(state.features);
+            installed = new HashSet<String>(state.installedFeatures);
+            managed = new HashSet<Long>(state.managedBundles);
+        }
+        List<String> featuresToAdd = new ArrayList<String>();
+        Map<String, Map<String, Feature>> featuresMap = getFeatures();
+        for (String feature : features) {
+            feature = normalize(feature);
+            String name = feature.substring(0, feature.indexOf("/"));
+            String version = feature.substring(feature.indexOf("/") + 1);
+            Feature f = getFeatureMatching(featuresMap.get(name), version);
+            if (f == null) {
+                if (!options.contains(Option.NoFailOnFeatureNotFound)) {
+                    throw new IllegalArgumentException("No matching features for " + feature);
+                }
+            } else {
+                featuresToAdd.add(normalize(f.getId()));
+            }
+        }
+        featuresToAdd = new ArrayList<String>(new LinkedHashSet<String>(featuresToAdd));
+        StringBuilder sb = new StringBuilder();
+        sb.append("Adding features: ");
+        for (int i = 0; i < featuresToAdd.size(); i++) {
+            if (i > 0) {
+                sb.append(", ");
+            }
+            sb.append(featuresToAdd.get(i));
+        }
+        print(sb.toString(), options.contains(Option.Verbose));
+        required.addAll(featuresToAdd);
+        doInstallFeaturesInThread(required, installed, managed, options);
+    }
+
+    public void uninstallFeatures(Set<String> features, EnumSet<Option> options) throws Exception {
+        Set<String> required;
+        Set<String> installed;
+        Set<Long> managed;
+        synchronized (lock) {
+            required = new HashSet<String>(state.features);
+            installed = new HashSet<String>(state.installedFeatures);
+            managed = new HashSet<Long>(state.managedBundles);
+        }
+        List<String> featuresToRemove = new ArrayList<String>();
+        for (String feature : new HashSet<String>(features)) {
+            List<String> toRemove = new ArrayList<String>();
+            feature = normalize(feature);
+            if (feature.endsWith("/0.0.0")) {
+                String nameSep = feature.substring(0, feature.indexOf("/") + 1);
+                for (String f : required) {
+                    if (normalize(f).startsWith(nameSep)) {
+                        toRemove.add(f);
+                    }
+                }
+            } else {
+                toRemove.add(feature);
+            }
+            toRemove.retainAll(required);
+            if (toRemove.isEmpty()) {
+                throw new IllegalArgumentException("Feature named '" + feature + "' is not installed");
+            } else if (toRemove.size() > 1) {
+                String name = feature.substring(0, feature.indexOf("/"));
+                StringBuilder sb = new StringBuilder();
+                sb.append("Feature named '").append(name).append("' has multiple versions installed (");
+                for (int i = 0; i < toRemove.size(); i++) {
+                    if (i > 0) {
+                        sb.append(", ");
+                    }
+                    sb.append(toRemove.get(i));
+                }
+                sb.append("). Please specify the version to uninstall.");
+                throw new IllegalArgumentException(sb.toString());
+            }
+            featuresToRemove.addAll(toRemove);
+        }
+        featuresToRemove = new ArrayList<String>(new LinkedHashSet<String>(featuresToRemove));
+        StringBuilder sb = new StringBuilder();
+        sb.append("Removing features: ");
+        for (int i = 0; i < featuresToRemove.size(); i++) {
+            if (i > 0) {
+                sb.append(", ");
+            }
+            sb.append(featuresToRemove.get(i));
+        }
+        print(sb.toString(), options.contains(Option.Verbose));
+        required.removeAll(featuresToRemove);
+        doInstallFeaturesInThread(required, installed, managed, options);
+    }
+
+    protected String normalize(String feature) {
+        if (!feature.contains("/")) {
+            feature += "/0.0.0";
+        }
+        int idx = feature.indexOf("/");
+        String name = feature.substring(0, idx);
+        String version = feature.substring(idx + 1);
+        return name + "/" + VersionTable.getVersion(version).toString();
+    }
+
+    /**
+     * Actual deployment needs to be done in a separate thread.
+     * The reason is that if the console is refreshed, the current thread which is running
+     * the command may be interrupted while waiting for the refresh to be done, leading
+     * to bundles not being started after the refresh.
+     */
+    public void doInstallFeaturesInThread(final Set<String> features,
+                                          final Set<String> installed,
+                                          final Set<Long> managed,
+                                          final EnumSet<Option> options) throws Exception {
+        ExecutorService executor = Executors.newCachedThreadPool();
+        try {
+            executor.submit(new Callable<Object>() {
+                @Override
+                public Object call() throws Exception {
+                    doInstallFeatures(features, installed, managed, options);
+                    return null;
+                }
+            }).get();
+        } catch (ExecutionException e) {
+            Throwable t = e.getCause();
+            if (t instanceof RuntimeException) {
+                throw ((RuntimeException) t);
+            } else if (t instanceof Error) {
+                throw ((Error) t);
+            } else if (t instanceof Exception) {
+                throw (Exception) t;
+            } else {
+                throw e;
+            }
+        } finally {
+            executor.shutdown();
+        }
+    }
+
+    public void doInstallFeatures(Set<String> features,    // all request features
+                                  Set<String> installed,   // installed features
+                                  Set<Long> managed,       // currently managed bundles
+                                  EnumSet<Option> options  // installation options
+                    ) throws Exception {
+
+        boolean noRefreshUnmanaged = options.contains(Option.NoAutoRefreshUnmanagedBundles);
+        boolean noRefreshManaged = options.contains(Option.NoAutoRefreshManagedBundles);
+        boolean noRefresh = options.contains(Option.NoAutoRefreshBundles);
+        boolean noStart = options.contains(Option.NoAutoStartBundles);
+        boolean verbose = options.contains(Option.Verbose);
+        boolean simulate = options.contains(Option.Simulate);
+
+        // Get a list of resolved and unmanaged bundles to use as capabilities during resolution
+        List<Resource> systemBundles = new ArrayList<Resource>();
+        Bundle[] bundles = systemBundleContext.getBundles();
+        for (Bundle bundle : bundles) {
+            if (bundle.getState() >= Bundle.RESOLVED && !managed.contains(bundle.getBundleId())) {
+                Resource res = bundle.adapt(BundleRevision.class);
+                systemBundles.add(res);
+            }
+        }
+        // Resolve
+        // TODO: requirements
+        // TODO: bundles
+        // TODO: regions: on isolated regions, we may need different resolution for each region
+        Set<String>  overrides    = Overrides.loadOverrides(this.overrides);
+        Repository[] repositories = listRepositories();
+        DeploymentBuilder builder = createDeploymentBuilder(repositories);
+        builder.setFeatureRange(featureResolutionRange);
+        builder.download(features,
+                         Collections.<String>emptySet(),
+                         Collections.<String>emptySet(),
+                         overrides,
+                         Collections.<String>emptySet());
+        Map<Resource, List<Wire>> resolution = builder.resolve(systemBundles);
+        Collection<Resource> allResources = resolution.keySet();
+        Map<String, StreamProvider> providers = builder.getProviders();
+
+        // Install conditionals
+        List<String> installedFeatureIds = getFeatureIds(allResources);
+        List<String> newFeatures = new ArrayList<String>(installedFeatureIds);
+        newFeatures.removeAll(installed);
+        List<String> delFeatures = new ArrayList<String>(installed);
+        delFeatures.removeAll(installedFeatureIds);
+
+        //
+        // Compute list of installable resources (those with uris)
+        //
+        List<Resource> resources = getBundles(allResources);
+
+        // Compute information for each bundle
+        Map<String, BundleInfo> bundleInfos = new HashMap<String, BundleInfo>();
+        for (Feature feature : getFeatures(repositories, getFeatureIds(allResources))) {
+            for (BundleInfo bi : feature.getBundles()) {
+                BundleInfo oldBi = bundleInfos.get(bi.getLocation());
+                if (oldBi != null) {
+                    bi = mergeBundleInfo(bi, oldBi);
+                }
+                bundleInfos.put(bi.getLocation(), bi);
+            }
+        }
+
+        // TODO: handle bundleInfo.isStart()
+
+        // Get all resources that will be used to satisfy the old features set
+        Set<Resource> resourceLinkedToOldFeatures = new HashSet<Resource>();
+        if (noStart) {
+            for (Resource resource : resolution.keySet()) {
+                String name = FeatureNamespace.getName(resource);
+                if (name != null) {
+                    Version version = FeatureNamespace.getVersion(resource);
+                    String id = version != null ? name + "/" + version : name;
+                    if (installed.contains(id)) {
+                        addTransitive(resource, resourceLinkedToOldFeatures, resolution);
+                    }
+                }
+            }
+        }
+
+        //
+        // Compute deployment
+        //
+        Map<String, Long> bundleChecksums = new HashMap<String, Long>();
+        synchronized (lock) {
+            bundleChecksums.putAll(state.bundleChecksums);
+        }
+        Deployment deployment = computeDeployment(managed, bundles, providers, resources, bundleChecksums);
+
+        if (deployment.toDelete.isEmpty() &&
+                deployment.toUpdate.isEmpty() &&
+                deployment.toInstall.isEmpty()) {
+            print("No deployment change.", verbose);
+            return;
+        }
+        //
+        // Log deployment
+        //
+        logDeployment(deployment, verbose);
+
+        //
+        // Compute the set of bundles to refresh
+        //
+        Set<Bundle> toRefresh = new HashSet<Bundle>();
+        toRefresh.addAll(deployment.toDelete);
+        toRefresh.addAll(deployment.toUpdate.keySet());
+
+        if (!noRefreshManaged) {
+            int size;
+            do {
+                size = toRefresh.size();
+                for (Bundle bundle : bundles) {
+                    // Continue if we already know about this bundle
+                    if (toRefresh.contains(bundle)) {
+                        continue;
+                    }
+                    // Ignore non resolved bundle
+                    BundleWiring wiring = bundle.adapt(BundleWiring.class);
+                    if (wiring == null) {
+                        continue;
+                    }
+                    // Get through the old resolution and flag this bundle
+                    // if it was wired to a bundle to be refreshed
+                    for (BundleWire wire : wiring.getRequiredWires(null)) {
+                        if (toRefresh.contains(wire.getProvider().getBundle())) {
+                            toRefresh.add(bundle);
+                            break;
+                        }
+                    }
+                    // Get through the new resolution and flag this bundle
+                    // if it's wired to any new bundle
+                    List<Wire> newWires = resolution.get(wiring.getRevision());
+                    if (newWires != null) {
+                        for (Wire wire : newWires) {
+                            Bundle b = null;
+                            if (wire.getProvider() instanceof BundleRevision) {
+                                b = ((BundleRevision) wire.getProvider()).getBundle();
+                            } else {
+                                b = deployment.resToBnd.get(wire.getProvider());
+                            }
+                            if (b == null || toRefresh.contains(b)) {
+                                toRefresh.add(bundle);
+                                break;
+                            }
+                        }
+                    }
+                }
+            } while (toRefresh.size() > size);
+        }
+        if (noRefreshUnmanaged) {
+            Set<Bundle> newSet = new HashSet<Bundle>();
+            for (Bundle bundle : toRefresh) {
+                if (managed.contains(bundle.getBundleId())) {
+                    newSet.add(bundle);
+                }
+            }
+            toRefresh = newSet;
+        }
+
+
+        if (simulate) {
+            if (!toRefresh.isEmpty()) {
+                print("  Bundles to refresh:", verbose);
+                for (Bundle bundle : toRefresh) {
+                    print("    " + bundle.getSymbolicName() + " / " + bundle.getVersion(), verbose);
+                }
+            }
+            return;
+        }
+
+        Set<Bundle> toStart = new HashSet<Bundle>();
+
+        //
+        // Execute deployment
+        //
+
+        // TODO: handle update on the features service itself
+        if (deployment.toUpdate.containsKey(bundle) ||
+                deployment.toDelete.contains(bundle)) {
+
+            LOGGER.warn("Updating or uninstalling of the FeaturesService is not supported");
+            deployment.toUpdate.remove(bundle);
+            deployment.toDelete.remove(bundle);
+
+        }
+
+        //
+        // Perform bundle operations
+        //
+
+        // Stop bundles by chunks
+        Set<Bundle> toStop = new HashSet<Bundle>();
+        toStop.addAll(deployment.toUpdate.keySet());
+        toStop.addAll(deployment.toDelete);
+        removeFragmentsAndBundlesInState(toStop, Bundle.UNINSTALLED | Bundle.RESOLVED | Bundle.STOPPING);
+        if (!toStop.isEmpty()) {
+            print("Stopping bundles:", verbose);
+            while (!toStop.isEmpty()) {
+                List<Bundle> bs = getBundlesToStop(toStop);
+                for (Bundle bundle : bs) {
+                    print("  " + bundle.getSymbolicName() + " / " + bundle.getVersion(), verbose);
+                    bundle.stop(Bundle.STOP_TRANSIENT);
+                    toStop.remove(bundle);
+                }
+            }
+        }
+        if (!deployment.toDelete.isEmpty()) {
+            print("Uninstalling bundles:", verbose);
+            for (Bundle bundle : deployment.toDelete) {
+                print("  " + bundle.getSymbolicName() + " / " + bundle.getVersion(), verbose);
+                bundle.uninstall();
+                managed.remove(bundle.getBundleId());
+            }
+        }
+        if (!deployment.toUpdate.isEmpty()) {
+            print("Updating bundles:", verbose);
+            for (Map.Entry<Bundle, Resource> entry : deployment.toUpdate.entrySet()) {
+                Bundle bundle = entry.getKey();
+                Resource resource = entry.getValue();
+                String uri = UriNamespace.getUri(resource);
+                print("  " + uri, verbose);
+                InputStream is = getBundleInputStream(resource, providers);
+                bundle.update(is);
+                toStart.add(bundle);
+                BundleInfo bi = bundleInfos.get(uri);
+                if (bi != null && bi.getStartLevel() > 0) {
+                    bundle.adapt(BundleStartLevel.class).setStartLevel(bi.getStartLevel());
+                }
+                // TODO: handle region
+            }
+        }
+        if (!deployment.toInstall.isEmpty()) {
+            print("Installing bundles:", verbose);
+            for (Resource resource : deployment.toInstall) {
+                String uri = UriNamespace.getUri(resource);
+                print("  " + uri, verbose);
+                InputStream is = getBundleInputStream(resource, providers);
+                Bundle bundle = systemBundleContext.installBundle(uri, is);
+                managed.add(bundle.getBundleId());
+                if (!noStart || resourceLinkedToOldFeatures.contains(resource)) {
+                    toStart.add(bundle);
+                }
+                deployment.resToBnd.put(resource, bundle);
+                // save a checksum of installed snapshot bundle
+                if (UPDATE_SNAPSHOTS_CRC.equals(updateSnaphots)
+                        && isUpdateable(resource) && !deployment.newCheckums.containsKey(bundle.getLocation())) {
+                    deployment.newCheckums.put(bundle.getLocation(), ChecksumUtils.checksum(getBundleInputStream(resource, providers)));
+                }
+                BundleInfo bi = bundleInfos.get(uri);
+                if (bi != null && bi.getStartLevel() > 0) {
+                    bundle.adapt(BundleStartLevel.class).setStartLevel(bi.getStartLevel());
+                }
+                // TODO: handle region
+            }
+        }
+
+        //
+        // Update and save state
+        //
+        synchronized (lock) {
+            state.bundleChecksums.putAll(deployment.newCheckums);
+            state.features.clear();
+            state.features.addAll(features);
+            state.installedFeatures.clear();
+            state.installedFeatures.addAll(installedFeatureIds);
+            state.managedBundles.clear();
+            state.managedBundles.addAll(managed);
+            saveState();
+        }
+
+        //
+        // Install configurations
+        //
+        if (configInstaller != null && !newFeatures.isEmpty()) {
+            for (Repository repository : repositories) {
+                for (Feature feature : repository.getFeatures()) {
+                    if (newFeatures.contains(feature.getId())) {
+                        configInstaller.installFeatureConfigs(feature);
+                    }
+                }
+            }
+        }
+
+        // TODO: remove this hack, but it avoids loading the class after the bundle is refreshed
+        new CopyOnWriteArrayIdentityList().iterator();
+        RequirementSort.sort(Collections.<Resource>emptyList());
+
+        if (!noRefresh) {
+            toStop = new HashSet<Bundle>();
+            toStop.addAll(toRefresh);
+            removeFragmentsAndBundlesInState(toStop, Bundle.UNINSTALLED | Bundle.RESOLVED | Bundle.STOPPING);
+            if (!toStop.isEmpty()) {
+                print("Stopping bundles:", verbose);
+                while (!toStop.isEmpty()) {
+                    List<Bundle> bs = getBundlesToStop(toStop);
+                    for (Bundle bundle : bs) {
+                        print("  " + bundle.getSymbolicName() + " / " + bundle.getVersion(), verbose);
+                        bundle.stop(Bundle.STOP_TRANSIENT);
+                        toStop.remove(bundle);
+                        toStart.add(bundle);
+                    }
+                }
+            }
+
+            if (!toRefresh.isEmpty()) {
+                print("Refreshing bundles:", verbose);
+                for (Bundle bundle : toRefresh) {
+                    print("  " + bundle.getSymbolicName() + " / " + bundle.getVersion(), verbose);
+                }
+                if (!toRefresh.isEmpty()) {
+                    refreshPackages(toRefresh);
+                }
+            }
+        }
+
+        // Compute bundles to start
+        removeFragmentsAndBundlesInState(toStart, Bundle.UNINSTALLED | Bundle.ACTIVE | Bundle.STARTING);
+        if (!toStart.isEmpty()) {
+            // Compute correct start order
+            List<Exception> exceptions = new ArrayList<Exception>();
+            print("Starting bundles:", verbose);
+            while (!toStart.isEmpty()) {
+                List<Bundle> bs = getBundlesToStart(toStart);
+                for (Bundle bundle : bs) {
+                    LOGGER.info("  " + bundle.getSymbolicName() + " / " + bundle.getVersion());
+                    try {
+                        bundle.start();
+                    } catch (BundleException e) {
+                        exceptions.add(e);
+                    }
+                    toStart.remove(bundle);
+                }
+            }
+            if (!exceptions.isEmpty()) {
+                throw new MultiException("Error restarting bundles", exceptions);
+            }
+        }
+
+        // Call listeners
+        for (Feature feature : getFeatures(repositories, delFeatures)) {
+            callListeners(new FeatureEvent(feature, FeatureEvent.EventType.FeatureUninstalled, false));
+        }
+        for (Feature feature : getFeatures(repositories, newFeatures)) {
+            callListeners(new FeatureEvent(feature, FeatureEvent.EventType.FeatureInstalled, false));
+        }
+
+        print("Done.", verbose);
+    }
+
+    private void addTransitive(Resource resource, Set<Resource> resources, Map<Resource, List<Wire>> resolution) {
+        if (resources.add(resource)) {
+            for (Wire wire : resolution.get(resource)) {
+                addTransitive(wire.getProvider(), resources, resolution);
+            }
+        }
+    }
+
+    protected BundleInfo mergeBundleInfo(BundleInfo bi, BundleInfo oldBi) {
+        // TODO: we need a proper merge strategy when a bundle
+        // TODO: comes from different features
+        return bi;
+    }
+
+    private void print(String message, boolean verbose) {
+        LOGGER.info(message);
+        if (verbose) {
+            System.out.println(message);
+        }
+    }
+
+    private void removeFragmentsAndBundlesInState(Collection<Bundle> bundles, int state) {
+        for (Bundle bundle : new ArrayList<Bundle>(bundles)) {
+            if ((bundle.getState() & state) != 0
+                     || bundle.getHeaders().get(Constants.FRAGMENT_HOST) != null) {
+                bundles.remove(bundle);
+            }
+        }
+    }
+
+    protected void logDeployment(Deployment deployment, boolean verbose) {
+        print("Changes to perform:", verbose);
+        if (!deployment.toDelete.isEmpty()) {
+            print("  Bundles to uninstall:", verbose);
+            for (Bundle bundle : deployment.toDelete) {
+                print("    " + bundle.getSymbolicName() + " / " + bundle.getVersion(), verbose);
+            }
+        }
+        if (!deployment.toUpdate.isEmpty()) {
+            print("  Bundles to update:", verbose);
+            for (Map.Entry<Bundle, Resource> entry : deployment.toUpdate.entrySet()) {
+                print("    " + entry.getKey().getSymbolicName() + " / " + entry.getKey().getVersion() + " with " + UriNamespace.getUri(entry.getValue()), verbose);
+            }
+        }
+        if (!deployment.toInstall.isEmpty()) {
+            print("  Bundles to install:", verbose);
+            for (Resource resource : deployment.toInstall) {
+                print("    " + UriNamespace.getUri(resource), verbose);
+            }
+        }
+    }
+
+    protected Deployment computeDeployment(
+                                Set<Long> managed,
+                                Bundle[] bundles,
+                                Map<String, StreamProvider> providers,
+                                List<Resource> resources,
+                                Map<String, Long> bundleChecksums) throws IOException {
+        Deployment deployment = new Deployment();
+
+        // TODO: regions
+        List<Resource> toDeploy = new ArrayList<Resource>(resources);
+
+        // First pass: go through all installed bundles and mark them
+        // as either to ignore or delete
+        for (Bundle bundle : bundles) {
+            if (bundle.getSymbolicName() != null && bundle.getBundleId() != 0) {
+                Resource resource = null;
+                for (Resource res : toDeploy) {
+                    if (bundle.getSymbolicName().equals(getSymbolicName(res))) {
+                        if (bundle.getVersion().equals(getVersion(res))) {
+                            resource = res;
+                            break;
+                        }
+                    }
+                }
+                // We found a matching bundle
+                if (resource != null) {
+                    // In case of snapshots, check if the snapshot is out of date
+                    // and flag it as to update
+                    if (managed.contains(bundle.getBundleId()) && isUpdateable(resource)) {
+                        // Always update snapshots
+                        if (UPDATE_SNAPSHOTS_ALWAYS.equalsIgnoreCase(updateSnaphots)) {
+                            LOGGER.debug("Update snapshot for " + bundle.getLocation());
+                            deployment.toUpdate.put(bundle, resource);
+                        }
+                        else if (UPDATE_SNAPSHOTS_CRC.equalsIgnoreCase(updateSnaphots)) {
+                            // if the checksum are different
+                            InputStream is = null;
+                            try {
+                                is = getBundleInputStream(resource, providers);
+                                long newCrc = ChecksumUtils.checksum(is);
+                                long oldCrc = bundleChecksums.containsKey(bundle.getLocation()) ? bundleChecksums.get(bundle.getLocation()) : 0l;
+                                if (newCrc != oldCrc) {
+                                    LOGGER.debug("New snapshot available for " + bundle.getLocation());
+                                    deployment.toUpdate.put(bundle, resource);
+                                    deployment.newCheckums.put(bundle.getLocation(), newCrc);
+                                }
+                            } finally {
+                                if (is != null) {
+                                    is.close();
+                                }
+                            }
+                        }
+                    }
+                    // We're done for this resource
+                    toDeploy.remove(resource);
+                    deployment.resToBnd.put(resource, bundle);
+                // There's no matching resource
+                // If the bundle is managed, we need to delete it
+                } else if (managed.contains(bundle.getBundleId())) {
+                    deployment.toDelete.add(bundle);
+                }
+            }
+        }
+
+        // Second pass on remaining resources
+        for (Resource resource : toDeploy) {
+            TreeMap<Version, Bundle> matching = new TreeMap<Version, Bundle>();
+            VersionRange range = new VersionRange(Macro.transform(bundleUpdateRange, getVersion(resource).toString()));
+            for (Bundle bundle : deployment.toDelete) {
+                if (bundle.getSymbolicName().equals(getSymbolicName(resource)) && range.contains(bundle.getVersion())) {
+                    matching.put(bundle.getVersion(), bundle);
+                }
+            }
+            if (!matching.isEmpty()) {
+                Bundle bundle = matching.lastEntry().getValue();
+                deployment.toUpdate.put(bundle, resource);
+                deployment.toDelete.remove(bundle);
+                deployment.resToBnd.put(resource, bundle);
+            } else {
+                deployment.toInstall.add(resource);
+            }
+        }
+        return deployment;
+    }
+
+    protected List<Resource> getBundles(Collection<Resource> allResources) {
+        Map<String, Resource> deploy = new TreeMap<String, Resource>();
+        for (Resource res : allResources) {
+            String uri = UriNamespace.getUri(res);
+            if (uri != null) {
+                deploy.put(uri, res);
+            }
+        }
+        return new ArrayList<Resource>(deploy.values());
+    }
+
+    protected List<Feature> getFeatures(Repository[] repositories, List<String> featureIds) throws Exception {
+        List<Feature> installedFeatures = new ArrayList<Feature>();
+        for (Repository repository : repositories) {
+            for (Feature feature : repository.getFeatures()) {
+                String id = feature.getName() + "/" + VersionTable.getVersion(feature.getVersion());
+                if (featureIds.contains(id)) {
+                    installedFeatures.add(feature);
+                }
+            }
+        }
+        return installedFeatures;
+    }
+
+    protected List<String> getFeatureIds(Collection<Resource> allResources) {
+        List<String> installedFeatureIds = new ArrayList<String>();
+        for (Resource resource : allResources) {
+            String name = FeatureNamespace.getName(resource);
+            if (name != null) {
+                Version version = FeatureNamespace.getVersion(resource);
+                String id = version != null ? name + "/" + version : name;
+                installedFeatureIds.add(id);
+            }
+        }
+        return installedFeatureIds;
+    }
+
+    protected DeploymentBuilder createDeploymentBuilder(Repository[] repositories) {
+        return new DeploymentBuilder(new SimpleDownloader(), Arrays.asList(repositories));
+    }
+
+
+    protected boolean isUpdateable(Resource resource) {
+        return (getVersion(resource).getQualifier().endsWith(SNAPSHOT) ||
+                UriNamespace.getUri(resource).contains(SNAPSHOT) ||
+                !UriNamespace.getUri(resource).contains(MAVEN));
+    }
+
+    protected List<Bundle> getBundlesToStart(Collection<Bundle> bundles) {
+        // TODO: make this pluggable ?
+        // TODO: honor respectStartLvlDuringFeatureStartup
+
+        // We hit FELIX-2949 if we don't use the correct order as Felix resolver isn't greedy.
+        // In order to minimize that, we make sure we resolve the bundles in the order they
+        // are given back by the resolution, meaning that all root bundles (i.e. those that were
+        // not flagged as dependencies in features) are started before the others.   This should
+        // make sure those important bundles are started first and minimize the problem.
+
+        // Restart the features service last, regardless of any other consideration
+        // so that we don't end up with the service trying to do stuff before we're done
+        boolean restart = bundles.remove(bundle);
+
+        List<BundleRevision> revs = new ArrayList<BundleRevision>();
+        for (Bundle bundle : bundles) {
+            revs.add(bundle.adapt(BundleRevision.class));
+        }
+        List<Bundle> sorted = new ArrayList<Bundle>();
+        for (BundleRevision rev : RequirementSort.sort(revs)) {
+            sorted.add(rev.getBundle());
+        }
+        if (restart) {
+            sorted.add(bundle);
+        }
+        return sorted;
+    }
+
+    protected List<Bundle> getBundlesToStop(Collection<Bundle> bundles) {
+        // TODO: make this pluggable ?
+        // TODO: honor respectStartLvlDuringFeatureUninstall
+
+        List<Bundle> bundlesToDestroy = new ArrayList<Bundle>();
+        for (Bundle bundle : bundles) {
+            ServiceReference[] references = bundle.getRegisteredServices();
+            int usage = 0;
+            if (references != null) {
+                for (ServiceReference reference : references) {
+                    usage += getServiceUsage(reference, bundles);
+                }
+            }
+            LOGGER.debug("Usage for bundle {} is {}", bundle, usage);
+            if (usage == 0) {
+                bundlesToDestroy.add(bundle);
+            }
+        }
+        if (!bundlesToDestroy.isEmpty()) {
+            Collections.sort(bundlesToDestroy, new Comparator<Bundle>() {
+                public int compare(Bundle b1, Bundle b2) {
+                    return (int) (b2.getLastModified() - b1.getLastModified());
+                }
+            });
+            LOGGER.debug("Selected bundles {} for destroy (no services in use)", bundlesToDestroy);
+        } else {
+            ServiceReference ref = null;
+            for (Bundle bundle : bundles) {
+                ServiceReference[] references = bundle.getRegisteredServices();
+                for (ServiceReference reference : references) {
+                    if (getServiceUsage(reference, bundles) == 0) {
+                        continue;
+                    }
+                    if (ref == null || reference.compareTo(ref) < 0) {
+                        LOGGER.debug("Currently selecting bundle {} for destroy (with reference {})", bundle, reference);
+                        ref = reference;
+                    }
+                }
+            }
+            if (ref != null) {
+                bundlesToDestroy.add(ref.getBundle());
+            }
+            LOGGER.debug("Selected bundle {} for destroy (lowest ranking service)", bundlesToDestroy);
+        }
+        return bundlesToDestroy;
+    }
+
+    private static int getServiceUsage(ServiceReference ref, Collection<Bundle> bundles) {
+        Bundle[] usingBundles = ref.getUsingBundles();
+        int nb = 0;
+        if (usingBundles != null) {
+            for (Bundle bundle : usingBundles) {
+                if (bundles.contains(bundle)) {
+                    nb++;
+                }
+            }
+        }
+        return nb;
+    }
+
+    protected InputStream getBundleInputStream(Resource resource, Map<String, StreamProvider> providers) throws IOException {
+        String uri = UriNamespace.getUri(resource);
+        if (uri == null) {
+            throw new IllegalStateException("Resource has no uri");
+        }
+        StreamProvider provider = providers.get(uri);
+        if (provider == null) {
+            throw new IllegalStateException("Resource " + uri + " has no StreamProvider");
+        }
+        return provider.open();
+    }
+
+    protected void refreshPackages(Collection<Bundle> bundles) throws InterruptedException {
+        final CountDownLatch latch = new CountDownLatch(1);
+        FrameworkWiring fw = systemBundleContext.getBundle().adapt(FrameworkWiring.class);
+        fw.refreshBundles(bundles, new FrameworkListener() {
+            @Override
+            public void frameworkEvent(FrameworkEvent event) {
+                if (event.getType() == FrameworkEvent.ERROR) {
+                    LOGGER.error("Framework error", event.getThrowable());
+                }
+                latch.countDown();
+            }
+        });
+        latch.await();
+    }
+
+
+    static class Deployment {
+        Map<String, Long> newCheckums = new HashMap<String, Long>();
+        Map<Resource, Bundle> resToBnd = new HashMap<Resource, Bundle>();
+        List<Resource> toInstall = new ArrayList<Resource>();
+        List<Bundle> toDelete = new ArrayList<Bundle>();
+        Map<Bundle, Resource> toUpdate = new HashMap<Bundle, Resource>();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/service/Overrides.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/Overrides.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/Overrides.java
new file mode 100644
index 0000000..233a8a2
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/Overrides.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.karaf.features.internal.service;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.felix.utils.manifest.Clause;
+import org.apache.felix.utils.manifest.Parser;
+import org.apache.felix.utils.version.VersionRange;
+import org.osgi.framework.Version;
+import org.osgi.resource.Resource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.felix.resolver.Util.getSymbolicName;
+import static org.apache.felix.resolver.Util.getVersion;
+
+/**
+ * Helper class to deal with overriden bundles at feature installation time.
+ */
+public class Overrides {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(Overrides.class);
+
+    protected static final String OVERRIDE_RANGE = "range";
+
+    /**
+     * Compute a list of bundles to install, taking into account overrides.
+     *
+     * The file containing the overrides will be loaded from the given url.
+     * Blank lines and lines starting with a '#' will be ignored, all other lines
+     * are considered as urls to override bundles.
+     *
+     * The list of resources to resolve will be scanned and for each bundle,
+     * if a bundle override matches that resource, it will be used instead.
+     *
+     * Matching is done on bundle symbolic name (they have to be the same)
+     * and version (the bundle override version needs to be greater than the
+     * resource to be resolved, and less than the next minor version.  A range
+     * directive can be added to the override url in which case, the matching
+     * will succeed if the resource to be resolved is within the given range.
+     *
+     * @param resources the list of resources to resolve
+     * @param overrides list of bundle overrides
+     */
+    public static void override(Map<String, Resource> resources, Collection<String> overrides) {
+        // Do override replacement
+        for (Clause override : Parser.parseClauses(overrides.toArray(new String[overrides.size()]))) {
+            String url = override.getName();
+            String vr  = override.getAttribute(OVERRIDE_RANGE);
+            Resource over = resources.get(url);
+            if (over == null) {
+                // Ignore invalid overrides
+                continue;
+            }
+            for (String uri : new ArrayList<String>(resources.keySet())) {
+                Resource res = resources.get(uri);
+                if (getSymbolicName(res).equals(getSymbolicName(over))) {
+                    VersionRange range;
+                    if (vr == null) {
+                        // default to micro version compatibility
+                        Version v1 = getVersion(res);
+                        Version v2 = new Version(v1.getMajor(), v1.getMinor() + 1, 0);
+                        range = new VersionRange(false, v1, v2, true);
+                    } else {
+                        range = VersionRange.parseVersionRange(vr);
+                    }
+                    // The resource matches, so replace it with the overridden resource
+                    // if the override is actually a newer version than what we currently have
+                    if (range.contains(getVersion(over)) && getVersion(res).compareTo(getVersion(over)) < 0) {
+                        resources.put(uri, over);
+                    }
+                }
+            }
+        }
+    }
+
+    public static Set<String> loadOverrides(String overridesUrl) {
+        Set<String> overrides = new HashSet<String>();
+        try {
+            if (overridesUrl != null) {
+                InputStream is = new URL(overridesUrl).openStream();
+                try {
+                    BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+                    String line;
+                    while ((line = reader.readLine()) != null) {
+                        line = line.trim();
+                        if (!line.isEmpty() && !line.startsWith("#")) {
+                            overrides.add(line);
+                        }
+                    }
+                } finally {
+                    is.close();
+                }
+            }
+        } catch (Exception e) {
+            LOGGER.debug("Unable to load overrides bundles list", e);
+        }
+        return overrides;
+    }
+
+    public static String extractUrl(String override) {
+        Clause[] cs = Parser.parseClauses(new String[] { override });
+        if (cs.length != 1) {
+            throw new IllegalStateException("Override contains more than one clause: " + override);
+        }
+        return cs[0].getName();
+    }
+
+}


[30/33] Revert "[KARAF-2852] Merge features/core and features/command"

Posted by gn...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/model/ConfigFile.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/model/ConfigFile.java b/features/core/src/main/java/org/apache/karaf/features/internal/model/ConfigFile.java
new file mode 100644
index 0000000..e5d9d94
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/model/ConfigFile.java
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.karaf.features.internal.model;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+import org.apache.karaf.features.ConfigFileInfo;
+
+
+/**
+ * 
+ * Additional configuration files which should be created during feature installation.
+ *             
+ * 
+ * <p>Java class for configFile complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="configFile">
+ *   &lt;simpleContent>
+ *     &lt;extension base="&lt;http://www.w3.org/2001/XMLSchema>string">
+ *       &lt;attribute name="finalname" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
+ *       &lt;attribute name="override" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ *     &lt;/extension>
+ *   &lt;/simpleContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "configFile", propOrder = {
+    "value"
+})
+public class ConfigFile implements ConfigFileInfo {
+
+    @XmlValue
+    protected String value;
+    @XmlAttribute(required = true)
+    protected String finalname;
+    @XmlAttribute
+    protected Boolean override;
+
+    /**
+     * Gets the value of the value property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getLocation() {
+        return value;
+    }
+
+    /**
+     * Sets the value of the value property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setLocation(String value) {
+        this.value = value;
+    }
+
+    /**
+     * Gets the value of the finalname property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getFinalname() {
+        return finalname;
+    }
+
+    /**
+     * Sets the value of the finalname property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setFinalname(String value) {
+    	this.finalname = value;
+    }
+
+    /**
+     * Gets the value of the override property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Boolean }
+     *     
+     */
+    public boolean isOverride() {
+        return override == null? false: override;
+    }
+
+    /**
+     * Sets the value of the override property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Boolean }
+     *     
+     */
+    public void setOverride(Boolean value) {
+    	this.override = value;
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/model/Content.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/model/Content.java b/features/core/src/main/java/org/apache/karaf/features/internal/model/Content.java
new file mode 100644
index 0000000..756e4c1
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/model/Content.java
@@ -0,0 +1,199 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.model;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+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.bind.annotation.XmlTransient;
+import org.apache.karaf.features.BundleInfo;
+import org.apache.karaf.features.ConfigFileInfo;
+
+@XmlTransient
+public class Content {
+
+    protected List<Config> config;
+    protected List<ConfigFile> configfile;
+    protected List<Dependency> feature;
+    protected List<Bundle> bundle;
+
+    /**
+     * Gets the value of the config property.
+     * <p/>
+     * <p/>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the config property.
+     * <p/>
+     * <p/>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getConfig().add(newItem);
+     * </pre>
+     * <p/>
+     * <p/>
+     * <p/>
+     * Objects of the following type(s) are allowed in the list
+     * {@link Config }
+     */
+    public List<Config> getConfig() {
+        if (config == null) {
+            config = new ArrayList<Config>();
+        }
+        return this.config;
+    }
+
+    /**
+     * Gets the value of the configfile property.
+     * <p/>
+     * <p/>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the configfile property.
+     * <p/>
+     * <p/>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getConfigfile().add(newItem);
+     * </pre>
+     * <p/>
+     * <p/>
+     * <p/>
+     * Objects of the following type(s) are allowed in the list
+     * {@link ConfigFile }
+     */
+    public List<ConfigFile> getConfigfile() {
+        if (configfile == null) {
+            configfile = new ArrayList<ConfigFile>();
+        }
+        return this.configfile;
+    }
+
+    /**
+     * Gets the value of the feature property.
+     * <p/>
+     * <p/>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the feature property.
+     * <p/>
+     * <p/>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getFeature().add(newItem);
+     * </pre>
+     * <p/>
+     * <p/>
+     * <p/>
+     * Objects of the following type(s) are allowed in the list
+     * {@link Dependency }
+     */
+    public List<Dependency> getFeature() {
+        if (feature == null) {
+            feature = new ArrayList<Dependency>();
+        }
+        return this.feature;
+    }
+
+    /**
+     * Gets the value of the bundle property.
+     * <p/>
+     * <p/>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the bundle property.
+     * <p/>
+     * <p/>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getBundle().add(newItem);
+     * </pre>
+     * <p/>
+     * <p/>
+     * <p/>
+     * Objects of the following type(s) are allowed in the list
+     * {@link Bundle }
+     */
+    public List<Bundle> getBundle() {
+        if (bundle == null) {
+            bundle = new ArrayList<Bundle>();
+        }
+        return this.bundle;
+    }
+
+    public List<org.apache.karaf.features.Dependency> getDependencies() {
+        return Collections.<org.apache.karaf.features.Dependency>unmodifiableList(getFeature());
+    }
+
+    public List<BundleInfo> getBundles() {
+        return Collections.<BundleInfo>unmodifiableList(getBundle());
+    }
+
+    public Map<String, Map<String, String>> getConfigurations() {
+        Map<String, Map<String, String>> result = new HashMap<String, Map<String, String>>();
+        for (Config config : getConfig()) {
+            String name = config.getName();
+            StringReader propStream = new StringReader(config.getValue());
+            Properties props = new Properties();
+            try {
+                props.load(propStream);
+            } catch (IOException e) {
+                //ignore??
+            }
+            interpolation(props);
+            Map<String, String> propMap = new HashMap<String, String>();
+            for (Map.Entry<Object, Object> entry : props.entrySet()) {
+                propMap.put((String) entry.getKey(), (String) entry.getValue());
+            }
+            result.put(name, propMap);
+        }
+        return result;
+    }
+
+    public List<ConfigFileInfo> getConfigurationFiles() {
+        return Collections.<ConfigFileInfo>unmodifiableList(getConfigfile());
+    }
+
+    @SuppressWarnings("rawtypes")
+	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);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/model/Dependency.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/model/Dependency.java b/features/core/src/main/java/org/apache/karaf/features/internal/model/Dependency.java
new file mode 100644
index 0000000..9c92a93
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/model/Dependency.java
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+package org.apache.karaf.features.internal.model;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+
+
+/**
+ * 
+ * Dependency of feature.
+ *             
+ * 
+ * <p>Java class for dependency complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="dependency">
+ *   &lt;simpleContent>
+ *     &lt;extension base="&lt;http://karaf.apache.org/xmlns/features/v1.0.0>featureName">
+ *       &lt;attribute name="version" type="{http://www.w3.org/2001/XMLSchema}string" default="0.0.0" />
+ *     &lt;/extension>
+ *   &lt;/simpleContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "dependency", propOrder = {
+    "value"
+})
+public class Dependency implements org.apache.karaf.features.Dependency {
+
+    @XmlValue
+    protected String value;
+    @XmlAttribute
+    protected String version;
+
+    /**
+     * 
+     * Feature name should be non empty string.
+     *             
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getName() {
+        return value;
+    }
+
+    /**
+     * Sets the value of the value property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setName(String value) {
+        this.value = value;
+    }
+
+    /**
+     * Gets the value of the version property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getVersion() {
+        if (version == null) {
+            return "0.0.0";
+        } else {
+            return version;
+        }
+    }
+
+    /**
+     * Sets the value of the version property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setVersion(String value) {
+        this.version = value;
+    }
+
+    public String toString() {
+    	String ret = getName() + Feature.SPLIT_FOR_NAME_AND_VERSION + getVersion();
+    	return ret;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/model/Feature.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/model/Feature.java b/features/core/src/main/java/org/apache/karaf/features/internal/model/Feature.java
new file mode 100644
index 0000000..46580da
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/model/Feature.java
@@ -0,0 +1,374 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.karaf.features.internal.model;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * 
+ * Definition of the Feature.
+ *             
+ * 
+ * <p>Java class for feature complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="feature">
+ *   &lt;complexContent>
+ *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       &lt;sequence>
+ *         &lt;element name="details" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         &lt;element name="config" type="{http://karaf.apache.org/xmlns/features/v1.0.0}config" maxOccurs="unbounded" minOccurs="0"/>
+ *         &lt;element name="configfile" type="{http://karaf.apache.org/xmlns/features/v1.0.0}configFile" maxOccurs="unbounded" minOccurs="0"/>
+ *         &lt;element name="feature" type="{http://karaf.apache.org/xmlns/features/v1.0.0}dependency" maxOccurs="unbounded" minOccurs="0"/>
+ *         &lt;element name="bundle" type="{http://karaf.apache.org/xmlns/features/v1.0.0}bundle" maxOccurs="unbounded" minOccurs="0"/>
+ *         &lt;element name="conditional" type="{http://karaf.apache.org/xmlns/features/v1.0.0}conditional" maxOccurs="unbounded" minOccurs="0"/>
+ *         &lt;element name="capability" type="{http://karaf.apache.org/xmlns/features/v1.0.0}capability" maxOccurs="unbounded" minOccurs="0"/>
+ *         &lt;element name="requirement" type="{http://karaf.apache.org/xmlns/features/v1.0.0}requirement" maxOccurs="unbounded" minOccurs="0"/>
+ *       &lt;/sequence>
+ *       &lt;attribute name="name" use="required" type="{http://karaf.apache.org/xmlns/features/v1.0.0}featureName" />
+ *       &lt;attribute name="version" type="{http://www.w3.org/2001/XMLSchema}string" default="0.0.0" />
+ *       &lt;attribute name="description" type="{http://www.w3.org/2001/XMLSchema}string" />
+ *       &lt;attribute name="resolver" type="{http://karaf.apache.org/xmlns/features/v1.0.0}resolver" />
+ *     &lt;/restriction>
+ *   &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "feature", propOrder = {
+    "details",
+    "config",
+    "configfile",
+    "feature",
+    "bundle",
+    "conditional",
+    "capability",
+    "requirement"
+})
+public class Feature extends Content implements org.apache.karaf.features.Feature {
+    public static String SPLIT_FOR_NAME_AND_VERSION = "/";
+    public static String DEFAULT_VERSION = "0.0.0";
+
+
+    protected String details;
+    @XmlAttribute(required = true)
+    protected String name;
+    @XmlAttribute
+    protected String version;
+    @XmlAttribute
+    protected String description;
+    @XmlAttribute
+    protected String resolver;
+    @XmlAttribute
+    protected String install;
+    @XmlAttribute(name = "start-level")
+    protected Integer startLevel;
+    @XmlAttribute
+    protected String region;
+    protected List<Conditional> conditional;
+    protected List<Capability> capability;
+    protected List<Requirement> requirement;
+
+    public Feature() {
+    }
+
+    public Feature(String name) {
+        this.name = name;
+    }
+
+    public Feature(String name, String version) {
+        this.name = name;
+        this.version = version;
+    }
+
+
+    public static org.apache.karaf.features.Feature valueOf(String str) {
+    	if (str.contains(SPLIT_FOR_NAME_AND_VERSION)) {
+    		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 Feature(strName, strVersion);
+    	} else {
+    		return new Feature(str);
+    	}
+
+
+    }
+
+
+    public String getId() {
+        return getName() + SPLIT_FOR_NAME_AND_VERSION + getVersion();
+    }
+
+    /**
+     * Gets the value of the name property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Sets the value of the name property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setName(String value) {
+        this.name = value;
+    }
+
+    /**
+     * Gets the value of the version property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getVersion() {
+        if (version == null) {
+            return DEFAULT_VERSION;
+        } else {
+            return version;
+        }
+    }
+
+    /**
+     * Sets the value of the version property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setVersion(String value) {
+        this.version = value;
+    }
+
+    /**
+     * Since version has a default value ("0.0.0"), returns
+     * whether or not the version has been set.
+     */
+    public boolean hasVersion() {
+        return this.version != null;
+    }
+
+    /**
+     * Gets the value of the description property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * Sets the value of the description property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setDescription(String value) {
+        this.description = value;
+    }
+
+    public String getDetails() {
+        return details;
+    }
+
+    public void setDetails(String details) {
+        this.details = details;
+    }
+
+    /**
+     * Gets the value of the resolver property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getResolver() {
+        return resolver;
+    }
+
+    public String getInstall() {
+        return install;
+    }
+
+    public void setInstall(String install) {
+        this.install = install;
+    }
+
+    /**
+     * Sets the value of the resolver property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setResolver(String value) {
+        this.resolver = value;
+    }
+    
+    /**
+     * Gets the value of the startLevel property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Integer }
+     *     
+     */
+    public int getStartLevel() {
+        return startLevel == null? 0: startLevel;
+    }
+
+    /**
+     * Sets the value of the startLevel property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Integer }
+     *     
+     */
+    public void setStartLevel(Integer value) {
+        this.startLevel = value;
+    }
+
+
+    public String getRegion() {
+        return region;
+    }
+
+    public void setRegion(String region) {
+        this.region = region;
+    }
+
+    /**
+     * Gets the value of the conditional property.
+     * <p/>
+     * <p/>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the feature property.
+     * <p/>
+     * <p/>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getConditionals().add(newItem);
+     * </pre>
+     * <p/>
+     * <p/>
+     * <p/>
+     * Objects of the following type(s) are allowed in the list
+     * {@link Conditional }
+     */
+    public List<Conditional> getConditional() {
+        if (conditional == null) {
+            conditional = new ArrayList<Conditional>();
+        }
+        return this.conditional;
+    }
+
+    public List<Capability> getCapabilities() {
+        if (capability == null) {
+            capability = new ArrayList<Capability>();
+        }
+        return this.capability;
+    }
+
+    public List<Requirement> getRequirements() {
+        if (requirement == null) {
+            requirement = new ArrayList<Requirement>();
+        }
+        return this.requirement;
+    }
+
+    public String toString() {
+    	return getId();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Feature feature = (Feature) o;
+
+        if (name != null ? !name.equals(feature.name) : feature.name != null) return false;
+        if (version != null ? !version.equals(feature.version) : feature.version != null) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = name != null ? name.hashCode() : 0;
+        result = 31 * result + (version != null ? version.hashCode() : 0);
+        return result;
+    }
+
+    @SuppressWarnings("rawtypes")
+	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);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/model/Features.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/model/Features.java b/features/core/src/main/java/org/apache/karaf/features/internal/model/Features.java
new file mode 100644
index 0000000..e116f31
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/model/Features.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.karaf.features.internal.model;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * 
+ * Root element of Feature definition. It contains optional attribute which allow
+ * name of repository. This name will be used in shell to display source repository
+ * of given feature.
+ *             
+ * 
+ * <p>Java class for featuresRoot complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="features">
+ *   &lt;complexContent>
+ *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       &lt;sequence>
+ *         &lt;element name="repository" type="{http://www.w3.org/2001/XMLSchema}anyURI" maxOccurs="unbounded" minOccurs="0"/>
+ *         &lt;element name="feature" type="{http://karaf.apache.org/xmlns/features/v1.0.0}feature" maxOccurs="unbounded" minOccurs="0"/>
+ *       &lt;/sequence>
+ *       &lt;attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
+ *     &lt;/restriction>
+ *   &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlRootElement(name = "features")
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "features", propOrder = {
+    "repository",
+    "feature"
+})
+public class Features {
+
+    @XmlSchemaType(name = "anyURI")
+    protected List<String> repository;
+    protected List<Feature> feature;
+    @XmlAttribute
+    protected String name;
+
+    /**
+     * Gets the value of the repository property.
+     * 
+     * <p>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the repository property.
+     * 
+     * <p>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getRepository().add(newItem);
+     * </pre>
+     * 
+     * 
+     * <p>
+     * Objects of the following type(s) are allowed in the list
+     * {@link String }
+     * 
+     * 
+     */
+    public List<String> getRepository() {
+        if (repository == null) {
+            repository = new ArrayList<String>();
+        }
+        return this.repository;
+    }
+
+    /**
+     * Gets the value of the feature property.
+     * 
+     * <p>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the feature property.
+     * 
+     * <p>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getFeature().add(newItem);
+     * </pre>
+     * 
+     * 
+     * <p>
+     * Objects of the following type(s) are allowed in the list
+     * {@link Feature }
+     * 
+     * 
+     */
+    public List<Feature> getFeature() {
+        if (feature == null) {
+            feature = new ArrayList<Feature>();
+        }
+        return this.feature;
+    }
+
+    /**
+     * Gets the value of the name property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Sets the value of the name property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setName(String value) {
+        this.name = value;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java b/features/core/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java
new file mode 100644
index 0000000..2036452
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java
@@ -0,0 +1,224 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.features.internal.model;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.net.URL;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.xml.XMLConstants;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.namespace.QName;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.sax.SAXSource;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+
+import org.apache.karaf.features.FeaturesNamespaces;
+import org.apache.karaf.util.XmlUtils;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLFilter;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.XMLFilterImpl;
+
+public class JaxbUtil {
+
+    private static final JAXBContext FEATURES_CONTEXT;
+    static {
+        try {
+            FEATURES_CONTEXT = JAXBContext.newInstance(Features.class);
+        } catch (JAXBException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static void marshal(Features features, OutputStream out) throws JAXBException {
+        Marshaller marshaller = FEATURES_CONTEXT.createMarshaller();
+
+        marshaller.setProperty("jaxb.formatted.output", true);
+
+        marshaller.marshal(features, out);
+    }
+
+    public static void marshal(Features features, Writer out) throws JAXBException {
+        Marshaller marshaller = FEATURES_CONTEXT.createMarshaller();
+
+        marshaller.setProperty("jaxb.formatted.output", true);
+
+        marshaller.marshal(features, out);
+    }
+
+
+    /**
+     * Read in a Features from the input stream.
+     *
+     * @param uri      uri to read
+     * @param validate whether to validate the input.
+     * @return a Features read from the input stream
+     */
+    public static Features unmarshal(String uri, boolean validate) {
+        if (validate) {
+            return unmarshalValidate(uri, null);
+        } else {
+            return unmarshalNoValidate(uri, null);
+        }
+    }
+
+    public static Features unmarshal(String uri, InputStream stream, boolean validate) {
+        if (validate) {
+            return unmarshalValidate(uri, stream);
+        } else {
+            return unmarshalNoValidate(uri, stream);
+        }
+    }
+
+    private static Features unmarshalValidate(String uri, InputStream stream) {
+        try {
+            Document doc;
+            if (stream != null) {
+                doc = XmlUtils.parse(stream);
+                doc.setDocumentURI(uri);
+            } else {
+                doc = XmlUtils.parse(uri);
+            }
+
+            Schema schema = getSchema(doc.getDocumentElement().getNamespaceURI());
+            try {
+                schema.newValidator().validate(new DOMSource(doc));
+            } catch (SAXException e) {
+                throw new IllegalArgumentException("Unable to validate " + uri, e);
+            }
+
+            fixDom(doc, doc.getDocumentElement());
+            Unmarshaller unmarshaller = FEATURES_CONTEXT.createUnmarshaller();
+            return (Features) unmarshaller.unmarshal(new DOMSource(doc));
+
+
+        } catch (RuntimeException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new RuntimeException("Unable to load " + uri, e);
+        }
+    }
+
+    private static Map<String, Schema> schemas = new ConcurrentHashMap<String, Schema>();
+    private static Schema getSchema(String namespace) throws SAXException {
+        Schema schema = schemas.get(namespace);
+        if (schema == null) {
+            String schemaLocation;
+            if (FeaturesNamespaces.URI_1_0_0.equals(namespace)) {
+                schemaLocation = "/org/apache/karaf/features/karaf-features-1.0.0.xsd";
+            } else if (FeaturesNamespaces.URI_1_1_0.equals(namespace)) {
+                schemaLocation = "/org/apache/karaf/features/karaf-features-1.1.0.xsd";
+            } else if (FeaturesNamespaces.URI_1_2_0.equals(namespace)) {
+                schemaLocation = "/org/apache/karaf/features/karaf-features-1.2.0.xsd";
+            } else if (FeaturesNamespaces.URI_1_3_0.equals(namespace)) {
+                schemaLocation = "/org/apache/karaf/features/karaf-features-1.3.0.xsd";
+            } else {
+                throw new IllegalArgumentException("Unsupported namespace: " + namespace);
+            }
+
+            SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+            // root element has namespace - we can use schema validation
+            URL url = JaxbUtil.class.getResource(schemaLocation);
+            if (url == null) {
+                throw new IllegalStateException("Could not find resource: " + schemaLocation);
+            }
+            schema = factory.newSchema(new StreamSource(url.toExternalForm()));
+            schemas.put(namespace, schema);
+        }
+        return schema;
+    }
+
+
+    private static void fixDom(Document doc, Node node) {
+        if (node.getNamespaceURI() != null && !FeaturesNamespaces.URI_CURRENT.equals(node.getNamespaceURI())) {
+            doc.renameNode(node, FeaturesNamespaces.URI_CURRENT, node.getLocalName());
+        }
+        NodeList children = node.getChildNodes();
+        for (int i = 0; i < children.getLength(); i++) {
+            fixDom(doc, children.item(i));
+        }
+    }
+
+    private static Features unmarshalNoValidate(String uri, InputStream stream) {
+        try {
+            Unmarshaller unmarshaller = FEATURES_CONTEXT.createUnmarshaller();
+            XMLFilter xmlFilter = new NoSourceAndNamespaceFilter(XmlUtils.xmlReader());
+            xmlFilter.setContentHandler(unmarshaller.getUnmarshallerHandler());
+
+
+            InputSource is = new InputSource(uri);
+            if (stream != null) {
+                is.setByteStream(stream);
+            }
+            SAXSource source = new SAXSource(xmlFilter, new InputSource(uri));
+            return (Features) unmarshaller.unmarshal(source);
+
+        } catch (RuntimeException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new RuntimeException("Unable to load " + uri, e);
+        }
+    }
+
+    /**
+     * Provides an empty inputsource for the entity resolver.
+     * Converts all elements to the features namespace to make old feature files
+     * compatible to the new format
+     */
+    public static class NoSourceAndNamespaceFilter extends XMLFilterImpl {        
+        private static final InputSource EMPTY_INPUT_SOURCE = new InputSource(new ByteArrayInputStream(new byte[0]));
+
+        public NoSourceAndNamespaceFilter(XMLReader xmlReader) {
+            super(xmlReader);
+        }
+
+        @Override
+        public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
+            return EMPTY_INPUT_SOURCE;
+        }
+
+        @Override
+        public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
+            super.startElement(FeaturesNamespaces.URI_CURRENT, localName, qName, atts);
+        }
+
+        @Override
+        public void endElement(String uri, String localName, String qName) throws SAXException {
+            super.endElement(FeaturesNamespaces.URI_CURRENT, localName, qName);
+        }
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/model/ObjectFactory.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/model/ObjectFactory.java b/features/core/src/main/java/org/apache/karaf/features/internal/model/ObjectFactory.java
new file mode 100644
index 0000000..96fbb0f
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/model/ObjectFactory.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.karaf.features.internal.model;
+
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.annotation.XmlElementDecl;
+import javax.xml.bind.annotation.XmlRegistry;
+import javax.xml.namespace.QName;
+
+
+/**
+ * This object contains factory methods for each 
+ * Java content interface and Java element interface 
+ * generated in the org.apache.karaf.features.wrapper package.
+ * <p>An ObjectFactory allows you to programatically 
+ * construct new instances of the Java representation 
+ * for XML content. The Java representation of XML 
+ * content can consist of schema derived interfaces 
+ * and classes representing the binding of schema 
+ * type definitions, element declarations and model 
+ * groups.  Factory methods for each of these are 
+ * provided in this class.
+ * 
+ */
+@XmlRegistry
+public class ObjectFactory {
+
+    private final static QName _Features_QNAME = new QName("http://karaf.apache.org/xmlns/features/v1.0.0", "features");
+
+    /**
+     * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: org.apache.karaf.features.wrapper
+     * 
+     */
+    public ObjectFactory() {
+    }
+
+    /**
+     * Create an instance of {@link ConfigFile }
+     * 
+     */
+    public ConfigFile createConfigFile() {
+        return new ConfigFile();
+    }
+
+    /**
+     * Create an instance of {@link Dependency }
+     * 
+     */
+    public Dependency createDependency() {
+        return new Dependency();
+    }
+
+    /**
+     * Create an instance of {@link Bundle }
+     * 
+     */
+    public Bundle createBundle() {
+        return new Bundle();
+    }
+
+    /**
+     * Create an instance of {@link Features }
+     * 
+     */
+    public Features createFeaturesRoot() {
+        return new Features();
+    }
+
+    /**
+     * Create an instance of {@link Config }
+     * 
+     */
+    public Config createConfig() {
+        return new Config();
+    }
+
+    /**
+     * Create an instance of {@link Feature }
+     * 
+     */
+    public Feature createFeature() {
+        return new Feature();
+    }
+
+    /**
+     * Create an instance of {@link JAXBElement }{@code <}{@link Features }{@code >}}
+     * 
+     */
+    @XmlElementDecl(namespace = "http://karaf.apache.org/xmlns/features/v1.0.0", name = "features")
+    public JAXBElement<Features> createFeatures(Features value) {
+        return new JAXBElement<Features>(_Features_QNAME, Features.class, null, value);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/model/Requirement.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/model/Requirement.java b/features/core/src/main/java/org/apache/karaf/features/internal/model/Requirement.java
new file mode 100644
index 0000000..f7b5775
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/model/Requirement.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+package org.apache.karaf.features.internal.model;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+
+
+/**
+ * 
+ * Additional requirement for a feature.
+ *             
+ * 
+ * <p>Java class for bundle complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="capability">
+ *   &lt;simpleContent>
+ *     &lt;extension base="&lt;http://www.w3.org/2001/XMLSchema>string">
+ *     &lt;/extension>
+ *   &lt;/simpleContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "requirement", propOrder = {
+    "value"
+})
+public class Requirement implements org.apache.karaf.features.Requirement {
+
+    @XmlValue
+    protected String value;
+
+
+    public Requirement() {
+    }
+
+    public Requirement(String value) {
+        this.value = value;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Requirement bundle = (Requirement) o;
+
+        if (value != null ? !value.equals(bundle.value) : bundle.value != null) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = value != null ? value.hashCode() : 0;
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/model/package-info.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/model/package-info.java b/features/core/src/main/java/org/apache/karaf/features/internal/model/package-info.java
new file mode 100644
index 0000000..c86a58c
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/model/package-info.java
@@ -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.
+ */
+
+@javax.xml.bind.annotation.XmlSchema(namespace = org.apache.karaf.features.FeaturesNamespaces.URI_CURRENT, elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
+package org.apache.karaf.features.internal.model;

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/osgi/Activator.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/osgi/Activator.java b/features/core/src/main/java/org/apache/karaf/features/internal/osgi/Activator.java
new file mode 100644
index 0000000..be0da05
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/osgi/Activator.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.karaf.features.internal.osgi;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import org.apache.karaf.features.FeaturesListener;
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.internal.service.EventAdminListener;
+import org.apache.karaf.features.internal.service.FeatureConfigInstaller;
+import org.apache.karaf.features.internal.service.FeatureFinder;
+import org.apache.karaf.features.internal.service.BootFeaturesInstaller;
+import org.apache.karaf.features.internal.service.FeaturesServiceImpl;
+import org.apache.karaf.features.internal.service.StateStorage;
+import org.apache.karaf.features.internal.management.FeaturesServiceMBeanImpl;
+import org.apache.karaf.features.RegionsPersistence;
+import org.apache.karaf.util.tracker.BaseActivator;
+import org.apache.karaf.util.tracker.SingleServiceTracker;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.service.url.URLStreamHandlerService;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+
+public class Activator extends BaseActivator {
+
+    public static final String FEATURES_REPOS_PID = "org.apache.karaf.features.repos";
+    public static final String FEATURES_SERVICE_CONFIG_FILE = "org.apache.karaf.features.cfg";
+
+    private ServiceTracker<FeaturesListener, FeaturesListener> featuresListenerTracker;
+    private FeaturesServiceImpl featuresService;
+    private SingleServiceTracker<RegionsPersistence> regionsTracker;
+
+    public Activator() {
+        // Special case here, as we don't want the activator to wait for current job to finish,
+        // else it would forbid the features service to refresh itself
+        setSchedulerStopTimeout(0);
+    }
+
+    @Override
+    protected void doOpen() throws Exception {
+        trackService(URLStreamHandlerService.class, "(url.handler.protocol=mvn)");
+        trackService(ConfigurationAdmin.class);
+
+        Properties configuration = new Properties();
+        File configFile = new File(System.getProperty("karaf.etc"), FEATURES_SERVICE_CONFIG_FILE);
+        if (configFile.isFile() && configFile.canRead()) {
+            try {
+                configuration.load(new FileReader(configFile));
+            } catch (IOException e) {
+                logger.warn("Error reading configuration file " + configFile.toString(), e);
+            }
+        }
+        updated((Dictionary) configuration);
+    }
+
+    protected void doStart() throws Exception {
+        ConfigurationAdmin configurationAdmin = getTrackedService(ConfigurationAdmin.class);
+        URLStreamHandlerService mvnUrlHandler = getTrackedService(URLStreamHandlerService.class);
+
+        if (configurationAdmin == null || mvnUrlHandler == null) {
+            return;
+        }
+
+        FeatureFinder featureFinder = new FeatureFinder();
+        Hashtable<String, Object> props = new Hashtable<String, Object>();
+        props.put(Constants.SERVICE_PID, FEATURES_REPOS_PID);
+        register(ManagedService.class, featureFinder, props);
+
+        // TODO: region support
+//        final BundleManager bundleManager = new BundleManager(bundleContext);
+//        regionsTracker = new SingleServiceTracker<RegionsPersistence>(bundleContext, RegionsPersistence.class,
+//                new SingleServiceTracker.SingleServiceListener() {
+//                    @Override
+//                    public void serviceFound() {
+//                        bundleManager.setRegionsPersistence(regionsTracker.getService());
+//                    }
+//                    @Override
+//                    public void serviceLost() {
+//                        serviceFound();
+//                    }
+//                    @Override
+//                    public void serviceReplaced() {
+//                        serviceFound();
+//                    }
+//                });
+//        regionsTracker.open();
+
+
+        FeatureConfigInstaller configInstaller = new FeatureConfigInstaller(configurationAdmin);
+        // TODO: honor respectStartLvlDuringFeatureStartup and respectStartLvlDuringFeatureUninstall
+//        boolean respectStartLvlDuringFeatureStartup = getBoolean("respectStartLvlDuringFeatureStartup", true);
+//        boolean respectStartLvlDuringFeatureUninstall = getBoolean("respectStartLvlDuringFeatureUninstall", true);
+        String overrides = getString("overrides", new File(System.getProperty("karaf.etc"), "overrides.properties").toURI().toString());
+        String featureResolutionRange = getString("featureResolutionRange", FeaturesServiceImpl.DEFAULT_FEATURE_RESOLUTION_RANGE);
+        String bundleUpdateRange = getString("bundleUpdateRange", FeaturesServiceImpl.DEFAULT_BUNDLE_UPDATE_RANGE);
+        String updateSnapshots = getString("updateSnapshots", FeaturesServiceImpl.DEFAULT_UPDATE_SNAPSHOTS);
+        StateStorage stateStorage = new StateStorage() {
+            @Override
+            protected InputStream getInputStream() throws IOException {
+                File file = bundleContext.getDataFile("FeaturesServiceState.properties");
+                if (file.exists()) {
+                    return new FileInputStream(file);
+                } else {
+                    return null;
+                }
+            }
+
+            @Override
+            protected OutputStream getOutputStream() throws IOException {
+                File file = bundleContext.getDataFile("FeaturesServiceState.properties");
+                return new FileOutputStream(file);
+            }
+        };
+        EventAdminListener eventAdminListener;
+        try {
+            eventAdminListener = new EventAdminListener(bundleContext);
+        } catch (Throwable t) {
+            eventAdminListener = null;
+        }
+        featuresService = new FeaturesServiceImpl(
+                                bundleContext.getBundle(),
+                                bundleContext.getBundle(0).getBundleContext(),
+                                stateStorage,
+                                featureFinder,
+                                eventAdminListener,
+                                configInstaller,
+                                overrides,
+                                featureResolutionRange,
+                                bundleUpdateRange,
+                                updateSnapshots);
+        register(FeaturesService.class, featuresService);
+
+        featuresListenerTracker = new ServiceTracker<FeaturesListener, FeaturesListener>(
+                bundleContext, FeaturesListener.class, new ServiceTrackerCustomizer<FeaturesListener, FeaturesListener>() {
+            @Override
+            public FeaturesListener addingService(ServiceReference<FeaturesListener> reference) {
+                FeaturesListener service = bundleContext.getService(reference);
+                featuresService.registerListener(service);
+                return service;
+            }
+            @Override
+            public void modifiedService(ServiceReference<FeaturesListener> reference, FeaturesListener service) {
+            }
+            @Override
+            public void removedService(ServiceReference<FeaturesListener> reference, FeaturesListener service) {
+                featuresService.unregisterListener(service);
+                bundleContext.ungetService(reference);
+            }
+        }
+        );
+        featuresListenerTracker.open();
+
+        String featuresRepositories = getString("featuresRepositories", "");
+        String featuresBoot = getString("featuresBoot", "");
+        boolean featuresBootAsynchronous = getBoolean("featuresBootAsynchronous", false);
+        BootFeaturesInstaller bootFeaturesInstaller = new BootFeaturesInstaller(
+                bundleContext, featuresService,
+                featuresRepositories, featuresBoot, featuresBootAsynchronous);
+        bootFeaturesInstaller.start();
+
+        FeaturesServiceMBeanImpl featuresServiceMBean = new FeaturesServiceMBeanImpl();
+        featuresServiceMBean.setBundleContext(bundleContext);
+        featuresServiceMBean.setFeaturesService(featuresService);
+        registerMBean(featuresServiceMBean, "type=feature");
+    }
+
+    protected void doStop() {
+        if (regionsTracker != null) {
+            regionsTracker.close();
+            regionsTracker = null;
+        }
+        if (featuresListenerTracker != null) {
+            featuresListenerTracker.close();
+            featuresListenerTracker = null;
+        }
+        super.doStop();
+        if (featuresService != null) {
+            featuresService = null;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/repository/AggregateRepository.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/repository/AggregateRepository.java b/features/core/src/main/java/org/apache/karaf/features/internal/repository/AggregateRepository.java
new file mode 100644
index 0000000..0d5e83d
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/repository/AggregateRepository.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.karaf.features.internal.repository;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.osgi.resource.Capability;
+import org.osgi.resource.Requirement;
+import org.osgi.service.repository.Repository;
+
+public class AggregateRepository implements Repository {
+
+    private final Collection<Repository> repositories;
+
+    public AggregateRepository(Collection<Repository> repositories) {
+        this.repositories = repositories;
+    }
+
+    @Override
+    public Map<Requirement, Collection<Capability>> findProviders(Collection<? extends Requirement> requirements) {
+        Map<Requirement, Collection<Capability>> result = new HashMap<Requirement, Collection<Capability>>();
+        for (Requirement requirement : requirements) {
+            List<Capability> caps = new ArrayList<Capability>();
+            for (Repository repository : repositories) {
+                Map<Requirement, Collection<Capability>> resMap =
+                        repository.findProviders(Collections.singleton(requirement));
+                Collection<Capability> res = resMap != null ? resMap.get(requirement) : null;
+                if (res != null) {
+                    caps.addAll(res);
+                }
+            }
+            result.put(requirement, caps);
+        }
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/repository/BaseRepository.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/repository/BaseRepository.java b/features/core/src/main/java/org/apache/karaf/features/internal/repository/BaseRepository.java
new file mode 100644
index 0000000..c4c0d16
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/repository/BaseRepository.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.karaf.features.internal.repository;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.karaf.features.internal.resolver.CapabilitySet;
+import org.apache.karaf.features.internal.resolver.RequirementImpl;
+import org.apache.karaf.features.internal.resolver.SimpleFilter;
+import org.osgi.framework.Constants;
+import org.osgi.resource.Capability;
+import org.osgi.resource.Requirement;
+import org.osgi.resource.Resource;
+import org.osgi.service.repository.Repository;
+
+/**
+ */
+public class BaseRepository implements Repository {
+
+    protected final List<Resource> resources;
+    protected final Map<String, CapabilitySet> capSets;
+
+    public BaseRepository() {
+        this.resources = new ArrayList<Resource>();
+        this.capSets = new HashMap<String, CapabilitySet>();
+    }
+
+    protected void addResource(Resource resource) {
+        for (Capability cap : resource.getCapabilities(null)) {
+            String ns = cap.getNamespace();
+            CapabilitySet set = capSets.get(ns);
+            if (set == null) {
+                set = new CapabilitySet(Collections.singletonList(ns));
+                capSets.put(ns, set);
+            }
+            set.addCapability(cap);
+        }
+        resources.add(resource);
+    }
+
+    public List<Resource> getResources() {
+        return resources;
+    }
+
+    @Override
+    public Map<Requirement, Collection<Capability>> findProviders(Collection<? extends Requirement> requirements) {
+        Map<Requirement, Collection<Capability>> result = new HashMap<Requirement, Collection<Capability>>();
+        for (Requirement requirement : requirements) {
+            CapabilitySet set = capSets.get(requirement.getNamespace());
+            if (set != null) {
+                SimpleFilter sf;
+                if (requirement instanceof RequirementImpl) {
+                    sf = ((RequirementImpl) requirement).getFilter();
+                } else {
+                    String filter = requirement.getDirectives().get(Constants.FILTER_DIRECTIVE);
+                    sf = (filter != null)
+                            ? SimpleFilter.parse(filter)
+                            : new SimpleFilter(null, null, SimpleFilter.MATCH_ALL);
+                }
+                result.put(requirement, set.match(sf, true));
+            } else {
+                result.put(requirement, Collections.<Capability>emptyList());
+            }
+        }
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/repository/CacheRepository.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/repository/CacheRepository.java b/features/core/src/main/java/org/apache/karaf/features/internal/repository/CacheRepository.java
new file mode 100644
index 0000000..7916821
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/repository/CacheRepository.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.karaf.features.internal.repository;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.osgi.resource.Capability;
+import org.osgi.resource.Requirement;
+import org.osgi.service.repository.Repository;
+
+public class CacheRepository implements Repository {
+
+    private final Repository repository;
+    private final Map<Requirement, Collection<Capability>> cache =
+            new ConcurrentHashMap<Requirement, Collection<Capability>>();
+
+    public CacheRepository(Repository repository) {
+        this.repository = repository;
+    }
+
+    @Override
+    public Map<Requirement, Collection<Capability>> findProviders(Collection<? extends Requirement> requirements) {
+        List<Requirement> missing = new ArrayList<Requirement>();
+        Map<Requirement, Collection<Capability>> result = new HashMap<Requirement, Collection<Capability>>();
+        for (Requirement requirement : requirements) {
+            Collection<Capability> caps = cache.get(requirement);
+            if (caps == null) {
+                missing.add(requirement);
+            } else {
+                result.put(requirement, caps);
+            }
+        }
+        Map<Requirement, Collection<Capability>> newCache = repository.findProviders(missing);
+        for (Requirement requirement : newCache.keySet()) {
+            cache.put(requirement, newCache.get(requirement));
+            result.put(requirement, newCache.get(requirement));
+        }
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/repository/HttpMetadataProvider.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/repository/HttpMetadataProvider.java b/features/core/src/main/java/org/apache/karaf/features/internal/repository/HttpMetadataProvider.java
new file mode 100644
index 0000000..1aecef1
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/repository/HttpMetadataProvider.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.repository;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.Map;
+import java.util.zip.GZIPInputStream;
+
+import org.apache.karaf.features.internal.util.JsonReader;
+
+/**
+ */
+public class HttpMetadataProvider implements MetadataProvider {
+
+    public static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding";
+    public static final String HEADER_CONTENT_ENCODING = "Content-Encoding";
+    public static final String GZIP = "gzip";
+
+    private final String url;
+    private long lastModified;
+    private Map<String, Map<String, String>> metadatas;
+
+    public HttpMetadataProvider(String url) {
+        this.url = url;
+    }
+
+    @Override
+    public long getLastModified() {
+        return lastModified;
+    }
+
+    @Override
+    public Map<String, Map<String, String>> getMetadatas() {
+        try {
+            HttpURLConnection.setFollowRedirects(false);
+            HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
+            if (lastModified > 0) {
+                con.setIfModifiedSince(lastModified);
+            }
+            con.setRequestProperty(HEADER_ACCEPT_ENCODING, GZIP);
+            if (con.getResponseCode() == HttpURLConnection.HTTP_OK) {
+                lastModified = con.getLastModified();
+                InputStream is = con.getInputStream();
+                if (GZIP.equals(con.getHeaderField(HEADER_CONTENT_ENCODING))) {
+                    is = new GZIPInputStream(is);
+                }
+                metadatas = verify(JsonReader.read(is));
+            } else if (con.getResponseCode() != HttpURLConnection.HTTP_NOT_MODIFIED) {
+                throw new IOException("Unexpected http response: "
+                        + con.getResponseCode() + " " + con.getResponseMessage());
+            }
+            return metadatas;
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private Map<String, Map<String, String>> verify(Object value) {
+        Map<?,?> obj = Map.class.cast(value);
+        for (Map.Entry<?,?> entry : obj.entrySet()) {
+            String.class.cast(entry.getKey());
+            Map<?,?> child = Map.class.cast(entry.getValue());
+            for (Map.Entry<?,?> ce : child.entrySet()) {
+                String.class.cast(ce.getKey());
+                String.class.cast(ce.getValue());
+            }
+        }
+        return (Map<String, Map<String, String>>) obj;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/repository/MetadataProvider.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/repository/MetadataProvider.java b/features/core/src/main/java/org/apache/karaf/features/internal/repository/MetadataProvider.java
new file mode 100644
index 0000000..9ac54a1
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/repository/MetadataProvider.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.karaf.features.internal.repository;
+
+import java.util.Map;
+
+/**
+ */
+public interface MetadataProvider {
+
+    long getLastModified();
+
+    Map<String, Map<String, String>> getMetadatas();
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/repository/MetadataRepository.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/repository/MetadataRepository.java b/features/core/src/main/java/org/apache/karaf/features/internal/repository/MetadataRepository.java
new file mode 100644
index 0000000..2d4fbba
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/repository/MetadataRepository.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.karaf.features.internal.repository;
+
+import java.util.Map;
+
+import org.apache.karaf.features.internal.resolver.ResourceBuilder;
+import org.osgi.resource.Resource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ */
+public class MetadataRepository extends BaseRepository {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(MetadataRepository.class);
+
+    public MetadataRepository(MetadataProvider provider) {
+        Map<String, Map<String, String>> metadatas = provider.getMetadatas();
+        for (Map.Entry<String, Map<String, String>> metadata : metadatas.entrySet()) {
+            try {
+                Resource resource = ResourceBuilder.build(metadata.getKey(), metadata.getValue());
+                addResource(resource);
+            } catch (Exception e) {
+                LOGGER.info("Unable to build resource for " + metadata.getKey(), e);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/repository/StaticRepository.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/repository/StaticRepository.java b/features/core/src/main/java/org/apache/karaf/features/internal/repository/StaticRepository.java
new file mode 100644
index 0000000..f289c8d
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/repository/StaticRepository.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.karaf.features.internal.repository;
+
+import java.util.Collection;
+
+import org.osgi.resource.Resource;
+
+/**
+ */
+public class StaticRepository extends BaseRepository {
+
+    public StaticRepository(Collection<Resource> resources) {
+        for (Resource resource : resources) {
+            addResource(resource);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/resolver/BaseClause.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/BaseClause.java b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/BaseClause.java
new file mode 100644
index 0000000..0653398
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/BaseClause.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.resolver;
+
+import java.util.Map;
+
+import org.osgi.framework.Version;
+import org.osgi.resource.Resource;
+
+/**
+ */
+public abstract class BaseClause {
+
+    public abstract Resource getResource();
+
+    public abstract String getNamespace();
+
+    public abstract Map<String, String> getDirectives();
+
+    public abstract Map<String, Object> getAttributes();
+
+    @Override
+    public String toString() {
+        return toString(getResource(), getNamespace(), getAttributes(), getDirectives());
+    }
+
+    public static String toString(Resource res, String namespace, Map<String, Object> attrs, Map<String, String> dirs) {
+        StringBuilder sb = new StringBuilder();
+        if (res != null) {
+            sb.append("[").append(res).append("] ");
+        }
+        sb.append(namespace);
+        for (String key : attrs.keySet()) {
+            sb.append("; ");
+            append(sb, key, attrs.get(key), true);
+        }
+        for (String key : dirs.keySet()) {
+            sb.append("; ");
+            append(sb, key, dirs.get(key), false);
+        }
+        return sb.toString();
+    }
+
+    private static void append(StringBuilder sb, String key, Object val, boolean attribute) {
+        sb.append(key);
+        if (val instanceof Version) {
+            sb.append(":Version=");
+            sb.append(val);
+        } else if (val instanceof Long) {
+            sb.append(":Long=");
+            sb.append(val);
+        } else if (val instanceof Double) {
+            sb.append(":Double=");
+            sb.append(val);
+        } else if (val instanceof Iterable) {
+            Iterable it = (Iterable) val;
+            String scalar = null;
+            for (Object o : it) {
+                String ts;
+                if (o instanceof String) {
+                    ts = "String";
+                } else if (o instanceof Long) {
+                    ts = "Long";
+                } else if (o instanceof Double) {
+                    ts = "Double";
+                } else if (o instanceof Version) {
+                    ts = "Version";
+                } else {
+                    throw new IllegalArgumentException("Unsupported scalar type: " + o);
+                }
+                if (scalar == null) {
+                    scalar = ts;
+                } else if (!scalar.equals(ts)) {
+                    throw new IllegalArgumentException("Unconsistent list type for attribute " + key);
+                }
+            }
+            sb.append(":List<").append(scalar).append(">=");
+            sb.append("\"");
+            boolean first = true;
+            for (Object o : it) {
+                if (first) {
+                    first = false;
+                } else {
+                    sb.append(",");
+                }
+                sb.append(o.toString().replace("\"", "\\\"").replace(",", "\\,"));
+            }
+            sb.append("\"");
+        } else {
+            sb.append(attribute ? "=" : ":=");
+            String s = val.toString();
+            if (s.matches("[0-9a-zA-Z_\\-.]*")) {
+                sb.append(s);
+            } else {
+                sb.append("\"").append(s.replace("\"", "\\\\")).append("\"");
+            }
+        }
+    }
+
+}


[23/33] Revert "[KARAF-2852] Merge features/core and features/command"

Posted by gn...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/FeaturesService.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/FeaturesService.java b/features/src/main/java/org/apache/karaf/features/FeaturesService.java
deleted file mode 100644
index ef3dbcf..0000000
--- a/features/src/main/java/org/apache/karaf/features/FeaturesService.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features;
-
-import java.net.URI;
-import java.util.EnumSet;
-import java.util.Set;
-
-/**
- * The service managing features repositories.
- */
-public interface FeaturesService {
-
-    enum Option {
-        NoFailOnFeatureNotFound,
-        NoAutoRefreshManagedBundles,
-        NoAutoRefreshUnmanagedBundles,
-        NoAutoRefreshBundles,
-        NoAutoStartBundles,
-        Simulate,
-        Verbose
-    }
-
-    /**
-     * Validate repository contents.
-     * 
-     * @param uri Repository uri.
-     * @throws Exception When validation fails.
-     */
-    void validateRepository(URI uri) throws Exception;
-
-    void addRepository(URI uri) throws Exception;
-
-    void addRepository(URI uri, boolean install) throws Exception;
-
-    void removeRepository(URI uri) throws Exception;
-
-    void removeRepository(URI uri, boolean uninstall) throws Exception;
-    
-    void restoreRepository(URI uri) throws Exception;
-
-    Repository[] listRequiredRepositories() throws Exception;
-
-    Repository[] listRepositories() throws Exception;
-    
-    Repository getRepository(String repoName) throws Exception;
-
-    void installFeature(String name) throws Exception;
-
-    void installFeature(String name, EnumSet<Option> options) throws Exception;
-    
-    void installFeature(String name, String version) throws Exception;
-
-    void installFeature(String name, String version, EnumSet<Option> options) throws Exception;
-
-    void installFeature(Feature f, EnumSet<Option> options) throws Exception;
-
-    void installFeatures(Set<String> features, EnumSet<Option> options) throws Exception;
-
-    void uninstallFeature(String name, EnumSet<Option> options) throws Exception;
-
-    void uninstallFeature(String name) throws Exception;
-
-    void uninstallFeature(String name, String version, EnumSet<Option> options) throws Exception;
-    
-    void uninstallFeature(String name, String version) throws Exception;
-
-    void uninstallFeatures(Set<String> features, EnumSet<Option> options) throws Exception;
-
-    Feature[] listFeatures() throws Exception;
-
-    Feature[] listRequiredFeatures() throws Exception;
-
-    Feature[] listInstalledFeatures() throws Exception;
-
-    boolean isRequired(Feature f);
-
-    boolean isInstalled(Feature f);
-
-    Feature getFeature(String name, String version) throws Exception;
-
-    Feature getFeature(String name) throws Exception;
-
-	void refreshRepository(URI uri) throws Exception;
-
-    public URI getRepositoryUriFor(String name, String version);
-
-    public String[] getRepositoryNames();
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/RegionsPersistence.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/RegionsPersistence.java b/features/src/main/java/org/apache/karaf/features/RegionsPersistence.java
deleted file mode 100644
index 96ca7da..0000000
--- a/features/src/main/java/org/apache/karaf/features/RegionsPersistence.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.karaf.features;
-
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleException;
-
-public interface RegionsPersistence {
-    void install(Bundle b, String regionName) throws BundleException;
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/Repository.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/Repository.java b/features/src/main/java/org/apache/karaf/features/Repository.java
deleted file mode 100644
index 3ea12ec..0000000
--- a/features/src/main/java/org/apache/karaf/features/Repository.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features;
-
-import java.io.IOException;
-import java.net.URI;
-
-/**
- * A repository of features.
- */
-public interface Repository {
-
-    String getName() throws IOException;
-
-    URI getURI();
-
-    URI[] getRepositories() throws Exception;
-
-    Feature[] getFeatures() throws Exception;
-    
-    boolean isValid();
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/RepositoryEvent.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/RepositoryEvent.java b/features/src/main/java/org/apache/karaf/features/RepositoryEvent.java
deleted file mode 100644
index 68f287b..0000000
--- a/features/src/main/java/org/apache/karaf/features/RepositoryEvent.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features;
-
-import java.util.EventObject;
-
-public class RepositoryEvent extends EventObject {
-
-    public static enum EventType {
-        RepositoryAdded,
-        RepositoryRemoved,
-    }
-
-    private final EventType type;
-    private final Repository repository;
-    private final boolean replay;
-
-    public RepositoryEvent(Repository repository, EventType type, boolean replay) {
-        super(repository);
-        this.type = type;
-        this.repository = repository;
-        this.replay = replay;
-    }
-
-    public EventType getType() {
-        return type;
-    }
-
-    public Repository getRepository() {
-        return repository;
-    }
-
-    public boolean isReplay() {
-        return replay;
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/Requirement.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/Requirement.java b/features/src/main/java/org/apache/karaf/features/Requirement.java
deleted file mode 100644
index 4446335..0000000
--- a/features/src/main/java/org/apache/karaf/features/Requirement.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features;
-
-public interface Requirement {
-
-    String getValue();
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/Resolver.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/Resolver.java b/features/src/main/java/org/apache/karaf/features/Resolver.java
deleted file mode 100644
index d2fa941..0000000
--- a/features/src/main/java/org/apache/karaf/features/Resolver.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features;
-
-import java.util.List;
-
-public interface Resolver {
-
-    List<BundleInfo> resolve(Feature feature) throws Exception;
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/command/FeaturesCommandSupport.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/command/FeaturesCommandSupport.java b/features/src/main/java/org/apache/karaf/features/command/FeaturesCommandSupport.java
deleted file mode 100644
index 076650d..0000000
--- a/features/src/main/java/org/apache/karaf/features/command/FeaturesCommandSupport.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.command;
-
-import org.apache.karaf.features.FeaturesService;
-import org.apache.karaf.shell.api.action.Action;
-import org.apache.karaf.shell.api.action.lifecycle.Reference;
-
-public abstract class FeaturesCommandSupport implements Action {
-
-    @Reference
-    private FeaturesService featuresService;
-
-    @Override
-    public Object execute() throws Exception {
-        if (featuresService == null) {
-            throw new IllegalStateException("FeaturesService not found");
-        }
-        doExecute(featuresService);
-        return null;
-    }
-
-    protected abstract void doExecute(FeaturesService admin) throws Exception;
-
-    public void setFeaturesService(FeaturesService featuresService) {
-        this.featuresService = featuresService;
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/command/InfoFeatureCommand.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/command/InfoFeatureCommand.java b/features/src/main/java/org/apache/karaf/features/command/InfoFeatureCommand.java
deleted file mode 100644
index 5ad855c..0000000
--- a/features/src/main/java/org/apache/karaf/features/command/InfoFeatureCommand.java
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.command;
-
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.karaf.features.BundleInfo;
-import org.apache.karaf.features.Conditional;
-import org.apache.karaf.features.ConfigFileInfo;
-import org.apache.karaf.features.Dependency;
-import org.apache.karaf.features.Feature;
-import org.apache.karaf.features.FeaturesService;
-import org.apache.karaf.features.command.completers.AllFeatureCompleter;
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.Completion;
-import org.apache.karaf.shell.api.action.Option;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-
-@Command(scope = "feature", name = "info", description = "Shows information about selected feature.")
-@Service
-public class InfoFeatureCommand extends FeaturesCommandSupport {
-
-    private static final String INDENT = "  ";
-    private static final String FEATURE_CONTENT = "Feature";
-    private static final String CONDITIONAL_CONTENT = "Conditional(%s)";
-
-	@Argument(index = 0, name = "name", description = "The name of the feature", required = true, multiValued = false)
-    @Completion(AllFeatureCompleter.class)
-    private String name;
-
-    @Argument(index = 1, name = "version", description = "The version of the feature", required = false, multiValued = false)
-    private String version;
-
-    @Option(name = "-c", aliases={"--configuration"}, description="Display configuration info", required = false, multiValued = false)
-    private boolean config;
-
-    @Option(name = "-d", aliases={"--dependency"}, description="Display dependencies info", required = false, multiValued = false)
-    private boolean dependency;
-
-    @Option(name = "-b", aliases={"--bundle"}, description="Display bundles info", required = false, multiValued = false)
-    private boolean bundle;
-
-    @Option(name = "--conditional", description="Display conditional info", required = false, multiValued = false)
-    private boolean conditional;
-
-    @Option(name = "-t", aliases={"--tree"}, description="Display feature tree", required = false, multiValued = false)
-    private boolean tree;
-
-    protected void doExecute(FeaturesService admin) throws Exception {
-        Feature feature = null;
-
-        if (version != null && version.length() > 0) {
-            feature = admin.getFeature(name, version);
-        } else {
-            feature = admin.getFeature(name);
-        }
-
-        if (feature == null) {
-            System.out.println("Feature not found");
-            return;
-        }
-
-        // default behavior
-        if (!config && !dependency && !bundle && !conditional) {
-            config = true;
-            dependency = true;
-            bundle = true;
-            conditional = true;
-        }
-
-        System.out.println("Feature " + feature.getName() + " " + feature.getVersion());
-        if (feature.getDescription() != null) {
-        	System.out.println("Description:");
-        	System.out.println(INDENT + feature.getDescription());
-        }
-        
-        if(feature.getDetails() != null) {
-        	System.out.println("Details:");
-        	printWithIndent(feature.getDetails());
-        }
-
-        if (config) {
-            displayConfigInformation(feature, FEATURE_CONTENT);
-            displayConfigFileInformation(feature, FEATURE_CONTENT);
-        }
-
-        if (dependency) {
-            displayDependencyInformation(feature, FEATURE_CONTENT);
-        }
-
-        if (bundle) {
-            displayBundleInformation(feature, FEATURE_CONTENT);
-        }
-
-        if(conditional) {
-           displayConditionalInfo(feature);
-        }
-
-        if (tree) {
-            if (config || dependency || bundle) {
-                System.out.println("\nFeature tree");
-            }
-
-            int unresolved = displayFeatureTree(admin, feature.getName(), feature.getVersion(), "");
-            if (unresolved > 0) {
-                System.out.println("Tree contains " + unresolved + " unresolved dependencies");
-                System.out.println(" * means that node declares dependency but the dependent feature is not available.");
-            }
-        }
-    }
-
-    private void printWithIndent(String details) {
-    	String[] lines = details.split("\r?\n");
-    	for (String line : lines) {
-			System.out.println(INDENT + line);
-		}
-	}
-
-	private void displayBundleInformation(Feature feature, String contentType) {
-        List<BundleInfo> bundleInfos = feature.getBundles();
-        if (bundleInfos.isEmpty()) {
-            System.out.println(contentType + " has no bundles.");
-        } else {
-            System.out.println(contentType + " contains followed bundles:");
-            for (BundleInfo featureBundle : bundleInfos) {
-                int startLevel = featureBundle.getStartLevel();
-                StringBuilder sb = new StringBuilder();
-                sb.append(INDENT).append(featureBundle.getLocation());
-                if(startLevel > 0) {
-                    sb.append(" start-level=").append(startLevel);
-                }
-                System.out.println(sb.toString());
-            }
-        }
-    }
-
-    private void displayDependencyInformation(Feature feature, String contentType) {
-        List<Dependency> dependencies = feature.getDependencies();
-        if (dependencies.isEmpty()) {
-            System.out.println(contentType + " has no dependencies.");
-        } else {
-            System.out.println(contentType + " depends on:");
-            for (Dependency featureDependency : dependencies) {
-                System.out.println(INDENT + featureDependency.getName() + " " + featureDependency.getVersion());
-            }
-        }
-    }
-
-    private void displayConfigInformation(Feature feature, String contentType) {
-        Map<String, Map<String, String>> configurations = feature.getConfigurations();
-        if (configurations.isEmpty()) {
-            System.out.println(contentType + " has no configuration");
-        } else {
-            System.out.println(contentType + " configuration:");
-            for (String name : configurations.keySet()) {
-                System.out.println(INDENT + name);
-            }
-        }
-    }
-    
-    private void displayConfigFileInformation(Feature feature, String contentType) {
-    	List<ConfigFileInfo> configurationFiles = feature.getConfigurationFiles();
-    	if (configurationFiles.isEmpty()) {
-    		System.out.println(contentType + " has no configuration files");
-    	} else {
-    		System.out.println(contentType + " configuration files: ");
-    		for (ConfigFileInfo configFileInfo : configurationFiles) {
-				System.out.println(INDENT + configFileInfo.getFinalname());
-			}
-    	}    	
-    }
-
-    /**
-     * Called originally with featureName and featureVersion that have already been resolved successfully.
-     *
-     * @param admin
-     * @param featureName
-     * @param featureVersion
-     * @param prefix
-     * @return
-     * @throws Exception
-     */
-    private int displayFeatureTree(FeaturesService admin, String featureName, String featureVersion, String prefix) throws Exception {
-        int unresolved = 0;
-
-        Feature resolved = admin.getFeature(featureName, featureVersion);
-        if (resolved != null) {
-            System.out.println(prefix + " " + resolved.getName() + " " + resolved.getVersion());
-        } else {
-            System.out.println(prefix + " " + featureName + " " + featureVersion + " *");
-            unresolved++;
-        }
-
-        if (resolved != null) {
-            if (bundle) {
-                List<String> bundleLocation = new LinkedList<String>();
-                List<BundleInfo> bundles = resolved.getBundles();
-                for (BundleInfo bundleInfo : bundles) {
-                    bundleLocation.add(bundleInfo.getLocation());
-                }
-
-                if (conditional) {
-                    for (Conditional cond : resolved.getConditional()) {
-                        List<String> condition = cond.getCondition();
-                        List<BundleInfo> conditionalBundles = cond.getBundles();
-                        for (BundleInfo bundleInfo : conditionalBundles) {
-                            bundleLocation.add(bundleInfo.getLocation() + "(condition:"+condition+")");
-                        }
-                    }
-                }
-                for (int i = 0, j = bundleLocation.size(); i < j; i++) {
-                    System.out.println(prefix + " " + (i + 1 == j ? "\\" : "+") + " " + bundleLocation.get(i));
-                }
-            }
-            prefix += "   ";
-            List<Dependency> dependencies = resolved.getDependencies();
-            for (int i = 0, j = dependencies.size(); i < j; i++) {
-                Dependency toDisplay =  dependencies.get(i);
-                unresolved += displayFeatureTree(admin, toDisplay.getName(), toDisplay.getVersion(), prefix +1);
-            }
-
-            if (conditional) {
-                for (Conditional cond : resolved.getConditional()) {
-                    List<Dependency> conditionDependencies = cond.getDependencies();
-                    for (int i = 0, j = conditionDependencies.size(); i < j; i++) {
-                        Dependency toDisplay =  dependencies.get(i);
-                        unresolved += displayFeatureTree(admin, toDisplay.getName(), toDisplay.getVersion(), prefix +1);
-                    }
-                }
-            }
-        }
-
-        return unresolved;
-    }
-
-    private void displayConditionalInfo(Feature feature) {
-        List<? extends Conditional> conditionals = feature.getConditional();
-        if (conditionals.isEmpty()) {
-            System.out.println("Feature has no conditionals.");
-        } else {
-            System.out.println("Feature contains followed conditionals:");
-            for (Conditional featureConditional : conditionals) {
-                String conditionDescription = getConditionDescription(featureConditional);
-                Feature wrappedConditional = featureConditional.asFeature(feature.getName(), feature.getVersion());
-                if (config) {
-                    displayConfigInformation(wrappedConditional, String.format(CONDITIONAL_CONTENT, conditionDescription));
-                    displayConfigFileInformation(wrappedConditional, String.format(CONDITIONAL_CONTENT, conditionDescription));
-                }
-
-                if (dependency) {
-                    displayDependencyInformation(wrappedConditional, String.format(CONDITIONAL_CONTENT, conditionDescription));
-                }
-
-                if (bundle) {
-                    displayBundleInformation(wrappedConditional, String.format(CONDITIONAL_CONTENT, conditionDescription));
-                }
-            }
-        }
-    }
-
-    private String getConditionDescription(Conditional cond) {
-        StringBuffer sb = new StringBuffer();
-        for (String dep : cond.getCondition()) {
-            if (sb.length() > 0) {
-                sb.append(" ");
-            }
-            sb.append(dep);
-        }
-        return sb.toString();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/command/InstallFeatureCommand.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/command/InstallFeatureCommand.java b/features/src/main/java/org/apache/karaf/features/command/InstallFeatureCommand.java
deleted file mode 100644
index b7f8184..0000000
--- a/features/src/main/java/org/apache/karaf/features/command/InstallFeatureCommand.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.command;
-
-import java.util.EnumSet;
-import java.util.HashSet;
-import java.util.List;
-
-import org.apache.karaf.features.FeaturesService;
-import org.apache.karaf.features.command.completers.AvailableFeatureCompleter;
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.Completion;
-import org.apache.karaf.shell.api.action.Option;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-
-@Command(scope = "feature", name = "install", description = "Installs a feature with the specified name and version.")
-@Service
-public class InstallFeatureCommand extends FeaturesCommandSupport {
-
-    private static String DEFAULT_VERSION = "0.0.0";
-
-    @Argument(index = 0, name = "feature", description = "The name and version of the features to install. A feature id looks like name/version. The version is optional.", required = true, multiValued = true)
-    @Completion(AvailableFeatureCompleter.class)
-    List<String> features;
-
-    @Option(name = "-r", aliases = "--no-auto-refresh", description = "Do not automatically refresh bundles", required = false, multiValued = false)
-    boolean noRefresh;
-
-    @Option(name = "-s", aliases = "--no-auto-start", description = "Do not start the bundles", required = false, multiValued = false)
-    boolean noStart;
-
-    @Option(name = "-v", aliases = "--verbose", description = "Explain what is being done", required = false, multiValued = false)
-    boolean verbose;
-
-    @Option(name = "-t", aliases = "--simulate", description = "Perform a simulation only", required = false, multiValued = false)
-    boolean simulate;
-
-    protected void doExecute(FeaturesService admin) throws Exception {
-        EnumSet<FeaturesService.Option> options = EnumSet.noneOf(FeaturesService.Option.class);
-        if (simulate) {
-            options.add(FeaturesService.Option.Simulate);
-        }
-        if (noStart) {
-            options.add(FeaturesService.Option.NoAutoStartBundles);
-        }
-        if (noRefresh) {
-            options.add(FeaturesService.Option.NoAutoRefreshBundles);
-        }
-        if (verbose) {
-            options.add(FeaturesService.Option.Verbose);
-        }
-        admin.installFeatures(new HashSet<String>(features), options);
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/command/ListFeatureVersionsCommand.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/command/ListFeatureVersionsCommand.java b/features/src/main/java/org/apache/karaf/features/command/ListFeatureVersionsCommand.java
deleted file mode 100644
index b2c5e42..0000000
--- a/features/src/main/java/org/apache/karaf/features/command/ListFeatureVersionsCommand.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.command;
-
-import java.util.Arrays;
-
-import org.apache.karaf.features.Feature;
-import org.apache.karaf.features.FeaturesService;
-import org.apache.karaf.features.Repository;
-import org.apache.karaf.features.command.completers.AllFeatureCompleter;
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.Completion;
-import org.apache.karaf.shell.api.action.Option;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.karaf.shell.support.table.ShellTable;
-
-@Command(scope = "feature", name = "version-list", description = "Lists all versions of a feature available from the currently available repositories.")
-@Service
-public class ListFeatureVersionsCommand extends FeaturesCommandSupport {
-
-	@Argument(index = 0, name = "feature", description = "Name of feature.", required = true, multiValued = false)
-    @Completion(AllFeatureCompleter.class)
-	String feature;
-
-    @Option(name = "--no-format", description = "Disable table rendered output", required = false, multiValued = false)
-    boolean noFormat;
-
-    protected void doExecute(FeaturesService admin) throws Exception {
-        ShellTable table = new ShellTable();
-        table.column("Version");
-        table.column("Repository");
-        table.column("Repository URL");
-        table.emptyTableText("No versions available for features '" + feature + "'");
-             
-        for (Repository r : Arrays.asList(admin.listRepositories())) {
-            for (Feature f : r.getFeatures()) {
-
-                if (f.getName().equals(feature)) {
-                    table.addRow().addContent(f.getVersion(), r.getName(), r.getURI());
-                }
-            }
-        }
-
-        table.print(System.out, !noFormat);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/command/ListFeaturesCommand.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/command/ListFeaturesCommand.java b/features/src/main/java/org/apache/karaf/features/command/ListFeaturesCommand.java
deleted file mode 100644
index e86ff64..0000000
--- a/features/src/main/java/org/apache/karaf/features/command/ListFeaturesCommand.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.command;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
-import org.apache.karaf.features.Feature;
-import org.apache.karaf.features.FeaturesService;
-import org.apache.karaf.features.Repository;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.Option;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.karaf.shell.support.table.ShellTable;
-
-@Command(scope = "feature", name = "list", description = "Lists all existing features available from the defined repositories.")
-@Service
-public class ListFeaturesCommand extends FeaturesCommandSupport {
-
-    @Option(name = "-i", aliases = {"--installed"}, description = "Display a list of all installed features only", required = false, multiValued = false)
-    boolean onlyInstalled;
-
-    @Option(name = "-r", aliases = {"--required"}, description = "Display a list of all required features only", required = false, multiValued = false)
-    boolean onlyRequired;
-
-    @Option(name = "-o", aliases = {"--ordered"}, description = "Display a list using alphabetical order ", required = false, multiValued = false)
-    boolean ordered;
-
-    @Option(name = "--no-format", description = "Disable table rendered output", required = false, multiValued = false)
-    boolean noFormat;
-
-    protected void doExecute(FeaturesService featuresService) throws Exception {
-        boolean needsLegend = false;
-        
-        ShellTable table = new ShellTable();
-        table.column("Name");
-        table.column("Version");
-        table.column("Required");
-        table.column("Installed");
-        table.column("Repository");
-        table.column("Description").maxSize(50);
-        table.emptyTableText(onlyInstalled ? "No features installed" : "No features available");
-
-        List<Repository> repos = Arrays.asList(featuresService.listRepositories());
-        for (Repository r : repos) {
-            List<Feature> features = Arrays.asList(r.getFeatures());
-            if (ordered) {
-                Collections.sort(features, new FeatureComparator());
-            }
-            for (Feature f : features) {
-                if (onlyInstalled && !featuresService.isInstalled(f)) {
-                    // Filter out not installed features if we only want to see the installed ones
-                    continue;
-                }
-                if (onlyRequired && !featuresService.isRequired(f)) {
-                    // Filter out not installed features if we only want to see the installed ones
-                    continue;
-                }
-                table.addRow().addContent(
-                        f.getName(),
-                        f.getVersion(),
-                        featuresService.isRequired(f) ? "x" : "",
-                        featuresService.isInstalled(f) ? "x" : "",
-                        r.getName(),
-                        f.getDescription());
-                if (isInstalledViaDeployDir(r.getName())) {
-                    needsLegend = true;
-                }
-            }
-        }
-
-        table.print(System.out, !noFormat);
-
-        if (needsLegend) {
-            System.out.println("* Installed via deploy directory");
-        }
-
-    }
-
-    private boolean isInstalledViaDeployDir(String st) {
-        return (st == null || st.length() <= 1) ? false : (st.charAt(st.length() - 1) == '*');
-    }
-
-    class FeatureComparator implements Comparator<Feature> {
-        public int compare(Feature o1, Feature o2) {
-            return o1.getName().toLowerCase().compareTo( o2.getName().toLowerCase() );
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/command/RepoAddCommand.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/command/RepoAddCommand.java b/features/src/main/java/org/apache/karaf/features/command/RepoAddCommand.java
deleted file mode 100644
index 16faf42..0000000
--- a/features/src/main/java/org/apache/karaf/features/command/RepoAddCommand.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.command;
-
-import java.net.URI;
-
-import org.apache.karaf.features.FeaturesService;
-import org.apache.karaf.features.command.completers.AvailableRepoNameCompleter;
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.Completion;
-import org.apache.karaf.shell.api.action.Option;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-
-@Command(scope = "feature", name = "repo-add", description = "Add a features repository")
-@Service
-public class RepoAddCommand extends FeaturesCommandSupport {
-
-    @Argument(index = 0, name = "name/url", description = "Shortcut name of the features repository or the full URL", required = true, multiValued = false)
-    @Completion(AvailableRepoNameCompleter.class)
-    private String nameOrUrl;
-    
-    @Argument(index = 1, name = "version", description = "The version of the features repository if using features repository name as first argument. It should be empty if using the URL", required = false, multiValued = false)
-    private String version;
-
-    @Option(name = "-i", aliases = { "--install" }, description = "Install all features contained in the features repository", required = false, multiValued = false)
-    private boolean install;
-
-    @Override
-    protected void doExecute(FeaturesService featuresService) throws Exception {
-        String effectiveVersion = (version == null) ? "LATEST" : version;
-        URI uri = featuresService.getRepositoryUriFor(nameOrUrl, effectiveVersion);
-        if (uri == null) {
-            uri = new URI(nameOrUrl);
-        }
-        System.out.println("Adding feature url " + uri);
-        featuresService.addRepository(uri, install);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/command/RepoListCommand.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/command/RepoListCommand.java b/features/src/main/java/org/apache/karaf/features/command/RepoListCommand.java
deleted file mode 100644
index 55acf79..0000000
--- a/features/src/main/java/org/apache/karaf/features/command/RepoListCommand.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.command;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.karaf.features.FeaturesService;
-import org.apache.karaf.features.Repository;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.Option;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.karaf.shell.support.MultiException;
-import org.apache.karaf.shell.support.table.ShellTable;
-
-@Command(scope = "feature", name = "repo-list", description = "Displays a list of all defined repositories.")
-@Service
-public class RepoListCommand extends FeaturesCommandSupport {
-
-    @Option(name="-r", description="Reload all feature urls", required = false, multiValued = false)
-    boolean reload;
-
-    @Option(name = "--no-format", description = "Disable table rendered output", required = false, multiValued = false)
-    boolean noFormat;
-    
-    protected void doExecute(FeaturesService featuresService) throws Exception {
-        if (reload) {
-            reloadAllRepos(featuresService);
-        }
-        
-        ShellTable table = new ShellTable();
-        table.column("Repository");
-        table.column("URL");
-        table.emptyTableText("No repositories available");
-
-        Repository[] repos = featuresService.listRepositories();
-     	for (Repository repo : repos) {
-            if (repo != null) {
-     	        table.addRow().addContent(repo.getName(), repo.getURI().toString()); 
-            }
-     	}
-     	table.print(System.out, !noFormat);
-    }
-
-    private void reloadAllRepos(FeaturesService featuresService) throws Exception {
-        System.out.println("Reloading all repositories from their urls");
-        System.out.println();
-        List<Exception> exceptions = new ArrayList<Exception>();
-        for (Repository repo : featuresService.listRepositories()) {
-            try {
-                featuresService.addRepository(repo.getURI());
-            } catch (Exception e) {
-                exceptions.add(e);
-            }
-        }
-        MultiException.throwIf("Unable to reload repositories", exceptions);
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/command/RepoRefreshCommand.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/command/RepoRefreshCommand.java b/features/src/main/java/org/apache/karaf/features/command/RepoRefreshCommand.java
deleted file mode 100644
index 8c7ed79..0000000
--- a/features/src/main/java/org/apache/karaf/features/command/RepoRefreshCommand.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.command;
-
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.karaf.features.FeaturesService;
-import org.apache.karaf.features.Repository;
-import org.apache.karaf.features.command.completers.InstalledRepoUriCompleter;
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.Completion;
-
-@Command(scope = "feature", name = "repo-refresh", description = "Refresh a features repository")
-public class RepoRefreshCommand extends FeaturesCommandSupport {
-    @Argument(index = 0, name = "Feature name or uri", description = "Shortcut name of the feature repository or the full URI", required = false, multiValued = false)
-    @Completion(InstalledRepoUriCompleter.class)
-    private String nameOrUrl;
-    
-    @Argument(index = 1, name = "Feature version", description = "The version of the feature if using the feature name. Should be empty if using the uri", required = false, multiValued = false)
-    private String version;
-
-    @Override
-    protected void doExecute(FeaturesService featuresService) throws Exception {
-        List<URI> uris = new ArrayList<URI>();
-    	if (nameOrUrl != null) {
-    		String effectiveVersion = (version == null) ? "LATEST" : version;
-        	URI uri = featuresService.getRepositoryUriFor(nameOrUrl, effectiveVersion);
-        	if (uri == null) {
-        		uri = new URI(nameOrUrl);
-        	}
-            uris.add(uri);
-    	} else {
-            Repository[] repos = featuresService.listRepositories();
-            for (Repository repo : repos) {
-                uris.add(repo.getURI());
-            }
-    	}
-        for (URI uri : uris) {
-            try {
-                System.out.println("Refreshing feature url " + uri);
-                featuresService.refreshRepository(uri);
-            } catch (Exception e) {
-                System.err.println("Error refreshing " + uri.toString() + ": " + e.getMessage());
-            }
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/command/RepoRemoveCommand.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/command/RepoRemoveCommand.java b/features/src/main/java/org/apache/karaf/features/command/RepoRemoveCommand.java
deleted file mode 100644
index 0710b72..0000000
--- a/features/src/main/java/org/apache/karaf/features/command/RepoRemoveCommand.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.command;
-
-import java.net.URI;
-
-import org.apache.karaf.features.FeaturesService;
-import org.apache.karaf.features.Repository;
-import org.apache.karaf.features.command.completers.InstalledRepoNameCompleter;
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.Completion;
-import org.apache.karaf.shell.api.action.Option;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-
-@Command(scope = "feature", name = "repo-remove", description = "Removes the specified repository features service.")
-@Service
-public class RepoRemoveCommand extends FeaturesCommandSupport {
-
-    @Argument(index = 0, name = "repository", description = "Name or url of the repository to remove.", required = true, multiValued = false)
-    @Completion(InstalledRepoNameCompleter.class)
-    private String repository;
-
-    @Option(name = "-u", aliases = { "--uninstall-all" }, description = "Uninstall all features from the repository", required = false, multiValued = false)
-    private boolean uninstall;
-
-    protected void doExecute(FeaturesService featuresService) throws Exception {
-    	URI uri = null;
-    	for (Repository r : featuresService.listRepositories()) {
-    		if (r.getName() != null && r.getName().equals(repository)) {
-    			uri = r.getURI();
-    			break;
-    		}
-    	}
-
-    	if (uri == null) {
-    	    uri = new URI(repository);
-    	}
-
-    	featuresService.removeRepository(uri, uninstall);
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/command/UninstallFeatureCommand.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/command/UninstallFeatureCommand.java b/features/src/main/java/org/apache/karaf/features/command/UninstallFeatureCommand.java
deleted file mode 100644
index e62f697..0000000
--- a/features/src/main/java/org/apache/karaf/features/command/UninstallFeatureCommand.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.command;
-
-import java.util.EnumSet;
-import java.util.HashSet;
-import java.util.List;
-
-import org.apache.karaf.features.FeaturesService;
-import org.apache.karaf.features.command.completers.RequiredFeatureCompleter;
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.Completion;
-import org.apache.karaf.shell.api.action.Option;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-
-@Command(scope = "feature", name = "uninstall", description = "Uninstalls a feature with the specified name and version.")
-@Service
-public class UninstallFeatureCommand extends FeaturesCommandSupport {
-
-    @Argument(index = 0, name = "features", description = "The name and version of the features to uninstall. A feature id looks like name/version. The version is optional.", required = true, multiValued = true)
-    @Completion(RequiredFeatureCompleter.class)
-    List<String> features;
-
-    @Option(name = "-r", aliases = "--no-auto-refresh", description = "Do not automatically refresh bundles", required = false, multiValued = false)
-    boolean noRefresh;
-
-    @Option(name = "-v", aliases = "--verbose", description = "Explain what is being done", required = false, multiValued = false)
-    boolean verbose;
-
-    @Option(name = "-t", aliases = "--simulate", description = "Perform a simulation only", required = false, multiValued = false)
-    boolean simulate;
-
-    protected void doExecute(FeaturesService admin) throws Exception {
-        // iterate in the provided feature
-        EnumSet<FeaturesService.Option> options = EnumSet.noneOf(FeaturesService.Option.class);
-        if (simulate) {
-            options.add(FeaturesService.Option.Simulate);
-        }
-        if (noRefresh) {
-            options.add(FeaturesService.Option.NoAutoRefreshBundles);
-        }
-        if (verbose) {
-            options.add(FeaturesService.Option.Verbose);
-        }
-        admin.uninstallFeatures(new HashSet<String>(features), options);
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/command/completers/AllFeatureCompleter.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/command/completers/AllFeatureCompleter.java b/features/src/main/java/org/apache/karaf/features/command/completers/AllFeatureCompleter.java
deleted file mode 100644
index 7444b95..0000000
--- a/features/src/main/java/org/apache/karaf/features/command/completers/AllFeatureCompleter.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.command.completers;
-
-import org.apache.karaf.features.Feature;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-
-/**
- * {@link org.apache.karaf.shell.console.Completer} for available features.
- */
-@Service
-public class AllFeatureCompleter extends FeatureCompleterSupport {
-
-    @Override
-    protected boolean acceptsFeature(Feature feature) {
-        return true;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/command/completers/AvailableFeatureCompleter.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/command/completers/AvailableFeatureCompleter.java b/features/src/main/java/org/apache/karaf/features/command/completers/AvailableFeatureCompleter.java
deleted file mode 100644
index 79cd280..0000000
--- a/features/src/main/java/org/apache/karaf/features/command/completers/AvailableFeatureCompleter.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.command.completers;
-
-import org.apache.karaf.features.Feature;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-
-/**
- * {@link org.apache.karaf.shell.console.Completer} for features not installed yet.
- */
-@Service
-public class AvailableFeatureCompleter extends FeatureCompleterSupport {
-
-    @Override
-    protected boolean acceptsFeature(Feature feature) {
-        return !featuresService.isInstalled(feature);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/command/completers/AvailableRepoNameCompleter.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/command/completers/AvailableRepoNameCompleter.java b/features/src/main/java/org/apache/karaf/features/command/completers/AvailableRepoNameCompleter.java
deleted file mode 100644
index acefe77..0000000
--- a/features/src/main/java/org/apache/karaf/features/command/completers/AvailableRepoNameCompleter.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.command.completers;
-
-import java.util.Arrays;
-import java.util.List;
-
-import org.apache.karaf.features.FeaturesService;
-import org.apache.karaf.shell.api.action.lifecycle.Reference;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.karaf.shell.api.console.CommandLine;
-import org.apache.karaf.shell.api.console.Completer;
-import org.apache.karaf.shell.api.console.Session;
-import org.apache.karaf.shell.support.completers.StringsCompleter;
-
-/**
- * Shows the list of feature repos that can be installed with their short name
- */
-@Service
-public class AvailableRepoNameCompleter implements Completer {
-
-    @Reference
-    private FeaturesService featuresService;
-
-    public void setFeaturesService(FeaturesService featuresService) {
-        this.featuresService = featuresService;
-    }
-
-    public int complete(Session session, CommandLine commandLine, final List<String> candidates) {
-        StringsCompleter delegate = new StringsCompleter(Arrays.asList(featuresService.getRepositoryNames()));
-        return delegate.complete(session, commandLine, candidates);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/command/completers/FeatureCompleterSupport.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/command/completers/FeatureCompleterSupport.java b/features/src/main/java/org/apache/karaf/features/command/completers/FeatureCompleterSupport.java
deleted file mode 100644
index d01e5af..0000000
--- a/features/src/main/java/org/apache/karaf/features/command/completers/FeatureCompleterSupport.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.command.completers;
-
-import java.util.List;
-
-import org.apache.karaf.features.Feature;
-import org.apache.karaf.features.FeaturesService;
-import org.apache.karaf.shell.api.action.lifecycle.Reference;
-import org.apache.karaf.shell.api.console.CommandLine;
-import org.apache.karaf.shell.api.console.Completer;
-import org.apache.karaf.shell.api.console.Session;
-import org.apache.karaf.shell.support.completers.StringsCompleter;
-
-/**
- * Base completer for feature commands.
- */
-public abstract class FeatureCompleterSupport implements Completer {
-
-    /**
-     * Feature service.
-     */
-    @Reference
-    protected FeaturesService featuresService;
-
-    public void setFeaturesService(FeaturesService featuresService) {
-        this.featuresService = featuresService;
-    }
-
-    public int complete(Session session, final CommandLine commandLine, final List<String> candidates) {
-        StringsCompleter delegate = new StringsCompleter();
-        try {
-            for (Feature feature : featuresService.listFeatures()) {
-                if (acceptsFeature(feature)) {
-                    delegate.getStrings().add(feature.getName());
-                }
-            }
-        } catch (Exception e) {
-            // Ignore
-        }
-        return delegate.complete(session, commandLine, candidates);
-    }
-
-    /**
-     * Method for filtering features.
-     *
-     * @param feature The feature.
-     * @return True if feature should be available in completer.
-     */
-    protected abstract boolean acceptsFeature(Feature feature);
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoNameCompleter.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoNameCompleter.java b/features/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoNameCompleter.java
deleted file mode 100644
index 94e4cf7..0000000
--- a/features/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoNameCompleter.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.command.completers;
-
-import java.util.List;
-
-import org.apache.karaf.features.FeaturesService;
-import org.apache.karaf.features.Repository;
-import org.apache.karaf.shell.api.action.lifecycle.Reference;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.karaf.shell.api.console.CommandLine;
-import org.apache.karaf.shell.api.console.Completer;
-import org.apache.karaf.shell.api.console.Session;
-import org.apache.karaf.shell.support.completers.StringsCompleter;
-
-/**
- * {@link Completer} for Feature Repository URLs.
- *
- * Displays a list of currently installed Feature repositories.
- *
- */
-@Service
-public class InstalledRepoNameCompleter implements Completer {
-
-    @Reference
-    private FeaturesService featuresService;
-
-    public void setFeaturesService(FeaturesService featuresService) {
-        this.featuresService = featuresService;
-    }
-
-    public int complete(Session session, final CommandLine commandLine, final List<String> candidates) {
-        StringsCompleter delegate = new StringsCompleter();
-        try {
-            for (Repository repository : featuresService.listRepositories()) {
-                delegate.getStrings().add(repository.getName());
-            }
-        } catch (Exception e) {
-            // Ignore
-        }
-        return delegate.complete(session, commandLine, candidates);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoUriCompleter.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoUriCompleter.java b/features/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoUriCompleter.java
deleted file mode 100644
index 7a760c2..0000000
--- a/features/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoUriCompleter.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.command.completers;
-
-import java.util.List;
-
-import org.apache.karaf.features.FeaturesService;
-import org.apache.karaf.features.Repository;
-import org.apache.karaf.shell.api.action.lifecycle.Reference;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.karaf.shell.api.console.CommandLine;
-import org.apache.karaf.shell.api.console.Completer;
-import org.apache.karaf.shell.api.console.Session;
-import org.apache.karaf.shell.support.completers.StringsCompleter;
-
-/**
- * {@link Completer} for Feature Repository URLs.
- *
- * Displays a list of currently installed Feature repositories.
- *
- */
-
-@Service
-public class InstalledRepoUriCompleter implements Completer {
-
-    @Reference
-    private FeaturesService featuresService;
-
-    public void setFeaturesService(FeaturesService featuresService) {
-        this.featuresService = featuresService;
-    }
-
-    public int complete(Session session, final CommandLine commandLine, final List<String> candidates) {
-        StringsCompleter delegate = new StringsCompleter();
-        try {
-            for (Repository repository : featuresService.listRepositories()) {
-                delegate.getStrings().add(repository.getURI().toString());
-            }
-        } catch (Exception e) {
-            // Ignore
-        }
-        return delegate.complete(session, commandLine, candidates);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/command/completers/RequiredFeatureCompleter.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/command/completers/RequiredFeatureCompleter.java b/features/src/main/java/org/apache/karaf/features/command/completers/RequiredFeatureCompleter.java
deleted file mode 100644
index a51f75f..0000000
--- a/features/src/main/java/org/apache/karaf/features/command/completers/RequiredFeatureCompleter.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.command.completers;
-
-import org.apache.karaf.features.Feature;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-
-/**
- * {@link org.apache.karaf.shell.console.Completer} for installed features.
- */
-@Service
-public class RequiredFeatureCompleter extends FeatureCompleterSupport {
-
-    @Override
-    protected boolean acceptsFeature(Feature feature) {
-        return featuresService.isRequired(feature);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/deployment/DeploymentBuilder.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/deployment/DeploymentBuilder.java b/features/src/main/java/org/apache/karaf/features/internal/deployment/DeploymentBuilder.java
deleted file mode 100644
index c3ac2b7..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/deployment/DeploymentBuilder.java
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.deployment;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.jar.Attributes;
-import java.util.jar.Manifest;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
-
-import org.apache.felix.resolver.ResolverImpl;
-import org.apache.felix.utils.version.VersionRange;
-import org.apache.felix.utils.version.VersionTable;
-import org.apache.karaf.features.BundleInfo;
-import org.apache.karaf.features.Conditional;
-import org.apache.karaf.features.Dependency;
-import org.apache.karaf.features.Feature;
-import org.apache.karaf.features.Repository;
-import org.apache.karaf.features.internal.repository.AggregateRepository;
-import org.apache.karaf.features.internal.repository.StaticRepository;
-import org.apache.karaf.features.internal.resolver.FeatureNamespace;
-import org.apache.karaf.features.internal.resolver.FeatureResource;
-import org.apache.karaf.features.internal.resolver.RequirementImpl;
-import org.apache.karaf.features.internal.resolver.ResolveContextImpl;
-import org.apache.karaf.features.internal.resolver.ResourceBuilder;
-import org.apache.karaf.features.internal.resolver.ResourceImpl;
-import org.apache.karaf.features.internal.resolver.Slf4jResolverLog;
-import org.apache.karaf.features.internal.service.Overrides;
-import org.apache.karaf.features.internal.util.Macro;
-import org.apache.karaf.features.internal.util.MultiException;
-import org.osgi.framework.BundleException;
-import org.osgi.framework.Version;
-import org.osgi.framework.namespace.IdentityNamespace;
-import org.osgi.resource.Capability;
-import org.osgi.resource.Requirement;
-import org.osgi.resource.Resource;
-import org.osgi.resource.Wire;
-import org.osgi.service.resolver.ResolutionException;
-import org.osgi.service.resolver.ResolveContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- */
-public class DeploymentBuilder {
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(DeploymentBuilder.class);
-
-    public static final String REQ_PROTOCOL = "req:";
-
-    private final Collection<Repository> repositories;
-
-    private final List<org.osgi.service.repository.Repository> resourceRepos;
-
-    String featureRange = "${range;[====,====]}";
-
-    Downloader downloader;
-    ResourceImpl requirements;
-    Map<String, Resource> resources;
-    Set<Resource> optionals;
-    Map<String, StreamProvider> providers;
-
-    Set<Feature> featuresToRegister = new HashSet<Feature>();
-
-    public DeploymentBuilder(Downloader downloader,
-                             Collection<Repository> repositories) {
-        this.downloader = downloader;
-        this.repositories = repositories;
-        this.resourceRepos = new ArrayList<org.osgi.service.repository.Repository>();
-    }
-
-    public void addResourceRepository(org.osgi.service.repository.Repository repository) {
-        resourceRepos.add(repository);
-    }
-
-    public Map<String, StreamProvider> getProviders() {
-        return providers;
-    }
-
-    public void setFeatureRange(String featureRange) {
-        this.featureRange = featureRange;
-    }
-
-    public Map<String, Resource> download(
-                         Set<String> features,
-                         Set<String> bundles,
-                         Set<String> reqs,
-                         Set<String> overrides,
-                         Set<String> optionals)
-                throws IOException, MultiException, InterruptedException, ResolutionException, BundleException {
-        this.resources = new ConcurrentHashMap<String, Resource>();
-        this.optionals = new HashSet<Resource>();
-        this.providers = new ConcurrentHashMap<String, StreamProvider>();
-        this.requirements = new ResourceImpl("dummy", "dummy", Version.emptyVersion);
-        // First, gather all bundle resources
-        for (String feature : features) {
-            registerMatchingFeatures(feature);
-        }
-        for (String bundle : bundles) {
-            downloadAndBuildResource(bundle);
-        }
-        for (String req : reqs) {
-            buildRequirement(req);
-        }
-        for (String override : overrides) {
-            // TODO: ignore download failures for overrides
-            downloadAndBuildResource(Overrides.extractUrl(override));
-        }
-        for (String optional : optionals) {
-            downloadAndBuildResource(optional);
-        }
-        // Wait for all resources to be created
-        downloader.await();
-        // Do override replacement
-        Overrides.override(resources, overrides);
-        // Build features resources
-        for (Feature feature : featuresToRegister) {
-            Resource resource = FeatureResource.build(feature, featureRange, resources);
-            resources.put("feature:" + feature.getName() + "/" + feature.getVersion(), resource);
-            for (Conditional cond : feature.getConditional()) {
-                this.optionals.add(FeatureResource.build(feature, cond, featureRange, resources));
-            }
-        }
-        // Build requirements
-        for (String feature : features) {
-            requireFeature(feature);
-        }
-        for (String bundle : bundles) {
-            requireResource(bundle);
-        }
-        for (String req : reqs) {
-            requireResource(REQ_PROTOCOL + req);
-        }
-        return resources;
-    }
-
-    public Map<Resource, List<Wire>> resolve(List<Resource> systemBundles) throws ResolutionException {
-        // Resolve
-        for (int i = 0; i < systemBundles.size(); i++) {
-            resources.put("system-bundle-" + i, systemBundles.get(i));
-        }
-
-        List<org.osgi.service.repository.Repository> repos = new ArrayList<org.osgi.service.repository.Repository>();
-        repos.add(new StaticRepository(resources.values()));
-        repos.addAll(resourceRepos);
-
-        ResolverImpl resolver = new ResolverImpl(new Slf4jResolverLog(LOGGER));
-        ResolveContext context = new ResolveContextImpl(
-                Collections.<Resource>singleton(requirements),
-                Collections.<Resource>emptySet(),
-                new AggregateRepository(repos),
-                false);
-        Map<Resource, List<Wire>> best = resolver.resolve(context);
-
-        // TODO: we actually need to use multiple passes for conditionals
-        // TODO: but it may be optimized by passing the old wiring instead
-        // TODO: of computing everything again
-        Set<Resource> resources = new HashSet<Resource>();
-        resources.add(requirements);
-        for (Resource optional : optionals) {
-            try {
-                Set<Resource> newSet = new HashSet<Resource>(resources);
-                newSet.add(optional);
-                context = new ResolveContextImpl(
-                        newSet,
-                        Collections.<Resource>emptySet(),
-                        new AggregateRepository(repos),
-                        false);
-                best = resolver.resolve(context);
-                resources = newSet;
-            } catch (ResolutionException e) {
-                // Ignore this resource
-            }
-        }
-        return best;
-    }
-
-    public void requireFeature(String feature) throws IOException {
-        // Find name and version range
-        String[] split = feature.split("/");
-        String name = split[0].trim();
-        String version = (split.length > 1) ? split[1].trim() : null;
-        if (version != null && !version.equals("0.0.0") && !version.startsWith("[") && !version.startsWith("(")) {
-            version = Macro.transform(featureRange, version);
-        }
-        VersionRange range = version != null ? new VersionRange(version) : VersionRange.ANY_VERSION;
-        // Add requirement
-        Map<String, Object> attrs = new HashMap<String, Object>();
-        attrs.put(IdentityNamespace.IDENTITY_NAMESPACE, name);
-        attrs.put(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE, FeatureNamespace.TYPE_FEATURE);
-        attrs.put(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, range);
-        requirements.addRequirement(
-                new RequirementImpl(requirements, IdentityNamespace.IDENTITY_NAMESPACE,
-                        Collections.<String, String>emptyMap(), attrs)
-        );
-    }
-
-    public void requireResource(String location) {
-        Resource res = resources.get(location);
-        if (res == null) {
-            throw new IllegalStateException("Could not find resource for " + location);
-        }
-        List<Capability> caps = res.getCapabilities(IdentityNamespace.IDENTITY_NAMESPACE);
-        if (caps.size() != 1) {
-            throw new IllegalStateException("Resource does not have a single " + IdentityNamespace.IDENTITY_NAMESPACE + " capability");
-        }
-        Capability cap = caps.get(0);
-        // Add requirement
-        Map<String, Object> attrs = new HashMap<String, Object>();
-        attrs.put(IdentityNamespace.IDENTITY_NAMESPACE, cap.getAttributes().get(IdentityNamespace.IDENTITY_NAMESPACE));
-        attrs.put(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE, cap.getAttributes().get(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE));
-        attrs.put(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, new VersionRange((Version) cap.getAttributes().get(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE), true));
-        requirements.addRequirement(
-                new RequirementImpl(requirements, IdentityNamespace.IDENTITY_NAMESPACE,
-                        Collections.<String, String>emptyMap(), attrs));
-
-    }
-
-    public void registerMatchingFeatures(String feature) throws IOException {
-        // Find name and version range
-        String[] split = feature.split("/");
-        String name = split[0].trim();
-        String version = (split.length > 1)
-                ? split[1].trim() : Version.emptyVersion.toString();
-        // Register matching features
-        registerMatchingFeatures(name, new VersionRange(version));
-    }
-
-    public void registerMatchingFeatures(String name, String version) throws IOException {
-        if (version != null && !version.equals("0.0.0") && !version.startsWith("[") && !version.startsWith("(")) {
-            version = Macro.transform(featureRange, version);
-        }
-        registerMatchingFeatures(name, version != null ? new VersionRange(version) : VersionRange.ANY_VERSION);
-    }
-
-    public void registerMatchingFeatures(String name, VersionRange range) throws IOException {
-        for (Repository repo : repositories) {
-            Feature[] features;
-            try {
-                features = repo.getFeatures();
-            } catch (Exception e) {
-                // This should not happen as the repository has been loaded already
-                throw new IllegalStateException(e);
-            }
-            for (Feature f : features) {
-                if (name.equals(f.getName())) {
-                    Version v = VersionTable.getVersion(f.getVersion());
-                    if (range.contains(v)) {
-                        featuresToRegister.add(f);
-                        for (Dependency dep : f.getDependencies()) {
-                            registerMatchingFeatures(dep.getName(), dep.getVersion());
-                        }
-                        for (BundleInfo bundle : f.getBundles()) {
-                            downloadAndBuildResource(bundle.getLocation());
-                        }
-                        for (Conditional cond : f.getConditional()) {
-                            Feature c = cond.asFeature(f.getName(), f.getVersion());
-                            featuresToRegister.add(c);
-                            for (BundleInfo bundle : c.getBundles()) {
-                                downloadAndBuildResource(bundle.getLocation());
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    public void buildRequirement(String requirement) {
-        try {
-            String location = REQ_PROTOCOL + requirement;
-            ResourceImpl resource = new ResourceImpl(location, "dummy", Version.emptyVersion);
-            for (Requirement req : ResourceBuilder.parseRequirement(resource, requirement)) {
-                resource.addRequirement(req);
-            }
-            resources.put(location, resource);
-        } catch (BundleException e) {
-            throw new IllegalArgumentException("Error parsing requirement: " + requirement, e);
-        }
-    }
-
-    public void downloadAndBuildResource(final String location) throws IOException {
-        if (!resources.containsKey(location)) {
-            downloader.download(location, new Downloader.DownloadCallback() {
-                @Override
-                public void downloaded(StreamProvider provider) throws Exception {
-                    manageResource(location, provider);
-                }
-            });
-        }
-    }
-
-    private void manageResource(String location, StreamProvider provider) throws Exception {
-        if (!resources.containsKey(location)) {
-            Attributes attributes = getAttributes(location, provider);
-            Resource resource = createResource(location, attributes);
-            resources.put(location, resource);
-            providers.put(location, provider);
-        }
-    }
-
-    private Resource createResource(String uri, Attributes attributes) throws Exception {
-        Map<String, String> headers = new HashMap<String, String>();
-        for (Map.Entry attr : attributes.entrySet()) {
-            headers.put(attr.getKey().toString(), attr.getValue().toString());
-        }
-        try {
-            return ResourceBuilder.build(uri, headers);
-        } catch (BundleException e) {
-            throw new Exception("Unable to create resource for bundle " + uri, e);
-        }
-    }
-
-    protected Attributes getAttributes(String uri, StreamProvider provider) throws Exception {
-        InputStream is = provider.open();
-        try {
-            ZipInputStream zis = new ZipInputStream(is);
-            ZipEntry entry;
-            while ( (entry = zis.getNextEntry()) != null ) {
-                if ("META-INF/MANIFEST.MF".equals(entry.getName())) {
-                    return new Manifest(zis).getMainAttributes();
-                }
-            }
-        } finally {
-            is.close();
-        }
-        throw new IllegalArgumentException("Resource " + uri + " does not contain a manifest");
-    }
-
-}


[07/33] [KARAF-2852] Merge jms/core and jms/command

Posted by gn...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/core/src/main/java/org/apache/karaf/jms/internal/JmsServiceImpl.java
----------------------------------------------------------------------
diff --git a/jms/core/src/main/java/org/apache/karaf/jms/internal/JmsServiceImpl.java b/jms/core/src/main/java/org/apache/karaf/jms/internal/JmsServiceImpl.java
deleted file mode 100644
index fe4b43d..0000000
--- a/jms/core/src/main/java/org/apache/karaf/jms/internal/JmsServiceImpl.java
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jms.internal;
-
-import org.apache.activemq.ActiveMQConnection;
-import org.apache.activemq.advisory.DestinationSource;
-import org.apache.activemq.command.ActiveMQQueue;
-import org.apache.activemq.command.ActiveMQTopic;
-import org.apache.activemq.pool.PooledConnection;
-import org.apache.karaf.jms.JmsMessage;
-import org.apache.karaf.jms.JmsService;
-import org.apache.karaf.util.TemplateUtils;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.ServiceReference;
-
-import javax.jms.*;
-
-import java.io.*;
-import java.lang.IllegalStateException;
-import java.util.*;
-
-/**
- * Default implementation of the JMS Service.
- */
-public class JmsServiceImpl implements JmsService {
-
-    private BundleContext bundleContext;
-    private File deployFolder;
-    
-    public JmsServiceImpl() {
-        File karafBase = new File(System.getProperty("karaf.base"));
-        deployFolder = new File(karafBase, "deploy");
-    }
-
-    @Override
-    public void create(String name, String type, String url) throws Exception {
-        if (!type.equalsIgnoreCase("activemq") && !type.equalsIgnoreCase("webspheremq")) {
-            throw new IllegalArgumentException("JMS connection factory type not known");
-        }
-
-        File outFile = getConnectionFactoryFile(name);
-        String template;
-        HashMap<String, String> properties = new HashMap<String, String>();
-        properties.put("name", name);
-
-        if (type.equalsIgnoreCase("activemq")) {
-            // activemq
-            properties.put("url", url);
-            template = "connectionfactory-activemq.xml";
-        } else {
-            // webspheremq
-            String[] splitted = url.split("/");
-            if (splitted.length != 4) {
-                throw new IllegalStateException("WebsphereMQ URI should be in the following format: host/port/queuemanager/channel");
-            }
-            
-            properties.put("host", splitted[0]);
-            properties.put("port", splitted[1]);
-            properties.put("queuemanager", splitted[2]);
-            properties.put("channel", splitted[3]);
-            template = "connectionfactory-webspheremq.xml";
-        }
-        InputStream is = this.getClass().getResourceAsStream(template);
-        if (is == null) {
-            throw new IllegalArgumentException("Template resource " + template + " doesn't exist");
-        }
-        TemplateUtils.createFromTemplate(outFile, is, properties);
-    }
-
-    private File getConnectionFactoryFile(String name) {
-        return new File(deployFolder, "connectionfactory-" + name + ".xml");
-    }
-
-    @Override
-    public void delete(String name) throws Exception {
-        File connectionFactoryFile = getConnectionFactoryFile(name);
-        if (!connectionFactoryFile.exists()) {
-            throw new IllegalStateException("The JMS connection factory file " + connectionFactoryFile.getPath() + " doesn't exist");
-        }
-        connectionFactoryFile.delete();
-    }
-
-    @SuppressWarnings("rawtypes")
-    @Override
-    public List<String> connectionFactories() throws Exception {
-        List<String> connectionFactories = new ArrayList<String>();
-        ServiceReference[] references = bundleContext.getServiceReferences(ConnectionFactory.class.getName(), null);
-        if (references != null) {
-            for (ServiceReference reference : references) {
-                if (reference.getProperty("osgi.jndi.service.name") != null) {
-                    connectionFactories.add((String) reference.getProperty("osgi.jndi.service.name"));
-                } else if (reference.getProperty("name") != null) {
-                    connectionFactories.add((String) reference.getProperty("name"));
-                } else {
-                    connectionFactories.add(reference.getProperty(Constants.SERVICE_ID).toString());
-                }
-            }
-        }
-        return connectionFactories;
-    }
-
-    @Override
-    public List<String> connectionFactoryFileNames() throws Exception {
-        String[] connectionFactoryFileNames = deployFolder.list(new FilenameFilter() {
-
-            @Override
-            public boolean accept(File dir, String name) {
-                return name.startsWith("connectionfactory-") && name.endsWith(".xml");
-            }
-        });
-
-        return Arrays.asList(connectionFactoryFileNames);
-    }
-
-    @Override
-    public Map<String, String> info(String connectionFactory, String username, String password) throws IOException, JMSException {
-        JmsConnector connector = new JmsConnector(bundleContext, connectionFactory, username, password);
-        try {
-            ConnectionMetaData metaData = connector.connect().getMetaData();
-            Map<String, String> map = new HashMap<String, String>();
-            map.put("product", metaData.getJMSProviderName());
-            map.put("version", metaData.getProviderVersion());
-            return map;
-        } finally {
-            connector.close();
-        }
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public int count(String connectionFactory, final String destination, String username, String password) throws IOException, JMSException {
-        JmsConnector connector = new JmsConnector(bundleContext, connectionFactory, username, password);
-        try  {
-            Session session = connector.createSession();
-            QueueBrowser browser = session.createBrowser(session.createQueue(destination));
-            Enumeration<Message> enumeration = browser.getEnumeration();
-            int count = 0;
-            while (enumeration.hasMoreElements()) {
-                enumeration.nextElement();
-                count++;
-            }
-            browser.close();
-            return count;
-        } finally {
-            connector.close();
-        }
-    }
-
-    private DestinationSource getDestinationSource(Connection connection) throws JMSException {
-        if (connection instanceof PooledConnection) {
-            connection = ((PooledConnection) connection).getConnection();
-        }
-        if (connection instanceof ActiveMQConnection) {
-            return ((ActiveMQConnection) connection).getDestinationSource();
-        } else {
-            return null;
-        }
-    }
-    
-    @Override
-    public List<String> queues(String connectionFactory, String username, String password) throws JMSException, IOException {
-        JmsConnector connector = new JmsConnector(bundleContext, connectionFactory, username, password);
-        try {
-            List<String> queues = new ArrayList<String>();
-            DestinationSource destinationSource = getDestinationSource(connector.connect());
-            if (destinationSource != null) {
-                Set<ActiveMQQueue> activeMQQueues = destinationSource.getQueues();
-                for (ActiveMQQueue activeMQQueue : activeMQQueues) {
-                    queues.add(activeMQQueue.getQueueName());
-                }
-            }
-            return queues;
-        } finally {
-            connector.close();
-        }
-    }
-
-    @Override
-    public List<String> topics(String connectionFactory, String username, String password) throws IOException, JMSException {
-        JmsConnector connector = new JmsConnector(bundleContext, connectionFactory, username, password);
-        try {
-            DestinationSource destinationSource = getDestinationSource(connector.connect());
-            List<String> topics = new ArrayList<String>();
-            if (destinationSource != null) {
-                Set<ActiveMQTopic> activeMQTopics = destinationSource.getTopics();
-                for (ActiveMQTopic activeMQTopic : activeMQTopics) {
-                    topics.add(activeMQTopic.getTopicName());
-                }
-            }
-            return topics;
-        } finally {
-            connector.close();
-        }
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public List<JmsMessage> browse(String connectionFactory, final String queue, final String filter,
-                                   String username, String password) throws JMSException, IOException {
-        JmsConnector connector = new JmsConnector(bundleContext, connectionFactory, username, password);
-        try {
-            List<JmsMessage> messages = new ArrayList<JmsMessage>();
-            Session session = connector.createSession();
-            QueueBrowser browser = session.createBrowser(session.createQueue(queue), filter);
-            Enumeration<Message> enumeration = browser.getEnumeration();
-            while (enumeration.hasMoreElements()) {
-                Message message = enumeration.nextElement();
-
-                messages.add(new JmsMessage(message));
-            }
-            browser.close();
-            return messages;
-        } finally {
-            connector.close();
-        }
-    }
-
-    @Override
-    public void send(String connectionFactory, final String queue, final String body, final String replyTo,
-                     String username, String password) throws IOException, JMSException {
-        JmsConnector connector = new JmsConnector(bundleContext, connectionFactory, username, password);
-        try {
-            Session session = connector.createSession();
-            Message message = session.createTextMessage(body);
-            if (replyTo != null) {
-                message.setJMSReplyTo(session.createQueue(replyTo));
-            }
-            MessageProducer producer = session.createProducer(session.createQueue(queue));
-            producer.send(message);
-            producer.close();
-        } finally {
-            connector.close();
-        }
-    }
-
-    @Override
-    public int consume(String connectionFactory, final String queue, final String selector, String username,
-                       String password) throws Exception {
-        JmsConnector connector = new JmsConnector(bundleContext, connectionFactory, username, password);
-        try {
-            int count = 0;
-            Session session = connector.createSession();
-            MessageConsumer consumer = session.createConsumer(session.createQueue(queue), selector);
-            Message message;
-            do {
-                message = consumer.receive(5000L);
-                if (message != null) {
-                    count++;
-                }
-            } while (message != null);
-            return count;
-        } finally {
-            connector.close();
-        }
-    }
-
-    @Override
-    public int move(String connectionFactory, final String sourceQueue, final String targetQueue,
-                    final String selector, String username, String password) throws IOException, JMSException {
-        JmsConnector connector = new JmsConnector(bundleContext, connectionFactory, username, password);
-        try {
-            int count = 0;
-            Session session = connector.createSession();
-            MessageConsumer consumer = session.createConsumer(session.createQueue(sourceQueue), selector);
-            Message message;
-            do {
-                message = consumer.receive(5000L);
-                if (message != null) {
-                    MessageProducer producer = session.createProducer(session.createQueue(targetQueue));
-                    producer.send(message);
-                    count++;
-                }
-            } while (message != null);
-            consumer.close();
-            return count;
-        } finally {
-            connector.close();
-        }
-    }
-
-    public void setBundleContext(BundleContext bundleContext) {
-        this.bundleContext = bundleContext;
-    }
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/core/src/main/resources/OSGI-INF/blueprint/jms-core.xml
----------------------------------------------------------------------
diff --git a/jms/core/src/main/resources/OSGI-INF/blueprint/jms-core.xml b/jms/core/src/main/resources/OSGI-INF/blueprint/jms-core.xml
deleted file mode 100644
index 7dd8070..0000000
--- a/jms/core/src/main/resources/OSGI-INF/blueprint/jms-core.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?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.
-    -->
-<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
-           xmlns:ext="http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.0.0"
-           default-activation="lazy">
-
-    <ext:property-placeholder placeholder-prefix="$[" placeholder-suffix="]"/>
-
-    <bean id="jmsService" class="org.apache.karaf.jms.internal.JmsServiceImpl">
-        <property name="bundleContext" ref="blueprintBundleContext"/>
-    </bean>
-
-    <service ref="jmsService" interface="org.apache.karaf.jms.JmsService" />
-
-    <!-- Management -->
-    <bean id="jmsMBeanImpl" class="org.apache.karaf.jms.internal.JmsMBeanImpl">
-        <property name="jmsService" ref="jmsService"/>
-    </bean>
-
-    <service ref="jmsMBeanImpl" auto-export="interfaces">
-        <service-properties>
-            <entry key="jmx.objectname" value="org.apache.karaf:type=jms,name=$[karaf.name]"/>
-        </service-properties>
-    </service>
-
-</blueprint>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/core/src/main/resources/OSGI-INF/bundle.info
----------------------------------------------------------------------
diff --git a/jms/core/src/main/resources/OSGI-INF/bundle.info b/jms/core/src/main/resources/OSGI-INF/bundle.info
deleted file mode 100644
index 1aeb646..0000000
--- a/jms/core/src/main/resources/OSGI-INF/bundle.info
+++ /dev/null
@@ -1,18 +0,0 @@
-h1. Synopsis
-
-${project.name}
-
-${project.description}
-
-Maven URL:
-[mvn:${project.groupId}/${project.artifactId}/${project.version}]
-
-h1. Description
-
-This bundle is the core implementation of the JMS service support.
-
-The JMS service allows you to create connection factories, and send/browse/consume messages.
-
-h1. See also
-
-JMS - section of the Karaf User Guide

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/core/src/main/resources/org/apache/karaf/jms/internal/connectionfactory-activemq.xml
----------------------------------------------------------------------
diff --git a/jms/core/src/main/resources/org/apache/karaf/jms/internal/connectionfactory-activemq.xml b/jms/core/src/main/resources/org/apache/karaf/jms/internal/connectionfactory-activemq.xml
deleted file mode 100644
index f0aabbd..0000000
--- a/jms/core/src/main/resources/org/apache/karaf/jms/internal/connectionfactory-activemq.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<?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.
-    -->
-<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
-
-    <bean id="activemqConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
-        <property name="brokerURL" value="${url}" />
-    </bean>
-
-    <bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory">
-        <property name="maxConnections" value="8" />
-        <property name="connectionFactory" ref="activemqConnectionFactory" />
-    </bean>
-
-    <bean id="resourceManager" class="org.apache.activemq.pool.ActiveMQResourceManager" init-method="recoverResource">
-        <property name="transactionManager" ref="transactionManager" />
-        <property name="connectionFactory" ref="activemqConnectionFactory" />
-        <property name="resourceName" value="activemq.localhost" />
-    </bean>
-
-    <reference id="transactionManager" interface="javax.transaction.TransactionManager" />
-
-    <service ref="pooledConnectionFactory" interface="javax.jms.ConnectionFactory">
-        <service-properties>
-            <entry key="name" value="${name}" />
-            <entry key="osgi.jndi.service.name" value="jms/${name}" />
-        </service-properties>
-    </service>
-
-</blueprint>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/core/src/main/resources/org/apache/karaf/jms/internal/connectionfactory-webspheremq.xml
----------------------------------------------------------------------
diff --git a/jms/core/src/main/resources/org/apache/karaf/jms/internal/connectionfactory-webspheremq.xml b/jms/core/src/main/resources/org/apache/karaf/jms/internal/connectionfactory-webspheremq.xml
deleted file mode 100644
index 3123f49..0000000
--- a/jms/core/src/main/resources/org/apache/karaf/jms/internal/connectionfactory-webspheremq.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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.
-    -->
-<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
-
-    <bean id="wmqConnectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory">
-        <property name="transportType" value="1" />
-        <property name="hostName" value="${hostname}" />
-        <property name="port" value="${port}" />
-        <property name="queueManager" value="${queuemanager}" />
-        <property name="channel" value="${channel}" />
-        <property name="useConnectionPooling" value="true" />
-    </bean>
-
-    <service ref="wmqConnectionFactory" interface="javax.jms.ConnectionFactory">
-        <service-properties>
-            <entry key="name" value="${name}"/>
-            <entry key="osgi.jndi.service.name" value="jms/${name}"/>
-        </service-properties>
-    </service>
-
-</blueprint>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/pom.xml
----------------------------------------------------------------------
diff --git a/jms/pom.xml b/jms/pom.xml
index 4a2d8d2..c7cd769 100644
--- a/jms/pom.xml
+++ b/jms/pom.xml
@@ -29,13 +29,83 @@
     </parent>
 
     <groupId>org.apache.karaf.jms</groupId>
-    <artifactId>jms</artifactId>
-    <packaging>pom</packaging>
-    <name>Apache Karaf :: JMS</name>
-
-    <modules>
-        <module>core</module>
-        <module>command</module>
-    </modules>
+    <artifactId>org.apache.karaf.jms.core</artifactId>
+    <packaging>bundle</packaging>
+    <name>Apache Karaf :: JMS :: Core</name>
+    <description>This bundle provides core implementation of the JMS service.</description>
+
+    <properties>
+        <appendedResourcesDirectory>${basedir}/../../etc/appended-resources</appendedResourcesDirectory>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.geronimo.specs</groupId>
+            <artifactId>geronimo-jms_1.1_spec</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.activemq</groupId>
+            <artifactId>activemq-pool</artifactId>
+            <version>5.9.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.karaf</groupId>
+            <artifactId>org.apache.karaf.util</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.karaf.shell</groupId>
+            <artifactId>org.apache.karaf.shell.core</artifactId>
+            <optional>true</optional>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <resources>
+            <resource>
+                <directory>${project.basedir}/src/main/resources</directory>
+                <includes>
+                    <include>**/*</include>
+                </includes>
+            </resource>
+            <resource>
+                <directory>${project.basedir}/src/main/resources</directory>
+                <filtering>true</filtering>
+                <includes>
+                    <include>**/*.info</include>
+                </includes>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Export-Package>
+                            org.apache.karaf.jms
+                        </Export-Package>
+                        <Import-Package>
+                            org.apache.activemq*;resolution:=optional,
+                            *
+                        </Import-Package>
+                        <Private-Package>
+                            org.apache.karaf.jms.command,
+                            org.apache.karaf.jms.command.completers,
+                            org.apache.karaf.jms.internal,
+                            org.apache.karaf.util
+                        </Private-Package>
+                        <Karaf-Commands>*</Karaf-Commands>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
 
 </project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/src/main/java/org/apache/karaf/jms/JmsMBean.java
----------------------------------------------------------------------
diff --git a/jms/src/main/java/org/apache/karaf/jms/JmsMBean.java b/jms/src/main/java/org/apache/karaf/jms/JmsMBean.java
new file mode 100644
index 0000000..8540b86
--- /dev/null
+++ b/jms/src/main/java/org/apache/karaf/jms/JmsMBean.java
@@ -0,0 +1,153 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.jms;
+
+import javax.management.MBeanException;
+import javax.management.openmbean.TabularData;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * JMS MBean.
+ */
+public interface JmsMBean {
+
+    /**
+     * List the JMS connection factories.
+     *
+     * @return the list of the JMS connection factories name.
+     * @throws MBeanException
+     */
+    List<String> getConnectionfactories() throws MBeanException;
+
+    /**
+     * Create a JMS connection factory.
+     *
+     * @param name the JMS connection factory name.
+     * @param type the JMS connection factory type (ActiveMQ or WebsphereMQ).
+     * @param url the JMS connection factory URL. NB: when type is WebsphereMQ, the URL has the format host/port/queuemanager/channel.
+     * @throws MBeanException
+     */
+    void create(String name, String type, String url) throws MBeanException;
+
+    /**
+     * Delete a JMS connection factory.
+     *
+     * @param name the JMS connection factory name.
+     * @throws MBeanException
+     */
+    void delete(String name) throws MBeanException;
+
+    /**
+     * Get details about a JMS connection factory.
+     *
+     * @param connectionFactory the JMS connection factory name.
+     * @param username optional username to connect to the JMS broker.
+     * @param password optional password to connect to the JMS broker.
+     * @return a map (property/value) containing details.
+     * @throws MBeanException
+     */
+    Map<String, String> info(String connectionFactory, String username, String password) throws MBeanException;
+
+    /**
+     * Count the messages on a given JMS queue.
+     *
+     * @param connectionFactory the JMS connection factory name.
+     * @param queue the JMS queue name.
+     * @param username optional username to connect to the JMS broker.
+     * @param password optional password to connect to the JMS broker.
+     * @return
+     * @throws MBeanException
+     */
+    int count(String connectionFactory, String queue, String username, String password) throws MBeanException;
+
+    /**
+     * List the JMS queues.
+     *
+     * @param connectionFactory the JMS connection factory name.
+     * @param username optional username to connect to the JMS broker.
+     * @param password optional password to connect to the JMS broker.
+     * @return the list of JMS queues.
+     * @throws MBeanException
+     */
+    List<String> queues(String connectionFactory, String username, String password) throws MBeanException;
+
+    /**
+     * List the JMS topics.
+     *
+     * @param connectionFactory the JMS connection factory name.
+     * @param username optional username to connect to the JMS broker.
+     * @param password optional password to connect to the JMS broker.
+     * @return the list of JMS topics.
+     * @throws MBeanException
+     */
+    List<String> topics(String connectionFactory, String username, String password) throws MBeanException;
+
+    /**
+     * Browse the messages in a JMS queue.
+     *
+     * @param connectionFactory the JMS connection factory name.
+     * @param queue the JMS queue name.
+     * @param selector a selector to use to browse only certain messages.
+     * @param username optional username to connect to the JMS broker.
+     * @param password optional password to connect to the JMS broker.
+     * @return a tabular data with messages details.
+     * @throws MBeanException
+     */
+    TabularData browse(String connectionFactory, String queue, String selector, String username, String password) throws MBeanException;
+
+    /**
+     * Send a JMS message to given queue.
+     *
+     * @param connectionFactory the JMS connection factory name.
+     * @param queue the JMS queue name.
+     * @param content the message content.
+     * @param replyTo the message ReplyTo.
+     * @param username optional username to connect to the JMS broker.
+     * @param password optional password to connect to the JMS broker.
+     * @throws MBeanException
+     */
+    void send(String connectionFactory, String queue, String content, String replyTo, String username, String password) throws MBeanException;
+
+    /**
+     * Consume JMS messages from a given queue.
+     *
+     * @param connectionFactory the JMS connection factory name.
+     * @param queue the JMS queue name.
+     * @param selector a selector to use to consume only certain messages.
+     * @param username optional username to connect to the JMS broker.
+     * @param password optional password to connect to the JMS broker.
+     * @return the number of messages consumed.
+     * @throws MBeanException
+     */
+    int consume(String connectionFactory, String queue, String selector, String username, String password) throws MBeanException;
+
+    /**
+     * Move JMS messages from one queue to another.
+     *
+     * @param connectionFactory the JMS connection factory name.
+     * @param source the source JMS queue name.
+     * @param destination the destination JMS queue name.
+     * @param selector a selector to move only certain messages.
+     * @param username optional username to connect to the JMS broker.
+     * @param password optional password to connect to the JMS broker.
+     * @return the number of messages moved.
+     * @throws MBeanException
+     */
+    int move(String connectionFactory, String source, String destination, String selector, String username, String password) throws MBeanException;
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/src/main/java/org/apache/karaf/jms/JmsMessage.java
----------------------------------------------------------------------
diff --git a/jms/src/main/java/org/apache/karaf/jms/JmsMessage.java b/jms/src/main/java/org/apache/karaf/jms/JmsMessage.java
new file mode 100644
index 0000000..a85af10
--- /dev/null
+++ b/jms/src/main/java/org/apache/karaf/jms/JmsMessage.java
@@ -0,0 +1,164 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.jms;
+
+import javax.jms.*;
+import java.io.UnsupportedEncodingException;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Describe a JMS message is more human readable way.
+ */
+public class JmsMessage {
+
+    private Map<String, Object> properties = new HashMap<String, Object>();
+
+    private String content;
+    private String charset = "UTF-8";
+    private String correlationID;
+    private String deliveryMode;
+    private String destination;
+    private String expiration;
+    private String messageId;
+    private int priority;
+    private boolean redelivered;
+    private String replyTo;
+    private String timestamp;
+    private String type;
+
+    public JmsMessage(Message message) {
+        try {
+            initFromMessage(message);
+        } catch (JMSException e) {
+            throw new RuntimeException(e.getMessage(), e);
+        }
+    }
+
+    public void initFromMessage(Message message) throws JMSException {
+        @SuppressWarnings("unchecked")
+        Enumeration<String> names = message.getPropertyNames();
+        while (names.hasMoreElements()) {
+            String key = names.nextElement();
+            Object value = message.getObjectProperty(key);
+            properties.put(key, value);
+        }
+
+        correlationID = message.getJMSCorrelationID();
+        if (message.getJMSDeliveryMode() == DeliveryMode.NON_PERSISTENT) {
+            deliveryMode = "Non Persistent";
+        } else {
+            deliveryMode = "Persistent";
+        }
+        Destination destinationDest = message.getJMSDestination();
+        if (destinationDest != null) {
+            destination = destinationDest.toString();
+        }
+        if (message.getJMSExpiration() > 0) {
+            expiration = new Date(message.getJMSExpiration()).toString();
+        } else {
+            expiration = "Never";
+        }
+        messageId = message.getJMSMessageID();
+        priority = message.getJMSPriority();
+        redelivered = message.getJMSRedelivered();
+        Destination replyToDest = message.getJMSReplyTo();
+        if (replyToDest != null) {
+            replyTo = replyToDest.toString();
+        }
+        if (message.getJMSTimestamp() > 0) {
+            timestamp = new Date(message.getJMSTimestamp()).toString();
+        } else {
+            timestamp = "";
+        }
+        type = message.getJMSType();
+        content = getMessageContent(message);
+    }
+
+
+    private String getMessageContent(Message message) throws JMSException {
+        if (message instanceof TextMessage) {
+            return ((TextMessage) message).getText();
+        } else if (message instanceof BytesMessage) {
+            BytesMessage bMessage = (BytesMessage) message;
+            long length = bMessage.getBodyLength();
+            byte[] content = new byte[(int) length];
+            bMessage.readBytes(content);
+            try {
+                return new String(content, charset);
+            } catch (UnsupportedEncodingException e) {
+                throw new RuntimeException(e.getMessage(), e);
+            }
+        }
+        return "";
+    }
+
+    public Map<String, Object> getProperties() {
+        return properties;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public String getCharset() {
+        return charset;
+    }
+
+    public String getCorrelationID() {
+        return correlationID;
+    }
+
+    public String getDeliveryMode() {
+        return deliveryMode;
+    }
+
+    public String getDestination() {
+        return destination;
+    }
+
+    public String getExpiration() {
+        return expiration;
+    }
+
+    public String getMessageId() {
+        return messageId;
+    }
+
+    public int getPriority() {
+        return priority;
+    }
+
+    public boolean isRedelivered() {
+        return redelivered;
+    }
+
+    public String getReplyTo() {
+        return replyTo;
+    }
+
+    public String getTimestamp() {
+        return timestamp;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/src/main/java/org/apache/karaf/jms/JmsService.java
----------------------------------------------------------------------
diff --git a/jms/src/main/java/org/apache/karaf/jms/JmsService.java b/jms/src/main/java/org/apache/karaf/jms/JmsService.java
new file mode 100644
index 0000000..8aa970f
--- /dev/null
+++ b/jms/src/main/java/org/apache/karaf/jms/JmsService.java
@@ -0,0 +1,159 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.jms;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * JMS Service.
+ */
+public interface JmsService {
+
+    /**
+     * List the JMS connection factories.
+     *
+     * @return the list of JMS connection factory names.
+     * @throws Exception
+     */
+    List<String> connectionFactories() throws Exception;
+
+    /**
+     * List the JMS connecion factories file names.
+     *
+     * @return the list of JMS connection factory file names.
+     * @throws Exception
+     */
+    List<String> connectionFactoryFileNames() throws Exception;
+
+    /**
+     * Create a new JMS connection factory.
+     *
+     * @param name the JMS connection factory name.
+     * @param type the JMS connection factory type (ActiveMQ, WebsphereMQ, ...).
+     * @param url the JMS URL to use.
+     * @throws Exception
+     */
+    void create(String name, String type, String url) throws Exception;
+
+    /**
+     * Delete a JMS connection factory.
+     *
+     * @param name the JMS connection factory name.
+     * @throws Exception
+     */
+    void delete(String name) throws Exception;
+
+    /**
+     * Get details about a given JMS connection factory.
+     *
+     * @param connectionFactory the JMS connection factory name.
+     * @param username optional username to connect to the JMS broker.
+     * @param password optional password to connect to the JMS broker.
+     * @return a map (property/value) containing details.
+     * @throws Exception
+     */
+    Map<String, String> info(String connectionFactory, String username, String password) throws Exception;
+
+    /**
+     * Count the number of messages in a JMS queue.
+     *
+     * @param connectionFactory the JMS connection factory name.
+     * @param queue the queue name.
+     * @param username optional username to connect to the JMS broker.
+     * @param password optional password to connect to the JMS broker.
+     * @return the number of messages in a JMS queue.
+     * @throws Exception
+     */
+    int count(String connectionFactory, String queue, String username, String password) throws Exception;
+
+    /**
+     * List the queues.
+     *
+     * @param connectionFactory the JMS connection factory name.
+     * @param username optional username to connect to the JMS broker.
+     * @param password optional password to connect to the JMS broker.
+     * @return the list of queues.
+     * @throws Exception
+     */
+    List<String> queues(String connectionFactory, String username, String password) throws Exception;
+
+    /**
+     * List the topics.
+     *
+     * @param connectionFactory the JMS connection factory name.
+     * @param username optional username to connect to the JMS broker.
+     * @param password optional password to connect to the JMS broker.
+     * @return the list of topics.
+     * @throws Exception
+     */
+    List<String> topics(String connectionFactory, String username, String password) throws Exception;
+
+    /**
+     * Browse a destination.
+     *
+     * @param connectionFactory the JMS connection factory name.
+     * @param queue the queue name.
+     * @param selector the selector.
+     * @param username optional username to connect to the JMS broker.
+     * @param password optional password to connect to the JMS broker.
+     * @return the list of messages.
+     * @throws Exception
+     */
+    List<JmsMessage> browse(String connectionFactory, String queue, String selector, String username, String password) throws Exception;
+
+    /**
+     * Send a message on the given queue.
+     *
+     * @param connectionFactory the JMS connection factory name.
+     * @param queue the queue name.
+     * @param body the message body.
+     * @param replyTo the message replyTo header.
+     * @param username optional username to connect to the JMS broker.
+     * @param password optional password to connect to the JMS broker.
+     * @throws Exception
+     */
+    void send(String connectionFactory, String queue, String body, String replyTo, String username, String password) throws Exception;
+
+    /**
+     * Consume messages from a given destination.
+     *
+     * @param connectionFactory the JMS connection factory name.
+     * @param queue the queue name.
+     * @param selector the messages selector.
+     * @param username optional username to connect to the JMS broker.
+     * @param password optional password to connect to the JMS broker.
+     * @return the number of messages consumed.
+     * @throws Exception
+     */
+    int consume(String connectionFactory, String queue, String selector, String username, String password) throws Exception;
+
+    /**
+     * Move messages from a destination to another.
+     *
+     * @param connectionFactory the JMS connection factory name.
+     * @param sourceQueue the source queue.
+     * @param targetQueue the target queue.
+     * @param selector the messages selector on the source queue.
+     * @param username optional username to connect to the JMS broker.
+     * @param password optional password to connect to the JMS broker.
+     * @return the number of messages moved.
+     * @throws Exception
+     */
+    int move(String connectionFactory, String sourceQueue, String targetQueue, String selector, String username, String password) throws Exception;
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/src/main/java/org/apache/karaf/jms/command/BrowseCommand.java
----------------------------------------------------------------------
diff --git a/jms/src/main/java/org/apache/karaf/jms/command/BrowseCommand.java b/jms/src/main/java/org/apache/karaf/jms/command/BrowseCommand.java
new file mode 100644
index 0000000..cb86aa6
--- /dev/null
+++ b/jms/src/main/java/org/apache/karaf/jms/command/BrowseCommand.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.karaf.jms.command;
+
+import java.util.List;
+
+import org.apache.karaf.jms.JmsMessage;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.table.ShellTable;
+
+@Command(scope = "jms", name = "browse", description = "Browse a JMS queue")
+@Service
+public class BrowseCommand extends JmsConnectionCommandSupport {
+
+    @Argument(index = 1, name = "queue", description = "The JMS queue to browse", required = true, multiValued = false)
+    String queue;
+
+    @Option(name = "-s", aliases = { "--selector" }, description = "The selector to select the messages to browse", required = false, multiValued = false)
+    String selector;
+
+    @Option(name = "-v", aliases = { "--verbose" }, description = "Display JMS properties", required = false, multiValued = false)
+    boolean verbose = false;
+
+    @Override
+    public Object execute() throws Exception {
+
+        ShellTable table = new ShellTable();
+        table.column("Message ID");
+        table.column("Content").maxSize(80);
+        table.column("Charset");
+        table.column("Type");
+        table.column("Correlation ID");
+        table.column("Delivery Mode");
+        table.column("Destination");
+        table.column("Expiration");
+        table.column("Priority");
+        table.column("Redelivered");
+        table.column("ReplyTo");
+        table.column("Timestamp");
+        if (verbose) {
+            table.column("Properties");
+        }
+
+        List<JmsMessage> messages = getJmsService().browse(connectionFactory, queue, selector, username, password);
+        for (JmsMessage message : messages) {
+            if (verbose) {
+                StringBuilder properties = new StringBuilder();
+                for (String property : message.getProperties().keySet()) {
+                    properties.append(property).append("=").append(message.getProperties().get(property)).append("\n");
+                }
+                table.addRow().addContent(
+                        message.getMessageId(),
+                        message.getContent(),
+                        message.getCharset(),
+                        message.getType(),
+                        message.getCorrelationID(),
+                        message.getDeliveryMode(),
+                        message.getDestination(),
+                        message.getExpiration(),
+                        message.getPriority(),
+                        message.isRedelivered(),
+                        message.getReplyTo(),
+                        message.getTimestamp(),
+                        properties.toString());
+            } else {
+                table.addRow().addContent(
+                        message.getMessageId(),
+                        message.getContent(),
+                        message.getCharset(),
+                        message.getType(),
+                        message.getCorrelationID(),
+                        message.getDeliveryMode(),
+                        message.getDestination(),
+                        message.getExpiration(),
+                        message.getPriority(),
+                        message.isRedelivered(),
+                        message.getReplyTo(),
+                        message.getTimestamp());
+            }
+        }
+
+        table.print(System.out);
+
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/src/main/java/org/apache/karaf/jms/command/ConnectionFactoriesCommand.java
----------------------------------------------------------------------
diff --git a/jms/src/main/java/org/apache/karaf/jms/command/ConnectionFactoriesCommand.java b/jms/src/main/java/org/apache/karaf/jms/command/ConnectionFactoriesCommand.java
new file mode 100644
index 0000000..b698336
--- /dev/null
+++ b/jms/src/main/java/org/apache/karaf/jms/command/ConnectionFactoriesCommand.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.karaf.jms.command;
+
+import java.util.List;
+
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.table.ShellTable;
+
+@Command(scope = "jms", name = "connectionfactories", description = "List the JMS connection factories")
+@Service
+public class ConnectionFactoriesCommand extends JmsCommandSupport {
+
+    @Override
+    public Object execute() throws Exception {
+
+        ShellTable table = new ShellTable();
+        table.column("JMS Connection Factory");
+
+        List<String> connectionFactories = getJmsService().connectionFactories();
+        for (String connectionFactory : connectionFactories) {
+            table.addRow().addContent(connectionFactory);
+        }
+
+        table.print(System.out);
+
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/src/main/java/org/apache/karaf/jms/command/ConsumeCommand.java
----------------------------------------------------------------------
diff --git a/jms/src/main/java/org/apache/karaf/jms/command/ConsumeCommand.java b/jms/src/main/java/org/apache/karaf/jms/command/ConsumeCommand.java
new file mode 100644
index 0000000..cd8caaf
--- /dev/null
+++ b/jms/src/main/java/org/apache/karaf/jms/command/ConsumeCommand.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.jms.command;
+
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "jms", name = "consume", description = "Consume messages from a JMS queue.")
+@Service
+public class ConsumeCommand extends JmsConnectionCommandSupport {
+
+    @Argument(index = 1, name = "queue", description = "The JMS queue where to consume messages", required = true, multiValued = false)
+    String queue;
+
+    @Option(name = "-s", aliases = { "--selector" }, description = "The selector to use to select the messages to consume", required = false, multiValued = false)
+    String selector;
+
+    @Override
+    public Object execute() throws Exception {
+        System.out.println(getJmsService().consume(connectionFactory, queue, selector, username, password) + " message(s) consumed");
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/src/main/java/org/apache/karaf/jms/command/CountCommand.java
----------------------------------------------------------------------
diff --git a/jms/src/main/java/org/apache/karaf/jms/command/CountCommand.java b/jms/src/main/java/org/apache/karaf/jms/command/CountCommand.java
new file mode 100644
index 0000000..576e8dd
--- /dev/null
+++ b/jms/src/main/java/org/apache/karaf/jms/command/CountCommand.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.karaf.jms.command;
+
+
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.table.ShellTable;
+
+@Command(scope = "jms", name = "count", description = "Count the number of messages on a JMS queue.")
+@Service
+public class CountCommand extends JmsConnectionCommandSupport {
+
+    @Argument(index = 1, name = "queue", description = "The JMS queue name", required = true, multiValued = false)
+    String queue;
+
+    @Override
+    public Object execute() throws Exception {
+        ShellTable table = new ShellTable();
+        table.column("Messages Count");
+        table.addRow().addContent(getJmsService().count(connectionFactory, queue, username, password));
+        table.print(System.out);
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/src/main/java/org/apache/karaf/jms/command/CreateCommand.java
----------------------------------------------------------------------
diff --git a/jms/src/main/java/org/apache/karaf/jms/command/CreateCommand.java b/jms/src/main/java/org/apache/karaf/jms/command/CreateCommand.java
new file mode 100644
index 0000000..c2c7eca
--- /dev/null
+++ b/jms/src/main/java/org/apache/karaf/jms/command/CreateCommand.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.karaf.jms.command;
+
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.completers.StringsCompleter;
+
+@Command(scope = "jms", name = "create", description = "Create a JMS connection factory.")
+@Service
+public class CreateCommand extends JmsCommandSupport {
+
+    @Argument(index = 0, name = "name", description = "The JMS connection factory name", required = true, multiValued = false)
+    String name;
+
+    @Option(name = "-t", aliases = { "--type" }, description = "The JMS connection factory type (ActiveMQ or WebsphereMQ)", required = false, multiValued = false)
+    @Completion(value = StringsCompleter.class, values = { "activemq", "webspheremq" })
+    String type = "ActiveMQ";
+
+    @Option(name = "--url", description = "URL of the JMS broker. For WebsphereMQ type, the URL is hostname/port/queuemanager/channel", required = false, multiValued = false)
+    String url = "tcp://localhost:61616";
+
+    @Override
+    public Object execute() throws Exception {
+        getJmsService().create(name, type, url);
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/src/main/java/org/apache/karaf/jms/command/DeleteCommand.java
----------------------------------------------------------------------
diff --git a/jms/src/main/java/org/apache/karaf/jms/command/DeleteCommand.java b/jms/src/main/java/org/apache/karaf/jms/command/DeleteCommand.java
new file mode 100644
index 0000000..cab3123
--- /dev/null
+++ b/jms/src/main/java/org/apache/karaf/jms/command/DeleteCommand.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.jms.command;
+
+
+import org.apache.karaf.jms.command.completers.ConnectionFactoriesFileNameCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "jms", name = "delete", description = "Delete a JMS connection factory")
+@Service
+public class DeleteCommand extends JmsCommandSupport {
+
+    @Argument(index = 0, name = "name", description = "The JMS connection factory name", required = true, multiValued = false)
+    @Completion(ConnectionFactoriesFileNameCompleter.class)
+    String name;
+
+    @Override
+    public Object execute() throws Exception {
+        getJmsService().delete(name);
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/src/main/java/org/apache/karaf/jms/command/InfoCommand.java
----------------------------------------------------------------------
diff --git a/jms/src/main/java/org/apache/karaf/jms/command/InfoCommand.java b/jms/src/main/java/org/apache/karaf/jms/command/InfoCommand.java
new file mode 100644
index 0000000..354db39
--- /dev/null
+++ b/jms/src/main/java/org/apache/karaf/jms/command/InfoCommand.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.karaf.jms.command;
+
+
+import java.util.Map;
+
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.table.ShellTable;
+
+@Command(scope = "jms", name = "info", description = "Provides details about a JMS connection factory.")
+@Service
+public class InfoCommand extends JmsConnectionCommandSupport {
+
+    @Override
+    public Object execute() throws Exception {
+        ShellTable table = new ShellTable();
+        table.column("Property");
+        table.column("Value");
+
+        Map<String, String> info = getJmsService().info(connectionFactory, username, password);
+        for (String key : info.keySet()) {
+            table.addRow().addContent(key, info.get(key));
+        }
+
+        table.print(System.out);
+
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/src/main/java/org/apache/karaf/jms/command/JmsCommandSupport.java
----------------------------------------------------------------------
diff --git a/jms/src/main/java/org/apache/karaf/jms/command/JmsCommandSupport.java b/jms/src/main/java/org/apache/karaf/jms/command/JmsCommandSupport.java
new file mode 100644
index 0000000..2f5df8f
--- /dev/null
+++ b/jms/src/main/java/org/apache/karaf/jms/command/JmsCommandSupport.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.karaf.jms.command;
+
+import org.apache.karaf.jms.JmsService;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+
+public abstract class JmsCommandSupport implements Action {
+
+    @Reference
+    private JmsService jmsService;
+
+    public JmsService getJmsService() {
+        return jmsService;
+    }
+
+    public void setJmsService(JmsService jmsService) {
+        this.jmsService = jmsService;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/src/main/java/org/apache/karaf/jms/command/JmsConnectionCommandSupport.java
----------------------------------------------------------------------
diff --git a/jms/src/main/java/org/apache/karaf/jms/command/JmsConnectionCommandSupport.java b/jms/src/main/java/org/apache/karaf/jms/command/JmsConnectionCommandSupport.java
new file mode 100644
index 0000000..64adfe4
--- /dev/null
+++ b/jms/src/main/java/org/apache/karaf/jms/command/JmsConnectionCommandSupport.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.karaf.jms.command;
+
+import org.apache.karaf.jms.command.completers.ConnectionFactoriesNameCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+
+/**
+ * For commands that need a connection factory and authentication information 
+ */
+public abstract class JmsConnectionCommandSupport extends JmsCommandSupport {
+
+    @Argument(index = 0, name = "connectionFactory", description = "The JMS connection factory name", required = true, multiValued = false)
+    @Completion(ConnectionFactoriesNameCompleter.class)
+    String connectionFactory;
+
+    @Option(name = "-u", aliases = { "--username" }, description = "Username to connect to the JMS broker", required = false, multiValued = false)
+    String username = "karaf";
+
+    @Option(name = "-p", aliases = { "--password" }, description = "Password to connect to the JMS broker", required = false, multiValued = false)
+    String password = "karaf";
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/src/main/java/org/apache/karaf/jms/command/MoveCommand.java
----------------------------------------------------------------------
diff --git a/jms/src/main/java/org/apache/karaf/jms/command/MoveCommand.java b/jms/src/main/java/org/apache/karaf/jms/command/MoveCommand.java
new file mode 100644
index 0000000..a4c8d12
--- /dev/null
+++ b/jms/src/main/java/org/apache/karaf/jms/command/MoveCommand.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.karaf.jms.command;
+
+
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "jms", name = "move", description = "Move messages from one JMS queue to another one.")
+@Service
+public class MoveCommand extends JmsConnectionCommandSupport {
+
+    @Argument(index = 1, name = "source", description = "The source JMS queue", required = true, multiValued = false)
+    String source;
+
+    @Argument(index = 2, name = "destination", description = "The destination JMS queue", required = true, multiValued = false)
+    String destination;
+
+    @Option(name = "-s", aliases = { "--selector" }, description = "Selector to move only some messages", required = false, multiValued = false)
+    String selector;
+
+    @Override
+    public Object execute() throws Exception {
+        System.out.println(getJmsService().move(connectionFactory, source, destination, selector, username, password) + " message(s) moved");
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/src/main/java/org/apache/karaf/jms/command/QueuesCommand.java
----------------------------------------------------------------------
diff --git a/jms/src/main/java/org/apache/karaf/jms/command/QueuesCommand.java b/jms/src/main/java/org/apache/karaf/jms/command/QueuesCommand.java
new file mode 100644
index 0000000..7cf1dac
--- /dev/null
+++ b/jms/src/main/java/org/apache/karaf/jms/command/QueuesCommand.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.karaf.jms.command;
+
+
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.table.ShellTable;
+
+@Command(scope = "jms", name = "queues", description = "List the JMS queues.")
+@Service
+public class QueuesCommand extends JmsConnectionCommandSupport {
+
+    @Override
+    public Object execute() throws Exception {
+        ShellTable table = new ShellTable();
+
+        table.column("JMS Queues");
+
+        for (String queue : getJmsService().queues(connectionFactory, username, password)) {
+            table.addRow().addContent(queue);
+        }
+
+        table.print(System.out);
+
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/src/main/java/org/apache/karaf/jms/command/SendCommand.java
----------------------------------------------------------------------
diff --git a/jms/src/main/java/org/apache/karaf/jms/command/SendCommand.java b/jms/src/main/java/org/apache/karaf/jms/command/SendCommand.java
new file mode 100644
index 0000000..63d3f4a
--- /dev/null
+++ b/jms/src/main/java/org/apache/karaf/jms/command/SendCommand.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.karaf.jms.command;
+
+
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "jms", name = "send", description = "Send a message to ")
+@Service
+public class SendCommand extends JmsConnectionCommandSupport {
+
+    @Argument(index = 1, name = "queue", description = "The JMS queue name", required = true, multiValued = false)
+    String queue;
+
+    @Argument(index = 2, name = "message", description = "The JMS message content", required = true, multiValued = false)
+    String message;
+
+    @Option(name = "-r", aliases = { "--replyTo" }, description = "Set the message ReplyTo", required = false, multiValued = false)
+    String replyTo;
+
+    @Override
+    public Object execute() throws Exception {
+        getJmsService().send(connectionFactory, queue, message, replyTo, username, password);
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/src/main/java/org/apache/karaf/jms/command/TopicsCommand.java
----------------------------------------------------------------------
diff --git a/jms/src/main/java/org/apache/karaf/jms/command/TopicsCommand.java b/jms/src/main/java/org/apache/karaf/jms/command/TopicsCommand.java
new file mode 100644
index 0000000..b583bc4
--- /dev/null
+++ b/jms/src/main/java/org/apache/karaf/jms/command/TopicsCommand.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.karaf.jms.command;
+
+
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.table.ShellTable;
+
+@Command(scope = "jms", name = "topics", description = "List the JMS topics.")
+@Service
+public class TopicsCommand extends JmsConnectionCommandSupport {
+
+    @Override
+    public Object execute() throws Exception {
+        ShellTable table = new ShellTable();
+
+        table.column("JMS Topics");
+
+        for (String topic : getJmsService().topics(connectionFactory, username, password)) {
+            table.addRow().addContent(topic);
+        }
+
+        table.print(System.out);
+
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/src/main/java/org/apache/karaf/jms/command/completers/ConnectionFactoriesFileNameCompleter.java
----------------------------------------------------------------------
diff --git a/jms/src/main/java/org/apache/karaf/jms/command/completers/ConnectionFactoriesFileNameCompleter.java b/jms/src/main/java/org/apache/karaf/jms/command/completers/ConnectionFactoriesFileNameCompleter.java
new file mode 100644
index 0000000..c33ff62
--- /dev/null
+++ b/jms/src/main/java/org/apache/karaf/jms/command/completers/ConnectionFactoriesFileNameCompleter.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.karaf.jms.command.completers;
+
+import java.util.List;
+
+import org.apache.karaf.jms.JmsService;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.completers.StringsCompleter;
+
+/**
+ * Completer on the JMS connection factory file names.
+ */
+@Service
+public class ConnectionFactoriesFileNameCompleter implements Completer {
+
+    @Reference
+    private JmsService jmsService;
+
+    @Override
+    public int complete(Session session, CommandLine commandLine, List<String> candidates) {
+        StringsCompleter delegate = new StringsCompleter();
+        try {
+            for (String connectionFactory : jmsService.connectionFactoryFileNames()) {
+                delegate.getStrings().add(connectionFactory.replace("connectionfactory-", "").replace(".xml", ""));
+            }
+        } catch (Exception e) {
+            // nothing to do
+        }
+        return delegate.complete(session, commandLine, candidates);
+    }
+
+    public JmsService getJmsService() {
+        return jmsService;
+    }
+
+    public void setJmsService(JmsService jmsService) {
+        this.jmsService = jmsService;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/src/main/java/org/apache/karaf/jms/command/completers/ConnectionFactoriesNameCompleter.java
----------------------------------------------------------------------
diff --git a/jms/src/main/java/org/apache/karaf/jms/command/completers/ConnectionFactoriesNameCompleter.java b/jms/src/main/java/org/apache/karaf/jms/command/completers/ConnectionFactoriesNameCompleter.java
new file mode 100644
index 0000000..98f97b3
--- /dev/null
+++ b/jms/src/main/java/org/apache/karaf/jms/command/completers/ConnectionFactoriesNameCompleter.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.karaf.jms.command.completers;
+
+import java.util.List;
+
+import org.apache.karaf.jms.JmsService;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.completers.StringsCompleter;
+
+/**
+ * Completer on the JMS connection factories name.
+ */
+@Service
+public class ConnectionFactoriesNameCompleter implements Completer {
+
+    @Reference
+    private JmsService jmsService;
+
+    @Override
+    public int complete(Session session, CommandLine commandLine, List<String> candidates) {
+        StringsCompleter delegate = new StringsCompleter();
+        try {
+            for (String connectionFactory : jmsService.connectionFactories()) {
+                delegate.getStrings().add(connectionFactory);
+            }
+        } catch (Exception e) {
+            // nothing to do
+        }
+        return delegate.complete(session, commandLine, candidates);
+    }
+
+    public JmsService getJmsService() {
+        return jmsService;
+    }
+
+    public void setJmsService(JmsService jmsService) {
+        this.jmsService = jmsService;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0f53437c/jms/src/main/java/org/apache/karaf/jms/internal/JmsConnector.java
----------------------------------------------------------------------
diff --git a/jms/src/main/java/org/apache/karaf/jms/internal/JmsConnector.java b/jms/src/main/java/org/apache/karaf/jms/internal/JmsConnector.java
new file mode 100644
index 0000000..ecace89
--- /dev/null
+++ b/jms/src/main/java/org/apache/karaf/jms/internal/JmsConnector.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.karaf.jms.internal;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.Collection;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.JMSException;
+import javax.jms.Session;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+public class JmsConnector implements Closeable {
+    private BundleContext bc;
+    private ServiceReference<ConnectionFactory> reference;
+    private Connection connection;
+    private Session session;
+    private String connectionFactoryName;
+    private String username;
+    private String password;
+
+    public JmsConnector(BundleContext bc, String connectionFactoryName, String username, String password) throws JMSException {
+        this.bc = bc;
+        this.connectionFactoryName = connectionFactoryName;
+        this.username = username;
+        this.password = password;
+    }
+    
+    private ServiceReference<ConnectionFactory> lookupConnectionFactory(String name) {
+        Collection<ServiceReference<ConnectionFactory>> references;
+        try {
+            references = bc.getServiceReferences(ConnectionFactory.class, "(|(osgi.jndi.service.name=" + name + ")(name=" + name + ")(service.id=" + name + "))");
+        } catch (InvalidSyntaxException e) {
+            throw new RuntimeException("Error finding connection factory service " + name, e);
+        }
+        if (references == null || references.size() == 0) {
+            throw new IllegalArgumentException("No JMS connection factory found for " + name);
+        }
+        if (references.size() > 1) {
+            throw new IllegalArgumentException("Multiple JMS connection factories found for " + name);
+        }
+        return references.iterator().next();
+    }
+
+    @Override
+    public void close() throws IOException {
+        if (session != null) {
+            try {
+                session.close();
+            } catch (JMSException e) {
+                // Ignore
+            }
+        }
+        if (connection != null) {
+            try {
+                connection.close();
+            } catch (JMSException e) {
+                // Ignore
+            }
+        }
+        if (reference != null) {
+            bc.ungetService(reference);
+        }
+    }
+
+    public Connection connect() throws JMSException {
+        reference = this.lookupConnectionFactory(connectionFactoryName);
+        ConnectionFactory cf = (ConnectionFactory) bc.getService(reference);
+        connection = cf.createConnection(username, password);
+        connection.start();
+        return connection;
+    }
+
+    public Session createSession() throws JMSException {
+        if (connection == null) {
+            connect();
+        }
+        return session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+    }
+}


[21/33] Revert "[KARAF-2852] Merge features/core and features/command"

Posted by gn...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/osgi/Activator.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/osgi/Activator.java b/features/src/main/java/org/apache/karaf/features/internal/osgi/Activator.java
deleted file mode 100644
index be0da05..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/osgi/Activator.java
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.osgi;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Dictionary;
-import java.util.Hashtable;
-import java.util.Properties;
-
-import org.apache.karaf.features.FeaturesListener;
-import org.apache.karaf.features.FeaturesService;
-import org.apache.karaf.features.internal.service.EventAdminListener;
-import org.apache.karaf.features.internal.service.FeatureConfigInstaller;
-import org.apache.karaf.features.internal.service.FeatureFinder;
-import org.apache.karaf.features.internal.service.BootFeaturesInstaller;
-import org.apache.karaf.features.internal.service.FeaturesServiceImpl;
-import org.apache.karaf.features.internal.service.StateStorage;
-import org.apache.karaf.features.internal.management.FeaturesServiceMBeanImpl;
-import org.apache.karaf.features.RegionsPersistence;
-import org.apache.karaf.util.tracker.BaseActivator;
-import org.apache.karaf.util.tracker.SingleServiceTracker;
-import org.osgi.framework.Constants;
-import org.osgi.framework.ServiceReference;
-import org.osgi.service.cm.ConfigurationAdmin;
-import org.osgi.service.cm.ManagedService;
-import org.osgi.service.url.URLStreamHandlerService;
-import org.osgi.util.tracker.ServiceTracker;
-import org.osgi.util.tracker.ServiceTrackerCustomizer;
-
-public class Activator extends BaseActivator {
-
-    public static final String FEATURES_REPOS_PID = "org.apache.karaf.features.repos";
-    public static final String FEATURES_SERVICE_CONFIG_FILE = "org.apache.karaf.features.cfg";
-
-    private ServiceTracker<FeaturesListener, FeaturesListener> featuresListenerTracker;
-    private FeaturesServiceImpl featuresService;
-    private SingleServiceTracker<RegionsPersistence> regionsTracker;
-
-    public Activator() {
-        // Special case here, as we don't want the activator to wait for current job to finish,
-        // else it would forbid the features service to refresh itself
-        setSchedulerStopTimeout(0);
-    }
-
-    @Override
-    protected void doOpen() throws Exception {
-        trackService(URLStreamHandlerService.class, "(url.handler.protocol=mvn)");
-        trackService(ConfigurationAdmin.class);
-
-        Properties configuration = new Properties();
-        File configFile = new File(System.getProperty("karaf.etc"), FEATURES_SERVICE_CONFIG_FILE);
-        if (configFile.isFile() && configFile.canRead()) {
-            try {
-                configuration.load(new FileReader(configFile));
-            } catch (IOException e) {
-                logger.warn("Error reading configuration file " + configFile.toString(), e);
-            }
-        }
-        updated((Dictionary) configuration);
-    }
-
-    protected void doStart() throws Exception {
-        ConfigurationAdmin configurationAdmin = getTrackedService(ConfigurationAdmin.class);
-        URLStreamHandlerService mvnUrlHandler = getTrackedService(URLStreamHandlerService.class);
-
-        if (configurationAdmin == null || mvnUrlHandler == null) {
-            return;
-        }
-
-        FeatureFinder featureFinder = new FeatureFinder();
-        Hashtable<String, Object> props = new Hashtable<String, Object>();
-        props.put(Constants.SERVICE_PID, FEATURES_REPOS_PID);
-        register(ManagedService.class, featureFinder, props);
-
-        // TODO: region support
-//        final BundleManager bundleManager = new BundleManager(bundleContext);
-//        regionsTracker = new SingleServiceTracker<RegionsPersistence>(bundleContext, RegionsPersistence.class,
-//                new SingleServiceTracker.SingleServiceListener() {
-//                    @Override
-//                    public void serviceFound() {
-//                        bundleManager.setRegionsPersistence(regionsTracker.getService());
-//                    }
-//                    @Override
-//                    public void serviceLost() {
-//                        serviceFound();
-//                    }
-//                    @Override
-//                    public void serviceReplaced() {
-//                        serviceFound();
-//                    }
-//                });
-//        regionsTracker.open();
-
-
-        FeatureConfigInstaller configInstaller = new FeatureConfigInstaller(configurationAdmin);
-        // TODO: honor respectStartLvlDuringFeatureStartup and respectStartLvlDuringFeatureUninstall
-//        boolean respectStartLvlDuringFeatureStartup = getBoolean("respectStartLvlDuringFeatureStartup", true);
-//        boolean respectStartLvlDuringFeatureUninstall = getBoolean("respectStartLvlDuringFeatureUninstall", true);
-        String overrides = getString("overrides", new File(System.getProperty("karaf.etc"), "overrides.properties").toURI().toString());
-        String featureResolutionRange = getString("featureResolutionRange", FeaturesServiceImpl.DEFAULT_FEATURE_RESOLUTION_RANGE);
-        String bundleUpdateRange = getString("bundleUpdateRange", FeaturesServiceImpl.DEFAULT_BUNDLE_UPDATE_RANGE);
-        String updateSnapshots = getString("updateSnapshots", FeaturesServiceImpl.DEFAULT_UPDATE_SNAPSHOTS);
-        StateStorage stateStorage = new StateStorage() {
-            @Override
-            protected InputStream getInputStream() throws IOException {
-                File file = bundleContext.getDataFile("FeaturesServiceState.properties");
-                if (file.exists()) {
-                    return new FileInputStream(file);
-                } else {
-                    return null;
-                }
-            }
-
-            @Override
-            protected OutputStream getOutputStream() throws IOException {
-                File file = bundleContext.getDataFile("FeaturesServiceState.properties");
-                return new FileOutputStream(file);
-            }
-        };
-        EventAdminListener eventAdminListener;
-        try {
-            eventAdminListener = new EventAdminListener(bundleContext);
-        } catch (Throwable t) {
-            eventAdminListener = null;
-        }
-        featuresService = new FeaturesServiceImpl(
-                                bundleContext.getBundle(),
-                                bundleContext.getBundle(0).getBundleContext(),
-                                stateStorage,
-                                featureFinder,
-                                eventAdminListener,
-                                configInstaller,
-                                overrides,
-                                featureResolutionRange,
-                                bundleUpdateRange,
-                                updateSnapshots);
-        register(FeaturesService.class, featuresService);
-
-        featuresListenerTracker = new ServiceTracker<FeaturesListener, FeaturesListener>(
-                bundleContext, FeaturesListener.class, new ServiceTrackerCustomizer<FeaturesListener, FeaturesListener>() {
-            @Override
-            public FeaturesListener addingService(ServiceReference<FeaturesListener> reference) {
-                FeaturesListener service = bundleContext.getService(reference);
-                featuresService.registerListener(service);
-                return service;
-            }
-            @Override
-            public void modifiedService(ServiceReference<FeaturesListener> reference, FeaturesListener service) {
-            }
-            @Override
-            public void removedService(ServiceReference<FeaturesListener> reference, FeaturesListener service) {
-                featuresService.unregisterListener(service);
-                bundleContext.ungetService(reference);
-            }
-        }
-        );
-        featuresListenerTracker.open();
-
-        String featuresRepositories = getString("featuresRepositories", "");
-        String featuresBoot = getString("featuresBoot", "");
-        boolean featuresBootAsynchronous = getBoolean("featuresBootAsynchronous", false);
-        BootFeaturesInstaller bootFeaturesInstaller = new BootFeaturesInstaller(
-                bundleContext, featuresService,
-                featuresRepositories, featuresBoot, featuresBootAsynchronous);
-        bootFeaturesInstaller.start();
-
-        FeaturesServiceMBeanImpl featuresServiceMBean = new FeaturesServiceMBeanImpl();
-        featuresServiceMBean.setBundleContext(bundleContext);
-        featuresServiceMBean.setFeaturesService(featuresService);
-        registerMBean(featuresServiceMBean, "type=feature");
-    }
-
-    protected void doStop() {
-        if (regionsTracker != null) {
-            regionsTracker.close();
-            regionsTracker = null;
-        }
-        if (featuresListenerTracker != null) {
-            featuresListenerTracker.close();
-            featuresListenerTracker = null;
-        }
-        super.doStop();
-        if (featuresService != null) {
-            featuresService = null;
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/repository/AggregateRepository.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/repository/AggregateRepository.java b/features/src/main/java/org/apache/karaf/features/internal/repository/AggregateRepository.java
deleted file mode 100644
index 0d5e83d..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/repository/AggregateRepository.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.repository;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.osgi.resource.Capability;
-import org.osgi.resource.Requirement;
-import org.osgi.service.repository.Repository;
-
-public class AggregateRepository implements Repository {
-
-    private final Collection<Repository> repositories;
-
-    public AggregateRepository(Collection<Repository> repositories) {
-        this.repositories = repositories;
-    }
-
-    @Override
-    public Map<Requirement, Collection<Capability>> findProviders(Collection<? extends Requirement> requirements) {
-        Map<Requirement, Collection<Capability>> result = new HashMap<Requirement, Collection<Capability>>();
-        for (Requirement requirement : requirements) {
-            List<Capability> caps = new ArrayList<Capability>();
-            for (Repository repository : repositories) {
-                Map<Requirement, Collection<Capability>> resMap =
-                        repository.findProviders(Collections.singleton(requirement));
-                Collection<Capability> res = resMap != null ? resMap.get(requirement) : null;
-                if (res != null) {
-                    caps.addAll(res);
-                }
-            }
-            result.put(requirement, caps);
-        }
-        return result;
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/repository/BaseRepository.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/repository/BaseRepository.java b/features/src/main/java/org/apache/karaf/features/internal/repository/BaseRepository.java
deleted file mode 100644
index c4c0d16..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/repository/BaseRepository.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.repository;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.karaf.features.internal.resolver.CapabilitySet;
-import org.apache.karaf.features.internal.resolver.RequirementImpl;
-import org.apache.karaf.features.internal.resolver.SimpleFilter;
-import org.osgi.framework.Constants;
-import org.osgi.resource.Capability;
-import org.osgi.resource.Requirement;
-import org.osgi.resource.Resource;
-import org.osgi.service.repository.Repository;
-
-/**
- */
-public class BaseRepository implements Repository {
-
-    protected final List<Resource> resources;
-    protected final Map<String, CapabilitySet> capSets;
-
-    public BaseRepository() {
-        this.resources = new ArrayList<Resource>();
-        this.capSets = new HashMap<String, CapabilitySet>();
-    }
-
-    protected void addResource(Resource resource) {
-        for (Capability cap : resource.getCapabilities(null)) {
-            String ns = cap.getNamespace();
-            CapabilitySet set = capSets.get(ns);
-            if (set == null) {
-                set = new CapabilitySet(Collections.singletonList(ns));
-                capSets.put(ns, set);
-            }
-            set.addCapability(cap);
-        }
-        resources.add(resource);
-    }
-
-    public List<Resource> getResources() {
-        return resources;
-    }
-
-    @Override
-    public Map<Requirement, Collection<Capability>> findProviders(Collection<? extends Requirement> requirements) {
-        Map<Requirement, Collection<Capability>> result = new HashMap<Requirement, Collection<Capability>>();
-        for (Requirement requirement : requirements) {
-            CapabilitySet set = capSets.get(requirement.getNamespace());
-            if (set != null) {
-                SimpleFilter sf;
-                if (requirement instanceof RequirementImpl) {
-                    sf = ((RequirementImpl) requirement).getFilter();
-                } else {
-                    String filter = requirement.getDirectives().get(Constants.FILTER_DIRECTIVE);
-                    sf = (filter != null)
-                            ? SimpleFilter.parse(filter)
-                            : new SimpleFilter(null, null, SimpleFilter.MATCH_ALL);
-                }
-                result.put(requirement, set.match(sf, true));
-            } else {
-                result.put(requirement, Collections.<Capability>emptyList());
-            }
-        }
-        return result;
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/repository/CacheRepository.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/repository/CacheRepository.java b/features/src/main/java/org/apache/karaf/features/internal/repository/CacheRepository.java
deleted file mode 100644
index 7916821..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/repository/CacheRepository.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.repository;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.osgi.resource.Capability;
-import org.osgi.resource.Requirement;
-import org.osgi.service.repository.Repository;
-
-public class CacheRepository implements Repository {
-
-    private final Repository repository;
-    private final Map<Requirement, Collection<Capability>> cache =
-            new ConcurrentHashMap<Requirement, Collection<Capability>>();
-
-    public CacheRepository(Repository repository) {
-        this.repository = repository;
-    }
-
-    @Override
-    public Map<Requirement, Collection<Capability>> findProviders(Collection<? extends Requirement> requirements) {
-        List<Requirement> missing = new ArrayList<Requirement>();
-        Map<Requirement, Collection<Capability>> result = new HashMap<Requirement, Collection<Capability>>();
-        for (Requirement requirement : requirements) {
-            Collection<Capability> caps = cache.get(requirement);
-            if (caps == null) {
-                missing.add(requirement);
-            } else {
-                result.put(requirement, caps);
-            }
-        }
-        Map<Requirement, Collection<Capability>> newCache = repository.findProviders(missing);
-        for (Requirement requirement : newCache.keySet()) {
-            cache.put(requirement, newCache.get(requirement));
-            result.put(requirement, newCache.get(requirement));
-        }
-        return result;
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/repository/HttpMetadataProvider.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/repository/HttpMetadataProvider.java b/features/src/main/java/org/apache/karaf/features/internal/repository/HttpMetadataProvider.java
deleted file mode 100644
index 1aecef1..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/repository/HttpMetadataProvider.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.repository;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.util.Map;
-import java.util.zip.GZIPInputStream;
-
-import org.apache.karaf.features.internal.util.JsonReader;
-
-/**
- */
-public class HttpMetadataProvider implements MetadataProvider {
-
-    public static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding";
-    public static final String HEADER_CONTENT_ENCODING = "Content-Encoding";
-    public static final String GZIP = "gzip";
-
-    private final String url;
-    private long lastModified;
-    private Map<String, Map<String, String>> metadatas;
-
-    public HttpMetadataProvider(String url) {
-        this.url = url;
-    }
-
-    @Override
-    public long getLastModified() {
-        return lastModified;
-    }
-
-    @Override
-    public Map<String, Map<String, String>> getMetadatas() {
-        try {
-            HttpURLConnection.setFollowRedirects(false);
-            HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
-            if (lastModified > 0) {
-                con.setIfModifiedSince(lastModified);
-            }
-            con.setRequestProperty(HEADER_ACCEPT_ENCODING, GZIP);
-            if (con.getResponseCode() == HttpURLConnection.HTTP_OK) {
-                lastModified = con.getLastModified();
-                InputStream is = con.getInputStream();
-                if (GZIP.equals(con.getHeaderField(HEADER_CONTENT_ENCODING))) {
-                    is = new GZIPInputStream(is);
-                }
-                metadatas = verify(JsonReader.read(is));
-            } else if (con.getResponseCode() != HttpURLConnection.HTTP_NOT_MODIFIED) {
-                throw new IOException("Unexpected http response: "
-                        + con.getResponseCode() + " " + con.getResponseMessage());
-            }
-            return metadatas;
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    private Map<String, Map<String, String>> verify(Object value) {
-        Map<?,?> obj = Map.class.cast(value);
-        for (Map.Entry<?,?> entry : obj.entrySet()) {
-            String.class.cast(entry.getKey());
-            Map<?,?> child = Map.class.cast(entry.getValue());
-            for (Map.Entry<?,?> ce : child.entrySet()) {
-                String.class.cast(ce.getKey());
-                String.class.cast(ce.getValue());
-            }
-        }
-        return (Map<String, Map<String, String>>) obj;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/repository/MetadataProvider.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/repository/MetadataProvider.java b/features/src/main/java/org/apache/karaf/features/internal/repository/MetadataProvider.java
deleted file mode 100644
index 9ac54a1..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/repository/MetadataProvider.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.repository;
-
-import java.util.Map;
-
-/**
- */
-public interface MetadataProvider {
-
-    long getLastModified();
-
-    Map<String, Map<String, String>> getMetadatas();
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/repository/MetadataRepository.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/repository/MetadataRepository.java b/features/src/main/java/org/apache/karaf/features/internal/repository/MetadataRepository.java
deleted file mode 100644
index 2d4fbba..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/repository/MetadataRepository.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.repository;
-
-import java.util.Map;
-
-import org.apache.karaf.features.internal.resolver.ResourceBuilder;
-import org.osgi.resource.Resource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- */
-public class MetadataRepository extends BaseRepository {
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(MetadataRepository.class);
-
-    public MetadataRepository(MetadataProvider provider) {
-        Map<String, Map<String, String>> metadatas = provider.getMetadatas();
-        for (Map.Entry<String, Map<String, String>> metadata : metadatas.entrySet()) {
-            try {
-                Resource resource = ResourceBuilder.build(metadata.getKey(), metadata.getValue());
-                addResource(resource);
-            } catch (Exception e) {
-                LOGGER.info("Unable to build resource for " + metadata.getKey(), e);
-            }
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/repository/StaticRepository.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/repository/StaticRepository.java b/features/src/main/java/org/apache/karaf/features/internal/repository/StaticRepository.java
deleted file mode 100644
index f289c8d..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/repository/StaticRepository.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.repository;
-
-import java.util.Collection;
-
-import org.osgi.resource.Resource;
-
-/**
- */
-public class StaticRepository extends BaseRepository {
-
-    public StaticRepository(Collection<Resource> resources) {
-        for (Resource resource : resources) {
-            addResource(resource);
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/resolver/BaseClause.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/resolver/BaseClause.java b/features/src/main/java/org/apache/karaf/features/internal/resolver/BaseClause.java
deleted file mode 100644
index 0653398..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/resolver/BaseClause.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.resolver;
-
-import java.util.Map;
-
-import org.osgi.framework.Version;
-import org.osgi.resource.Resource;
-
-/**
- */
-public abstract class BaseClause {
-
-    public abstract Resource getResource();
-
-    public abstract String getNamespace();
-
-    public abstract Map<String, String> getDirectives();
-
-    public abstract Map<String, Object> getAttributes();
-
-    @Override
-    public String toString() {
-        return toString(getResource(), getNamespace(), getAttributes(), getDirectives());
-    }
-
-    public static String toString(Resource res, String namespace, Map<String, Object> attrs, Map<String, String> dirs) {
-        StringBuilder sb = new StringBuilder();
-        if (res != null) {
-            sb.append("[").append(res).append("] ");
-        }
-        sb.append(namespace);
-        for (String key : attrs.keySet()) {
-            sb.append("; ");
-            append(sb, key, attrs.get(key), true);
-        }
-        for (String key : dirs.keySet()) {
-            sb.append("; ");
-            append(sb, key, dirs.get(key), false);
-        }
-        return sb.toString();
-    }
-
-    private static void append(StringBuilder sb, String key, Object val, boolean attribute) {
-        sb.append(key);
-        if (val instanceof Version) {
-            sb.append(":Version=");
-            sb.append(val);
-        } else if (val instanceof Long) {
-            sb.append(":Long=");
-            sb.append(val);
-        } else if (val instanceof Double) {
-            sb.append(":Double=");
-            sb.append(val);
-        } else if (val instanceof Iterable) {
-            Iterable it = (Iterable) val;
-            String scalar = null;
-            for (Object o : it) {
-                String ts;
-                if (o instanceof String) {
-                    ts = "String";
-                } else if (o instanceof Long) {
-                    ts = "Long";
-                } else if (o instanceof Double) {
-                    ts = "Double";
-                } else if (o instanceof Version) {
-                    ts = "Version";
-                } else {
-                    throw new IllegalArgumentException("Unsupported scalar type: " + o);
-                }
-                if (scalar == null) {
-                    scalar = ts;
-                } else if (!scalar.equals(ts)) {
-                    throw new IllegalArgumentException("Unconsistent list type for attribute " + key);
-                }
-            }
-            sb.append(":List<").append(scalar).append(">=");
-            sb.append("\"");
-            boolean first = true;
-            for (Object o : it) {
-                if (first) {
-                    first = false;
-                } else {
-                    sb.append(",");
-                }
-                sb.append(o.toString().replace("\"", "\\\"").replace(",", "\\,"));
-            }
-            sb.append("\"");
-        } else {
-            sb.append(attribute ? "=" : ":=");
-            String s = val.toString();
-            if (s.matches("[0-9a-zA-Z_\\-.]*")) {
-                sb.append(s);
-            } else {
-                sb.append("\"").append(s.replace("\"", "\\\\")).append("\"");
-            }
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/resolver/CandidateComparator.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/resolver/CandidateComparator.java b/features/src/main/java/org/apache/karaf/features/internal/resolver/CandidateComparator.java
deleted file mode 100644
index ad4cc85..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/resolver/CandidateComparator.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.resolver;
-
-import java.util.Comparator;
-
-import org.osgi.framework.Version;
-import org.osgi.framework.namespace.BundleNamespace;
-import org.osgi.framework.namespace.PackageNamespace;
-import org.osgi.framework.wiring.BundleCapability;
-import org.osgi.resource.Capability;
-
-public class CandidateComparator implements Comparator<Capability>
-{
-    public int compare(Capability cap1, Capability cap2)
-    {
-        int c = 0;
-        // Always prefer system bundle
-        if (cap1 instanceof BundleCapability && !(cap2 instanceof BundleCapability)) {
-            c = -1;
-        } else if (!(cap1 instanceof BundleCapability) && cap2 instanceof BundleCapability) {
-            c = 1;
-        }
-        // Compare revision capabilities.
-        if ((c == 0) && cap1.getNamespace().equals(BundleNamespace.BUNDLE_NAMESPACE))
-        {
-            c = ((Comparable) cap1.getAttributes().get(BundleNamespace.BUNDLE_NAMESPACE))
-                    .compareTo(cap2.getAttributes().get(BundleNamespace.BUNDLE_NAMESPACE));
-            if (c == 0)
-            {
-                Version v1 = (!cap1.getAttributes().containsKey(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE))
-                        ? Version.emptyVersion
-                        : (Version) cap1.getAttributes().get(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE);
-                Version v2 = (!cap2.getAttributes().containsKey(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE))
-                        ? Version.emptyVersion
-                        : (Version) cap2.getAttributes().get(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE);
-                // Compare these in reverse order, since we want
-                // highest version to have priority.
-                c = compareVersions(v2, v1);
-            }
-        }
-        // Compare package capabilities.
-        else if ((c == 0) && cap1.getNamespace().equals(PackageNamespace.PACKAGE_NAMESPACE))
-        {
-            c = ((Comparable) cap1.getAttributes().get(PackageNamespace.PACKAGE_NAMESPACE))
-                    .compareTo(cap2.getAttributes().get(PackageNamespace.PACKAGE_NAMESPACE));
-            if (c == 0)
-            {
-                Version v1 = (!cap1.getAttributes().containsKey(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE))
-                        ? Version.emptyVersion
-                        : (Version) cap1.getAttributes().get(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE);
-                Version v2 = (!cap2.getAttributes().containsKey(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE))
-                        ? Version.emptyVersion
-                        : (Version) cap2.getAttributes().get(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE);
-                // Compare these in reverse order, since we want
-                // highest version to have priority.
-                c = compareVersions(v2, v1);
-                // if same version, rather compare on the bundle version
-                if (c == 0)
-                {
-                    v1 = (!cap1.getAttributes().containsKey(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE))
-                            ? Version.emptyVersion
-                            : (Version) cap1.getAttributes().get(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE);
-                    v2 = (!cap2.getAttributes().containsKey(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE))
-                            ? Version.emptyVersion
-                            : (Version) cap2.getAttributes().get(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE);
-                    // Compare these in reverse order, since we want
-                    // highest version to have priority.
-                    c = compareVersions(v2, v1);
-                }
-            }
-        }
-        // Compare feature capabilities
-        else if ((c == 0) && cap1.getNamespace().equals(FeatureNamespace.FEATURE_NAMESPACE))
-        {
-            c = ((Comparable) cap1.getAttributes().get(FeatureNamespace.FEATURE_NAMESPACE))
-                    .compareTo(cap2.getAttributes().get(FeatureNamespace.FEATURE_NAMESPACE));
-            if (c == 0)
-            {
-                Version v1 = (!cap1.getAttributes().containsKey(FeatureNamespace.CAPABILITY_VERSION_ATTRIBUTE))
-                        ? Version.emptyVersion
-                        : (Version) cap1.getAttributes().get(FeatureNamespace.CAPABILITY_VERSION_ATTRIBUTE);
-                Version v2 = (!cap2.getAttributes().containsKey(FeatureNamespace.CAPABILITY_VERSION_ATTRIBUTE))
-                        ? Version.emptyVersion
-                        : (Version) cap2.getAttributes().get(FeatureNamespace.CAPABILITY_VERSION_ATTRIBUTE);
-                // Compare these in reverse order, since we want
-                // highest version to have priority.
-                c = compareVersions(v2, v1);
-            }
-        }
-        return c;
-    }
-
-    private int compareVersions(Version v1, Version v2) {
-        int c = v1.getMajor() - v2.getMajor();
-        if (c != 0) {
-            return c;
-        }
-        c = v1.getMinor() - v2.getMinor();
-        if (c != 0) {
-            return c;
-        }
-        c = v1.getMicro() - v2.getMicro();
-        if (c != 0) {
-            return c;
-        }
-        String q1 = cleanQualifierForComparison(v1.getQualifier());
-        String q2 = cleanQualifierForComparison(v2.getQualifier());
-        return q1.compareTo(q2);
-    }
-
-    private String cleanQualifierForComparison(String qualifier) {
-        return qualifier.replaceAll("(redhat-[0-9]{3})([0-9]{3})", "$1-$2");
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/resolver/CapabilityImpl.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/resolver/CapabilityImpl.java b/features/src/main/java/org/apache/karaf/features/internal/resolver/CapabilityImpl.java
deleted file mode 100644
index bfe9b40..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/resolver/CapabilityImpl.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.resolver;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.StringTokenizer;
-
-import org.osgi.framework.Constants;
-import org.osgi.resource.Capability;
-import org.osgi.resource.Resource;
-
-public class CapabilityImpl extends BaseClause implements Capability {
-
-    private final Resource m_resource;
-    private final String m_namespace;
-    private final Map<String, String> m_dirs;
-    private final Map<String, Object> m_attrs;
-    private final List<String> m_uses;
-    private final List<List<String>> m_includeFilter;
-    private final List<List<String>> m_excludeFilter;
-    private final Set<String> m_mandatory;
-
-    public CapabilityImpl(Capability capability) {
-        this(null, capability.getNamespace(), capability.getDirectives(), capability.getAttributes());
-    }
-
-    public CapabilityImpl(Resource resource, String namespace,
-                          Map<String, String> dirs, Map<String, Object> attrs) {
-        m_namespace = namespace;
-        m_resource = resource;
-        m_dirs = dirs;
-        m_attrs = attrs;
-
-        // Find all export directives: uses, mandatory, include, and exclude.
-
-        List<String> uses = Collections.emptyList();
-        String value = m_dirs.get(Constants.USES_DIRECTIVE);
-        if (value != null) {
-            // Parse these uses directive.
-            StringTokenizer tok = new StringTokenizer(value, ",");
-            uses = new ArrayList<String>(tok.countTokens());
-            while (tok.hasMoreTokens()) {
-                uses.add(tok.nextToken().trim());
-            }
-        }
-        m_uses = uses;
-
-        value = m_dirs.get(Constants.INCLUDE_DIRECTIVE);
-        if (value != null) {
-            List<String> filters = ResourceBuilder.parseDelimitedString(value, ",");
-            m_includeFilter = new ArrayList<List<String>>(filters.size());
-            for (String filter : filters) {
-                List<String> substrings = SimpleFilter.parseSubstring(filter);
-                m_includeFilter.add(substrings);
-            }
-        } else {
-            m_includeFilter = null;
-        }
-
-        value = m_dirs.get(Constants.EXCLUDE_DIRECTIVE);
-        if (value != null) {
-            List<String> filters = ResourceBuilder.parseDelimitedString(value, ",");
-            m_excludeFilter = new ArrayList<List<String>>(filters.size());
-            for (String filter : filters) {
-                List<String> substrings = SimpleFilter.parseSubstring(filter);
-                m_excludeFilter.add(substrings);
-            }
-        } else {
-            m_excludeFilter = null;
-        }
-
-        Set<String> mandatory = Collections.emptySet();
-        value = m_dirs.get(Constants.MANDATORY_DIRECTIVE);
-        if (value != null) {
-            List<String> names = ResourceBuilder.parseDelimitedString(value, ",");
-            mandatory = new HashSet<String>(names.size());
-            for (String name : names) {
-                // If attribute exists, then record it as mandatory.
-                if (m_attrs.containsKey(name)) {
-                    mandatory.add(name);
-                }
-                // Otherwise, report an error.
-                else {
-                    throw new IllegalArgumentException("Mandatory attribute '" + name + "' does not exist.");
-                }
-            }
-        }
-        m_mandatory = mandatory;
-    }
-
-    public Resource getResource() {
-        return m_resource;
-    }
-
-    public String getNamespace() {
-        return m_namespace;
-    }
-
-    public Map<String, String> getDirectives() {
-        return m_dirs;
-    }
-
-    public Map<String, Object> getAttributes() {
-        return m_attrs;
-    }
-
-    public boolean isAttributeMandatory(String name) {
-        return !m_mandatory.isEmpty() && m_mandatory.contains(name);
-    }
-
-    public List<String> getUses() {
-        return m_uses;
-    }
-
-    public boolean isIncluded(String name) {
-        if ((m_includeFilter == null) && (m_excludeFilter == null)) {
-            return true;
-        }
-
-        // Get the class name portion of the target class.
-        String className = getClassName(name);
-
-        // If there are no include filters then all classes are included
-        // by default, otherwise try to find one match.
-        boolean included = (m_includeFilter == null);
-        for (int i = 0; !included && m_includeFilter != null && i < m_includeFilter.size(); i++) {
-            included = SimpleFilter.compareSubstring(m_includeFilter.get(i), className);
-        }
-
-        // If there are no exclude filters then no classes are excluded
-        // by default, otherwise try to find one match.
-        boolean excluded = false;
-        for (int i = 0; (!excluded) && (m_excludeFilter != null) && (i < m_excludeFilter.size()); i++) {
-            excluded = SimpleFilter.compareSubstring(m_excludeFilter.get(i), className);
-        }
-        return included && !excluded;
-    }
-
-    private static String getClassName(String className) {
-        if (className == null) {
-            className = "";
-        }
-        return (className.lastIndexOf('.') < 0) ? "" : className.substring(className.lastIndexOf('.') + 1);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/resolver/CapabilitySet.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/resolver/CapabilitySet.java b/features/src/main/java/org/apache/karaf/features/internal/resolver/CapabilitySet.java
deleted file mode 100644
index 4c5656d..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/resolver/CapabilitySet.java
+++ /dev/null
@@ -1,612 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.resolver;
-
-import java.lang.reflect.Array;
-import java.lang.reflect.Constructor;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.TreeMap;
-
-import org.osgi.framework.Constants;
-import org.osgi.resource.Capability;
-
-public class CapabilitySet
-{
-    private final Map<String, Map<Object, Set<Capability>>> m_indices;
-    private final Set<Capability> m_capSet = new HashSet<Capability>();
-
-public void dump()
-{
-    for (Entry<String, Map<Object, Set<Capability>>> entry : m_indices.entrySet())
-    {
-        boolean header1 = false;
-        for (Entry<Object, Set<Capability>> entry2 : entry.getValue().entrySet())
-        {
-            boolean header2 = false;
-            for (Capability cap : entry2.getValue())
-            {
-                if (!header1)
-                {
-                    System.out.println(entry.getKey() + ":");
-                    header1 = true;
-                }
-                if (!header2)
-                {
-                    System.out.println("   " + entry2.getKey());
-                    header2 = true;
-                }
-                System.out.println("      " + cap);
-            }
-        }
-    }
-}
-
-    public CapabilitySet(List<String> indexProps)
-    {
-        m_indices = new TreeMap<String, Map<Object, Set<Capability>>>();
-        for (int i = 0; (indexProps != null) && (i < indexProps.size()); i++)
-        {
-            m_indices.put(
-                indexProps.get(i), new HashMap<Object, Set<Capability>>());
-        }
-    }
-
-    public void addCapability(Capability cap)
-    {
-        m_capSet.add(cap);
-
-        // Index capability.
-        for (Entry<String, Map<Object, Set<Capability>>> entry : m_indices.entrySet())
-        {
-            Object value = cap.getAttributes().get(entry.getKey());
-            if (value != null)
-            {
-                if (value.getClass().isArray())
-                {
-                    value = convertArrayToList(value);
-                }
-
-                Map<Object, Set<Capability>> index = entry.getValue();
-
-                if (value instanceof Collection)
-                {
-                    Collection c = (Collection) value;
-                    for (Object o : c)
-                    {
-                        indexCapability(index, cap, o);
-                    }
-                }
-                else
-                {
-                    indexCapability(index, cap, value);
-                }
-            }
-        }
-    }
-
-    private void indexCapability(
-        Map<Object, Set<Capability>> index, Capability cap, Object capValue)
-    {
-        Set<Capability> caps = index.get(capValue);
-        if (caps == null)
-        {
-            caps = new HashSet<Capability>();
-            index.put(capValue, caps);
-        }
-        caps.add(cap);
-    }
-
-    public void removeCapability(Capability cap)
-    {
-        if (m_capSet.remove(cap))
-        {
-            for (Entry<String, Map<Object, Set<Capability>>> entry : m_indices.entrySet())
-            {
-                Object value = cap.getAttributes().get(entry.getKey());
-                if (value != null)
-                {
-                    if (value.getClass().isArray())
-                    {
-                        value = convertArrayToList(value);
-                    }
-
-                    Map<Object, Set<Capability>> index = entry.getValue();
-
-                    if (value instanceof Collection)
-                    {
-                        Collection c = (Collection) value;
-                        for (Object o : c)
-                        {
-                            deindexCapability(index, cap, o);
-                        }
-                    }
-                    else
-                    {
-                        deindexCapability(index, cap, value);
-                    }
-                }
-            }
-        }
-    }
-
-    private void deindexCapability(
-        Map<Object, Set<Capability>> index, Capability cap, Object value)
-    {
-        Set<Capability> caps = index.get(value);
-        if (caps != null)
-        {
-            caps.remove(cap);
-            if (caps.isEmpty())
-            {
-                index.remove(value);
-            }
-        }
-    }
-
-    public Set<Capability> match(SimpleFilter sf, boolean obeyMandatory)
-    {
-        Set<Capability> matches = match(m_capSet, sf);
-        return (obeyMandatory)
-            ? matchMandatory(matches, sf)
-            : matches;
-    }
-
-    private Set<Capability> match(Set<Capability> caps, SimpleFilter sf)
-    {
-        Set<Capability> matches = new HashSet<Capability>();
-
-        if (sf.getOperation() == SimpleFilter.MATCH_ALL)
-        {
-            matches.addAll(caps);
-        }
-        else if (sf.getOperation() == SimpleFilter.AND)
-        {
-            // Evaluate each subfilter against the remaining capabilities.
-            // For AND we calculate the intersection of each subfilter.
-            // We can short-circuit the AND operation if there are no
-            // remaining capabilities.
-            List<SimpleFilter> sfs = (List<SimpleFilter>) sf.getValue();
-            for (int i = 0; (caps.size() > 0) && (i < sfs.size()); i++)
-            {
-                matches = match(caps, sfs.get(i));
-                caps = matches;
-            }
-        }
-        else if (sf.getOperation() == SimpleFilter.OR)
-        {
-            // Evaluate each subfilter against the remaining capabilities.
-            // For OR we calculate the union of each subfilter.
-            List<SimpleFilter> sfs = (List<SimpleFilter>) sf.getValue();
-            for (int i = 0; i < sfs.size(); i++)
-            {
-                matches.addAll(match(caps, sfs.get(i)));
-            }
-        }
-        else if (sf.getOperation() == SimpleFilter.NOT)
-        {
-            // Evaluate each subfilter against the remaining capabilities.
-            // For OR we calculate the union of each subfilter.
-            matches.addAll(caps);
-            List<SimpleFilter> sfs = (List<SimpleFilter>) sf.getValue();
-            for (int i = 0; i < sfs.size(); i++)
-            {
-                matches.removeAll(match(caps, sfs.get(i)));
-            }
-        }
-        else
-        {
-            Map<Object, Set<Capability>> index = m_indices.get(sf.getName());
-            if ((sf.getOperation() == SimpleFilter.EQ) && (index != null))
-            {
-                Set<Capability> existingCaps = index.get(sf.getValue());
-                if (existingCaps != null)
-                {
-                    matches.addAll(existingCaps);
-                    matches.retainAll(caps);
-                }
-            }
-            else
-            {
-                for (Iterator<Capability> it = caps.iterator(); it.hasNext(); )
-                {
-                    Capability cap = it.next();
-                    Object lhs = cap.getAttributes().get(sf.getName());
-                    if (lhs != null)
-                    {
-                        if (compare(lhs, sf.getValue(), sf.getOperation()))
-                        {
-                            matches.add(cap);
-                        }
-                    }
-                }
-            }
-        }
-
-        return matches;
-    }
-
-    public static boolean matches(Capability cap, SimpleFilter sf)
-    {
-        return matchesInternal(cap, sf) && matchMandatory(cap, sf);
-    }
-
-    private static boolean matchesInternal(Capability cap, SimpleFilter sf)
-    {
-        boolean matched = true;
-
-        if (sf.getOperation() == SimpleFilter.MATCH_ALL)
-        {
-            matched = true;
-        }
-        else if (sf.getOperation() == SimpleFilter.AND)
-        {
-            // Evaluate each subfilter against the remaining capabilities.
-            // For AND we calculate the intersection of each subfilter.
-            // We can short-circuit the AND operation if there are no
-            // remaining capabilities.
-            List<SimpleFilter> sfs = (List<SimpleFilter>) sf.getValue();
-            for (int i = 0; matched && (i < sfs.size()); i++)
-            {
-                matched = matchesInternal(cap, sfs.get(i));
-            }
-        }
-        else if (sf.getOperation() == SimpleFilter.OR)
-        {
-            // Evaluate each subfilter against the remaining capabilities.
-            // For OR we calculate the union of each subfilter.
-            matched = false;
-            List<SimpleFilter> sfs = (List<SimpleFilter>) sf.getValue();
-            for (int i = 0; !matched && (i < sfs.size()); i++)
-            {
-                matched = matchesInternal(cap, sfs.get(i));
-            }
-        }
-        else if (sf.getOperation() == SimpleFilter.NOT)
-        {
-            // Evaluate each subfilter against the remaining capabilities.
-            // For OR we calculate the union of each subfilter.
-            List<SimpleFilter> sfs = (List<SimpleFilter>) sf.getValue();
-            for (int i = 0; i < sfs.size(); i++)
-            {
-                matched = !(matchesInternal(cap, sfs.get(i)));
-            }
-        }
-        else
-        {
-            matched = false;
-            Object lhs = cap.getAttributes().get(sf.getName());
-            if (lhs != null)
-            {
-                matched = compare(lhs, sf.getValue(), sf.getOperation());
-            }
-        }
-
-        return matched;
-    }
-
-    private static Set<Capability> matchMandatory(
-        Set<Capability> caps, SimpleFilter sf)
-    {
-        for (Iterator<Capability> it = caps.iterator(); it.hasNext(); )
-        {
-            Capability cap = it.next();
-            if (!matchMandatory(cap, sf))
-            {
-                it.remove();
-            }
-        }
-        return caps;
-    }
-
-    private static boolean matchMandatory(Capability cap, SimpleFilter sf)
-    {
-        if (cap instanceof CapabilityImpl) {
-            for (Entry<String, Object> entry : cap.getAttributes().entrySet())
-            {
-                if (((CapabilityImpl) cap).isAttributeMandatory(entry.getKey())
-                    && !matchMandatoryAttribute(entry.getKey(), sf))
-                {
-                    return false;
-                }
-            }
-        } else {
-            String value = cap.getDirectives().get(Constants.MANDATORY_DIRECTIVE);
-            if (value != null) {
-                List<String> names = ResourceBuilder.parseDelimitedString(value, ",");
-                for (Entry<String, Object> entry : cap.getAttributes().entrySet())
-                {
-                    if (names.contains(entry.getKey())
-                            && !matchMandatoryAttribute(entry.getKey(), sf))
-                    {
-                        return false;
-                    }
-                }
-            }
-
-        }
-        return true;
-    }
-
-    private static boolean matchMandatoryAttribute(String attrName, SimpleFilter sf)
-    {
-        if ((sf.getName() != null) && sf.getName().equals(attrName))
-        {
-            return true;
-        }
-        else if (sf.getOperation() == SimpleFilter.AND)
-        {
-            List list = (List) sf.getValue();
-            for (int i = 0; i < list.size(); i++)
-            {
-                SimpleFilter sf2 = (SimpleFilter) list.get(i);
-                if ((sf2.getName() != null)
-                    && sf2.getName().equals(attrName))
-                {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    private static final Class<?>[] STRING_CLASS = new Class[] { String.class };
-
-    private static boolean compare(Object lhs, Object rhsUnknown, int op)
-    {
-        if (lhs == null)
-        {
-            return false;
-        }
-
-        // If this is a PRESENT operation, then just return true immediately
-        // since we wouldn't be here if the attribute wasn't present.
-        if (op == SimpleFilter.PRESENT)
-        {
-            return true;
-        }
-
-        // If the type is comparable, then we can just return the
-        // result immediately.
-        if (lhs instanceof Comparable)
-        {
-            // Spec says SUBSTRING is false for all types other than string.
-            if ((op == SimpleFilter.SUBSTRING) && !(lhs instanceof String))
-            {
-                return false;
-            }
-
-            Object rhs;
-            if (op == SimpleFilter.SUBSTRING)
-            {
-                rhs = rhsUnknown;
-            }
-            else
-            {
-                try
-                {
-                    rhs = coerceType(lhs, (String) rhsUnknown);
-                }
-                catch (Exception ex)
-                {
-                    return false;
-                }
-            }
-
-            switch (op)
-            {
-                case SimpleFilter.EQ :
-                    try
-                    {
-                        return (((Comparable) lhs).compareTo(rhs) == 0);
-                    }
-                    catch (Exception ex)
-                    {
-                        return false;
-                    }
-                case SimpleFilter.GTE :
-                    try
-                    {
-                        return (((Comparable) lhs).compareTo(rhs) >= 0);
-                    }
-                    catch (Exception ex)
-                    {
-                        return false;
-                    }
-                case SimpleFilter.LTE :
-                    try
-                    {
-                        return (((Comparable) lhs).compareTo(rhs) <= 0);
-                    }
-                    catch (Exception ex)
-                    {
-                        return false;
-                    }
-                case SimpleFilter.APPROX :
-                    return compareApproximate(((Comparable) lhs), rhs);
-                case SimpleFilter.SUBSTRING :
-                    return SimpleFilter.compareSubstring((List<String>) rhs, (String) lhs);
-                default:
-                    throw new RuntimeException(
-                        "Unknown comparison operator: " + op);
-            }
-        }
-        // Booleans do not implement comparable, so special case them.
-        else if (lhs instanceof Boolean)
-        {
-            Object rhs;
-            try
-            {
-                rhs = coerceType(lhs, (String) rhsUnknown);
-            }
-            catch (Exception ex)
-            {
-                return false;
-            }
-
-            switch (op)
-            {
-                case SimpleFilter.EQ :
-                case SimpleFilter.GTE :
-                case SimpleFilter.LTE :
-                case SimpleFilter.APPROX :
-                    return (lhs.equals(rhs));
-                default:
-                    throw new RuntimeException(
-                        "Unknown comparison operator: " + op);
-            }
-        }
-
-        // If the LHS is not a comparable or boolean, check if it is an
-        // array. If so, convert it to a list so we can treat it as a
-        // collection.
-        if (lhs.getClass().isArray())
-        {
-            lhs = convertArrayToList(lhs);
-        }
-
-        // If LHS is a collection, then call compare() on each element
-        // of the collection until a match is found.
-        if (lhs instanceof Collection)
-        {
-            for (Iterator iter = ((Collection) lhs).iterator(); iter.hasNext(); )
-            {
-                if (compare(iter.next(), rhsUnknown, op))
-                {
-                    return true;
-                }
-            }
-
-            return false;
-        }
-
-        // Spec says SUBSTRING is false for all types other than string.
-        if ((op == SimpleFilter.SUBSTRING) && !(lhs instanceof String))
-        {
-            return false;
-        }
-
-        // Since we cannot identify the LHS type, then we can only perform
-        // equality comparison.
-        try
-        {
-            return lhs.equals(coerceType(lhs, (String) rhsUnknown));
-        }
-        catch (Exception ex)
-        {
-            return false;
-        }
-    }
-
-    private static boolean compareApproximate(Object lhs, Object rhs)
-    {
-        if (rhs instanceof String)
-        {
-            return removeWhitespace((String) lhs)
-                .equalsIgnoreCase(removeWhitespace((String) rhs));
-        }
-        else if (rhs instanceof Character)
-        {
-            return Character.toLowerCase(((Character) lhs))
-                == Character.toLowerCase(((Character) rhs));
-        }
-        return lhs.equals(rhs);
-    }
-
-    private static String removeWhitespace(String s)
-    {
-        StringBuffer sb = new StringBuffer(s.length());
-        for (int i = 0; i < s.length(); i++)
-        {
-            if (!Character.isWhitespace(s.charAt(i)))
-            {
-                sb.append(s.charAt(i));
-            }
-        }
-        return sb.toString();
-    }
-
-    private static Object coerceType(Object lhs, String rhsString) throws Exception
-    {
-        // If the LHS expects a string, then we can just return
-        // the RHS since it is a string.
-        if (lhs.getClass() == rhsString.getClass())
-        {
-            return rhsString;
-        }
-
-        // Try to convert the RHS type to the LHS type by using
-        // the string constructor of the LHS class, if it has one.
-        Object rhs = null;
-        try
-        {
-            // The Character class is a special case, since its constructor
-            // does not take a string, so handle it separately.
-            if (lhs instanceof Character)
-            {
-                rhs = new Character(rhsString.charAt(0));
-            }
-            else
-            {
-                // Spec says we should trim number types.
-                if ((lhs instanceof Number) || (lhs instanceof Boolean))
-                {
-                    rhsString = rhsString.trim();
-                }
-                Constructor ctor = lhs.getClass().getConstructor(STRING_CLASS);
-                ctor.setAccessible(true);
-                rhs = ctor.newInstance(new Object[] { rhsString });
-            }
-        }
-        catch (Exception ex)
-        {
-            throw new Exception(
-                "Could not instantiate class "
-                    + lhs.getClass().getName()
-                    + " from string constructor with argument '"
-                    + rhsString + "' because " + ex);
-        }
-
-        return rhs;
-    }
-
-    /**
-     * This is an ugly utility method to convert an array of primitives
-     * to an array of primitive wrapper objects. This method simplifies
-     * processing LDAP filters since the special case of primitive arrays
-     * can be ignored.
-     * @param array An array of primitive types.
-     * @return An corresponding array using pritive wrapper objects.
-    **/
-    private static List convertArrayToList(Object array)
-    {
-        int len = Array.getLength(array);
-        List list = new ArrayList(len);
-        for (int i = 0; i < len; i++)
-        {
-            list.add(Array.get(array, i));
-        }
-        return list;
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/resolver/FeatureNamespace.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/resolver/FeatureNamespace.java b/features/src/main/java/org/apache/karaf/features/internal/resolver/FeatureNamespace.java
deleted file mode 100644
index e211618..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/resolver/FeatureNamespace.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.resolver;
-
-import java.util.List;
-
-import org.osgi.framework.Version;
-import org.osgi.resource.Capability;
-import org.osgi.resource.Namespace;
-import org.osgi.resource.Resource;
-
-/**
- */
-public final class FeatureNamespace extends Namespace {
-
-    public static final String FEATURE_NAMESPACE = "karaf.feature";
-
-    public static final String	CAPABILITY_VERSION_ATTRIBUTE	= "version";
-
-    /**
-     * The attribute value identifying the resource
-     * {@link org.osgi.framework.namespace.IdentityNamespace#CAPABILITY_TYPE_ATTRIBUTE type} as an OSGi bundle.
-     *
-     * @see org.osgi.framework.namespace.IdentityNamespace#CAPABILITY_TYPE_ATTRIBUTE
-     */
-    public static final String	TYPE_FEATURE = "karaf.feature";
-
-    public static String getName(Resource resource)
-    {
-        List<Capability> caps = resource.getCapabilities(null);
-        for (Capability cap : caps)
-        {
-            if (cap.getNamespace().equals(FEATURE_NAMESPACE))
-            {
-                return cap.getAttributes().get(FEATURE_NAMESPACE).toString();
-            }
-        }
-        return null;
-    }
-
-    public static Version getVersion(Resource resource)
-    {
-        List<Capability> caps = resource.getCapabilities(null);
-        for (Capability cap : caps)
-        {
-            if (cap.getNamespace().equals(FEATURE_NAMESPACE))
-            {
-                return (Version)
-                        cap.getAttributes().get(CAPABILITY_VERSION_ATTRIBUTE);
-            }
-        }
-        return null;
-    }
-
-
-    private FeatureNamespace() {
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/resolver/FeatureResource.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/resolver/FeatureResource.java b/features/src/main/java/org/apache/karaf/features/internal/resolver/FeatureResource.java
deleted file mode 100644
index e3b0101..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/resolver/FeatureResource.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.resolver;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.felix.utils.version.VersionRange;
-import org.apache.felix.utils.version.VersionTable;
-import org.apache.karaf.features.BundleInfo;
-import org.apache.karaf.features.Conditional;
-import org.apache.karaf.features.Dependency;
-import org.apache.karaf.features.Feature;
-import org.apache.karaf.features.internal.util.Macro;
-import org.osgi.framework.BundleException;
-import org.osgi.framework.Constants;
-import org.osgi.framework.Version;
-import org.osgi.framework.namespace.IdentityNamespace;
-import org.osgi.resource.Capability;
-import org.osgi.resource.Requirement;
-import org.osgi.resource.Resource;
-
-/**
-*/
-public class FeatureResource extends ResourceImpl {
-
-    private final Feature feature;
-
-    public static Resource build(Feature feature, Conditional conditional, String featureRange, Map<String, Resource> locToRes) throws BundleException {
-        Feature fcond = conditional.asFeature(feature.getName(), feature.getVersion());
-        FeatureResource resource = (FeatureResource) build(fcond, featureRange, locToRes);
-        for (String cond : conditional.getCondition()) {
-            if (cond.startsWith("req:")) {
-                cond = cond.substring("req:".length());
-                List<Requirement> reqs = ResourceBuilder.parseRequirement(resource, cond);
-                resource.addRequirements(reqs);
-            } else {
-                org.apache.karaf.features.internal.model.Dependency dep = new org.apache.karaf.features.internal.model.Dependency();
-                String[] p = cond.split("/");
-                dep.setName(p[0]);
-                if (p.length > 1) {
-                    dep.setVersion(p[1]);
-                }
-                addDependency(resource, dep, featureRange);
-            }
-        }
-        org.apache.karaf.features.internal.model.Dependency dep = new org.apache.karaf.features.internal.model.Dependency();
-        dep.setName(feature.getName());
-        dep.setVersion(feature.getVersion());
-        addDependency(resource, dep, featureRange);
-        return resource;
-    }
-
-    public static Resource build(Feature feature, String featureRange, Map<String, Resource> locToRes) throws BundleException {
-        FeatureResource resource = new FeatureResource(feature);
-        Map<String, String> dirs = new HashMap<String, String>();
-        Map<String, Object> attrs = new HashMap<String, Object>();
-        attrs.put(FeatureNamespace.FEATURE_NAMESPACE, feature.getName());
-        attrs.put(FeatureNamespace.CAPABILITY_VERSION_ATTRIBUTE, VersionTable.getVersion(feature.getVersion()));
-        resource.addCapability(new CapabilityImpl(resource, FeatureNamespace.FEATURE_NAMESPACE, dirs, attrs));
-        for (BundleInfo info : feature.getBundles()) {
-            if (!info.isDependency()) {
-                Resource res = locToRes.get(info.getLocation());
-                if (res == null) {
-                    throw new IllegalStateException("Resource not found for url " + info.getLocation());
-                }
-                List<Capability> caps = res.getCapabilities(IdentityNamespace.IDENTITY_NAMESPACE);
-                if (caps.size() != 1) {
-                    throw new IllegalStateException("Resource does not have a single " + IdentityNamespace.IDENTITY_NAMESPACE + " capability");
-                }
-                dirs = new HashMap<String, String>();
-                attrs = new HashMap<String, Object>();
-                attrs.put(IdentityNamespace.IDENTITY_NAMESPACE, caps.get(0).getAttributes().get(IdentityNamespace.IDENTITY_NAMESPACE));
-                attrs.put(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE, caps.get(0).getAttributes().get(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE));
-                attrs.put(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, new VersionRange((Version) caps.get(0).getAttributes().get(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE), true));
-                resource.addRequirement(new RequirementImpl(resource, IdentityNamespace.IDENTITY_NAMESPACE, dirs, attrs));
-            }
-        }
-        for (Dependency dep : feature.getDependencies()) {
-            addDependency(resource, dep, featureRange);
-        }
-        for (org.apache.karaf.features.Capability cap : feature.getCapabilities()) {
-            resource.addCapabilities(ResourceBuilder.parseCapability(resource, cap.getValue()));
-        }
-        for (org.apache.karaf.features.Requirement req : feature.getRequirements()) {
-            resource.addRequirements(ResourceBuilder.parseRequirement(resource, req.getValue()));
-        }
-        return resource;
-    }
-
-    protected static void addDependency(FeatureResource resource, Dependency dep, String featureRange) {
-        Map<String, String> dirs;
-        Map<String, Object> attrs;
-        String name = dep.getName();
-        String version = dep.getVersion();
-        if (version.equals("0.0.0")) {
-            version = null;
-        } else if (!version.startsWith("[") && !version.startsWith("(")) {
-            version = Macro.transform(featureRange, version);
-        }
-        dirs = new HashMap<String, String>();
-        attrs = new HashMap<String, Object>();
-        attrs.put(FeatureNamespace.FEATURE_NAMESPACE, name);
-        if (version != null) {
-            attrs.put(FeatureNamespace.CAPABILITY_VERSION_ATTRIBUTE, new VersionRange(version));
-        }
-        resource.addRequirement(new RequirementImpl(resource, FeatureNamespace.FEATURE_NAMESPACE, dirs, attrs));
-    }
-
-    public FeatureResource(Feature feature) {
-        super(feature.getName(), FeatureNamespace.TYPE_FEATURE, VersionTable.getVersion(feature.getVersion()));
-        this.feature = feature;
-    }
-
-    public Feature getFeature() {
-        return feature;
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/resolver/IdentityCapability.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/resolver/IdentityCapability.java b/features/src/main/java/org/apache/karaf/features/internal/resolver/IdentityCapability.java
deleted file mode 100644
index cdc00d1..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/resolver/IdentityCapability.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.resolver;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.osgi.framework.Version;
-import org.osgi.framework.namespace.IdentityNamespace;
-import org.osgi.resource.Capability;
-import org.osgi.resource.Resource;
-
-class IdentityCapability extends BaseClause implements Capability
-{
-    private final Resource m_resource;
-    private final Map<String, String> m_dirs;
-    private final Map<String, Object> m_attrs;
-
-    public IdentityCapability(Resource resource, String name, String type, Version version)
-    {
-        m_resource = resource;
-        m_dirs = new HashMap<String, String>();
-        m_attrs = new HashMap<String, Object>();
-        m_attrs.put(IdentityNamespace.IDENTITY_NAMESPACE, name);
-        m_attrs.put(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE, type);
-        m_attrs.put(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, version);
-    }
-
-    public String getNamespace()
-    {
-        return IdentityNamespace.IDENTITY_NAMESPACE;
-    }
-
-    public Map<String, String> getDirectives()
-    {
-        return m_dirs;
-    }
-
-    public Map<String, Object> getAttributes()
-    {
-        return m_attrs;
-    }
-
-    public Resource getResource()
-    {
-        return m_resource;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/internal/resolver/RequirementImpl.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/resolver/RequirementImpl.java b/features/src/main/java/org/apache/karaf/features/internal/resolver/RequirementImpl.java
deleted file mode 100644
index a4ef775..0000000
--- a/features/src/main/java/org/apache/karaf/features/internal/resolver/RequirementImpl.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.resolver;
-
-import java.util.Map;
-
-import org.osgi.framework.Constants;
-import org.osgi.resource.Capability;
-import org.osgi.resource.Requirement;
-import org.osgi.resource.Resource;
-
-public class RequirementImpl extends BaseClause implements Requirement {
-    private final Resource m_resource;
-    private final String m_namespace;
-    private final SimpleFilter m_filter;
-    private final boolean m_optional;
-    private final Map<String, String> m_dirs;
-    private final Map<String, Object> m_attrs;
-
-    public RequirementImpl(
-            Resource resource, String namespace,
-            Map<String, String> dirs, Map<String, Object> attrs, SimpleFilter filter) {
-        m_resource = resource;
-        m_namespace = namespace;
-        m_dirs = dirs;
-        m_attrs = attrs;
-        m_filter = filter;
-        // Find resolution import directives.
-        m_optional = Constants.RESOLUTION_OPTIONAL.equals(m_dirs.get(Constants.RESOLUTION_DIRECTIVE));
-    }
-
-    public RequirementImpl(
-            Resource resource, String namespace,
-            Map<String, String> dirs, Map<String, Object> attrs) {
-        this(resource, namespace, dirs, attrs, SimpleFilter.convert(attrs));
-    }
-
-    public String getNamespace() {
-        return m_namespace;
-    }
-
-    public Map<String, String> getDirectives() {
-        return m_dirs;
-    }
-
-    public Map<String, Object> getAttributes() {
-        return m_attrs;
-    }
-
-    public Resource getResource() {
-        return m_resource;
-    }
-
-    public boolean matches(Capability cap) {
-        return CapabilitySet.matches(cap, getFilter());
-    }
-
-    public boolean isOptional() {
-        return m_optional;
-    }
-
-    public SimpleFilter getFilter() {
-        return m_filter;
-    }
-
-}


[24/33] Revert "[KARAF-2852] Merge features/core and features/command"

Posted by gn...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/test/java/org/apache/karaf/features/internal/service/BundleManagerTest.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/internal/service/BundleManagerTest.java b/features/core/src/test/java/org/apache/karaf/features/internal/service/BundleManagerTest.java
new file mode 100644
index 0000000..bed8104
--- /dev/null
+++ b/features/core/src/test/java/org/apache/karaf/features/internal/service/BundleManagerTest.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.karaf.features.internal.service;
+
+import org.apache.karaf.features.TestBase;
+
+public class BundleManagerTest extends TestBase {
+
+    /*
+    @Test
+    public void testfindBundlestoRefreshWithHostToRefresh() throws Exception {
+        Bundle hostBundle = createDummyBundle(12345l, "Host", headers());
+        Bundle fragmentBundle = createDummyBundle(54321l, "fragment", headers(Constants.FRAGMENT_HOST, "Host"));
+
+        BundleContext bundleContext = EasyMock.createMock(BundleContext.class);
+        BundleManager bundleManager = new BundleManager(bundleContext);
+
+        // Host was already installed, fragment is new
+        Set<Bundle> existing = new HashSet<Bundle>(Arrays.asList(hostBundle, fragmentBundle));
+        Set<Bundle> installed = new HashSet<Bundle>(Arrays.asList(fragmentBundle));
+        
+        replay(bundleContext);
+        Set<Bundle> bundles = bundleManager.findBundlesWithFragmentsToRefresh(existing, installed);
+        EasyMock.verify(bundleContext);
+
+        Assert.assertEquals(1, bundles.size());
+        Assert.assertEquals(hostBundle, bundles.iterator().next());
+    }
+    
+    @Test
+    public void testfindBundlestoRefreshWithOptionalPackages() throws Exception {
+        Bundle exporterBundle = createDummyBundle(12345l, "exporter", headers(Constants.EXPORT_PACKAGE, "org.my.package"));
+        Bundle importerBundle = createDummyBundle(54321l, "importer", headers(Constants.IMPORT_PACKAGE, "org.my.package;resolution:=optional"));
+
+        BundleContext bundleContext = EasyMock.createMock(BundleContext.class);
+        BundleManager bundleManager = new BundleManager(bundleContext);
+
+        // Importer was already installed, exporter is new
+        Set<Bundle> existing = new HashSet<Bundle>(Arrays.asList(importerBundle, exporterBundle));
+        Set<Bundle> installed = new HashSet<Bundle>(Arrays.asList(exporterBundle));
+        
+        replay(bundleContext);
+        Set<Bundle> bundles = bundleManager.findBundlesWithOptionalPackagesToRefresh(existing, installed);
+        EasyMock.verify(bundleContext);
+
+        Assert.assertEquals(1, bundles.size());
+        Assert.assertEquals(importerBundle, bundles.iterator().next());
+    }
+    */
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/test/java/org/apache/karaf/features/internal/service/FeaturesServiceImplTest.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/internal/service/FeaturesServiceImplTest.java b/features/core/src/test/java/org/apache/karaf/features/internal/service/FeaturesServiceImplTest.java
new file mode 100644
index 0000000..b8b5fc0
--- /dev/null
+++ b/features/core/src/test/java/org/apache/karaf/features/internal/service/FeaturesServiceImplTest.java
@@ -0,0 +1,167 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.service;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Map;
+
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.TestBase;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test cases for {@link org.apache.karaf.features.internal.service.FeaturesServiceImpl}
+ */
+public class FeaturesServiceImplTest extends TestBase {
+    
+    File dataFile;
+
+    @Before
+    public void setUp() throws IOException {
+        dataFile = File.createTempFile("features", null, null);
+    }
+
+    @Test
+    public void testGetFeature() throws Exception {
+        Feature transactionFeature = feature("transaction", "1.0.0");
+        final Map<String, Map<String, Feature>> features = features(transactionFeature);
+        final FeaturesServiceImpl impl = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, "", null, null, null) {
+            protected Map<String,Map<String,Feature>> getFeatures() throws Exception {
+                return features;
+            }
+        };
+        assertNotNull(impl.getFeature("transaction", org.apache.karaf.features.internal.model.Feature.DEFAULT_VERSION));
+        assertSame(transactionFeature, impl.getFeature("transaction", org.apache.karaf.features.internal.model.Feature.DEFAULT_VERSION));
+    }
+    
+    @Test
+    public void testGetFeatureStripVersion() throws Exception {
+        final FeaturesServiceImpl impl = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, "", null, null, null) {
+            protected Map<String,Map<String,Feature>> getFeatures() throws Exception {
+                return features(feature("transaction", "1.0.0"));
+            }
+        };
+        Feature feature = impl.getFeature("transaction", "  1.0.0  ");
+        assertNotNull(feature);
+        assertSame("transaction", feature.getName());
+    }
+    
+    @Test
+    public void testGetFeatureNotAvailable() throws Exception {
+        final FeaturesServiceImpl impl = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, "", null, null, null) {
+            protected Map<String,Map<String,Feature>> getFeatures() throws Exception {
+                return features(feature("transaction", "1.0.0"));
+            }
+        };
+        assertNull(impl.getFeature("activemq", org.apache.karaf.features.internal.model.Feature.DEFAULT_VERSION));
+    }
+    
+    @Test
+    public void testGetFeatureHighestAvailable() throws Exception {
+        final Map<String, Map<String, Feature>> features = features(
+                feature("transaction", "1.0.0"),
+                feature("transaction", "2.0.0")
+        );
+        final FeaturesServiceImpl impl = new FeaturesServiceImpl(null, null, new Storage(), null, null, null, "", null, null, null) {
+            protected Map<String,Map<String,Feature>> getFeatures() throws Exception {
+                return features;
+            }
+        };
+        assertNotNull(impl.getFeature("transaction", org.apache.karaf.features.internal.model.Feature.DEFAULT_VERSION));
+        assertSame("2.0.0", impl.getFeature("transaction", org.apache.karaf.features.internal.model.Feature.DEFAULT_VERSION).getVersion());
+    }
+
+    /**
+     * This test ensures that every feature get installed only once, even if it appears multiple times in the list
+     * of transitive feature dependencies (KARAF-1600)
+     */
+    /*
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testNoDuplicateFeaturesInstallation() throws Exception {
+        final List<Feature> installed = new LinkedList<Feature>();
+        BundleManager bundleManager = EasyMock.createMock(BundleManager.class);
+        expect(bundleManager.installBundleIfNeeded(EasyMock.anyObject(String.class), EasyMock.anyInt(), EasyMock.anyObject(String.class)))
+            .andReturn(new BundleInstallerResult(createDummyBundle(1l, "", headers()), true)).anyTimes();
+        bundleManager.refreshBundles(EasyMock.anyObject(Set.class), EasyMock.anyObject(Set.class), EasyMock.anyObject(EnumSet.class));
+        EasyMock.expectLastCall();
+        final FeaturesServiceImpl impl = new FeaturesServiceImpl(bundleManager, null) {
+            // override methods which refers to bundle context to avoid mocking everything
+            @Override
+            protected boolean loadState() {
+                return true;
+            }
+
+            @Override
+            protected void saveState() {
+
+            }
+
+            @Override
+            protected void doInstallFeature(InstallationState state, Feature feature, boolean verbose) throws Exception {
+                installed.add(feature);
+
+                super.doInstallFeature(state, feature, verbose);
+            }
+
+        };
+        replay(bundleManager);
+        impl.addRepository(getClass().getResource("repo2.xml").toURI());
+        impl.installFeature("all");
+
+        // copying the features to a set to filter out the duplicates
+        Set<Feature> noduplicates = new HashSet<Feature>();
+        noduplicates.addAll(installed);
+
+        assertEquals("Every feature should only have been installed once", installed.size(), noduplicates.size());
+    }
+
+    @Test
+    public void testGetOptionalImportsOnly() {
+        BundleManager bundleManager = new BundleManager(null, 0l);
+
+        List<Clause> result = bundleManager.getOptionalImports("org.apache.karaf,org.apache.karaf.optional;resolution:=optional");
+        assertEquals("One optional import expected", 1, result.size());
+        assertEquals("org.apache.karaf.optional", result.get(0).getName());
+
+        result = bundleManager.getOptionalImports(null);
+        assertNotNull(result);
+        assertEquals("No optional imports expected", 0, result.size());
+    }
+    */
+
+    static class Storage extends StateStorage {
+        @Override
+        protected InputStream getInputStream() throws IOException {
+            return null;
+        }
+        @Override
+        protected OutputStream getOutputStream() throws IOException {
+            return null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/test/java/org/apache/karaf/features/internal/service/FeaturesValidationTest.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/internal/service/FeaturesValidationTest.java b/features/core/src/test/java/org/apache/karaf/features/internal/service/FeaturesValidationTest.java
new file mode 100644
index 0000000..9e33ee3
--- /dev/null
+++ b/features/core/src/test/java/org/apache/karaf/features/internal/service/FeaturesValidationTest.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.karaf.features.internal.service;
+
+import java.io.InputStream;
+import java.net.URL;
+
+import org.apache.karaf.features.Repository;
+import org.apache.karaf.features.internal.model.Features;
+import org.apache.karaf.features.internal.model.JaxbUtil;
+import org.junit.Test;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+public class FeaturesValidationTest {
+
+    @Test
+    public void testNs10() throws Exception {
+        FeatureValidationUtil.validate(getClass().getResource("f02.xml").toURI());
+    }
+
+    @Test
+    public void testNs10Unmarshall() throws Exception {
+        URL url = getClass().getResource("f02.xml");
+        Features features = JaxbUtil.unmarshal(url.toExternalForm(), true);
+        assertNotNull(features);
+    }
+
+    @Test
+    public void testNs10NoName() throws Exception {
+        FeatureValidationUtil.validate(getClass().getResource("f03.xml").toURI());
+    }
+
+    @Test
+    public void testNs10NoNameUnmarshall() throws Exception {
+        URL url = getClass().getResource("f03.xml");
+        Features features = JaxbUtil.unmarshal(url.toExternalForm(), true);
+        assertNotNull(features);
+    }
+
+    @Test
+    public void testNs11() throws Exception {
+        FeatureValidationUtil.validate(getClass().getResource("f04.xml").toURI());
+    }
+
+    @Test
+    public void testNs11Unmarshall() throws Exception {
+        URL url = getClass().getResource("f04.xml");
+        Features features = JaxbUtil.unmarshal(url.toExternalForm(), true);
+        assertNotNull(features);
+    }
+
+    @Test
+    public void testNs11NoName() throws Exception {
+        try {
+            FeatureValidationUtil.validate(getClass().getResource("f05.xml").toURI());
+            fail("Validation should have failed");
+        } catch (Exception e) {
+            // ok
+        }
+    }
+
+    @Test
+    public void testNs12() throws Exception {
+        FeatureValidationUtil.validate(getClass().getResource("f06.xml").toURI());
+    }
+
+    @Test
+    public void testNs12Unmarshall() throws Exception {
+        URL url = getClass().getResource("f06.xml");
+        Features features = JaxbUtil.unmarshal(url.toExternalForm(), true);
+        assertNotNull(features);
+    }
+
+    @Test
+    public void testNs13() throws Exception {
+        FeatureValidationUtil.validate(getClass().getResource("f07.xml").toURI());
+    }
+
+    @Test
+    public void testNs13Unmarshall() throws Exception {
+        URL url = getClass().getResource("f07.xml");
+        Features features = JaxbUtil.unmarshal(url.toExternalForm(), true);
+        assertNotNull(features);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/test/java/org/apache/karaf/features/internal/service/OverridesTest.java
----------------------------------------------------------------------
diff --git a/features/core/src/test/java/org/apache/karaf/features/internal/service/OverridesTest.java b/features/core/src/test/java/org/apache/karaf/features/internal/service/OverridesTest.java
new file mode 100644
index 0000000..c4976cf
--- /dev/null
+++ b/features/core/src/test/java/org/apache/karaf/features/internal/service/OverridesTest.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.karaf.features.internal.service;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.felix.utils.manifest.Clause;
+import org.apache.felix.utils.manifest.Parser;
+import org.apache.karaf.features.BundleInfo;
+import org.apache.karaf.features.internal.model.Bundle;
+import org.apache.karaf.features.internal.resolver.ResourceBuilder;
+import org.apache.karaf.features.internal.resolver.UriNamespace;
+import org.junit.Before;
+import org.junit.Test;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.BundleException;
+import org.osgi.resource.Resource;
+
+import static org.apache.karaf.features.internal.resolver.UriNamespace.getUri;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class OverridesTest {
+
+    private String bsn = "bsn";
+    private Resource b100;
+    private Resource b101;
+    private Resource b102;
+    private Resource b110;
+    private Resource c100;
+    private Resource c101;
+    private Resource c110;
+
+    @Before
+    public void setUp() throws BundleException {
+        b100 = resource("karaf-100.jar")
+                .set("Bundle-SymbolicName", bsn)
+                .set("Bundle-Version", "1.0.0")
+                .build();
+
+        b101 = resource("karaf-101.jar")
+                .set("Bundle-SymbolicName", bsn)
+                .set("Bundle-Version", "1.0.1")
+                .build();
+
+        b102 = resource("karaf-102.jar")
+                .set("Bundle-SymbolicName", bsn)
+                .set("Bundle-Version", "1.0.2")
+                .build();
+
+        b110 = resource("karaf-110.jar")
+                .set("Bundle-SymbolicName", bsn)
+                .set("Bundle-Version", "1.1.0")
+                .build();
+
+        c100 = resource("karafc-100.jar")
+                .set("Bundle-SymbolicName", bsn)
+                .set("Bundle-Version", "1.0.0")
+                .set("Bundle-Vendor", "Apache")
+                .build();
+
+        c101 = resource("karafc-101.jar")
+                .set("Bundle-SymbolicName", bsn)
+                .set("Bundle-Version", "1.0.1")
+                .set("Bundle-Vendor", "NotApache")
+                .build();
+
+        c110 = resource("karafc-110.jar")
+                .set("Bundle-SymbolicName", bsn)
+                .set("Bundle-Version", "1.1.0")
+                .set("Bundle-Vendor", "NotApache")
+                .build();
+    }
+
+    @Test
+    public void testDifferentVendors() throws IOException {
+        Map<String, Resource> map = asResourceMap(c100, c101, c110);
+        assertEquals(c100, map.get(getUri(c100)));
+        Overrides.override(map, Arrays.asList(getUri(c101), getUri(c110)));
+        assertEquals(c101, map.get(getUri(c100)));
+    }
+
+    @Test
+    public void testMatching101() throws IOException {
+        Map<String, Resource> map = asResourceMap(b100, b101, b110);
+        assertEquals(b100, map.get(getUri(b100)));
+        Overrides.override(map, Arrays.asList(getUri(b101), getUri(b110)));
+        assertEquals(b101, map.get(getUri(b100)));
+    }
+
+    @Test
+    public void testMatching102() throws IOException {
+        Map<String, Resource> map = asResourceMap(b100, b101, b102, b110);
+        assertEquals(b100, map.get(getUri(b100)));
+        Overrides.override(map, Arrays.asList(getUri(b101), getUri(b102), getUri(b110)));
+        assertEquals(b102, map.get(getUri(b100)));
+    }
+
+    @Test
+    public void testMatchingRange() throws IOException {
+        Map<String, Resource> map = asResourceMap(b100, b101, b110);
+        assertEquals(b100, map.get(getUri(b100)));
+        Overrides.override(map, Arrays.asList(getUri(b101), getUri(b110) + ";range=\"[1.0, 2.0)\""));
+        assertEquals(b110, map.get(getUri(b100)));
+    }
+
+    @Test
+    public void testNotMatching() throws IOException {
+        Map<String, Resource> map = asResourceMap(b100, b110);
+        assertEquals(b100, map.get(getUri(b100)));
+        Overrides.override(map, Arrays.asList(getUri(b110)));
+        assertEquals(b100, map.get(getUri(b100)));
+    }
+
+    @Test
+    public void testLoadOverrides() {
+        Set<String> overrides = Overrides.loadOverrides(getClass().getResource("overrides.properties").toExternalForm());
+        assertEquals(2, overrides.size());
+
+        Clause karafAdminCommand = null;
+        Clause karafAdminCore = null;
+        for (Clause clause : Parser.parseClauses(overrides.toArray(new String[overrides.size()]))) {
+            if (clause.getName().equals("mvn:org.apache.karaf.admin/org.apache.karaf.admin.command/2.3.0.redhat-61033X")) {
+                karafAdminCommand = clause;
+            }
+            if (clause.getName().equals("mvn:org.apache.karaf.admin/org.apache.karaf.admin.core/2.3.0.redhat-61033X")) {
+                karafAdminCore = clause;
+            }
+        }
+        assertNotNull("Missing admin.command bundle override", karafAdminCommand);
+        assertNotNull("Missing admin.core bundle override", karafAdminCore);
+        assertNotNull("Missing range on admin.core override", karafAdminCore.getAttribute(Overrides.OVERRIDE_RANGE));
+    }
+
+    /**
+     * Copies the content of {@link java.io.InputStream} to {@link java.io.OutputStream}.
+     *
+     * @param input
+     * @param output
+     * @throws java.io.IOException
+     */
+    private void copy(final InputStream input, final OutputStream output) throws IOException {
+        byte[] buffer = new byte[1024 * 16];
+        int n;
+        while (-1 != (n = input.read(buffer))) {
+            output.write(buffer, 0, n);
+            output.flush();
+        }
+        input.close();
+        output.close();
+    }
+
+    static Builder resource(String uri) {
+        return new Builder(uri);
+    }
+
+    static Map<String, Resource> asResourceMap(Resource... resources) {
+        Map<String, Resource> map = new HashMap<String, Resource>();
+        for (Resource resource : resources) {
+            map.put(getUri(resource), resource);
+        }
+        return map;
+    }
+
+    static class Builder {
+        String uri;
+        Map<String,String> headers = new HashMap<String,String>();
+        Builder(String uri) {
+            this.uri = uri;
+            this.headers.put("Bundle-ManifestVersion", "2");
+        }
+        Builder set(String key, String value) {
+            this.headers.put(key, value);
+            return this;
+        }
+        Resource build() throws BundleException {
+            return ResourceBuilder.build(uri, headers);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/test/resources/org/apache/karaf/features/internal/service/f01.xml
----------------------------------------------------------------------
diff --git a/features/core/src/test/resources/org/apache/karaf/features/internal/service/f01.xml b/features/core/src/test/resources/org/apache/karaf/features/internal/service/f01.xml
new file mode 100644
index 0000000..814c722
--- /dev/null
+++ b/features/core/src/test/resources/org/apache/karaf/features/internal/service/f01.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.
+-->
+<features name="karaf-2.0.0">
+    <feature name="spring" version="3.0.3.RELEASE">
+        <bundle>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.aopalliance/1.0_6</bundle>
+        <bundle>mvn:org.springframework/spring-core/3.0.3.RELEASE</bundle>
+        <bundle>mvn:org.springframework/spring-asm/3.0.3.RELEASE</bundle>
+        <bundle>mvn:org.springframework/spring-expression/3.0.3.RELEASE</bundle>
+        <bundle>mvn:org.springframework/spring-beans/3.0.3.RELEASE</bundle>
+        <bundle>mvn:org.springframework/spring-aop/3.0.3.RELEASE</bundle>
+        <bundle>mvn:org.springframework/spring-context/3.0.3.RELEASE</bundle>
+        <bundle>mvn:org.springframework/spring-context-support/3.0.3.RELEASE</bundle>
+    </feature>
+    <feature name="spring-dm" version="1.2.0">
+        <feature version="3.0.3.RELEASE">spring</feature>
+        <bundle>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.cglib/2.2.2_1</bundle>
+        <bundle>mvn:org.springframework.osgi/spring-osgi-io/1.2.0</bundle>
+        <bundle>mvn:org.springframework.osgi/spring-osgi-core/1.2.0</bundle>
+        <bundle>mvn:org.springframework.osgi/spring-osgi-extender/1.2.0</bundle>
+        <bundle>mvn:org.springframework.osgi/spring-osgi-annotation/1.2.0</bundle>
+        <bundle>mvn:org.apache.karaf.deployer/org.apache.karaf.deployer.spring/2.0.0</bundle>
+    </feature>
+    <feature name="wrapper" version="2.0.0">
+        <bundle>mvn:org.apache.karaf.shell/org.apache.karaf.shell.wrapper/2.0.0</bundle>
+    </feature>
+    <feature name="obr" version="2.0.0">
+        <bundle>mvn:org.apache.felix/org.apache.felix.bundlerepository/1.6.4</bundle>
+        <bundle>mvn:org.apache.karaf.shell/org.apache.karaf.shell.obr/2.0.0</bundle>
+        <bundle>mvn:org.apache.karaf.features/org.apache.karaf.features.obr/2.0.0</bundle>
+    </feature>
+    <feature name="http" version="2.0.0">
+        <config name="org.ops4j.pax.web">
+            org.osgi.service.http.port=8181
+        </config>
+        <bundle>mvn:org.apache.geronimo.specs/geronimo-servlet_2.5_spec/1.1.2</bundle>
+        <bundle>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.jetty-bundle/6.1.22_1</bundle>
+        <bundle>mvn:org.ops4j.pax.web/pax-web-api/0.7.2</bundle>
+        <bundle>mvn:org.ops4j.pax.web/pax-web-spi/0.7.2</bundle>
+        <bundle>mvn:org.ops4j.pax.web/pax-web-runtime/0.7.2</bundle>
+        <bundle>mvn:org.ops4j.pax.web/pax-web-jetty/0.7.2</bundle>
+    </feature>
+    <feature name="war" version="2.0.0">
+        <feature version="2.0.0">http</feature>
+        <bundle>mvn:org.ops4j.pax.web/pax-web-jsp/0.7.2</bundle>
+        <bundle>mvn:org.ops4j.pax.web/pax-web-extender-war/0.7.2</bundle>
+        <bundle>mvn:org.ops4j.pax.web/pax-web-extender-whiteboard/0.7.2</bundle>
+        <bundle>mvn:org.ops4j.pax.url/pax-url-war/1.1.3</bundle>
+        <bundle>mvn:org.apache.karaf.deployer/org.apache.karaf.deployer.war/2.0.0</bundle>
+    </feature>
+    <feature name="webconsole" version="2.0.0">
+        <feature version="2.0.0">http</feature>
+        <config name="org.apache.karaf.webconsole">
+            realm=karaf
+        </config>
+        <bundle>mvn:org.apache.felix/org.apache.felix.metatype/1.0.2</bundle>
+        <bundle>mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.branding/2.0.0</bundle>
+        <bundle>mvn:org.apache.felix/org.apache.felix.webconsole/3.1.0</bundle>
+        <bundle>mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.admin/2.0.0</bundle>
+        <bundle>mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.features/2.0.0</bundle>
+        <bundle>mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.gogo/2.0.0</bundle>
+    </feature>
+    <feature name="ssh" version="2.0.0">
+        <config name="org.apache.karaf.shell.ssh">
+            sshPort=8101
+            sshHost=0.0.0.0
+            sshRealm=karaf
+        </config>
+        <bundle>mvn:org.apache.mina/mina-core/2.0.0-RC1</bundle>
+        <bundle>mvn:org.apache.sshd/sshd-core/0.4.0</bundle>
+        <bundle>mvn:org.apache.karaf.shell/org.apache.karaf.shell.ssh/2.0.0</bundle>
+    </feature>
+    <feature name="management" version="2.0.0">
+        <bundle>mvn:org.apache.karaf/org.apache.karaf.management/2.0.0</bundle>
+        <bundle>mvn:org.apache.aries.jmx/org.apache.aries.jmx/0.1-r964701</bundle>
+        <bundle>mvn:org.apache.aries.jmx/org.apache.aries.jmx.blueprint/0.1-r964701</bundle>
+    </feature>
+</features>

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/test/resources/org/apache/karaf/features/internal/service/f02.xml
----------------------------------------------------------------------
diff --git a/features/core/src/test/resources/org/apache/karaf/features/internal/service/f02.xml b/features/core/src/test/resources/org/apache/karaf/features/internal/service/f02.xml
new file mode 100644
index 0000000..1578faa
--- /dev/null
+++ b/features/core/src/test/resources/org/apache/karaf/features/internal/service/f02.xml
@@ -0,0 +1,164 @@
+<?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 name="karaf-2.2.0" xmlns="http://karaf.apache.org/xmlns/features/v1.0.0">
+    <feature name="spring" version="2.5.6.SEC02" resolver="(obr)">
+        <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.aopalliance/1.0_6</bundle>
+        <bundle>mvn:org.springframework/spring-core/2.5.6.SEC02</bundle>
+        <bundle>mvn:org.springframework/spring-beans/2.5.6.SEC02</bundle>
+        <bundle>mvn:org.springframework/spring-aop/2.5.6.SEC02</bundle>
+        <bundle>mvn:org.springframework/spring-context/2.5.6.SEC02</bundle>
+        <bundle>mvn:org.springframework/spring-context-support/2.5.6.SEC02</bundle>
+    </feature>
+    <feature name="spring-web" version="2.5.6.SEC02" resolver="(obr)">
+    	<feature version="2.5.6.SEC02">spring</feature>
+    	<feature version="2.2.0">http</feature>
+    	<bundle>mvn:org.springframework/spring-web/2.5.6.SEC02</bundle>
+		<bundle>mvn:org.springframework/spring-webmvc/2.5.6.SEC02</bundle>
+    </feature>
+    <feature name="spring" version="3.0.5.RELEASE" resolver="(obr)">
+        <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.aopalliance/1.0_6</bundle>
+        <bundle>mvn:org.springframework/spring-core/3.0.5.RELEASE</bundle>
+        <bundle>mvn:org.springframework/spring-asm/3.0.5.RELEASE</bundle>
+        <bundle>mvn:org.springframework/spring-expression/3.0.5.RELEASE</bundle>
+        <bundle>mvn:org.springframework/spring-beans/3.0.5.RELEASE</bundle>
+        <bundle>mvn:org.springframework/spring-aop/3.0.5.RELEASE</bundle>
+        <bundle>mvn:org.springframework/spring-context/3.0.5.RELEASE</bundle>
+        <bundle>mvn:org.springframework/spring-context-support/3.0.5.RELEASE</bundle>
+    </feature>
+    <feature name="spring-web" version="3.0.5.RELEASE" resolver="(obr)">
+    	<feature version="3.0.5.RELEASE">spring</feature>
+    	<feature version="2.2.0">http</feature>
+    	<bundle>mvn:org.springframework/spring-web/3.0.5.RELEASE</bundle>
+		<bundle>mvn:org.springframework/spring-webmvc/3.0.5.RELEASE</bundle>
+    </feature>
+    <feature name="spring-dm" version="1.2.1" resolver="(obr)">
+        <feature version="[2.5.6,4)">spring</feature>
+        <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.cglib/2.2.2_1</bundle>
+        <bundle>mvn:org.springframework.osgi/spring-osgi-io/1.2.1</bundle>
+        <bundle>mvn:org.springframework.osgi/spring-osgi-core/1.2.1</bundle>
+        <bundle>mvn:org.springframework.osgi/spring-osgi-extender/1.2.1</bundle>
+        <bundle>mvn:org.springframework.osgi/spring-osgi-annotation/1.2.1</bundle>
+        <bundle>mvn:org.apache.karaf.deployer/org.apache.karaf.deployer.spring/2.2.0</bundle>
+    </feature>
+    <feature name="spring-dm-web" version="1.2.1" resolver="(obr)">
+    	<feature version="1.2.1">spring-dm</feature>
+    	<feature version="[2.5.6,4)">spring-web</feature>
+    	<feature version="2.2.0">http</feature>
+		<bundle>mvn:org.springframework.osgi/spring-osgi-web/1.2.1</bundle>
+    </feature>
+    <feature name="wrapper" version="2.2.0">
+        <bundle>mvn:org.apache.karaf.shell/org.apache.karaf.shell.wrapper/2.2.0</bundle>
+    </feature>
+    <feature name="obr" version="2.2.0">
+        <bundle>mvn:org.apache.felix/org.apache.felix.bundlerepository/1.6.4</bundle>
+        <bundle>mvn:org.apache.karaf.shell/org.apache.karaf.shell.obr/2.2.0</bundle>
+        <bundle>mvn:org.apache.karaf.features/org.apache.karaf.features.obr/2.2.0</bundle>
+    </feature>
+    <feature name="config" version="2.2.0">
+        <bundle start-level='30'>mvn:org.apache.karaf.shell/org.apache.karaf.shell.config/2.2.0</bundle>
+    </feature>
+	<feature name="jetty" version="7.2.2.v20101205" resolver="(obr)">
+		<bundle dependency='true'>mvn:org.apache.geronimo.specs/geronimo-servlet_2.5_spec/1.1.2</bundle>
+        <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.asm/3.3_1</bundle>
+	    <bundle>mvn:org.eclipse.jetty/jetty-util/7.2.2.v20101205</bundle>
+	    <bundle>mvn:org.eclipse.jetty/jetty-io/7.2.2.v20101205</bundle>
+	    <bundle>mvn:org.eclipse.jetty/jetty-http/7.2.2.v20101205</bundle>
+	    <bundle>mvn:org.eclipse.jetty/jetty-continuation/7.2.2.v20101205</bundle>
+	    <bundle>mvn:org.eclipse.jetty/jetty-server/7.2.2.v20101205</bundle>
+	    <bundle>mvn:org.eclipse.jetty/jetty-security/7.2.2.v20101205</bundle>
+	    <bundle>mvn:org.eclipse.jetty/jetty-servlet/7.2.2.v20101205</bundle>
+    	<bundle>mvn:org.eclipse.jetty/jetty-xml/7.2.2.v20101205</bundle>
+	</feature>
+	<feature name="jetty-jaas" version="7.2.2.v20101205" resolver="(obr)">
+		<feature version="[7.0,8.0)">jetty</feature>
+		<bundle dependency='true'>mvn:javax.mail/mail/1.4.3</bundle>
+		<bundle dependency='true'>mvn:org.apache.geronimo.specs/geronimo-jta_1.1_spec/1.1.1</bundle>
+		<bundle>mvn:org.eclipse.jetty/jetty-webapp/7.2.2.v20101205</bundle>
+		<bundle>mvn:org.eclipse.jetty/jetty-jndi/7.2.2.v20101205</bundle>
+		<bundle>mvn:org.eclipse.jetty/jetty-plus/7.2.2.v20101205</bundle>
+	</feature>
+    <feature name="http" version="2.2.0" resolver="(obr)">
+    	<configfile finalname="/etc/jetty.xml">mvn:org.apache.karaf/apache-karaf/2.2.0/xml/jettyconfig</configfile>
+		<config name="org.ops4j.pax.web">
+            org.osgi.service.http.port=8181
+            javax.servlet.context.tempdir=${karaf.data}/pax-web-jsp
+            org.ops4j.pax.web.config.file=${karaf.etc}/jetty.xml
+        </config>
+        <feature version="[7.0,8.0)">jetty</feature>
+    	<bundle>mvn:org.ops4j.pax.web/pax-web-api/1.0.1</bundle>
+        <bundle>mvn:org.ops4j.pax.web/pax-web-spi/1.0.1</bundle>
+        <bundle>mvn:org.ops4j.pax.web/pax-web-runtime/1.0.1</bundle>
+        <bundle>mvn:org.ops4j.pax.web/pax-web-jetty/1.0.1</bundle>
+    </feature>
+    <feature name="war" version="2.2.0" resolver="(obr)">
+        <config name="org.ops4j.pax.url.war">
+            org.ops4j.pax.url.war.importPaxLoggingPackages=true
+        </config>
+        <feature>http</feature>
+        <bundle start-level='30'>mvn:org.apache.karaf.shell/org.apache.karaf.shell.web/2.2.0</bundle>
+        <bundle>mvn:org.ops4j.pax.web/pax-web-jsp/1.0.1</bundle>
+        <bundle>mvn:org.ops4j.pax.web/pax-web-extender-war/1.0.1</bundle>
+        <bundle>mvn:org.ops4j.pax.web/pax-web-extender-whiteboard/1.0.1</bundle>
+        <bundle>mvn:org.ops4j.pax.web/pax-web-deployer/1.0.1</bundle>
+        <bundle>mvn:org.ops4j.pax.url/pax-url-war/1.2.5</bundle>
+    </feature>
+    <feature name="kar" version="2.2.0">
+        <bundle>mvn:org.apache.karaf.deployer/org.apache.karaf.deployer.kar/2.2.0</bundle>
+    </feature>
+    <feature name="webconsole-base" version="2.2.0">
+        <config name="org.apache.karaf.webconsole">
+            realm=karaf
+        </config>
+        <feature>http</feature>
+        <bundle>mvn:org.apache.felix/org.apache.felix.metatype/1.0.4</bundle>
+        <bundle>mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.branding/2.2.0</bundle>
+        <bundle>mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.console/2.2.0</bundle>
+    </feature>
+    <feature name="webconsole" version="2.2.0">
+        <feature version="2.2.0">webconsole-base</feature>
+        <bundle>mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.admin/2.2.0</bundle>
+        <bundle>mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.features/2.2.0</bundle>
+        <bundle>mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.gogo/2.2.0</bundle>
+		<bundle>mvn:org.apache.felix/org.apache.felix.webconsole.plugins.event/1.0.2</bundle>
+    </feature>
+    <feature name="ssh" version="2.2.0">
+        <config name="org.apache.karaf.shell">
+            sshPort=8101
+            sshHost=0.0.0.0
+            sshRealm=karaf
+            hostKey=${karaf.etc}/host.key
+        </config>
+        <bundle dependency='true'>mvn:org.apache.mina/mina-core/2.0.1</bundle>
+        <bundle dependency='true'>mvn:org.apache.sshd/sshd-core/0.5.0</bundle>
+        <bundle>mvn:org.apache.karaf.shell/org.apache.karaf.shell.ssh/2.2.0</bundle>
+    </feature>
+    <feature name="management" version="2.2.0">
+        <bundle>mvn:org.apache.karaf/org.apache.karaf.management/2.2.0</bundle>
+        <bundle>mvn:org.apache.aries.jmx/org.apache.aries.jmx/0.3</bundle>
+        <bundle>mvn:org.apache.aries.jmx/org.apache.aries.jmx.blueprint/0.3</bundle>
+    </feature>
+    <feature name="eventadmin" version="2.2.0">
+		<bundle start-level='30'>mvn:org.apache.felix/org.apache.felix.eventadmin/1.2.8</bundle>
+    </feature>
+    <feature name="jasypt-encryption" version="2.2.0" resolver="(obr)">
+        <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.commons-codec/1.3_3</bundle>
+        <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.commons-lang/2.4_4</bundle>
+        <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.jasypt/1.7_1</bundle>
+        <bundle>mvn:org.apache.karaf.jaas/org.apache.karaf.jaas.jasypt/2.2.0</bundle>
+    </feature>
+</features>

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/test/resources/org/apache/karaf/features/internal/service/f03.xml
----------------------------------------------------------------------
diff --git a/features/core/src/test/resources/org/apache/karaf/features/internal/service/f03.xml b/features/core/src/test/resources/org/apache/karaf/features/internal/service/f03.xml
new file mode 100644
index 0000000..c058095
--- /dev/null
+++ b/features/core/src/test/resources/org/apache/karaf/features/internal/service/f03.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 xmlns="http://karaf.apache.org/xmlns/features/v1.0.0">
+    <feature name="spring" version="2.5.6.SEC02" resolver="(obr)">
+        <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.aopalliance/1.0_6</bundle>
+        <bundle>mvn:org.springframework/spring-core/2.5.6.SEC02</bundle>
+        <bundle>mvn:org.springframework/spring-beans/2.5.6.SEC02</bundle>
+        <bundle>mvn:org.springframework/spring-aop/2.5.6.SEC02</bundle>
+        <bundle>mvn:org.springframework/spring-context/2.5.6.SEC02</bundle>
+        <bundle>mvn:org.springframework/spring-context-support/2.5.6.SEC02</bundle>
+    </feature>
+</features>

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/test/resources/org/apache/karaf/features/internal/service/f04.xml
----------------------------------------------------------------------
diff --git a/features/core/src/test/resources/org/apache/karaf/features/internal/service/f04.xml b/features/core/src/test/resources/org/apache/karaf/features/internal/service/f04.xml
new file mode 100644
index 0000000..85f28ad
--- /dev/null
+++ b/features/core/src/test/resources/org/apache/karaf/features/internal/service/f04.xml
@@ -0,0 +1,28 @@
+<?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 name="karaf" xmlns="http://karaf.apache.org/xmlns/features/v1.1.0">
+    <feature name="spring" version="2.5.6.SEC02" resolver="(obr)">
+        <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.aopalliance/1.0_6</bundle>
+        <bundle>mvn:org.springframework/spring-core/2.5.6.SEC02</bundle>
+        <bundle>mvn:org.springframework/spring-beans/2.5.6.SEC02</bundle>
+        <bundle>mvn:org.springframework/spring-aop/2.5.6.SEC02</bundle>
+        <bundle>mvn:org.springframework/spring-context/2.5.6.SEC02</bundle>
+        <bundle>mvn:org.springframework/spring-context-support/2.5.6.SEC02</bundle>
+    </feature>
+</features>
+

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/test/resources/org/apache/karaf/features/internal/service/f05.xml
----------------------------------------------------------------------
diff --git a/features/core/src/test/resources/org/apache/karaf/features/internal/service/f05.xml b/features/core/src/test/resources/org/apache/karaf/features/internal/service/f05.xml
new file mode 100644
index 0000000..15d84e2
--- /dev/null
+++ b/features/core/src/test/resources/org/apache/karaf/features/internal/service/f05.xml
@@ -0,0 +1,28 @@
+<?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 xmlns="http://karaf.apache.org/xmlns/features/v1.1.0">
+    <feature name="spring" version="2.5.6.SEC02" resolver="(obr)">
+        <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.aopalliance/1.0_6</bundle>
+        <bundle>mvn:org.springframework/spring-core/2.5.6.SEC02</bundle>
+        <bundle>mvn:org.springframework/spring-beans/2.5.6.SEC02</bundle>
+        <bundle>mvn:org.springframework/spring-aop/2.5.6.SEC02</bundle>
+        <bundle>mvn:org.springframework/spring-context/2.5.6.SEC02</bundle>
+        <bundle>mvn:org.springframework/spring-context-support/2.5.6.SEC02</bundle>
+    </feature>
+</features>
+

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/test/resources/org/apache/karaf/features/internal/service/f06.xml
----------------------------------------------------------------------
diff --git a/features/core/src/test/resources/org/apache/karaf/features/internal/service/f06.xml b/features/core/src/test/resources/org/apache/karaf/features/internal/service/f06.xml
new file mode 100644
index 0000000..51e78f1
--- /dev/null
+++ b/features/core/src/test/resources/org/apache/karaf/features/internal/service/f06.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.
+-->
+<features name="karaf" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0">
+    <feature name="spring" version="2.5.6.SEC02" resolver="(obr)">
+        <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.aopalliance/1.0_4</bundle>
+        <bundle>mvn:org.springframework/spring-core/2.5.6.SEC02</bundle>
+        <bundle>mvn:org.springframework/spring-beans/2.5.6.SEC02</bundle>
+        <bundle>mvn:org.springframework/spring-aop/2.5.6.SEC02</bundle>
+        <bundle>mvn:org.springframework/spring-context/2.5.6.SEC02</bundle>
+        <bundle>mvn:org.springframework/spring-context-support/2.5.6.SEC02</bundle>
+        <conditional>
+            <condition>http</condition>
+            <bundle>mvn:org.springframework/spring-web/2.5.6.SEC02</bundle>
+        </conditional>
+        <conditional>
+            <condition>req:osgi.ee;filter:="(&amp;(osgi.ee=JavaSE)(!(version>=1.7)))"</condition>
+            <bundle start="true" start-level="30">mvn:org.apache.mina/mina-core/${mina.version}</bundle>
+        </conditional>
+    </feature>
+</features>
+

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/test/resources/org/apache/karaf/features/internal/service/f07.xml
----------------------------------------------------------------------
diff --git a/features/core/src/test/resources/org/apache/karaf/features/internal/service/f07.xml b/features/core/src/test/resources/org/apache/karaf/features/internal/service/f07.xml
new file mode 100644
index 0000000..5b7dd90
--- /dev/null
+++ b/features/core/src/test/resources/org/apache/karaf/features/internal/service/f07.xml
@@ -0,0 +1,35 @@
+<?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 name="karaf" xmlns="http://karaf.apache.org/xmlns/features/v1.3.0">
+    <feature name="spring" version="2.5.6.SEC02" resolver="(obr)">
+        <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.aopalliance/1.0_4</bundle>
+        <bundle>mvn:org.springframework/spring-core/2.5.6.SEC02</bundle>
+        <bundle>mvn:org.springframework/spring-beans/2.5.6.SEC02</bundle>
+        <bundle>mvn:org.springframework/spring-aop/2.5.6.SEC02</bundle>
+        <bundle>mvn:org.springframework/spring-context/2.5.6.SEC02</bundle>
+        <bundle>mvn:org.springframework/spring-context-support/2.5.6.SEC02</bundle>
+        <conditional>
+            <condition>http</condition>
+            <bundle>mvn:org.springframework/spring-web/2.5.6.SEC02</bundle>
+        </conditional>
+        <capability>
+            service-reference;effective:=active;objectClass=org.apache.aries.proxy.ProxyManager
+        </capability>
+    </feature>
+</features>
+

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/test/resources/org/apache/karaf/features/internal/service/overrides.properties
----------------------------------------------------------------------
diff --git a/features/core/src/test/resources/org/apache/karaf/features/internal/service/overrides.properties b/features/core/src/test/resources/org/apache/karaf/features/internal/service/overrides.properties
new file mode 100644
index 0000000..d34fa7e
--- /dev/null
+++ b/features/core/src/test/resources/org/apache/karaf/features/internal/service/overrides.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.
+#
+################################################################################
+
+# Sample etc/overrides.properties file for testing purposes
+mvn:org.apache.karaf.admin/org.apache.karaf.admin.command/2.3.0.redhat-61033X
+mvn:org.apache.karaf.admin/org.apache.karaf.admin.core/2.3.0.redhat-61033X;range=[2.3.0,2.5)

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/test/resources/org/apache/karaf/features/internal/service/repo2.xml
----------------------------------------------------------------------
diff --git a/features/core/src/test/resources/org/apache/karaf/features/internal/service/repo2.xml b/features/core/src/test/resources/org/apache/karaf/features/internal/service/repo2.xml
new file mode 100644
index 0000000..5fd51d0
--- /dev/null
+++ b/features/core/src/test/resources/org/apache/karaf/features/internal/service/repo2.xml
@@ -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.
+-->
+<features name="repo2">
+    <feature name="common">
+        <bundle>b1</bundle>
+    </feature>
+    <feature name="f1">
+        <feature>common</feature>
+        <bundle>b2</bundle>
+    </feature>
+    <feature name="f2">
+        <feature>common</feature>
+        <feature>f1</feature>
+        <bundle>b3</bundle>
+    </feature>
+    <feature name="f3">
+        <feature>f1</feature>
+        <feature>f2</feature>
+    	<bundle>b4</bundle>
+    </feature>
+    <feature name="all">
+        <feature>f1</feature>
+        <feature>f2</feature>
+        <feature>f3</feature>
+    </feature>
+</features>

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/test/resources/org/apache/karaf/features/repo1.xml
----------------------------------------------------------------------
diff --git a/features/core/src/test/resources/org/apache/karaf/features/repo1.xml b/features/core/src/test/resources/org/apache/karaf/features/repo1.xml
new file mode 100644
index 0000000..641ef12
--- /dev/null
+++ b/features/core/src/test/resources/org/apache/karaf/features/repo1.xml
@@ -0,0 +1,35 @@
+<?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 name="test" xmlns="http://karaf.apache.org/xmlns/features/v1.1.0">
+    <repository>urn:r1</repository>
+    <feature name="f1" region="foo">
+        <config name="c1">
+            k=v
+        </config>
+        <bundle>b1</bundle>
+        <bundle>b2</bundle>
+    </feature>
+    <feature name="f2">
+        <feature>f1</feature>
+        <bundle>b3</bundle>
+    </feature>
+    <feature name="f3">
+    	<configfile finalname="cf1" override="true">cfloc</configfile>
+    	<bundle>b4</bundle> 
+    </feature>
+</features>

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/test/resources/org/apache/karaf/features/repo2.xml
----------------------------------------------------------------------
diff --git a/features/core/src/test/resources/org/apache/karaf/features/repo2.xml b/features/core/src/test/resources/org/apache/karaf/features/repo2.xml
new file mode 100644
index 0000000..f5e96ae
--- /dev/null
+++ b/features/core/src/test/resources/org/apache/karaf/features/repo2.xml
@@ -0,0 +1,37 @@
+<?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 name="test" xmlns="http://karaf.apache.org/xmlns/features/v1.0.0">
+    <repository>
+        urn:r1
+    </repository>
+    <feature name="f1" region="foo">
+        <config name="c1">
+            k=v
+        </config>
+        <bundle>b1</bundle>
+        <bundle>b2</bundle>
+    </feature>
+    <feature name="f2">
+        <feature>f1</feature>
+        <bundle>b3</bundle>
+    </feature>
+    <feature name="f3">
+    	<configfile finalname="cf1" override="true">cfloc</configfile>
+    	<bundle>b4</bundle> 
+    </feature>
+</features>

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/test/resources/org/apache/karaf/features/repo3.xml
----------------------------------------------------------------------
diff --git a/features/core/src/test/resources/org/apache/karaf/features/repo3.xml b/features/core/src/test/resources/org/apache/karaf/features/repo3.xml
new file mode 100644
index 0000000..ffe08ed
--- /dev/null
+++ b/features/core/src/test/resources/org/apache/karaf/features/repo3.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 name="test" xmlns="http://karaf.apache.org/xmlns/features/v1.3.0">
+    <feature name="f1">
+        <capability>
+            cap
+        </capability>
+        <requirement>
+            req
+        </requirement>
+    </feature>
+</features>

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/pom.xml
----------------------------------------------------------------------
diff --git a/features/pom.xml b/features/pom.xml
index d722ada..8cfede1 100644
--- a/features/pom.xml
+++ b/features/pom.xml
@@ -29,124 +29,13 @@
     </parent>
 
     <groupId>org.apache.karaf.features</groupId>
-    <artifactId>org.apache.karaf.features.core</artifactId>
-    <packaging>bundle</packaging>
-    <name>Apache Karaf :: Features :: Core</name>
-    <description>This bundle is the core implementation of the Karaf features support.</description>
-
-    <properties>
-        <appendedResourcesDirectory>${basedir}/../../etc/appended-resources</appendedResourcesDirectory>
-    </properties>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.core</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.compendium</artifactId>
-            <scope>provided</scope>
-            <optional>true</optional>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.felix</groupId>
-            <artifactId>org.apache.felix.utils</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-api</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.karaf</groupId>
-            <artifactId>org.apache.karaf.util</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.felix</groupId>
-            <artifactId>org.apache.felix.resolver</artifactId>
-            <scope>provided</scope>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.karaf.shell</groupId>
-            <artifactId>org.apache.karaf.shell.core</artifactId>
-            <optional>true</optional>
-        </dependency>
-
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-jdk14</artifactId>
-            <scope>test</scope>
-        </dependency>
-
-        <dependency>
-            <groupId>org.ops4j.pax.tinybundles</groupId>
-            <artifactId>tinybundles</artifactId>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-
-    <build>
-        <resources>
-            <resource>
-                <directory>${project.basedir}/src/main/resources</directory>
-                <includes>
-                    <include>**/*</include>
-                </includes>
-            </resource>
-            <resource>
-                <directory>${project.basedir}/src/main/resources</directory>
-                <filtering>true</filtering>
-                <includes>
-                    <include>**/*.info</include>
-                </includes>
-            </resource>
-        </resources>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-bundle-plugin</artifactId>
-                <configuration>
-                    <instructions>
-                        <Export-Package>
-                            org.apache.karaf.features;
-                            org.apache.karaf.features.command;
-                            org.apache.karaf.features.command.completers;
-                            org.apache.karaf.features.management;
-                            org.apache.karaf.features.management.codec;
-                                -noimport:=true
-                        </Export-Package>
-                        <Provide-Capability>
-                            service-reference;effective:=active;objectClass=org.apache.karaf.features.FeaturesService
-                        </Provide-Capability>
-                        <Private-Package>
-                            org.apache.karaf.features.internal.*,
-                            org.apache.felix.resolver,
-                            org.apache.felix.utils.version,
-                            org.apache.felix.utils.manifest,
-                            org.apache.karaf.util,
-                            org.apache.karaf.util.collections,
-                            org.apache.karaf.util.json,
-                            org.apache.karaf.util.tracker,
-                            org.osgi.service.resolver,
-                            org.osgi.service.repository
-                        </Private-Package>
-                        <Embed-Dependency>
-                            org.apache.karaf.util;inline="org/apache/karaf/util/XmlUtils*.class"
-                        </Embed-Dependency>
-                        <Bundle-Activator>
-                            org.apache.karaf.features.internal.osgi.Activator
-                        </Bundle-Activator>
-                        <Karaf-Commands>org.apache.karaf.features.command.*</Karaf-Commands>
-                    </instructions>
-                </configuration>
-            </plugin>
-        </plugins>
-    </build>
+    <artifactId>features</artifactId>
+    <packaging>pom</packaging>
+    <name>Apache Karaf :: Features</name>
+
+    <modules>
+        <module>core</module>
+        <module>command</module>
+    </modules>
 
 </project>

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/BootFinished.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/BootFinished.java b/features/src/main/java/org/apache/karaf/features/BootFinished.java
deleted file mode 100644
index aa72248..0000000
--- a/features/src/main/java/org/apache/karaf/features/BootFinished.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features;
-
-/**
- * Marker interface for a service that announces when the karaf boot is finished
- */
-public interface BootFinished {
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/BundleInfo.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/BundleInfo.java b/features/src/main/java/org/apache/karaf/features/BundleInfo.java
deleted file mode 100644
index 97a541f..0000000
--- a/features/src/main/java/org/apache/karaf/features/BundleInfo.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features;
-
-/**
- * A bundle info holds info about a Bundle.
- */
-public interface BundleInfo {
-
-	String getLocation();
-	
-    int getStartLevel();
-    
-    boolean isStart();
-
-    boolean isDependency();
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/Capability.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/Capability.java b/features/src/main/java/org/apache/karaf/features/Capability.java
deleted file mode 100644
index d329708..0000000
--- a/features/src/main/java/org/apache/karaf/features/Capability.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features;
-
-public interface Capability {
-
-    String getValue();
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/Conditional.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/Conditional.java b/features/src/main/java/org/apache/karaf/features/Conditional.java
deleted file mode 100644
index fdc9261..0000000
--- a/features/src/main/java/org/apache/karaf/features/Conditional.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features;
-
-import java.util.List;
-import java.util.Map;
-
-public interface Conditional {
-
-    List<String> getCondition();
-
-    List<Dependency> getDependencies();
-
-    List<BundleInfo> getBundles();
-
-    Map<String, Map<String, String>> getConfigurations();
-
-    List<ConfigFileInfo> getConfigurationFiles();
-
-    Feature asFeature(String name, String version);
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/ConfigFileInfo.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/ConfigFileInfo.java b/features/src/main/java/org/apache/karaf/features/ConfigFileInfo.java
deleted file mode 100644
index 960fb31..0000000
--- a/features/src/main/java/org/apache/karaf/features/ConfigFileInfo.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features;
-
-public interface ConfigFileInfo {
-	
-	String getLocation();
-	
-	String getFinalname();
-	
-	boolean isOverride();
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/Dependency.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/Dependency.java b/features/src/main/java/org/apache/karaf/features/Dependency.java
deleted file mode 100644
index cafdd92..0000000
--- a/features/src/main/java/org/apache/karaf/features/Dependency.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-
-package org.apache.karaf.features;
-
-public interface Dependency {
-
-    String getName();
-
-    String getVersion();
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/EventConstants.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/EventConstants.java b/features/src/main/java/org/apache/karaf/features/EventConstants.java
deleted file mode 100644
index f83f185..0000000
--- a/features/src/main/java/org/apache/karaf/features/EventConstants.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features;
-
-/**
- * Constants for EventAdmin events
- */
-public final class EventConstants {
-
-    public static final String TYPE = "type";
-    public static final String EVENT = "event";
-    public static final String TIMESTAMP = "timestamp";
-
-    public static final String FEATURE_NAME = "name";
-    public static final String FEATURE_VERSION = "version";
-
-    public static final String REPOSITORY_NAME = "name";
-    public static final String REPOSITORY_URI = "uri";
-
-    public static final String TOPIC_EVENTS = "org/apache/karaf/features";
-    public static final String TOPIC_FEATURES_INSTALLED = TOPIC_EVENTS + "/features/INSTALLED";
-    public static final String TOPIC_FEATURES_UNINSTALLED = TOPIC_EVENTS + "/features/UNINSTALLED";
-    public static final String TOPIC_REPOSITORY_ADDED = TOPIC_EVENTS + "/repositories/ADDED";
-    public static final String TOPIC_REPOSITORY_REMOVED = TOPIC_EVENTS + "/repositories/REMOVED";
-
-    private EventConstants() {
-        // non-instantiable class
-    }
-
-
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/Feature.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/Feature.java b/features/src/main/java/org/apache/karaf/features/Feature.java
deleted file mode 100644
index 2f9f001..0000000
--- a/features/src/main/java/org/apache/karaf/features/Feature.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * A feature is a list of bundles associated identified by its name.
- */
-public interface Feature {
-
-    public static String DEFAULT_INSTALL_MODE = "auto";
-
-    String getId();
-
-    String getName();
-
-    String getDescription();
-
-    String getDetails();
-
-    String getVersion();
-
-    boolean hasVersion();
-
-    String getResolver();
-
-    String getInstall();
-
-    List<Dependency> getDependencies();
-
-    List<BundleInfo> getBundles();
-
-    Map<String, Map<String, String>> getConfigurations();
-
-    List<ConfigFileInfo> getConfigurationFiles();
-
-    List<? extends Conditional> getConditional();
-    
-    int getStartLevel();
-
-    String getRegion();
-
-    List<? extends Capability> getCapabilities();
-
-    List<? extends Requirement> getRequirements();
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/FeatureEvent.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/FeatureEvent.java b/features/src/main/java/org/apache/karaf/features/FeatureEvent.java
deleted file mode 100644
index 516c988..0000000
--- a/features/src/main/java/org/apache/karaf/features/FeatureEvent.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features;
-
-import java.util.EventObject;
-
-public class FeatureEvent extends EventObject {
-
-    public static enum EventType {
-        FeatureInstalled,
-        FeatureUninstalled
-    }
-
-    private final EventType type;
-    private final Feature feature;
-    private final boolean replay;
-
-    public FeatureEvent(Feature feature, EventType type, boolean replay) {
-        super(feature);
-        this.type = type;
-        this.feature = feature;
-        this.replay = replay;
-    }
-
-    public EventType getType() {
-        return type;
-    }
-
-    public Feature getFeature() {
-        return feature;
-    }
-
-    public boolean isReplay() {
-        return replay;
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/FeaturesListener.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/FeaturesListener.java b/features/src/main/java/org/apache/karaf/features/FeaturesListener.java
deleted file mode 100644
index 69f68c6..0000000
--- a/features/src/main/java/org/apache/karaf/features/FeaturesListener.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features;
-
-public interface FeaturesListener {
-
-    void featureEvent(FeatureEvent event);
-
-    void repositoryEvent(RepositoryEvent event);
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/src/main/java/org/apache/karaf/features/FeaturesNamespaces.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/FeaturesNamespaces.java b/features/src/main/java/org/apache/karaf/features/FeaturesNamespaces.java
deleted file mode 100644
index 282ff71..0000000
--- a/features/src/main/java/org/apache/karaf/features/FeaturesNamespaces.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-package org.apache.karaf.features;
-
-import javax.xml.namespace.QName;
-
-/**
- * Provides features XML/XSD constants.
- */
-public interface FeaturesNamespaces {
-
-    String URI_0_0_0 = "";
-    String URI_1_0_0 = "http://karaf.apache.org/xmlns/features/v1.0.0";
-    String URI_1_1_0 = "http://karaf.apache.org/xmlns/features/v1.1.0";
-    String URI_1_2_0 = "http://karaf.apache.org/xmlns/features/v1.2.0";
-    String URI_1_3_0 = "http://karaf.apache.org/xmlns/features/v1.3.0";
-
-    String URI_CURRENT = URI_1_3_0;
-
-    QName FEATURES_0_0_0 = new QName("features");
-    QName FEATURES_1_0_0 = new QName(URI_1_0_0, "features");
-    QName FEATURES_1_1_0 = new QName(URI_1_1_0, "features");
-    QName FEATURES_1_2_0 = new QName(URI_1_2_0, "features");
-    QName FEATURES_1_3_0 = new QName(URI_1_3_0, "features");
-
-    QName FEATURES_CURRENT = FEATURES_1_3_0;
-
-}


[12/33] git commit: [KARAF-2852] Remove obsolete artifacts references

Posted by gn...@apache.org.
[KARAF-2852] Remove obsolete artifacts references


Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/286939f9
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/286939f9
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/286939f9

Branch: refs/heads/master
Commit: 286939f9bb41391c06dbbf7a69ecf810d726086d
Parents: 1306af5
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Fri Apr 11 11:15:19 2014 +0200
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Fri Apr 11 19:20:03 2014 +0200

----------------------------------------------------------------------
 assemblies/features/standard/pom.xml | 67 +---------------------
 pom.xml                              | 95 -------------------------------
 2 files changed, 1 insertion(+), 161 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/286939f9/assemblies/features/standard/pom.xml
----------------------------------------------------------------------
diff --git a/assemblies/features/standard/pom.xml b/assemblies/features/standard/pom.xml
index dda4142..e693f54 100644
--- a/assemblies/features/standard/pom.xml
+++ b/assemblies/features/standard/pom.xml
@@ -51,21 +51,11 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>org.apache.karaf.features</groupId>
-            <artifactId>org.apache.karaf.features.command</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
             <groupId>org.apache.karaf.instance</groupId>
             <artifactId>org.apache.karaf.instance.core</artifactId>
             <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>org.apache.karaf.instance</groupId>
-            <artifactId>org.apache.karaf.instance.command</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
             <groupId>org.apache.karaf.jaas</groupId>
             <artifactId>org.apache.karaf.jaas.modules</artifactId>
             <scope>provided</scope>
@@ -86,31 +76,16 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>org.apache.karaf.diagnostic</groupId>
-            <artifactId>org.apache.karaf.diagnostic.command</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
             <groupId>org.apache.karaf.log</groupId>
             <artifactId>org.apache.karaf.log.core</artifactId>
             <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>org.apache.karaf.log</groupId>
-            <artifactId>org.apache.karaf.log.command</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
             <groupId>org.apache.karaf.service</groupId>
             <artifactId>org.apache.karaf.service.core</artifactId>
             <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>org.apache.karaf.service</groupId>
-            <artifactId>org.apache.karaf.service.command</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
             <groupId>org.apache.karaf.shell</groupId>
             <artifactId>org.apache.karaf.shell.core</artifactId>
             <scope>provided</scope>
@@ -144,11 +119,6 @@
             <artifactId>org.apache.karaf.wrapper.core</artifactId>
             <scope>provided</scope>
         </dependency>
-        <dependency>
-            <groupId>org.apache.karaf.wrapper</groupId>
-            <artifactId>org.apache.karaf.wrapper.command</artifactId>
-            <scope>provided</scope>
-        </dependency>
 
         <!-- obr deps -->
         <dependency>
@@ -177,11 +147,6 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>org.apache.karaf.obr</groupId>
-            <artifactId>org.apache.karaf.obr.command</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
             <groupId>org.ops4j.pax.swissbox</groupId>
             <artifactId>pax-swissbox-lifecycle</artifactId>
             <scope>provided</scope>
@@ -209,11 +174,6 @@
             <artifactId>org.apache.karaf.config.core</artifactId>
             <scope>provided</scope>
         </dependency>
-        <dependency>
-            <groupId>org.apache.karaf.config</groupId>
-            <artifactId>org.apache.karaf.config.command</artifactId>
-            <scope>provided</scope>
-        </dependency>
 
         <!-- region deps -->
         <dependency>
@@ -223,12 +183,7 @@
         </dependency>
         <dependency>
             <groupId>org.apache.karaf.region</groupId>
-            <artifactId>org.apache.karaf.region.persist</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.karaf.region</groupId>
-            <artifactId>org.apache.karaf.region.command</artifactId>
+            <artifactId>org.apache.karaf.region.core</artifactId>
             <scope>provided</scope>
         </dependency>
 
@@ -270,11 +225,6 @@
             <artifactId>org.apache.karaf.package.core</artifactId>
             <scope>provided</scope>
         </dependency>
-        <dependency>
-            <groupId>org.apache.karaf.package</groupId>
-            <artifactId>org.apache.karaf.package.command</artifactId>
-            <scope>provided</scope>
-        </dependency>
 
         <!-- http deps -->
         <dependency>
@@ -302,11 +252,6 @@
             <artifactId>org.apache.karaf.http.core</artifactId>
             <scope>provided</scope>
         </dependency>
-        <dependency>
-            <groupId>org.apache.karaf.http</groupId>
-            <artifactId>org.apache.karaf.http.command</artifactId>
-            <scope>provided</scope>
-        </dependency>
 
         <!-- http-whiteboard deps -->
         <dependency>
@@ -362,11 +307,6 @@
             <artifactId>org.apache.karaf.web.core</artifactId>
             <scope>provided</scope>
         </dependency>
-        <dependency>
-            <groupId>org.apache.karaf.web</groupId>
-            <artifactId>org.apache.karaf.web.command</artifactId>
-            <scope>provided</scope>
-        </dependency>
 
         <!-- kar deps -->
         <dependency>
@@ -375,11 +315,6 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>org.apache.karaf.kar</groupId>
-            <artifactId>org.apache.karaf.kar.command</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
             <groupId>org.apache.karaf.deployer</groupId>
             <artifactId>org.apache.karaf.deployer.kar</artifactId>
             <scope>provided</scope>

http://git-wip-us.apache.org/repos/asf/karaf/blob/286939f9/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index d5f8423..48c5951 100644
--- a/pom.xml
+++ b/pom.xml
@@ -385,11 +385,6 @@
             </dependency>
             <dependency>
                 <groupId>org.apache.karaf.bundle</groupId>
-                <artifactId>org.apache.karaf.bundle.command</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.karaf.bundle</groupId>
                 <artifactId>org.apache.karaf.bundle.springstate</artifactId>
                 <version>${project.version}</version>
             </dependency>
@@ -404,55 +399,30 @@
                 <artifactId>org.apache.karaf.package.core</artifactId>
                 <version>${project.version}</version>
             </dependency>
-            <dependency>
-                <groupId>org.apache.karaf.package</groupId>
-                <artifactId>org.apache.karaf.package.command</artifactId>
-                <version>${project.version}</version>
-            </dependency>
 
             <dependency>
                 <groupId>org.apache.karaf.http</groupId>
                 <artifactId>org.apache.karaf.http.core</artifactId>
                 <version>${project.version}</version>
             </dependency>
-            <dependency>
-                <groupId>org.apache.karaf.http</groupId>
-                <artifactId>org.apache.karaf.http.command</artifactId>
-                <version>${project.version}</version>
-            </dependency>
 
             <dependency>
                 <groupId>org.apache.karaf.jdbc</groupId>
                 <artifactId>org.apache.karaf.jdbc.core</artifactId>
                 <version>${project.version}</version>
             </dependency>
-            <dependency>
-                <groupId>org.apache.karaf.jdbc</groupId>
-                <artifactId>org.apache.karaf.jdbc.command</artifactId>
-                <version>${project.version}</version>
-            </dependency>
 
             <dependency>
                 <groupId>org.apache.karaf.jms</groupId>
                 <artifactId>org.apache.karaf.jms.core</artifactId>
                 <version>${project.version}</version>
             </dependency>
-            <dependency>
-                <groupId>org.apache.karaf.jms</groupId>
-                <artifactId>org.apache.karaf.jms.command</artifactId>
-                <version>${project.version}</version>
-            </dependency>
 
             <dependency>
                 <groupId>org.apache.karaf.jndi</groupId>
                 <artifactId>org.apache.karaf.jndi.core</artifactId>
                 <version>${project.version}</version>
             </dependency>
-            <dependency>
-                <groupId>org.apache.karaf.jndi</groupId>
-                <artifactId>org.apache.karaf.jndi.command</artifactId>
-                <version>${project.version}</version>
-            </dependency>
 
             <dependency>
                 <groupId>org.apache.karaf.service</groupId>
@@ -461,11 +431,6 @@
             </dependency>
             <dependency>
                 <groupId>org.apache.karaf.service</groupId>
-                <artifactId>org.apache.karaf.service.command</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.karaf.service</groupId>
                 <artifactId>org.apache.karaf.service.guard</artifactId>
                 <version>${project.version}</version>
             </dependency>
@@ -475,22 +440,12 @@
                 <artifactId>org.apache.karaf.log.core</artifactId>
                 <version>${project.version}</version>
             </dependency>
-            <dependency>
-                <groupId>org.apache.karaf.log</groupId>
-                <artifactId>org.apache.karaf.log.command</artifactId>
-                <version>${project.version}</version>
-            </dependency>
 
             <dependency>
                 <groupId>org.apache.karaf.config</groupId>
                 <artifactId>org.apache.karaf.config.core</artifactId>
                 <version>${project.version}</version>
             </dependency>
-            <dependency>
-                <groupId>org.apache.karaf.config</groupId>
-                <artifactId>org.apache.karaf.config.command</artifactId>
-                <version>${project.version}</version>
-            </dependency>
 
             <dependency>
                 <groupId>org.apache.karaf.deployer</groupId>
@@ -520,22 +475,12 @@
 
             <dependency>
                 <groupId>org.apache.karaf.kar</groupId>
-                <artifactId>org.apache.karaf.kar.command</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.karaf.kar</groupId>
                 <artifactId>org.apache.karaf.kar.core</artifactId>
                 <version>${project.version}</version>
             </dependency>
 
             <dependency>
                 <groupId>org.apache.karaf.obr</groupId>
-                <artifactId>org.apache.karaf.obr.command</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.karaf.obr</groupId>
                 <artifactId>org.apache.karaf.obr.core</artifactId>
                 <version>${project.version}</version>
             </dependency>
@@ -564,11 +509,6 @@
             </dependency>
             <dependency>
                 <groupId>org.apache.karaf.features</groupId>
-                <artifactId>org.apache.karaf.features.command</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.karaf.features</groupId>
                 <artifactId>org.apache.karaf.features.obr</artifactId>
                 <version>${project.version}</version>
             </dependency>
@@ -578,52 +518,27 @@
                 <artifactId>org.apache.karaf.diagnostic.core</artifactId>
                 <version>${project.version}</version>
             </dependency>
-            <dependency>
-                <groupId>org.apache.karaf.diagnostic</groupId>
-                <artifactId>org.apache.karaf.diagnostic.command</artifactId>
-                <version>${project.version}</version>
-            </dependency>
 
             <dependency>
                 <groupId>org.apache.karaf.instance</groupId>
                 <artifactId>org.apache.karaf.instance.core</artifactId>
                 <version>${project.version}</version>
             </dependency>
-            <dependency>
-                <groupId>org.apache.karaf.instance</groupId>
-                <artifactId>org.apache.karaf.instance.command</artifactId>
-                <version>${project.version}</version>
-            </dependency>
 
             <dependency>
                 <groupId>org.apache.karaf.system</groupId>
-                <artifactId>org.apache.karaf.system.command</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.karaf.system</groupId>
                 <artifactId>org.apache.karaf.system.core</artifactId>
                 <version>${project.version}</version>
             </dependency>
 
             <dependency>
                 <groupId>org.apache.karaf.web</groupId>
-                <artifactId>org.apache.karaf.web.command</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.karaf.web</groupId>
                 <artifactId>org.apache.karaf.web.core</artifactId>
                 <version>${project.version}</version>
             </dependency>
 
             <dependency>
                 <groupId>org.apache.karaf.wrapper</groupId>
-                <artifactId>org.apache.karaf.wrapper.command</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.karaf.wrapper</groupId>
                 <artifactId>org.apache.karaf.wrapper.core</artifactId>
                 <version>${project.version}</version>
             </dependency>
@@ -633,16 +548,6 @@
                 <artifactId>org.apache.karaf.region.core</artifactId>
                 <version>${project.version}</version>
             </dependency>
-            <dependency>
-                <groupId>org.apache.karaf.region</groupId>
-                <artifactId>org.apache.karaf.region.command</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.karaf.region</groupId>
-                <artifactId>org.apache.karaf.region.persist</artifactId>
-                <version>${project.version}</version>
-            </dependency>
 
             <dependency>
                 <groupId>org.apache.karaf.shell</groupId>


[31/33] Revert "[KARAF-2852] Merge features/core and features/command"

Posted by gn...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/pom.xml
----------------------------------------------------------------------
diff --git a/features/core/pom.xml b/features/core/pom.xml
new file mode 100644
index 0000000..d8a2620
--- /dev/null
+++ b/features/core/pom.xml
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <!--
+
+        Licensed to the Apache Software Foundation (ASF) under one or more
+        contributor license agreements.  See the NOTICE file distributed with
+        this work for additional information regarding copyright ownership.
+        The ASF licenses this file to You under the Apache License, Version 2.0
+        (the "License"); you may not use this file except in compliance with
+        the License.  You may obtain a copy of the License at
+
+            http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software
+        distributed under the License is distributed on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        See the License for the specific language governing permissions and
+        limitations under the License.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.karaf.features</groupId>
+        <artifactId>features</artifactId>
+        <version>4.0.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>org.apache.karaf.features.core</artifactId>
+    <packaging>bundle</packaging>
+    <name>Apache Karaf :: Features :: Core</name>
+    <description>This bundle is the core implementation of the Karaf features support.</description>
+
+    <properties>
+        <appendedResourcesDirectory>${basedir}/../../etc/appended-resources</appendedResourcesDirectory>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+            <scope>provided</scope>
+            <optional>true</optional>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.utils</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.karaf</groupId>
+            <artifactId>org.apache.karaf.util</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.resolver</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-jdk14</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.ops4j.pax.tinybundles</groupId>
+            <artifactId>tinybundles</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <resources>
+            <resource>
+                <directory>${project.basedir}/src/main/resources</directory>
+                <includes>
+                    <include>**/*</include>
+                </includes>
+            </resource>
+            <resource>
+                <directory>${project.basedir}/src/main/resources</directory>
+                <filtering>true</filtering>
+                <includes>
+                    <include>**/*.info</include>
+                </includes>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Export-Package>
+                            org.apache.karaf.features;
+                            org.apache.karaf.features.management;
+                            org.apache.karaf.features.management.codec;
+                                -noimport:=true
+                        </Export-Package>
+                        <Provide-Capability>
+                            service-reference;effective:=active;objectClass=org.apache.karaf.features.FeaturesService
+                        </Provide-Capability>
+                        <Private-Package>
+                            org.apache.karaf.features.internal.*,
+                            org.apache.felix.resolver,
+                            org.apache.felix.utils.version,
+                            org.apache.felix.utils.manifest,
+                            org.apache.karaf.util.collections,
+                            org.apache.karaf.util.json,
+                            org.apache.karaf.util.tracker,
+                            org.osgi.service.resolver,
+                            org.osgi.service.repository
+                        </Private-Package>
+                        <Embed-Dependency>
+                            org.apache.karaf.util;inline="org/apache/karaf/util/XmlUtils*.class"
+                        </Embed-Dependency>
+                        <Bundle-Activator>
+                            org.apache.karaf.features.internal.osgi.Activator
+                        </Bundle-Activator>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/BootFinished.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/BootFinished.java b/features/core/src/main/java/org/apache/karaf/features/BootFinished.java
new file mode 100644
index 0000000..aa72248
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/BootFinished.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.karaf.features;
+
+/**
+ * Marker interface for a service that announces when the karaf boot is finished
+ */
+public interface BootFinished {
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/BundleInfo.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/BundleInfo.java b/features/core/src/main/java/org/apache/karaf/features/BundleInfo.java
new file mode 100644
index 0000000..97a541f
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/BundleInfo.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.karaf.features;
+
+/**
+ * A bundle info holds info about a Bundle.
+ */
+public interface BundleInfo {
+
+	String getLocation();
+	
+    int getStartLevel();
+    
+    boolean isStart();
+
+    boolean isDependency();
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/Capability.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/Capability.java b/features/core/src/main/java/org/apache/karaf/features/Capability.java
new file mode 100644
index 0000000..d329708
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/Capability.java
@@ -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.
+ */
+package org.apache.karaf.features;
+
+public interface Capability {
+
+    String getValue();
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/Conditional.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/Conditional.java b/features/core/src/main/java/org/apache/karaf/features/Conditional.java
new file mode 100644
index 0000000..fdc9261
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/Conditional.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.karaf.features;
+
+import java.util.List;
+import java.util.Map;
+
+public interface Conditional {
+
+    List<String> getCondition();
+
+    List<Dependency> getDependencies();
+
+    List<BundleInfo> getBundles();
+
+    Map<String, Map<String, String>> getConfigurations();
+
+    List<ConfigFileInfo> getConfigurationFiles();
+
+    Feature asFeature(String name, String version);
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/ConfigFileInfo.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/ConfigFileInfo.java b/features/core/src/main/java/org/apache/karaf/features/ConfigFileInfo.java
new file mode 100644
index 0000000..960fb31
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/ConfigFileInfo.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.karaf.features;
+
+public interface ConfigFileInfo {
+	
+	String getLocation();
+	
+	String getFinalname();
+	
+	boolean isOverride();
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/Dependency.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/Dependency.java b/features/core/src/main/java/org/apache/karaf/features/Dependency.java
new file mode 100644
index 0000000..cafdd92
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/Dependency.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.karaf.features;
+
+public interface Dependency {
+
+    String getName();
+
+    String getVersion();
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/EventConstants.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/EventConstants.java b/features/core/src/main/java/org/apache/karaf/features/EventConstants.java
new file mode 100644
index 0000000..f83f185
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/EventConstants.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.karaf.features;
+
+/**
+ * Constants for EventAdmin events
+ */
+public final class EventConstants {
+
+    public static final String TYPE = "type";
+    public static final String EVENT = "event";
+    public static final String TIMESTAMP = "timestamp";
+
+    public static final String FEATURE_NAME = "name";
+    public static final String FEATURE_VERSION = "version";
+
+    public static final String REPOSITORY_NAME = "name";
+    public static final String REPOSITORY_URI = "uri";
+
+    public static final String TOPIC_EVENTS = "org/apache/karaf/features";
+    public static final String TOPIC_FEATURES_INSTALLED = TOPIC_EVENTS + "/features/INSTALLED";
+    public static final String TOPIC_FEATURES_UNINSTALLED = TOPIC_EVENTS + "/features/UNINSTALLED";
+    public static final String TOPIC_REPOSITORY_ADDED = TOPIC_EVENTS + "/repositories/ADDED";
+    public static final String TOPIC_REPOSITORY_REMOVED = TOPIC_EVENTS + "/repositories/REMOVED";
+
+    private EventConstants() {
+        // non-instantiable class
+    }
+
+
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/Feature.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/Feature.java b/features/core/src/main/java/org/apache/karaf/features/Feature.java
new file mode 100644
index 0000000..2f9f001
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/Feature.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.karaf.features;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A feature is a list of bundles associated identified by its name.
+ */
+public interface Feature {
+
+    public static String DEFAULT_INSTALL_MODE = "auto";
+
+    String getId();
+
+    String getName();
+
+    String getDescription();
+
+    String getDetails();
+
+    String getVersion();
+
+    boolean hasVersion();
+
+    String getResolver();
+
+    String getInstall();
+
+    List<Dependency> getDependencies();
+
+    List<BundleInfo> getBundles();
+
+    Map<String, Map<String, String>> getConfigurations();
+
+    List<ConfigFileInfo> getConfigurationFiles();
+
+    List<? extends Conditional> getConditional();
+    
+    int getStartLevel();
+
+    String getRegion();
+
+    List<? extends Capability> getCapabilities();
+
+    List<? extends Requirement> getRequirements();
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/FeatureEvent.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/FeatureEvent.java b/features/core/src/main/java/org/apache/karaf/features/FeatureEvent.java
new file mode 100644
index 0000000..516c988
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/FeatureEvent.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.karaf.features;
+
+import java.util.EventObject;
+
+public class FeatureEvent extends EventObject {
+
+    public static enum EventType {
+        FeatureInstalled,
+        FeatureUninstalled
+    }
+
+    private final EventType type;
+    private final Feature feature;
+    private final boolean replay;
+
+    public FeatureEvent(Feature feature, EventType type, boolean replay) {
+        super(feature);
+        this.type = type;
+        this.feature = feature;
+        this.replay = replay;
+    }
+
+    public EventType getType() {
+        return type;
+    }
+
+    public Feature getFeature() {
+        return feature;
+    }
+
+    public boolean isReplay() {
+        return replay;
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/FeaturesListener.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/FeaturesListener.java b/features/core/src/main/java/org/apache/karaf/features/FeaturesListener.java
new file mode 100644
index 0000000..69f68c6
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/FeaturesListener.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features;
+
+public interface FeaturesListener {
+
+    void featureEvent(FeatureEvent event);
+
+    void repositoryEvent(RepositoryEvent event);
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/FeaturesNamespaces.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/FeaturesNamespaces.java b/features/core/src/main/java/org/apache/karaf/features/FeaturesNamespaces.java
new file mode 100644
index 0000000..282ff71
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/FeaturesNamespaces.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.karaf.features;
+
+import javax.xml.namespace.QName;
+
+/**
+ * Provides features XML/XSD constants.
+ */
+public interface FeaturesNamespaces {
+
+    String URI_0_0_0 = "";
+    String URI_1_0_0 = "http://karaf.apache.org/xmlns/features/v1.0.0";
+    String URI_1_1_0 = "http://karaf.apache.org/xmlns/features/v1.1.0";
+    String URI_1_2_0 = "http://karaf.apache.org/xmlns/features/v1.2.0";
+    String URI_1_3_0 = "http://karaf.apache.org/xmlns/features/v1.3.0";
+
+    String URI_CURRENT = URI_1_3_0;
+
+    QName FEATURES_0_0_0 = new QName("features");
+    QName FEATURES_1_0_0 = new QName(URI_1_0_0, "features");
+    QName FEATURES_1_1_0 = new QName(URI_1_1_0, "features");
+    QName FEATURES_1_2_0 = new QName(URI_1_2_0, "features");
+    QName FEATURES_1_3_0 = new QName(URI_1_3_0, "features");
+
+    QName FEATURES_CURRENT = FEATURES_1_3_0;
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/FeaturesService.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/FeaturesService.java b/features/core/src/main/java/org/apache/karaf/features/FeaturesService.java
new file mode 100644
index 0000000..ef3dbcf
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/FeaturesService.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.karaf.features;
+
+import java.net.URI;
+import java.util.EnumSet;
+import java.util.Set;
+
+/**
+ * The service managing features repositories.
+ */
+public interface FeaturesService {
+
+    enum Option {
+        NoFailOnFeatureNotFound,
+        NoAutoRefreshManagedBundles,
+        NoAutoRefreshUnmanagedBundles,
+        NoAutoRefreshBundles,
+        NoAutoStartBundles,
+        Simulate,
+        Verbose
+    }
+
+    /**
+     * Validate repository contents.
+     * 
+     * @param uri Repository uri.
+     * @throws Exception When validation fails.
+     */
+    void validateRepository(URI uri) throws Exception;
+
+    void addRepository(URI uri) throws Exception;
+
+    void addRepository(URI uri, boolean install) throws Exception;
+
+    void removeRepository(URI uri) throws Exception;
+
+    void removeRepository(URI uri, boolean uninstall) throws Exception;
+    
+    void restoreRepository(URI uri) throws Exception;
+
+    Repository[] listRequiredRepositories() throws Exception;
+
+    Repository[] listRepositories() throws Exception;
+    
+    Repository getRepository(String repoName) throws Exception;
+
+    void installFeature(String name) throws Exception;
+
+    void installFeature(String name, EnumSet<Option> options) throws Exception;
+    
+    void installFeature(String name, String version) throws Exception;
+
+    void installFeature(String name, String version, EnumSet<Option> options) throws Exception;
+
+    void installFeature(Feature f, EnumSet<Option> options) throws Exception;
+
+    void installFeatures(Set<String> features, EnumSet<Option> options) throws Exception;
+
+    void uninstallFeature(String name, EnumSet<Option> options) throws Exception;
+
+    void uninstallFeature(String name) throws Exception;
+
+    void uninstallFeature(String name, String version, EnumSet<Option> options) throws Exception;
+    
+    void uninstallFeature(String name, String version) throws Exception;
+
+    void uninstallFeatures(Set<String> features, EnumSet<Option> options) throws Exception;
+
+    Feature[] listFeatures() throws Exception;
+
+    Feature[] listRequiredFeatures() throws Exception;
+
+    Feature[] listInstalledFeatures() throws Exception;
+
+    boolean isRequired(Feature f);
+
+    boolean isInstalled(Feature f);
+
+    Feature getFeature(String name, String version) throws Exception;
+
+    Feature getFeature(String name) throws Exception;
+
+	void refreshRepository(URI uri) throws Exception;
+
+    public URI getRepositoryUriFor(String name, String version);
+
+    public String[] getRepositoryNames();
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/RegionsPersistence.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/RegionsPersistence.java b/features/core/src/main/java/org/apache/karaf/features/RegionsPersistence.java
new file mode 100644
index 0000000..96ca7da
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/RegionsPersistence.java
@@ -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.
+ */
+package org.apache.karaf.features;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+
+public interface RegionsPersistence {
+    void install(Bundle b, String regionName) throws BundleException;
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/Repository.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/Repository.java b/features/core/src/main/java/org/apache/karaf/features/Repository.java
new file mode 100644
index 0000000..3ea12ec
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/Repository.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.karaf.features;
+
+import java.io.IOException;
+import java.net.URI;
+
+/**
+ * A repository of features.
+ */
+public interface Repository {
+
+    String getName() throws IOException;
+
+    URI getURI();
+
+    URI[] getRepositories() throws Exception;
+
+    Feature[] getFeatures() throws Exception;
+    
+    boolean isValid();
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/RepositoryEvent.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/RepositoryEvent.java b/features/core/src/main/java/org/apache/karaf/features/RepositoryEvent.java
new file mode 100644
index 0000000..68f287b
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/RepositoryEvent.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.karaf.features;
+
+import java.util.EventObject;
+
+public class RepositoryEvent extends EventObject {
+
+    public static enum EventType {
+        RepositoryAdded,
+        RepositoryRemoved,
+    }
+
+    private final EventType type;
+    private final Repository repository;
+    private final boolean replay;
+
+    public RepositoryEvent(Repository repository, EventType type, boolean replay) {
+        super(repository);
+        this.type = type;
+        this.repository = repository;
+        this.replay = replay;
+    }
+
+    public EventType getType() {
+        return type;
+    }
+
+    public Repository getRepository() {
+        return repository;
+    }
+
+    public boolean isReplay() {
+        return replay;
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/Requirement.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/Requirement.java b/features/core/src/main/java/org/apache/karaf/features/Requirement.java
new file mode 100644
index 0000000..4446335
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/Requirement.java
@@ -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.
+ */
+package org.apache.karaf.features;
+
+public interface Requirement {
+
+    String getValue();
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/Resolver.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/Resolver.java b/features/core/src/main/java/org/apache/karaf/features/Resolver.java
new file mode 100644
index 0000000..d2fa941
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/Resolver.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features;
+
+import java.util.List;
+
+public interface Resolver {
+
+    List<BundleInfo> resolve(Feature feature) throws Exception;
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/deployment/DeploymentBuilder.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/deployment/DeploymentBuilder.java b/features/core/src/main/java/org/apache/karaf/features/internal/deployment/DeploymentBuilder.java
new file mode 100644
index 0000000..c3ac2b7
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/deployment/DeploymentBuilder.java
@@ -0,0 +1,354 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.deployment;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import org.apache.felix.resolver.ResolverImpl;
+import org.apache.felix.utils.version.VersionRange;
+import org.apache.felix.utils.version.VersionTable;
+import org.apache.karaf.features.BundleInfo;
+import org.apache.karaf.features.Conditional;
+import org.apache.karaf.features.Dependency;
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.Repository;
+import org.apache.karaf.features.internal.repository.AggregateRepository;
+import org.apache.karaf.features.internal.repository.StaticRepository;
+import org.apache.karaf.features.internal.resolver.FeatureNamespace;
+import org.apache.karaf.features.internal.resolver.FeatureResource;
+import org.apache.karaf.features.internal.resolver.RequirementImpl;
+import org.apache.karaf.features.internal.resolver.ResolveContextImpl;
+import org.apache.karaf.features.internal.resolver.ResourceBuilder;
+import org.apache.karaf.features.internal.resolver.ResourceImpl;
+import org.apache.karaf.features.internal.resolver.Slf4jResolverLog;
+import org.apache.karaf.features.internal.service.Overrides;
+import org.apache.karaf.features.internal.util.Macro;
+import org.apache.karaf.features.internal.util.MultiException;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Version;
+import org.osgi.framework.namespace.IdentityNamespace;
+import org.osgi.resource.Capability;
+import org.osgi.resource.Requirement;
+import org.osgi.resource.Resource;
+import org.osgi.resource.Wire;
+import org.osgi.service.resolver.ResolutionException;
+import org.osgi.service.resolver.ResolveContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ */
+public class DeploymentBuilder {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(DeploymentBuilder.class);
+
+    public static final String REQ_PROTOCOL = "req:";
+
+    private final Collection<Repository> repositories;
+
+    private final List<org.osgi.service.repository.Repository> resourceRepos;
+
+    String featureRange = "${range;[====,====]}";
+
+    Downloader downloader;
+    ResourceImpl requirements;
+    Map<String, Resource> resources;
+    Set<Resource> optionals;
+    Map<String, StreamProvider> providers;
+
+    Set<Feature> featuresToRegister = new HashSet<Feature>();
+
+    public DeploymentBuilder(Downloader downloader,
+                             Collection<Repository> repositories) {
+        this.downloader = downloader;
+        this.repositories = repositories;
+        this.resourceRepos = new ArrayList<org.osgi.service.repository.Repository>();
+    }
+
+    public void addResourceRepository(org.osgi.service.repository.Repository repository) {
+        resourceRepos.add(repository);
+    }
+
+    public Map<String, StreamProvider> getProviders() {
+        return providers;
+    }
+
+    public void setFeatureRange(String featureRange) {
+        this.featureRange = featureRange;
+    }
+
+    public Map<String, Resource> download(
+                         Set<String> features,
+                         Set<String> bundles,
+                         Set<String> reqs,
+                         Set<String> overrides,
+                         Set<String> optionals)
+                throws IOException, MultiException, InterruptedException, ResolutionException, BundleException {
+        this.resources = new ConcurrentHashMap<String, Resource>();
+        this.optionals = new HashSet<Resource>();
+        this.providers = new ConcurrentHashMap<String, StreamProvider>();
+        this.requirements = new ResourceImpl("dummy", "dummy", Version.emptyVersion);
+        // First, gather all bundle resources
+        for (String feature : features) {
+            registerMatchingFeatures(feature);
+        }
+        for (String bundle : bundles) {
+            downloadAndBuildResource(bundle);
+        }
+        for (String req : reqs) {
+            buildRequirement(req);
+        }
+        for (String override : overrides) {
+            // TODO: ignore download failures for overrides
+            downloadAndBuildResource(Overrides.extractUrl(override));
+        }
+        for (String optional : optionals) {
+            downloadAndBuildResource(optional);
+        }
+        // Wait for all resources to be created
+        downloader.await();
+        // Do override replacement
+        Overrides.override(resources, overrides);
+        // Build features resources
+        for (Feature feature : featuresToRegister) {
+            Resource resource = FeatureResource.build(feature, featureRange, resources);
+            resources.put("feature:" + feature.getName() + "/" + feature.getVersion(), resource);
+            for (Conditional cond : feature.getConditional()) {
+                this.optionals.add(FeatureResource.build(feature, cond, featureRange, resources));
+            }
+        }
+        // Build requirements
+        for (String feature : features) {
+            requireFeature(feature);
+        }
+        for (String bundle : bundles) {
+            requireResource(bundle);
+        }
+        for (String req : reqs) {
+            requireResource(REQ_PROTOCOL + req);
+        }
+        return resources;
+    }
+
+    public Map<Resource, List<Wire>> resolve(List<Resource> systemBundles) throws ResolutionException {
+        // Resolve
+        for (int i = 0; i < systemBundles.size(); i++) {
+            resources.put("system-bundle-" + i, systemBundles.get(i));
+        }
+
+        List<org.osgi.service.repository.Repository> repos = new ArrayList<org.osgi.service.repository.Repository>();
+        repos.add(new StaticRepository(resources.values()));
+        repos.addAll(resourceRepos);
+
+        ResolverImpl resolver = new ResolverImpl(new Slf4jResolverLog(LOGGER));
+        ResolveContext context = new ResolveContextImpl(
+                Collections.<Resource>singleton(requirements),
+                Collections.<Resource>emptySet(),
+                new AggregateRepository(repos),
+                false);
+        Map<Resource, List<Wire>> best = resolver.resolve(context);
+
+        // TODO: we actually need to use multiple passes for conditionals
+        // TODO: but it may be optimized by passing the old wiring instead
+        // TODO: of computing everything again
+        Set<Resource> resources = new HashSet<Resource>();
+        resources.add(requirements);
+        for (Resource optional : optionals) {
+            try {
+                Set<Resource> newSet = new HashSet<Resource>(resources);
+                newSet.add(optional);
+                context = new ResolveContextImpl(
+                        newSet,
+                        Collections.<Resource>emptySet(),
+                        new AggregateRepository(repos),
+                        false);
+                best = resolver.resolve(context);
+                resources = newSet;
+            } catch (ResolutionException e) {
+                // Ignore this resource
+            }
+        }
+        return best;
+    }
+
+    public void requireFeature(String feature) throws IOException {
+        // Find name and version range
+        String[] split = feature.split("/");
+        String name = split[0].trim();
+        String version = (split.length > 1) ? split[1].trim() : null;
+        if (version != null && !version.equals("0.0.0") && !version.startsWith("[") && !version.startsWith("(")) {
+            version = Macro.transform(featureRange, version);
+        }
+        VersionRange range = version != null ? new VersionRange(version) : VersionRange.ANY_VERSION;
+        // Add requirement
+        Map<String, Object> attrs = new HashMap<String, Object>();
+        attrs.put(IdentityNamespace.IDENTITY_NAMESPACE, name);
+        attrs.put(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE, FeatureNamespace.TYPE_FEATURE);
+        attrs.put(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, range);
+        requirements.addRequirement(
+                new RequirementImpl(requirements, IdentityNamespace.IDENTITY_NAMESPACE,
+                        Collections.<String, String>emptyMap(), attrs)
+        );
+    }
+
+    public void requireResource(String location) {
+        Resource res = resources.get(location);
+        if (res == null) {
+            throw new IllegalStateException("Could not find resource for " + location);
+        }
+        List<Capability> caps = res.getCapabilities(IdentityNamespace.IDENTITY_NAMESPACE);
+        if (caps.size() != 1) {
+            throw new IllegalStateException("Resource does not have a single " + IdentityNamespace.IDENTITY_NAMESPACE + " capability");
+        }
+        Capability cap = caps.get(0);
+        // Add requirement
+        Map<String, Object> attrs = new HashMap<String, Object>();
+        attrs.put(IdentityNamespace.IDENTITY_NAMESPACE, cap.getAttributes().get(IdentityNamespace.IDENTITY_NAMESPACE));
+        attrs.put(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE, cap.getAttributes().get(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE));
+        attrs.put(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, new VersionRange((Version) cap.getAttributes().get(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE), true));
+        requirements.addRequirement(
+                new RequirementImpl(requirements, IdentityNamespace.IDENTITY_NAMESPACE,
+                        Collections.<String, String>emptyMap(), attrs));
+
+    }
+
+    public void registerMatchingFeatures(String feature) throws IOException {
+        // Find name and version range
+        String[] split = feature.split("/");
+        String name = split[0].trim();
+        String version = (split.length > 1)
+                ? split[1].trim() : Version.emptyVersion.toString();
+        // Register matching features
+        registerMatchingFeatures(name, new VersionRange(version));
+    }
+
+    public void registerMatchingFeatures(String name, String version) throws IOException {
+        if (version != null && !version.equals("0.0.0") && !version.startsWith("[") && !version.startsWith("(")) {
+            version = Macro.transform(featureRange, version);
+        }
+        registerMatchingFeatures(name, version != null ? new VersionRange(version) : VersionRange.ANY_VERSION);
+    }
+
+    public void registerMatchingFeatures(String name, VersionRange range) throws IOException {
+        for (Repository repo : repositories) {
+            Feature[] features;
+            try {
+                features = repo.getFeatures();
+            } catch (Exception e) {
+                // This should not happen as the repository has been loaded already
+                throw new IllegalStateException(e);
+            }
+            for (Feature f : features) {
+                if (name.equals(f.getName())) {
+                    Version v = VersionTable.getVersion(f.getVersion());
+                    if (range.contains(v)) {
+                        featuresToRegister.add(f);
+                        for (Dependency dep : f.getDependencies()) {
+                            registerMatchingFeatures(dep.getName(), dep.getVersion());
+                        }
+                        for (BundleInfo bundle : f.getBundles()) {
+                            downloadAndBuildResource(bundle.getLocation());
+                        }
+                        for (Conditional cond : f.getConditional()) {
+                            Feature c = cond.asFeature(f.getName(), f.getVersion());
+                            featuresToRegister.add(c);
+                            for (BundleInfo bundle : c.getBundles()) {
+                                downloadAndBuildResource(bundle.getLocation());
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    public void buildRequirement(String requirement) {
+        try {
+            String location = REQ_PROTOCOL + requirement;
+            ResourceImpl resource = new ResourceImpl(location, "dummy", Version.emptyVersion);
+            for (Requirement req : ResourceBuilder.parseRequirement(resource, requirement)) {
+                resource.addRequirement(req);
+            }
+            resources.put(location, resource);
+        } catch (BundleException e) {
+            throw new IllegalArgumentException("Error parsing requirement: " + requirement, e);
+        }
+    }
+
+    public void downloadAndBuildResource(final String location) throws IOException {
+        if (!resources.containsKey(location)) {
+            downloader.download(location, new Downloader.DownloadCallback() {
+                @Override
+                public void downloaded(StreamProvider provider) throws Exception {
+                    manageResource(location, provider);
+                }
+            });
+        }
+    }
+
+    private void manageResource(String location, StreamProvider provider) throws Exception {
+        if (!resources.containsKey(location)) {
+            Attributes attributes = getAttributes(location, provider);
+            Resource resource = createResource(location, attributes);
+            resources.put(location, resource);
+            providers.put(location, provider);
+        }
+    }
+
+    private Resource createResource(String uri, Attributes attributes) throws Exception {
+        Map<String, String> headers = new HashMap<String, String>();
+        for (Map.Entry attr : attributes.entrySet()) {
+            headers.put(attr.getKey().toString(), attr.getValue().toString());
+        }
+        try {
+            return ResourceBuilder.build(uri, headers);
+        } catch (BundleException e) {
+            throw new Exception("Unable to create resource for bundle " + uri, e);
+        }
+    }
+
+    protected Attributes getAttributes(String uri, StreamProvider provider) throws Exception {
+        InputStream is = provider.open();
+        try {
+            ZipInputStream zis = new ZipInputStream(is);
+            ZipEntry entry;
+            while ( (entry = zis.getNextEntry()) != null ) {
+                if ("META-INF/MANIFEST.MF".equals(entry.getName())) {
+                    return new Manifest(zis).getMainAttributes();
+                }
+            }
+        } finally {
+            is.close();
+        }
+        throw new IllegalArgumentException("Resource " + uri + " does not contain a manifest");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/deployment/Downloader.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/deployment/Downloader.java b/features/core/src/main/java/org/apache/karaf/features/internal/deployment/Downloader.java
new file mode 100644
index 0000000..2d5dd98
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/deployment/Downloader.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.karaf.features.internal.deployment;
+
+import java.net.MalformedURLException;
+
+import org.apache.karaf.features.internal.util.MultiException;
+
+public interface Downloader {
+
+    void await() throws InterruptedException, MultiException;
+
+    void download(String location, DownloadCallback downloadCallback) throws MalformedURLException;
+
+    interface DownloadCallback {
+
+        void downloaded(StreamProvider provider) throws Exception;
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/deployment/StreamProvider.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/deployment/StreamProvider.java b/features/core/src/main/java/org/apache/karaf/features/internal/deployment/StreamProvider.java
new file mode 100644
index 0000000..60a3dfc
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/deployment/StreamProvider.java
@@ -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.
+ */
+package org.apache.karaf.features.internal.deployment;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public interface StreamProvider {
+
+    InputStream open() throws IOException;
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/management/FeaturesServiceMBeanImpl.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/management/FeaturesServiceMBeanImpl.java b/features/core/src/main/java/org/apache/karaf/features/internal/management/FeaturesServiceMBeanImpl.java
new file mode 100644
index 0000000..b1a5865
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/management/FeaturesServiceMBeanImpl.java
@@ -0,0 +1,290 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.karaf.features.internal.management;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.Hashtable;
+import java.util.List;
+
+import javax.management.MBeanNotificationInfo;
+import javax.management.MBeanRegistration;
+import javax.management.MBeanServer;
+import javax.management.NotCompliantMBeanException;
+import javax.management.Notification;
+import javax.management.ObjectName;
+import javax.management.openmbean.TabularData;
+
+import org.apache.karaf.features.*;
+import org.apache.karaf.features.management.FeaturesServiceMBean;
+import org.apache.karaf.features.management.codec.JmxFeature;
+import org.apache.karaf.features.management.codec.JmxFeatureEvent;
+import org.apache.karaf.features.management.codec.JmxRepository;
+import org.apache.karaf.features.management.codec.JmxRepositoryEvent;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * Implementation of {@link FeaturesServiceMBean}.
+ */
+public class FeaturesServiceMBeanImpl extends StandardEmitterMBean implements
+        MBeanRegistration, FeaturesServiceMBean {
+
+    private ServiceRegistration<FeaturesListener> registration;
+
+    private BundleContext bundleContext;
+
+    private ObjectName objectName;
+
+    private volatile long sequenceNumber = 0;
+
+    private org.apache.karaf.features.FeaturesService featuresService;
+
+    public FeaturesServiceMBeanImpl() throws NotCompliantMBeanException {
+        super(FeaturesServiceMBean.class);
+    }
+
+    public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception {
+        objectName = name;
+        return name;
+    }
+
+    public void postRegister(Boolean registrationDone) {
+        registration = bundleContext.registerService(FeaturesListener.class,
+                getFeaturesListener(), new Hashtable<String, String>());
+    }
+
+    public void preDeregister() throws Exception {
+        registration.unregister();
+    }
+
+    public void postDeregister() {
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public TabularData getFeatures() throws Exception {
+        try {
+            List<Feature> allFeatures = Arrays.asList(featuresService.listFeatures());
+            List<Feature> insFeatures = Arrays.asList(featuresService.listInstalledFeatures());
+            ArrayList<JmxFeature> features = new ArrayList<JmxFeature>();
+            for (Feature feature : allFeatures) {
+                try {
+                    features.add(new JmxFeature(feature, insFeatures.contains(feature)));
+                } catch (Throwable t) {
+                    t.printStackTrace();
+                }
+            }
+            TabularData table = JmxFeature.tableFrom(features);
+            return table;
+        } catch (Throwable t) {
+            t.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public TabularData getRepositories() throws Exception {
+        try {
+            List<Repository> allRepositories = Arrays.asList(featuresService.listRepositories());
+            ArrayList<JmxRepository> repositories = new ArrayList<JmxRepository>();
+            for (Repository repository : allRepositories) {
+                try {
+                    repositories.add(new JmxRepository(repository));
+                } catch (Throwable t) {
+                    t.printStackTrace();
+                }
+            }
+            TabularData table = JmxRepository.tableFrom(repositories);
+            return table;
+        } catch (Throwable t) {
+            t.printStackTrace();
+            return null;
+        }
+    }
+
+    public void addRepository(String uri) throws Exception {
+        featuresService.addRepository(new URI(uri));
+    }
+
+    public void addRepository(String uri, boolean install) throws Exception {
+        featuresService.addRepository(new URI(uri), install);
+    }
+
+    public void removeRepository(String uri) throws Exception {
+        featuresService.removeRepository(new URI(uri));
+    }
+
+    public void removeRepository(String uri, boolean uninstall) throws Exception {
+        featuresService.removeRepository(new URI(uri), uninstall);
+    }
+
+    public void installFeature(String name) throws Exception {
+        featuresService.installFeature(name);
+    }
+
+    public void installFeature(String name, boolean noRefresh) throws Exception {
+        EnumSet<org.apache.karaf.features.FeaturesService.Option> options = EnumSet.noneOf(org.apache.karaf.features.FeaturesService.Option.class);
+        if (noRefresh) {
+            options.add(org.apache.karaf.features.FeaturesService.Option.NoAutoRefreshBundles);
+        }
+        featuresService.installFeature(name, options);
+    }
+
+    public void installFeature(String name, boolean noRefresh, boolean noStart) throws Exception {
+        EnumSet<org.apache.karaf.features.FeaturesService.Option> options = EnumSet.noneOf(org.apache.karaf.features.FeaturesService.Option.class);
+        if (noRefresh) {
+            options.add(org.apache.karaf.features.FeaturesService.Option.NoAutoRefreshBundles);
+        }
+        if (noStart) {
+            options.add(org.apache.karaf.features.FeaturesService.Option.NoAutoStartBundles);
+        }
+        featuresService.installFeature(name, options);
+    }
+
+    public void installFeature(String name, String version) throws Exception {
+        featuresService.installFeature(name, version);
+    }
+
+    public void installFeature(String name, String version, boolean noRefresh) throws Exception {
+        EnumSet<org.apache.karaf.features.FeaturesService.Option> options = EnumSet.noneOf(org.apache.karaf.features.FeaturesService.Option.class);
+        if (noRefresh) {
+            options.add(org.apache.karaf.features.FeaturesService.Option.NoAutoRefreshBundles);
+        }
+        featuresService.installFeature(name, version, options);
+    }
+
+    public void installFeature(String name, String version, boolean noRefresh, boolean noStart) throws Exception {
+        EnumSet<org.apache.karaf.features.FeaturesService.Option> options = EnumSet.noneOf(org.apache.karaf.features.FeaturesService.Option.class);
+        if (noRefresh) {
+            options.add(org.apache.karaf.features.FeaturesService.Option.NoAutoRefreshBundles);
+        }
+        if (noStart) {
+            options.add(org.apache.karaf.features.FeaturesService.Option.NoAutoStartBundles);
+        }
+        featuresService.installFeature(name, version, options);
+    }
+
+    public TabularData infoFeature(String name) throws Exception {
+        try {
+            Feature feature = featuresService.getFeature(name);
+            return infoFeature(feature);
+        } catch (Throwable t) {
+            t.printStackTrace();
+            return null;
+        }
+    }
+
+    public TabularData infoFeature(String name, String version) throws Exception {
+        try {
+            Feature feature = featuresService.getFeature(name, version);
+            return infoFeature(feature);
+        } catch (Throwable t) {
+            t.printStackTrace();
+            return null;
+        }
+    }
+
+    private TabularData infoFeature(Feature feature) throws Exception {
+        JmxFeature jmxFeature = null;
+        if (featuresService.isInstalled(feature)) {
+            jmxFeature = new JmxFeature(feature, true);
+        } else {
+            jmxFeature = new JmxFeature(feature, false);
+        }
+        ArrayList<JmxFeature> features = new ArrayList<JmxFeature>();
+        features.add(jmxFeature);
+        TabularData table = JmxFeature.tableFrom(features);
+        return table;
+    }
+
+    public void uninstallFeature(String name) throws Exception {
+        featuresService.uninstallFeature(name);
+    }
+
+    public void uninstallFeature(String name, boolean noRefresh) throws Exception {
+        EnumSet<org.apache.karaf.features.FeaturesService.Option> options = EnumSet.noneOf(org.apache.karaf.features.FeaturesService.Option.class);
+        if (noRefresh) {
+            options.add(org.apache.karaf.features.FeaturesService.Option.NoAutoRefreshBundles);
+        }
+        featuresService.uninstallFeature(name, options);
+    }
+
+    public void uninstallFeature(String name, String version) throws Exception {
+        featuresService.uninstallFeature(name, version);
+    }
+
+    public void uninstallFeature(String name, String version, boolean noRefresh) throws Exception {
+        EnumSet<org.apache.karaf.features.FeaturesService.Option> options = EnumSet.noneOf(org.apache.karaf.features.FeaturesService.Option.class);
+        if (noRefresh) {
+            options.add(org.apache.karaf.features.FeaturesService.Option.NoAutoRefreshBundles);
+        }
+        featuresService.uninstallFeature(name, version, options);
+    }
+
+    public void setBundleContext(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+
+    public void setFeaturesService(org.apache.karaf.features.FeaturesService featuresService) {
+        this.featuresService = featuresService;
+    }
+
+    public FeaturesListener getFeaturesListener() {
+        return new FeaturesListener() {
+            public void featureEvent(FeatureEvent event) {
+                if (!event.isReplay()) {
+                    Notification notification = new Notification(FEATURE_EVENT_TYPE, objectName, sequenceNumber++);
+                    notification.setUserData(new JmxFeatureEvent(event).asCompositeData());
+                    sendNotification(notification);
+                }
+            }
+
+            public void repositoryEvent(RepositoryEvent event) {
+                if (!event.isReplay()) {
+                    Notification notification = new Notification(REPOSITORY_EVENT_TYPE, objectName, sequenceNumber++);
+                    notification.setUserData(new JmxRepositoryEvent(event).asCompositeData());
+                    sendNotification(notification);
+                }
+            }
+
+            public boolean equals(Object o) {
+                if (this == o) {
+                    return true;
+                }
+                return o.equals(this);
+            }
+
+        };
+    }
+
+    public MBeanNotificationInfo[] getNotificationInfo() {
+        return getBroadcastInfo();
+    }
+
+    private static MBeanNotificationInfo[] getBroadcastInfo() {
+        String type = Notification.class.getCanonicalName();
+        MBeanNotificationInfo info1 = new MBeanNotificationInfo(new String[]{FEATURE_EVENT_EVENT_TYPE},
+                type, "Some features notification");
+        MBeanNotificationInfo info2 = new MBeanNotificationInfo(new String[]{REPOSITORY_EVENT_EVENT_TYPE},
+                type, "Some repository notification");
+        return new MBeanNotificationInfo[]{info1, info2};
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/management/StandardEmitterMBean.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/management/StandardEmitterMBean.java b/features/core/src/main/java/org/apache/karaf/features/internal/management/StandardEmitterMBean.java
new file mode 100644
index 0000000..13a4b6c
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/management/StandardEmitterMBean.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.karaf.features.internal.management;
+
+import javax.management.*;
+
+public class StandardEmitterMBean extends StandardMBean implements NotificationEmitter {
+
+    private final NotificationBroadcasterSupport emitter;
+
+    @SuppressWarnings("rawtypes")
+	public StandardEmitterMBean(Class mbeanInterface) throws NotCompliantMBeanException {
+        super(mbeanInterface);
+        this.emitter = new NotificationBroadcasterSupport() {
+            @Override
+            public MBeanNotificationInfo[] getNotificationInfo() {
+                return StandardEmitterMBean.this.getNotificationInfo();
+            }
+        };
+    }
+
+    public void sendNotification(Notification notification) {
+        emitter.sendNotification(notification);
+    }
+
+
+    public void removeNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws ListenerNotFoundException {
+        emitter.removeNotificationListener(listener, filter, handback);
+    }
+
+    public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws IllegalArgumentException {
+        emitter.addNotificationListener(listener, filter, handback);
+    }
+
+    public void removeNotificationListener(NotificationListener listener) throws ListenerNotFoundException {
+        emitter.removeNotificationListener(listener);
+    }
+
+    public MBeanNotificationInfo[] getNotificationInfo() {
+        return new MBeanNotificationInfo[0];
+    }
+
+    @Override
+    public MBeanInfo getMBeanInfo() {
+        MBeanInfo mbeanInfo = super.getMBeanInfo();
+        if (mbeanInfo != null) {
+            MBeanNotificationInfo[] notificationInfo = getNotificationInfo();
+            mbeanInfo = new MBeanInfo(mbeanInfo.getClassName(), mbeanInfo.getDescription(), mbeanInfo.getAttributes(),
+                    mbeanInfo.getConstructors(), mbeanInfo.getOperations(), notificationInfo);
+        }
+        return mbeanInfo;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/model/Bundle.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/model/Bundle.java b/features/core/src/main/java/org/apache/karaf/features/internal/model/Bundle.java
new file mode 100644
index 0000000..7eebbe5
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/model/Bundle.java
@@ -0,0 +1,198 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+package org.apache.karaf.features.internal.model;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+import org.apache.karaf.features.BundleInfo;
+
+
+/**
+ * 
+ * Deployable element to install.
+ *             
+ * 
+ * <p>Java class for bundle complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="bundle">
+ *   &lt;simpleContent>
+ *     &lt;extension base="&lt;http://www.w3.org/2001/XMLSchema>anyURI">
+ *       &lt;attribute name="start-level" type="{http://www.w3.org/2001/XMLSchema}int" />
+ *       &lt;attribute name="start" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ *       &lt;attribute name="dependency" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ *     &lt;/extension>
+ *   &lt;/simpleContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "bundle", propOrder = {
+    "value"
+})
+public class Bundle implements BundleInfo {
+
+    @XmlValue
+    @XmlSchemaType(name = "anyURI")
+    protected String value;
+    @XmlAttribute(name = "start-level")
+    protected Integer startLevel;
+    @XmlAttribute
+    protected Boolean start;// = true;
+    @XmlAttribute
+    protected Boolean dependency;
+
+
+    public Bundle() {
+    }
+
+    public Bundle(String value) {
+        this.value = value;
+    }
+
+    /**
+     * Gets the value of the value property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getLocation() {
+        return value;
+    }
+
+    /**
+     * Sets the value of the value property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setLocation(String value) {
+        this.value = value;
+    }
+
+    /**
+     * Gets the value of the startLevel property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Integer }
+     *     
+     */
+    public int getStartLevel() {
+        return startLevel == null? 0: startLevel;
+    }
+
+    /**
+     * Sets the value of the startLevel property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Integer }
+     *     
+     */
+    public void setStartLevel(Integer value) {
+        this.startLevel = value;
+    }
+
+    /**
+     * Gets the value of the start property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Boolean }
+     *     
+     */
+    public boolean isStart() {
+        return start == null? true: start;
+    }
+
+    /**
+     * Sets the value of the start property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Boolean }
+     *     
+     */
+    public void setStart(Boolean value) {
+        this.start = value;
+    }
+
+    /**
+     * Gets the value of the dependency property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Boolean }
+     *     
+     */
+    public boolean isDependency() {
+        return dependency == null? false: dependency;
+    }
+
+    /**
+     * Sets the value of the dependency property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Boolean }
+     *     
+     */
+    public void setDependency(Boolean value) {
+        this.dependency = value;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Bundle bundle = (Bundle) o;
+
+        if (dependency != bundle.dependency) return false;
+        if (start != bundle.start) return false;
+        if (startLevel != bundle.startLevel) return false;
+        if (value != null ? !value.equals(bundle.value) : bundle.value != null) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = value != null ? value.hashCode() : 0;
+        result = 31 * result + getStartLevel();
+        result = 31 * result + (isStart() ? 1 : 0);
+        result = 31 * result + (isDependency() ? 1 : 0);
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/model/Capability.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/model/Capability.java b/features/core/src/main/java/org/apache/karaf/features/internal/model/Capability.java
new file mode 100644
index 0000000..b866151
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/model/Capability.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+package org.apache.karaf.features.internal.model;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+
+import org.apache.karaf.features.BundleInfo;
+
+
+/**
+ * 
+ * Additional capability for a feature.
+ *             
+ * 
+ * <p>Java class for bundle complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="capability">
+ *   &lt;simpleContent>
+ *     &lt;extension base="&lt;http://www.w3.org/2001/XMLSchema>string">
+ *     &lt;/extension>
+ *   &lt;/simpleContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "capability", propOrder = {
+    "value"
+})
+public class Capability implements org.apache.karaf.features.Capability {
+
+    @XmlValue
+    protected String value;
+
+
+    public Capability() {
+    }
+
+    public Capability(String value) {
+        this.value = value;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Capability bundle = (Capability) o;
+
+        if (value != null ? !value.equals(bundle.value) : bundle.value != null) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = value != null ? value.hashCode() : 0;
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/model/Conditional.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/model/Conditional.java b/features/core/src/main/java/org/apache/karaf/features/internal/model/Conditional.java
new file mode 100644
index 0000000..ed0e8ff
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/model/Conditional.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.model;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.karaf.features.Feature;
+
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "conditional", propOrder = {
+        "condition",
+        "config",
+        "configfile",
+        "feature",
+        "bundle"
+})
+public class Conditional extends Content implements org.apache.karaf.features.Conditional {
+
+    @XmlElement(name = "condition")
+    protected List<String> condition;
+
+    public List<String> getCondition() {
+        if (condition == null) {
+            this.condition = new ArrayList<String>();
+        }
+        return condition;
+    }
+
+    @Override
+    public Feature asFeature(String name, String version) {
+        String conditionName = name + "-condition-" + getConditionId().replaceAll("[^A-Za-z0-9 ]", "_");
+        org.apache.karaf.features.internal.model.Feature f = new org.apache.karaf.features.internal.model.Feature(conditionName, version);
+        f.getBundle().addAll(getBundle());
+        f.getConfig().addAll(getConfig());
+        f.getConfigfile().addAll(getConfigfile());
+        f.getFeature().addAll(getFeature());
+        return f;
+    }
+
+    private String getConditionId() {
+        StringBuffer sb = new StringBuffer();
+        for (String cond : getCondition()) {
+            if (sb.length() > 0) {
+                sb.append("_");
+            }
+            sb.append(cond);
+        }
+        return sb.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/src/main/java/org/apache/karaf/features/internal/model/Config.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/model/Config.java b/features/core/src/main/java/org/apache/karaf/features/internal/model/Config.java
new file mode 100644
index 0000000..a2c6674
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/model/Config.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.karaf.features.internal.model;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+
+
+/**
+ * 
+ * Configuration entries which should be created during feature installation. This
+ * configuration may be used with OSGi Configuration Admin.
+ *             
+ * 
+ * <p>Java class for config complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="config">
+ *   &lt;simpleContent>
+ *     &lt;extension base="&lt;http://www.w3.org/2001/XMLSchema>string">
+ *       &lt;attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
+ *     &lt;/extension>
+ *   &lt;/simpleContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "config", propOrder = {
+    "value"
+})
+public class Config {
+
+    @XmlValue
+    protected String value;
+    @XmlAttribute(required = true)
+    protected String name;
+
+    /**
+     * Gets the value of the value property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getValue() {
+        return value;
+    }
+
+    /**
+     * Sets the value of the value property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    /**
+     * Gets the value of the name property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Sets the value of the name property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setName(String value) {
+        this.name = value;
+    }
+
+}


[04/33] git commit: [KARAF-2888] Better computation of bundles to refresh and print them in simulation

Posted by gn...@apache.org.
[KARAF-2888] Better computation of bundles to refresh and print them in simulation


Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/53996d9c
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/53996d9c
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/53996d9c

Branch: refs/heads/master
Commit: 53996d9c13aa766b590cfa34a77b738df2c50afa
Parents: 6a19214
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Thu Apr 10 23:39:15 2014 +0200
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Fri Apr 11 19:20:02 2014 +0200

----------------------------------------------------------------------
 .../internal/service/FeaturesServiceImpl.java   | 172 ++++++++-----------
 1 file changed, 71 insertions(+), 101 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/53996d9c/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java b/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
index e6dbc32..0bd1e67 100644
--- a/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
+++ b/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
@@ -69,6 +69,8 @@ import org.osgi.framework.startlevel.BundleStartLevel;
 import org.osgi.framework.wiring.BundleCapability;
 import org.osgi.framework.wiring.BundleRequirement;
 import org.osgi.framework.wiring.BundleRevision;
+import org.osgi.framework.wiring.BundleWire;
+import org.osgi.framework.wiring.BundleWiring;
 import org.osgi.framework.wiring.FrameworkWiring;
 import org.osgi.resource.Resource;
 import org.osgi.resource.Wire;
@@ -793,7 +795,7 @@ public class FeaturesServiceImpl implements FeaturesService {
                          Collections.<String>emptySet(),
                          overrides,
                          Collections.<String>emptySet());
-        Map<Resource, List<Wire>> resolution = builder.resolve(systemBundles, false);
+        Map<Resource, List<Wire>> resolution = builder.resolve(systemBundles, true);
         Collection<Resource> allResources = resolution.keySet();
         Map<String, StreamProvider> providers = builder.getProviders();
 
@@ -858,14 +860,76 @@ public class FeaturesServiceImpl implements FeaturesService {
         //
         logDeployment(deployment, verbose);
 
+        //
+        // Compute the set of bundles to refresh
+        //
+        Set<Bundle> toRefresh = new HashSet<Bundle>();
+        toRefresh.addAll(deployment.toDelete);
+        toRefresh.addAll(deployment.toUpdate.keySet());
+
+        if (!noRefreshManaged) {
+            int size;
+            do {
+                size = toRefresh.size();
+                for (Bundle bundle : bundles) {
+                    // Continue if we already know about this bundle
+                    if (toRefresh.contains(bundle)) {
+                        continue;
+                    }
+                    // Ignore non resolved bundle
+                    BundleWiring wiring = bundle.adapt(BundleWiring.class);
+                    if (wiring == null) {
+                        continue;
+                    }
+                    // Get through the old resolution and flag this bundle
+                    // if it was wired to a bundle to be refreshed
+                    for (BundleWire wire : wiring.getRequiredWires(null)) {
+                        if (toRefresh.contains(wire.getProvider().getBundle())) {
+                            toRefresh.add(bundle);
+                            break;
+                        }
+                    }
+                    // Get through the new resolution and flag this bundle
+                    // if it's wired to any new bundle
+                    List<Wire> newWires = resolution.get(wiring.getRevision());
+                    if (newWires != null) {
+                        for (Wire wire : newWires) {
+                            Bundle b = null;
+                            if (wire.getProvider() instanceof BundleRevision) {
+                                b = ((BundleRevision) wire.getProvider()).getBundle();
+                            } else {
+                                b = deployment.resToBnd.get(wire.getProvider());
+                            }
+                            if (b == null || toRefresh.contains(b)) {
+                                toRefresh.add(bundle);
+                                break;
+                            }
+                        }
+                    }
+                }
+            } while (toRefresh.size() > size);
+        }
+        if (noRefreshUnmanaged) {
+            Set<Bundle> newSet = new HashSet<Bundle>();
+            for (Bundle bundle : toRefresh) {
+                if (managed.contains(bundle.getBundleId())) {
+                    newSet.add(bundle);
+                }
+            }
+            toRefresh = newSet;
+        }
+
+
         if (simulate) {
-            // TODO: it would be nice to print bundles that will be refreshed
-            // TODO: it could be done by checking the differences between
-            // TODO: the resolution result and the actual wiring state
+            if (!toRefresh.isEmpty()) {
+                print("  Bundles to refresh:", verbose);
+                for (Bundle bundle : toRefresh) {
+                    print("    " + bundle.getSymbolicName() + " / " + bundle.getVersion(), verbose);
+                }
+            }
             return;
         }
 
-        Set<Bundle> toRefresh = new HashSet<Bundle>();
         Set<Bundle> toStart = new HashSet<Bundle>();
 
         //
@@ -908,7 +972,6 @@ public class FeaturesServiceImpl implements FeaturesService {
                 print("  " + bundle.getSymbolicName() + " / " + bundle.getVersion(), verbose);
                 bundle.uninstall();
                 managed.remove(bundle.getBundleId());
-                toRefresh.add(bundle);
             }
         }
         if (!deployment.toUpdate.isEmpty()) {
@@ -920,7 +983,6 @@ public class FeaturesServiceImpl implements FeaturesService {
                 print("  " + uri, verbose);
                 InputStream is = getBundleInputStream(resource, providers);
                 bundle.update(is);
-                toRefresh.add(bundle);
                 toStart.add(bundle);
                 BundleInfo bi = bundleInfos.get(uri);
                 if (bi != null && bi.getStartLevel() > 0) {
@@ -940,7 +1002,6 @@ public class FeaturesServiceImpl implements FeaturesService {
                 if (!noStart || resourceLinkedToOldFeatures.contains(resource)) {
                     toStart.add(bundle);
                 }
-                toRefresh.add(bundle);
                 deployment.resToBnd.put(resource, bundle);
                 // save a checksum of installed snapshot bundle
                 if (UPDATE_SNAPSHOTS_CRC.equals(updateSnaphots)
@@ -982,23 +1043,9 @@ public class FeaturesServiceImpl implements FeaturesService {
             }
         }
 
-        if (!noRefreshManaged) {
-            findBundlesWithOptionalPackagesToRefresh(toRefresh);
-            findBundlesWithFragmentsToRefresh(toRefresh);
-        }
-
-        if (noRefreshUnmanaged) {
-            Set<Bundle> newSet = new HashSet<Bundle>();
-            for (Bundle bundle : toRefresh) {
-                if (managed.contains(bundle.getBundleId())) {
-                    newSet.add(bundle);
-                }
-            }
-            toRefresh = newSet;
-        }
-
         // TODO: remove this hack, but it avoids loading the class after the bundle is refreshed
-        RequirementSort sort = new RequirementSort();
+        new CopyOnWriteArrayIdentityList().iterator();
+        new RequirementSort();
 
         if (!noRefresh) {
             toStop = new HashSet<Bundle>();
@@ -1347,83 +1394,6 @@ public class FeaturesServiceImpl implements FeaturesService {
         return provider.open();
     }
 
-    protected void findBundlesWithOptionalPackagesToRefresh(Set<Bundle> toRefresh) {
-        // First pass: include all bundles contained in these features
-        if (toRefresh.isEmpty()) {
-            return;
-        }
-        Set<Bundle> bundles = new HashSet<Bundle>(Arrays.asList(systemBundleContext.getBundles()));
-        bundles.removeAll(toRefresh);
-        if (bundles.isEmpty()) {
-            return;
-        }
-        // Second pass: for each bundle, check if there is any unresolved optional package that could be resolved
-        for (Bundle bundle : bundles) {
-            BundleRevision rev = bundle.adapt(BundleRevision.class);
-            boolean matches = false;
-            if (rev != null) {
-                for (BundleRequirement req : rev.getDeclaredRequirements(null)) {
-                    if (PackageNamespace.PACKAGE_NAMESPACE.equals(req.getNamespace())
-                            && PackageNamespace.RESOLUTION_OPTIONAL.equals(req.getDirectives().get(PackageNamespace.REQUIREMENT_RESOLUTION_DIRECTIVE))) {
-                        // This requirement is an optional import package
-                        for (Bundle provider : toRefresh) {
-                            BundleRevision providerRev = provider.adapt(BundleRevision.class);
-                            if (providerRev != null) {
-                                for (BundleCapability cap : providerRev.getDeclaredCapabilities(null)) {
-                                    if (req.matches(cap)) {
-                                        matches = true;
-                                        break;
-                                    }
-                                }
-                            }
-                            if (matches) {
-                                break;
-                            }
-                        }
-                    }
-                    if (matches) {
-                        break;
-                    }
-                }
-            }
-            if (matches) {
-                toRefresh.add(bundle);
-            }
-        }
-    }
-
-    protected void findBundlesWithFragmentsToRefresh(Set<Bundle> toRefresh) {
-        if (toRefresh.isEmpty()) {
-            return;
-        }
-        Set<Bundle> bundles = new HashSet<Bundle>(Arrays.asList(systemBundleContext.getBundles()));
-        bundles.removeAll(toRefresh);
-        if (bundles.isEmpty()) {
-            return;
-        }
-        for (Bundle bundle : new ArrayList<Bundle>(toRefresh)) {
-            BundleRevision rev = bundle.adapt(BundleRevision.class);
-            if (rev != null) {
-                for (BundleRequirement req : rev.getDeclaredRequirements(null)) {
-                    if (BundleRevision.HOST_NAMESPACE.equals(req.getNamespace())) {
-                        for (Bundle hostBundle : bundles) {
-                            if (!toRefresh.contains(hostBundle)) {
-                                BundleRevision hostRev = hostBundle.adapt(BundleRevision.class);
-                                if (hostRev != null) {
-                                    for (BundleCapability cap : hostRev.getDeclaredCapabilities(null)) {
-                                        if (req.matches(cap)) {
-                                            toRefresh.add(hostBundle);
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
     protected void refreshPackages(Collection<Bundle> bundles) throws InterruptedException {
         final CountDownLatch latch = new CountDownLatch(1);
         FrameworkWiring fw = systemBundleContext.getBundle().adapt(FrameworkWiring.class);


[10/33] git commit: [KARAF-2852] Remove unused files

Posted by gn...@apache.org.
[KARAF-2852] Remove unused files


Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/fc37f55e
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/fc37f55e
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/fc37f55e

Branch: refs/heads/master
Commit: fc37f55e2b3946490296eeef54a383fed21b0381
Parents: 78fbae7
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Fri Apr 11 15:50:24 2014 +0200
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Fri Apr 11 19:20:03 2014 +0200

----------------------------------------------------------------------
 service/command/NOTICE                          | 71 --------------
 service/command/pom.xml                         | 98 --------------------
 .../src/main/resources/OSGI-INF/bundle.info     | 20 ----
 3 files changed, 189 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/fc37f55e/service/command/NOTICE
----------------------------------------------------------------------
diff --git a/service/command/NOTICE b/service/command/NOTICE
deleted file mode 100644
index b70f1f9..0000000
--- a/service/command/NOTICE
+++ /dev/null
@@ -1,71 +0,0 @@
-Apache Karaf
-Copyright 2010-2014 The Apache Software Foundation
-
-
-I. Included Software
-
-This product includes software developed at
-The Apache Software Foundation (http://www.apache.org/).
-Licensed under the Apache License 2.0.
-
-This product uses software developed at
-The OSGi Alliance (http://www.osgi.org/).
-Copyright (c) OSGi Alliance (2000, 2010).
-Licensed under the Apache License 2.0.
-
-This product includes software developed at
-OW2 (http://www.ow2.org/).
-Licensed under the BSD License.
-
-This product includes software developed at
-OPS4J (http://www.ops4j.org/).
-Licensed under the Apache License 2.0.
-
-This product includes software developed at
-Eclipse Foundation (http://www.eclipse.org/).
-Licensed under the EPL.
-
-This product includes software written by
-Antony Lesuisse.
-Licensed under Public Domain.
-
-
-II. Used Software
-
-This product uses software developed at
-FUSE Source (http://www.fusesource.org/).
-Licensed under the Apache License 2.0.
-
-This product uses software developed at
-AOP Alliance (http://aopalliance.sourceforge.net/).
-Licensed under the Public Domain.
-
-This product uses software developed at
-Tanuki Software (http://www.tanukisoftware.com/).
-Licensed under the Apache License 2.0.
-
-This product uses software developed at
-Jasypt (http://jasypt.sourceforge.net/).
-Licensed under the Apache License 2.0.
-
-This product uses software developed at
-JLine (http://jline.sourceforge.net).
-Licensed under the BSD License.
-
-This product uses software developed at
-SLF4J (http://www.slf4j.org/).
-Licensed under the MIT License.
-
-This product uses software developed at
-SpringSource (http://www.springsource.org/).
-Licensed under the Apache License 2.0.
-
-This product includes software from http://www.json.org.
-Copyright (c) 2002 JSON.org
-
-
-III. License Summary
-- Apache License 2.0
-- BSD License
-- EPL License
-- MIT License

http://git-wip-us.apache.org/repos/asf/karaf/blob/fc37f55e/service/command/pom.xml
----------------------------------------------------------------------
diff --git a/service/command/pom.xml b/service/command/pom.xml
deleted file mode 100644
index c33e13d..0000000
--- a/service/command/pom.xml
+++ /dev/null
@@ -1,98 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-
-    <!--
-
-        Licensed to the Apache Software Foundation (ASF) under one or more
-        contributor license agreements.  See the NOTICE file distributed with
-        this work for additional information regarding copyright ownership.
-        The ASF licenses this file to You under the Apache License, Version 2.0
-        (the "License"); you may not use this file except in compliance with
-        the License.  You may obtain a copy of the License at
-
-           http://www.apache.org/licenses/LICENSE-2.0
-
-        Unless required by applicable law or agreed to in writing, software
-        distributed under the License is distributed on an "AS IS" BASIS,
-        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-        See the License for the specific language governing permissions and
-        limitations under the License.
-    -->
-
-    <modelVersion>4.0.0</modelVersion>
-
-    <parent>
-        <groupId>org.apache.karaf.service</groupId>
-        <artifactId>service</artifactId>
-        <version>4.0.0-SNAPSHOT</version>
-        <relativePath>../pom.xml</relativePath>
-    </parent>
-
-    <artifactId>org.apache.karaf.service.command</artifactId>
-    <packaging>bundle</packaging>
-    <name>Apache Karaf :: Service :: Command</name>
-    <description>Provides shell commands to manipulate OSGi services</description>
-
-    <properties>
-        <appendedResourcesDirectory>${basedir}/../../etc/appended-resources</appendedResourcesDirectory>
-    </properties>
-
-    <dependencies>
-
-        <dependency>
-            <groupId>org.apache.karaf.shell</groupId>
-            <artifactId>org.apache.karaf.shell.core</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.karaf.bundle</groupId>
-            <artifactId>org.apache.karaf.bundle.command</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.core</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.compendium</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-jdk14</artifactId>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-
-    <build>
-        <resources>
-            <resource>
-                <directory>src/main/resources</directory>
-                <includes>
-                    <include>**/*</include>
-                </includes>
-            </resource>
-            <resource>
-                <directory>src/main/resources</directory>
-                <filtering>true</filtering>
-                <includes>
-                    <include>**/*.info</include>
-                </includes>
-            </resource>
-        </resources>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-bundle-plugin</artifactId>
-                <configuration>
-                    <instructions>
-                        <Karaf-Commands>org.apache.karaf.service.command</Karaf-Commands>
-                    </instructions>
-                </configuration>
-            </plugin>
-        </plugins>
-    </build>
-
-</project>

http://git-wip-us.apache.org/repos/asf/karaf/blob/fc37f55e/service/command/src/main/resources/OSGI-INF/bundle.info
----------------------------------------------------------------------
diff --git a/service/command/src/main/resources/OSGI-INF/bundle.info b/service/command/src/main/resources/OSGI-INF/bundle.info
deleted file mode 100644
index eff1072..0000000
--- a/service/command/src/main/resources/OSGI-INF/bundle.info
+++ /dev/null
@@ -1,20 +0,0 @@
-h1. Synopsis
-
-${project.name}
-
-${project.description}
-
-Maven URL:
-   [mvn:${project.groupId}/${project.artifactId}/${project.version}]
-
-h1. Description
-
-This bundle provides the shell commands to manipulate OSGi services.
-
-The following commands are available:
-* services:list - Gets the list of OSGi services available
-* service:wait - Wait for a given OSGi service
-
-h1. See also
-
-Commands and Using the console sections of the Karaf User Guide