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:47 UTC
[25/33] Revert "[KARAF-2852] Merge features/core and features/command"
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);
+ }
+
+}