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:53 UTC

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

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;
+    }
+
+}