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/10 16:15:29 UTC
[07/59] [abbrv] [KARAF-2852] Merge features/core and features/command
http://git-wip-us.apache.org/repos/asf/karaf/blob/999f4970/features/src/main/java/org/apache/karaf/features/internal/management/FeaturesServiceMBeanImpl.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/management/FeaturesServiceMBeanImpl.java b/features/src/main/java/org/apache/karaf/features/internal/management/FeaturesServiceMBeanImpl.java
new file mode 100644
index 0000000..b1a5865
--- /dev/null
+++ b/features/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/999f4970/features/src/main/java/org/apache/karaf/features/internal/management/StandardEmitterMBean.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/management/StandardEmitterMBean.java b/features/src/main/java/org/apache/karaf/features/internal/management/StandardEmitterMBean.java
new file mode 100644
index 0000000..13a4b6c
--- /dev/null
+++ b/features/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/999f4970/features/src/main/java/org/apache/karaf/features/internal/model/Bundle.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/model/Bundle.java b/features/src/main/java/org/apache/karaf/features/internal/model/Bundle.java
new file mode 100644
index 0000000..7eebbe5
--- /dev/null
+++ b/features/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/999f4970/features/src/main/java/org/apache/karaf/features/internal/model/Capability.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/model/Capability.java b/features/src/main/java/org/apache/karaf/features/internal/model/Capability.java
new file mode 100644
index 0000000..ef60454
--- /dev/null
+++ b/features/src/main/java/org/apache/karaf/features/internal/model/Capability.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+package org.apache.karaf.features.internal.model;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+
+import org.apache.karaf.features.BundleInfo;
+
+
+/**
+ *
+ * Additional capability for a feature.
+ *
+ *
+ * <p>Java class for bundle complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * <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/999f4970/features/src/main/java/org/apache/karaf/features/internal/model/Conditional.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/model/Conditional.java b/features/src/main/java/org/apache/karaf/features/internal/model/Conditional.java
new file mode 100644
index 0000000..5bc0b95
--- /dev/null
+++ b/features/src/main/java/org/apache/karaf/features/internal/model/Conditional.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.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<Dependency> condition;
+
+ public List<Dependency> getCondition() {
+ if (condition == null) {
+ this.condition = new ArrayList<Dependency>();
+ }
+ 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();
+ Iterator<Dependency> di = getCondition().iterator();
+ while (di.hasNext()) {
+ Dependency dependency = di.next();
+ sb.append(dependency.getName() + "_" + dependency.getVersion());
+ if (di.hasNext()) {
+ sb.append("_");
+ }
+ }
+ return sb.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/999f4970/features/src/main/java/org/apache/karaf/features/internal/model/Config.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/model/Config.java b/features/src/main/java/org/apache/karaf/features/internal/model/Config.java
new file mode 100644
index 0000000..a2c6674
--- /dev/null
+++ b/features/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;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/999f4970/features/src/main/java/org/apache/karaf/features/internal/model/ConfigFile.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/model/ConfigFile.java b/features/src/main/java/org/apache/karaf/features/internal/model/ConfigFile.java
new file mode 100644
index 0000000..e5d9d94
--- /dev/null
+++ b/features/src/main/java/org/apache/karaf/features/internal/model/ConfigFile.java
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.karaf.features.internal.model;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+import org.apache.karaf.features.ConfigFileInfo;
+
+
+/**
+ *
+ * Additional configuration files which should be created during feature installation.
+ *
+ *
+ * <p>Java class for configFile complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * <complexType name="configFile">
+ * <simpleContent>
+ * <extension base="<http://www.w3.org/2001/XMLSchema>string">
+ * <attribute name="finalname" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="override" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * </extension>
+ * </simpleContent>
+ * </complexType>
+ * </pre>
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "configFile", propOrder = {
+ "value"
+})
+public class ConfigFile implements ConfigFileInfo {
+
+ @XmlValue
+ protected String value;
+ @XmlAttribute(required = true)
+ protected String finalname;
+ @XmlAttribute
+ protected Boolean override;
+
+ /**
+ * Gets the value of the value property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getLocation() {
+ return value;
+ }
+
+ /**
+ * Sets the value of the value property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setLocation(String value) {
+ this.value = value;
+ }
+
+ /**
+ * Gets the value of the finalname property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getFinalname() {
+ return finalname;
+ }
+
+ /**
+ * Sets the value of the finalname property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setFinalname(String value) {
+ this.finalname = value;
+ }
+
+ /**
+ * Gets the value of the override property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public boolean isOverride() {
+ return override == null? false: override;
+ }
+
+ /**
+ * Sets the value of the override property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setOverride(Boolean value) {
+ this.override = value;
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/999f4970/features/src/main/java/org/apache/karaf/features/internal/model/Content.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/model/Content.java b/features/src/main/java/org/apache/karaf/features/internal/model/Content.java
new file mode 100644
index 0000000..756e4c1
--- /dev/null
+++ b/features/src/main/java/org/apache/karaf/features/internal/model/Content.java
@@ -0,0 +1,199 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.model;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.xml.bind.annotation.XmlTransient;
+import org.apache.karaf.features.BundleInfo;
+import org.apache.karaf.features.ConfigFileInfo;
+
+@XmlTransient
+public class Content {
+
+ protected List<Config> config;
+ protected List<ConfigFile> configfile;
+ protected List<Dependency> feature;
+ protected List<Bundle> bundle;
+
+ /**
+ * Gets the value of the config property.
+ * <p/>
+ * <p/>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the config property.
+ * <p/>
+ * <p/>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getConfig().add(newItem);
+ * </pre>
+ * <p/>
+ * <p/>
+ * <p/>
+ * Objects of the following type(s) are allowed in the list
+ * {@link Config }
+ */
+ public List<Config> getConfig() {
+ if (config == null) {
+ config = new ArrayList<Config>();
+ }
+ return this.config;
+ }
+
+ /**
+ * Gets the value of the configfile property.
+ * <p/>
+ * <p/>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the configfile property.
+ * <p/>
+ * <p/>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getConfigfile().add(newItem);
+ * </pre>
+ * <p/>
+ * <p/>
+ * <p/>
+ * Objects of the following type(s) are allowed in the list
+ * {@link ConfigFile }
+ */
+ public List<ConfigFile> getConfigfile() {
+ if (configfile == null) {
+ configfile = new ArrayList<ConfigFile>();
+ }
+ return this.configfile;
+ }
+
+ /**
+ * Gets the value of the feature property.
+ * <p/>
+ * <p/>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the feature property.
+ * <p/>
+ * <p/>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getFeature().add(newItem);
+ * </pre>
+ * <p/>
+ * <p/>
+ * <p/>
+ * Objects of the following type(s) are allowed in the list
+ * {@link Dependency }
+ */
+ public List<Dependency> getFeature() {
+ if (feature == null) {
+ feature = new ArrayList<Dependency>();
+ }
+ return this.feature;
+ }
+
+ /**
+ * Gets the value of the bundle property.
+ * <p/>
+ * <p/>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the bundle property.
+ * <p/>
+ * <p/>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getBundle().add(newItem);
+ * </pre>
+ * <p/>
+ * <p/>
+ * <p/>
+ * Objects of the following type(s) are allowed in the list
+ * {@link Bundle }
+ */
+ public List<Bundle> getBundle() {
+ if (bundle == null) {
+ bundle = new ArrayList<Bundle>();
+ }
+ return this.bundle;
+ }
+
+ public List<org.apache.karaf.features.Dependency> getDependencies() {
+ return Collections.<org.apache.karaf.features.Dependency>unmodifiableList(getFeature());
+ }
+
+ public List<BundleInfo> getBundles() {
+ return Collections.<BundleInfo>unmodifiableList(getBundle());
+ }
+
+ public Map<String, Map<String, String>> getConfigurations() {
+ Map<String, Map<String, String>> result = new HashMap<String, Map<String, String>>();
+ for (Config config : getConfig()) {
+ String name = config.getName();
+ StringReader propStream = new StringReader(config.getValue());
+ Properties props = new Properties();
+ try {
+ props.load(propStream);
+ } catch (IOException e) {
+ //ignore??
+ }
+ interpolation(props);
+ Map<String, String> propMap = new HashMap<String, String>();
+ for (Map.Entry<Object, Object> entry : props.entrySet()) {
+ propMap.put((String) entry.getKey(), (String) entry.getValue());
+ }
+ result.put(name, propMap);
+ }
+ return result;
+ }
+
+ public List<ConfigFileInfo> getConfigurationFiles() {
+ return Collections.<ConfigFileInfo>unmodifiableList(getConfigfile());
+ }
+
+ @SuppressWarnings("rawtypes")
+ protected void interpolation(Properties properties) {
+ for (Enumeration e = properties.propertyNames(); e.hasMoreElements(); ) {
+ String key = (String) e.nextElement();
+ String val = properties.getProperty(key);
+ Matcher matcher = Pattern.compile("\\$\\{([^}]+)\\}").matcher(val);
+ while (matcher.find()) {
+ String rep = System.getProperty(matcher.group(1));
+ if (rep != null) {
+ val = val.replace(matcher.group(0), rep);
+ matcher.reset(val);
+ }
+ }
+ properties.put(key, val);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/999f4970/features/src/main/java/org/apache/karaf/features/internal/model/Dependency.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/model/Dependency.java b/features/src/main/java/org/apache/karaf/features/internal/model/Dependency.java
new file mode 100644
index 0000000..9c92a93
--- /dev/null
+++ b/features/src/main/java/org/apache/karaf/features/internal/model/Dependency.java
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+package org.apache.karaf.features.internal.model;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+
+
+/**
+ *
+ * Dependency of feature.
+ *
+ *
+ * <p>Java class for dependency complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * <complexType name="dependency">
+ * <simpleContent>
+ * <extension base="<http://karaf.apache.org/xmlns/features/v1.0.0>featureName">
+ * <attribute name="version" type="{http://www.w3.org/2001/XMLSchema}string" default="0.0.0" />
+ * </extension>
+ * </simpleContent>
+ * </complexType>
+ * </pre>
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "dependency", propOrder = {
+ "value"
+})
+public class Dependency implements org.apache.karaf.features.Dependency {
+
+ @XmlValue
+ protected String value;
+ @XmlAttribute
+ protected String version;
+
+ /**
+ *
+ * Feature name should be non empty string.
+ *
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getName() {
+ return value;
+ }
+
+ /**
+ * Sets the value of the value property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setName(String value) {
+ this.value = value;
+ }
+
+ /**
+ * Gets the value of the version property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getVersion() {
+ if (version == null) {
+ return "0.0.0";
+ } else {
+ return version;
+ }
+ }
+
+ /**
+ * Sets the value of the version property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setVersion(String value) {
+ this.version = value;
+ }
+
+ public String toString() {
+ String ret = getName() + Feature.SPLIT_FOR_NAME_AND_VERSION + getVersion();
+ return ret;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/999f4970/features/src/main/java/org/apache/karaf/features/internal/model/Feature.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/model/Feature.java b/features/src/main/java/org/apache/karaf/features/internal/model/Feature.java
new file mode 100644
index 0000000..46580da
--- /dev/null
+++ b/features/src/main/java/org/apache/karaf/features/internal/model/Feature.java
@@ -0,0 +1,374 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.karaf.features.internal.model;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ *
+ * Definition of the Feature.
+ *
+ *
+ * <p>Java class for feature complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * <complexType name="feature">
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="details" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ * <element name="config" type="{http://karaf.apache.org/xmlns/features/v1.0.0}config" maxOccurs="unbounded" minOccurs="0"/>
+ * <element name="configfile" type="{http://karaf.apache.org/xmlns/features/v1.0.0}configFile" maxOccurs="unbounded" minOccurs="0"/>
+ * <element name="feature" type="{http://karaf.apache.org/xmlns/features/v1.0.0}dependency" maxOccurs="unbounded" minOccurs="0"/>
+ * <element name="bundle" type="{http://karaf.apache.org/xmlns/features/v1.0.0}bundle" maxOccurs="unbounded" minOccurs="0"/>
+ * <element name="conditional" type="{http://karaf.apache.org/xmlns/features/v1.0.0}conditional" maxOccurs="unbounded" minOccurs="0"/>
+ * <element name="capability" type="{http://karaf.apache.org/xmlns/features/v1.0.0}capability" maxOccurs="unbounded" minOccurs="0"/>
+ * <element name="requirement" type="{http://karaf.apache.org/xmlns/features/v1.0.0}requirement" maxOccurs="unbounded" minOccurs="0"/>
+ * </sequence>
+ * <attribute name="name" use="required" type="{http://karaf.apache.org/xmlns/features/v1.0.0}featureName" />
+ * <attribute name="version" type="{http://www.w3.org/2001/XMLSchema}string" default="0.0.0" />
+ * <attribute name="description" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="resolver" type="{http://karaf.apache.org/xmlns/features/v1.0.0}resolver" />
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </pre>
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "feature", propOrder = {
+ "details",
+ "config",
+ "configfile",
+ "feature",
+ "bundle",
+ "conditional",
+ "capability",
+ "requirement"
+})
+public class Feature extends Content implements org.apache.karaf.features.Feature {
+ public static String SPLIT_FOR_NAME_AND_VERSION = "/";
+ public static String DEFAULT_VERSION = "0.0.0";
+
+
+ protected String details;
+ @XmlAttribute(required = true)
+ protected String name;
+ @XmlAttribute
+ protected String version;
+ @XmlAttribute
+ protected String description;
+ @XmlAttribute
+ protected String resolver;
+ @XmlAttribute
+ protected String install;
+ @XmlAttribute(name = "start-level")
+ protected Integer startLevel;
+ @XmlAttribute
+ protected String region;
+ protected List<Conditional> conditional;
+ protected List<Capability> capability;
+ protected List<Requirement> requirement;
+
+ public Feature() {
+ }
+
+ public Feature(String name) {
+ this.name = name;
+ }
+
+ public Feature(String name, String version) {
+ this.name = name;
+ this.version = version;
+ }
+
+
+ public static org.apache.karaf.features.Feature valueOf(String str) {
+ if (str.contains(SPLIT_FOR_NAME_AND_VERSION)) {
+ String strName = str.substring(0, str.indexOf(SPLIT_FOR_NAME_AND_VERSION));
+ String strVersion = str.substring(str.indexOf(SPLIT_FOR_NAME_AND_VERSION)
+ + SPLIT_FOR_NAME_AND_VERSION.length(), str.length());
+ return new Feature(strName, strVersion);
+ } else {
+ return new Feature(str);
+ }
+
+
+ }
+
+
+ public String getId() {
+ return getName() + SPLIT_FOR_NAME_AND_VERSION + getVersion();
+ }
+
+ /**
+ * Gets the value of the name property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the value of the name property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setName(String value) {
+ this.name = value;
+ }
+
+ /**
+ * Gets the value of the version property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getVersion() {
+ if (version == null) {
+ return DEFAULT_VERSION;
+ } else {
+ return version;
+ }
+ }
+
+ /**
+ * Sets the value of the version property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setVersion(String value) {
+ this.version = value;
+ }
+
+ /**
+ * Since version has a default value ("0.0.0"), returns
+ * whether or not the version has been set.
+ */
+ public boolean hasVersion() {
+ return this.version != null;
+ }
+
+ /**
+ * Gets the value of the description property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * Sets the value of the description property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setDescription(String value) {
+ this.description = value;
+ }
+
+ public String getDetails() {
+ return details;
+ }
+
+ public void setDetails(String details) {
+ this.details = details;
+ }
+
+ /**
+ * Gets the value of the resolver property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getResolver() {
+ return resolver;
+ }
+
+ public String getInstall() {
+ return install;
+ }
+
+ public void setInstall(String install) {
+ this.install = install;
+ }
+
+ /**
+ * Sets the value of the resolver property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setResolver(String value) {
+ this.resolver = value;
+ }
+
+ /**
+ * Gets the value of the startLevel property.
+ *
+ * @return
+ * possible object is
+ * {@link Integer }
+ *
+ */
+ public int getStartLevel() {
+ return startLevel == null? 0: startLevel;
+ }
+
+ /**
+ * Sets the value of the startLevel property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Integer }
+ *
+ */
+ public void setStartLevel(Integer value) {
+ this.startLevel = value;
+ }
+
+
+ public String getRegion() {
+ return region;
+ }
+
+ public void setRegion(String region) {
+ this.region = region;
+ }
+
+ /**
+ * Gets the value of the conditional property.
+ * <p/>
+ * <p/>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the feature property.
+ * <p/>
+ * <p/>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getConditionals().add(newItem);
+ * </pre>
+ * <p/>
+ * <p/>
+ * <p/>
+ * Objects of the following type(s) are allowed in the list
+ * {@link Conditional }
+ */
+ public List<Conditional> getConditional() {
+ if (conditional == null) {
+ conditional = new ArrayList<Conditional>();
+ }
+ return this.conditional;
+ }
+
+ public List<Capability> getCapabilities() {
+ if (capability == null) {
+ capability = new ArrayList<Capability>();
+ }
+ return this.capability;
+ }
+
+ public List<Requirement> getRequirements() {
+ if (requirement == null) {
+ requirement = new ArrayList<Requirement>();
+ }
+ return this.requirement;
+ }
+
+ public String toString() {
+ return getId();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Feature feature = (Feature) o;
+
+ if (name != null ? !name.equals(feature.name) : feature.name != null) return false;
+ if (version != null ? !version.equals(feature.version) : feature.version != null) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = name != null ? name.hashCode() : 0;
+ result = 31 * result + (version != null ? version.hashCode() : 0);
+ return result;
+ }
+
+ @SuppressWarnings("rawtypes")
+ protected void interpolation(Properties properties) {
+ for (Enumeration e = properties.propertyNames(); e.hasMoreElements();) {
+ String key = (String) e.nextElement();
+ String val = properties.getProperty(key);
+ Matcher matcher = Pattern.compile("\\$\\{([^}]+)\\}").matcher(val);
+ while (matcher.find()) {
+ String rep = System.getProperty(matcher.group(1));
+ if (rep != null) {
+ val = val.replace(matcher.group(0), rep);
+ matcher.reset(val);
+ }
+ }
+ properties.put(key, val);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/999f4970/features/src/main/java/org/apache/karaf/features/internal/model/Features.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/model/Features.java b/features/src/main/java/org/apache/karaf/features/internal/model/Features.java
new file mode 100644
index 0000000..e116f31
--- /dev/null
+++ b/features/src/main/java/org/apache/karaf/features/internal/model/Features.java
@@ -0,0 +1,155 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.karaf.features.internal.model;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ *
+ * Root element of Feature definition. It contains optional attribute which allow
+ * name of repository. This name will be used in shell to display source repository
+ * of given feature.
+ *
+ *
+ * <p>Java class for featuresRoot complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * <complexType name="features">
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="repository" type="{http://www.w3.org/2001/XMLSchema}anyURI" maxOccurs="unbounded" minOccurs="0"/>
+ * <element name="feature" type="{http://karaf.apache.org/xmlns/features/v1.0.0}feature" maxOccurs="unbounded" minOccurs="0"/>
+ * </sequence>
+ * <attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </pre>
+ *
+ *
+ */
+@XmlRootElement(name = "features")
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "features", propOrder = {
+ "repository",
+ "feature"
+})
+public class Features {
+
+ @XmlSchemaType(name = "anyURI")
+ protected List<String> repository;
+ protected List<Feature> feature;
+ @XmlAttribute
+ protected String name;
+
+ /**
+ * Gets the value of the repository property.
+ *
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the repository property.
+ *
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getRepository().add(newItem);
+ * </pre>
+ *
+ *
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link String }
+ *
+ *
+ */
+ public List<String> getRepository() {
+ if (repository == null) {
+ repository = new ArrayList<String>();
+ }
+ return this.repository;
+ }
+
+ /**
+ * Gets the value of the feature property.
+ *
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the feature property.
+ *
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getFeature().add(newItem);
+ * </pre>
+ *
+ *
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link Feature }
+ *
+ *
+ */
+ public List<Feature> getFeature() {
+ if (feature == null) {
+ feature = new ArrayList<Feature>();
+ }
+ return this.feature;
+ }
+
+ /**
+ * Gets the value of the name property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the value of the name property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setName(String value) {
+ this.name = value;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/999f4970/features/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java b/features/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java
new file mode 100644
index 0000000..39c057a
--- /dev/null
+++ b/features/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.features.internal.model;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Writer;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.ValidationEvent;
+import javax.xml.bind.ValidationEventHandler;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.transform.sax.SAXSource;
+
+import org.apache.karaf.features.FeaturesNamespaces;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLFilter;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.XMLFilterImpl;
+
+public class JaxbUtil {
+
+ public static final XMLInputFactory XMLINPUT_FACTORY = XMLInputFactory.newInstance();
+ private static final JAXBContext FEATURES_CONTEXT;
+ static {
+ try {
+ FEATURES_CONTEXT = JAXBContext.newInstance(Features.class);
+ } catch (JAXBException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static void marshal(Features features, OutputStream out) throws JAXBException {
+ Marshaller marshaller = FEATURES_CONTEXT.createMarshaller();
+
+ marshaller.setProperty("jaxb.formatted.output", true);
+
+ marshaller.marshal(features, out);
+ }
+
+ public static void marshal(Features features, Writer out) throws JAXBException {
+ Marshaller marshaller = FEATURES_CONTEXT.createMarshaller();
+
+ marshaller.setProperty("jaxb.formatted.output", true);
+
+ marshaller.marshal(features, out);
+ }
+
+
+ /**
+ * Read in a Features from the input stream.
+ *
+ * @param in input stream to read
+ * @param validate whether to validate the input.
+ * @return a Features read from the input stream
+ * @throws ParserConfigurationException is the SAX parser can not be configured
+ * @throws SAXException if there is an xml problem
+ * @throws JAXBException if the xml cannot be marshalled into a T.
+ */
+ public static Features unmarshal(InputStream in, boolean validate) {
+ InputSource inputSource = new InputSource(in);
+
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ factory.setNamespaceAware(true);
+ factory.setValidating(validate);
+ SAXParser parser;
+ try {
+ parser = factory.newSAXParser();
+
+
+ Unmarshaller unmarshaller = FEATURES_CONTEXT.createUnmarshaller();
+ unmarshaller.setEventHandler(new ValidationEventHandler() {
+ public boolean handleEvent(ValidationEvent validationEvent) {
+ System.out.println(validationEvent);
+ return false;
+ }
+ });
+
+ XMLFilter xmlFilter = new NoSourceAndNamespaceFilter(parser.getXMLReader());
+ xmlFilter.setContentHandler(unmarshaller.getUnmarshallerHandler());
+
+ SAXSource source = new SAXSource(xmlFilter, inputSource);
+
+ return (Features)unmarshaller.unmarshal(source);
+
+ } catch (ParserConfigurationException e) {
+ throw new RuntimeException(e);
+ } catch (JAXBException e) {
+ throw new RuntimeException(e);
+ } catch (SAXException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Provides an empty inputsource for the entity resolver.
+ * Converts all elements to the features namespace to make old feature files
+ * compatible to the new format
+ */
+ public static class NoSourceAndNamespaceFilter extends XMLFilterImpl {
+ private static final InputSource EMPTY_INPUT_SOURCE = new InputSource(new ByteArrayInputStream(new byte[0]));
+
+ public NoSourceAndNamespaceFilter(XMLReader xmlReader) {
+ super(xmlReader);
+ }
+
+ @Override
+ public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
+ return EMPTY_INPUT_SOURCE;
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
+ super.startElement(FeaturesNamespaces.URI_CURRENT, localName, qName, atts);
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String qName) throws SAXException {
+ super.endElement(FeaturesNamespaces.URI_CURRENT, localName, qName);
+ }
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/999f4970/features/src/main/java/org/apache/karaf/features/internal/model/ObjectFactory.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/model/ObjectFactory.java b/features/src/main/java/org/apache/karaf/features/internal/model/ObjectFactory.java
new file mode 100644
index 0000000..96fbb0f
--- /dev/null
+++ b/features/src/main/java/org/apache/karaf/features/internal/model/ObjectFactory.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.karaf.features.internal.model;
+
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.annotation.XmlElementDecl;
+import javax.xml.bind.annotation.XmlRegistry;
+import javax.xml.namespace.QName;
+
+
+/**
+ * This object contains factory methods for each
+ * Java content interface and Java element interface
+ * generated in the org.apache.karaf.features.wrapper package.
+ * <p>An ObjectFactory allows you to programatically
+ * construct new instances of the Java representation
+ * for XML content. The Java representation of XML
+ * content can consist of schema derived interfaces
+ * and classes representing the binding of schema
+ * type definitions, element declarations and model
+ * groups. Factory methods for each of these are
+ * provided in this class.
+ *
+ */
+@XmlRegistry
+public class ObjectFactory {
+
+ private final static QName _Features_QNAME = new QName("http://karaf.apache.org/xmlns/features/v1.0.0", "features");
+
+ /**
+ * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: org.apache.karaf.features.wrapper
+ *
+ */
+ public ObjectFactory() {
+ }
+
+ /**
+ * Create an instance of {@link ConfigFile }
+ *
+ */
+ public ConfigFile createConfigFile() {
+ return new ConfigFile();
+ }
+
+ /**
+ * Create an instance of {@link Dependency }
+ *
+ */
+ public Dependency createDependency() {
+ return new Dependency();
+ }
+
+ /**
+ * Create an instance of {@link Bundle }
+ *
+ */
+ public Bundle createBundle() {
+ return new Bundle();
+ }
+
+ /**
+ * Create an instance of {@link Features }
+ *
+ */
+ public Features createFeaturesRoot() {
+ return new Features();
+ }
+
+ /**
+ * Create an instance of {@link Config }
+ *
+ */
+ public Config createConfig() {
+ return new Config();
+ }
+
+ /**
+ * Create an instance of {@link Feature }
+ *
+ */
+ public Feature createFeature() {
+ return new Feature();
+ }
+
+ /**
+ * Create an instance of {@link JAXBElement }{@code <}{@link Features }{@code >}}
+ *
+ */
+ @XmlElementDecl(namespace = "http://karaf.apache.org/xmlns/features/v1.0.0", name = "features")
+ public JAXBElement<Features> createFeatures(Features value) {
+ return new JAXBElement<Features>(_Features_QNAME, Features.class, null, value);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/999f4970/features/src/main/java/org/apache/karaf/features/internal/model/Requirement.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/model/Requirement.java b/features/src/main/java/org/apache/karaf/features/internal/model/Requirement.java
new file mode 100644
index 0000000..f7b5775
--- /dev/null
+++ b/features/src/main/java/org/apache/karaf/features/internal/model/Requirement.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+package org.apache.karaf.features.internal.model;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+
+
+/**
+ *
+ * Additional requirement for a feature.
+ *
+ *
+ * <p>Java class for bundle complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * <complexType name="capability">
+ * <simpleContent>
+ * <extension base="<http://www.w3.org/2001/XMLSchema>string">
+ * </extension>
+ * </simpleContent>
+ * </complexType>
+ * </pre>
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "requirement", propOrder = {
+ "value"
+})
+public class Requirement implements org.apache.karaf.features.Requirement {
+
+ @XmlValue
+ protected String value;
+
+
+ public Requirement() {
+ }
+
+ public Requirement(String value) {
+ this.value = value;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Requirement bundle = (Requirement) o;
+
+ if (value != null ? !value.equals(bundle.value) : bundle.value != null) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = value != null ? value.hashCode() : 0;
+ return result;
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/999f4970/features/src/main/java/org/apache/karaf/features/internal/model/package-info.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/model/package-info.java b/features/src/main/java/org/apache/karaf/features/internal/model/package-info.java
new file mode 100644
index 0000000..c86a58c
--- /dev/null
+++ b/features/src/main/java/org/apache/karaf/features/internal/model/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+@javax.xml.bind.annotation.XmlSchema(namespace = org.apache.karaf.features.FeaturesNamespaces.URI_CURRENT, elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
+package org.apache.karaf.features.internal.model;
http://git-wip-us.apache.org/repos/asf/karaf/blob/999f4970/features/src/main/java/org/apache/karaf/features/internal/osgi/Activator.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/osgi/Activator.java b/features/src/main/java/org/apache/karaf/features/internal/osgi/Activator.java
new file mode 100644
index 0000000..be0da05
--- /dev/null
+++ b/features/src/main/java/org/apache/karaf/features/internal/osgi/Activator.java
@@ -0,0 +1,208 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.osgi;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import org.apache.karaf.features.FeaturesListener;
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.internal.service.EventAdminListener;
+import org.apache.karaf.features.internal.service.FeatureConfigInstaller;
+import org.apache.karaf.features.internal.service.FeatureFinder;
+import org.apache.karaf.features.internal.service.BootFeaturesInstaller;
+import org.apache.karaf.features.internal.service.FeaturesServiceImpl;
+import org.apache.karaf.features.internal.service.StateStorage;
+import org.apache.karaf.features.internal.management.FeaturesServiceMBeanImpl;
+import org.apache.karaf.features.RegionsPersistence;
+import org.apache.karaf.util.tracker.BaseActivator;
+import org.apache.karaf.util.tracker.SingleServiceTracker;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.service.url.URLStreamHandlerService;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+
+public class Activator extends BaseActivator {
+
+ public static final String FEATURES_REPOS_PID = "org.apache.karaf.features.repos";
+ public static final String FEATURES_SERVICE_CONFIG_FILE = "org.apache.karaf.features.cfg";
+
+ private ServiceTracker<FeaturesListener, FeaturesListener> featuresListenerTracker;
+ private FeaturesServiceImpl featuresService;
+ private SingleServiceTracker<RegionsPersistence> regionsTracker;
+
+ public Activator() {
+ // Special case here, as we don't want the activator to wait for current job to finish,
+ // else it would forbid the features service to refresh itself
+ setSchedulerStopTimeout(0);
+ }
+
+ @Override
+ protected void doOpen() throws Exception {
+ trackService(URLStreamHandlerService.class, "(url.handler.protocol=mvn)");
+ trackService(ConfigurationAdmin.class);
+
+ Properties configuration = new Properties();
+ File configFile = new File(System.getProperty("karaf.etc"), FEATURES_SERVICE_CONFIG_FILE);
+ if (configFile.isFile() && configFile.canRead()) {
+ try {
+ configuration.load(new FileReader(configFile));
+ } catch (IOException e) {
+ logger.warn("Error reading configuration file " + configFile.toString(), e);
+ }
+ }
+ updated((Dictionary) configuration);
+ }
+
+ protected void doStart() throws Exception {
+ ConfigurationAdmin configurationAdmin = getTrackedService(ConfigurationAdmin.class);
+ URLStreamHandlerService mvnUrlHandler = getTrackedService(URLStreamHandlerService.class);
+
+ if (configurationAdmin == null || mvnUrlHandler == null) {
+ return;
+ }
+
+ FeatureFinder featureFinder = new FeatureFinder();
+ Hashtable<String, Object> props = new Hashtable<String, Object>();
+ props.put(Constants.SERVICE_PID, FEATURES_REPOS_PID);
+ register(ManagedService.class, featureFinder, props);
+
+ // TODO: region support
+// final BundleManager bundleManager = new BundleManager(bundleContext);
+// regionsTracker = new SingleServiceTracker<RegionsPersistence>(bundleContext, RegionsPersistence.class,
+// new SingleServiceTracker.SingleServiceListener() {
+// @Override
+// public void serviceFound() {
+// bundleManager.setRegionsPersistence(regionsTracker.getService());
+// }
+// @Override
+// public void serviceLost() {
+// serviceFound();
+// }
+// @Override
+// public void serviceReplaced() {
+// serviceFound();
+// }
+// });
+// regionsTracker.open();
+
+
+ FeatureConfigInstaller configInstaller = new FeatureConfigInstaller(configurationAdmin);
+ // TODO: honor respectStartLvlDuringFeatureStartup and respectStartLvlDuringFeatureUninstall
+// boolean respectStartLvlDuringFeatureStartup = getBoolean("respectStartLvlDuringFeatureStartup", true);
+// boolean respectStartLvlDuringFeatureUninstall = getBoolean("respectStartLvlDuringFeatureUninstall", true);
+ String overrides = getString("overrides", new File(System.getProperty("karaf.etc"), "overrides.properties").toURI().toString());
+ String featureResolutionRange = getString("featureResolutionRange", FeaturesServiceImpl.DEFAULT_FEATURE_RESOLUTION_RANGE);
+ String bundleUpdateRange = getString("bundleUpdateRange", FeaturesServiceImpl.DEFAULT_BUNDLE_UPDATE_RANGE);
+ String updateSnapshots = getString("updateSnapshots", FeaturesServiceImpl.DEFAULT_UPDATE_SNAPSHOTS);
+ StateStorage stateStorage = new StateStorage() {
+ @Override
+ protected InputStream getInputStream() throws IOException {
+ File file = bundleContext.getDataFile("FeaturesServiceState.properties");
+ if (file.exists()) {
+ return new FileInputStream(file);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ protected OutputStream getOutputStream() throws IOException {
+ File file = bundleContext.getDataFile("FeaturesServiceState.properties");
+ return new FileOutputStream(file);
+ }
+ };
+ EventAdminListener eventAdminListener;
+ try {
+ eventAdminListener = new EventAdminListener(bundleContext);
+ } catch (Throwable t) {
+ eventAdminListener = null;
+ }
+ featuresService = new FeaturesServiceImpl(
+ bundleContext.getBundle(),
+ bundleContext.getBundle(0).getBundleContext(),
+ stateStorage,
+ featureFinder,
+ eventAdminListener,
+ configInstaller,
+ overrides,
+ featureResolutionRange,
+ bundleUpdateRange,
+ updateSnapshots);
+ register(FeaturesService.class, featuresService);
+
+ featuresListenerTracker = new ServiceTracker<FeaturesListener, FeaturesListener>(
+ bundleContext, FeaturesListener.class, new ServiceTrackerCustomizer<FeaturesListener, FeaturesListener>() {
+ @Override
+ public FeaturesListener addingService(ServiceReference<FeaturesListener> reference) {
+ FeaturesListener service = bundleContext.getService(reference);
+ featuresService.registerListener(service);
+ return service;
+ }
+ @Override
+ public void modifiedService(ServiceReference<FeaturesListener> reference, FeaturesListener service) {
+ }
+ @Override
+ public void removedService(ServiceReference<FeaturesListener> reference, FeaturesListener service) {
+ featuresService.unregisterListener(service);
+ bundleContext.ungetService(reference);
+ }
+ }
+ );
+ featuresListenerTracker.open();
+
+ String featuresRepositories = getString("featuresRepositories", "");
+ String featuresBoot = getString("featuresBoot", "");
+ boolean featuresBootAsynchronous = getBoolean("featuresBootAsynchronous", false);
+ BootFeaturesInstaller bootFeaturesInstaller = new BootFeaturesInstaller(
+ bundleContext, featuresService,
+ featuresRepositories, featuresBoot, featuresBootAsynchronous);
+ bootFeaturesInstaller.start();
+
+ FeaturesServiceMBeanImpl featuresServiceMBean = new FeaturesServiceMBeanImpl();
+ featuresServiceMBean.setBundleContext(bundleContext);
+ featuresServiceMBean.setFeaturesService(featuresService);
+ registerMBean(featuresServiceMBean, "type=feature");
+ }
+
+ protected void doStop() {
+ if (regionsTracker != null) {
+ regionsTracker.close();
+ regionsTracker = null;
+ }
+ if (featuresListenerTracker != null) {
+ featuresListenerTracker.close();
+ featuresListenerTracker = null;
+ }
+ super.doStop();
+ if (featuresService != null) {
+ featuresService = null;
+ }
+ }
+
+}