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>
+ * <complexType name="bundle">
+ * <simpleContent>
+ * <extension base="<http://www.w3.org/2001/XMLSchema>anyURI">
+ * <attribute name="start-level" type="{http://www.w3.org/2001/XMLSchema}int" />
+ * <attribute name="start" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="dependency" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * </extension>
+ * </simpleContent>
+ * </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>
+ * <complexType name="capability">
+ * <simpleContent>
+ * <extension base="<http://www.w3.org/2001/XMLSchema>string">
+ * </extension>
+ * </simpleContent>
+ * </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>
+ * <complexType name="config">
+ * <simpleContent>
+ * <extension base="<http://www.w3.org/2001/XMLSchema>string">
+ * <attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * </extension>
+ * </simpleContent>
+ * </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;
+ }
+
+}