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/18 23:35:54 UTC
[4/6] [KARAF-2923] Region support in features service
http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/region/CandidateComparator.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/region/CandidateComparator.java b/features/core/src/main/java/org/apache/karaf/features/internal/region/CandidateComparator.java
new file mode 100644
index 0000000..74c014b
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/region/CandidateComparator.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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.region;
+
+import java.util.Comparator;
+
+import org.osgi.framework.Version;
+import org.osgi.framework.namespace.BundleNamespace;
+import org.osgi.framework.namespace.IdentityNamespace;
+import org.osgi.framework.namespace.PackageNamespace;
+import org.osgi.framework.wiring.BundleCapability;
+import org.osgi.resource.Capability;
+
+public class CandidateComparator implements Comparator<Capability>
+{
+ public int compare(Capability cap1, Capability cap2)
+ {
+ int c = 0;
+ // Always prefer system bundle
+ if (cap1 instanceof BundleCapability && !(cap2 instanceof BundleCapability)) {
+ c = -1;
+ } else if (!(cap1 instanceof BundleCapability) && cap2 instanceof BundleCapability) {
+ c = 1;
+ }
+ // Compare revision capabilities.
+ if ((c == 0) && cap1.getNamespace().equals(BundleNamespace.BUNDLE_NAMESPACE))
+ {
+ c = ((Comparable) cap1.getAttributes().get(BundleNamespace.BUNDLE_NAMESPACE))
+ .compareTo(cap2.getAttributes().get(BundleNamespace.BUNDLE_NAMESPACE));
+ if (c == 0)
+ {
+ Version v1 = (!cap1.getAttributes().containsKey(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE))
+ ? Version.emptyVersion
+ : (Version) cap1.getAttributes().get(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE);
+ Version v2 = (!cap2.getAttributes().containsKey(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE))
+ ? Version.emptyVersion
+ : (Version) cap2.getAttributes().get(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE);
+ // Compare these in reverse order, since we want
+ // highest version to have priority.
+ c = compareVersions(v2, v1);
+ }
+ }
+ // Compare package capabilities.
+ else if ((c == 0) && cap1.getNamespace().equals(PackageNamespace.PACKAGE_NAMESPACE))
+ {
+ c = ((Comparable) cap1.getAttributes().get(PackageNamespace.PACKAGE_NAMESPACE))
+ .compareTo(cap2.getAttributes().get(PackageNamespace.PACKAGE_NAMESPACE));
+ if (c == 0)
+ {
+ Version v1 = (!cap1.getAttributes().containsKey(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE))
+ ? Version.emptyVersion
+ : (Version) cap1.getAttributes().get(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE);
+ Version v2 = (!cap2.getAttributes().containsKey(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE))
+ ? Version.emptyVersion
+ : (Version) cap2.getAttributes().get(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE);
+ // Compare these in reverse order, since we want
+ // highest version to have priority.
+ c = compareVersions(v2, v1);
+ // if same version, rather compare on the bundle version
+ if (c == 0)
+ {
+ v1 = (!cap1.getAttributes().containsKey(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE))
+ ? Version.emptyVersion
+ : (Version) cap1.getAttributes().get(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE);
+ v2 = (!cap2.getAttributes().containsKey(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE))
+ ? Version.emptyVersion
+ : (Version) cap2.getAttributes().get(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE);
+ // Compare these in reverse order, since we want
+ // highest version to have priority.
+ c = compareVersions(v2, v1);
+ }
+ }
+ }
+ // Compare feature capabilities
+ else if ((c == 0) && cap1.getNamespace().equals(IdentityNamespace.IDENTITY_NAMESPACE))
+ {
+ c = ((Comparable) cap1.getAttributes().get(IdentityNamespace.IDENTITY_NAMESPACE))
+ .compareTo(cap2.getAttributes().get(IdentityNamespace.IDENTITY_NAMESPACE));
+ if (c == 0)
+ {
+ Version v1 = (!cap1.getAttributes().containsKey(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE))
+ ? Version.emptyVersion
+ : (Version) cap1.getAttributes().get(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE);
+ Version v2 = (!cap2.getAttributes().containsKey(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE))
+ ? Version.emptyVersion
+ : (Version) cap2.getAttributes().get(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE);
+ // Compare these in reverse order, since we want
+ // highest version to have priority.
+ c = compareVersions(v2, v1);
+ }
+ }
+ return c;
+ }
+
+ private int compareVersions(Version v1, Version v2) {
+ int c = v1.getMajor() - v2.getMajor();
+ if (c != 0) {
+ return c;
+ }
+ c = v1.getMinor() - v2.getMinor();
+ if (c != 0) {
+ return c;
+ }
+ c = v1.getMicro() - v2.getMicro();
+ if (c != 0) {
+ return c;
+ }
+ return v1.getQualifier().compareTo(v2.getQualifier());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/region/ResourceComparator.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/region/ResourceComparator.java b/features/core/src/main/java/org/apache/karaf/features/internal/region/ResourceComparator.java
new file mode 100644
index 0000000..19ba529
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/region/ResourceComparator.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.region;
+
+import java.util.Comparator;
+
+import org.apache.felix.resolver.Util;
+import org.osgi.framework.Version;
+import org.osgi.resource.Resource;
+
+public class ResourceComparator implements Comparator<Resource> {
+
+ @Override
+ public int compare(Resource o1, Resource o2) {
+ String bsn1 = Util.getSymbolicName(o1);
+ String bsn2 = Util.getSymbolicName(o2);
+ int c = bsn1.compareTo(bsn2);
+ if (c == 0) {
+ Version v1 = Util.getVersion(o1);
+ Version v2 = Util.getVersion(o2);
+ c = v1.compareTo(v2);
+ if (c == 0) {
+ c = o1.hashCode() - o2.hashCode();
+ }
+ }
+ return c;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/region/Subsystem.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/region/Subsystem.java b/features/core/src/main/java/org/apache/karaf/features/internal/region/Subsystem.java
new file mode 100644
index 0000000..8d55317
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/region/Subsystem.java
@@ -0,0 +1,341 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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.region;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.felix.resolver.Util;
+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.ScopeFilter;
+import org.apache.karaf.features.internal.download.DownloadCallback;
+import org.apache.karaf.features.internal.download.DownloadManager;
+import org.apache.karaf.features.internal.download.Downloader;
+import org.apache.karaf.features.internal.download.StreamProvider;
+import org.apache.karaf.features.internal.resolver.FeatureResource;
+import org.apache.karaf.features.internal.resolver.RequirementImpl;
+import org.apache.karaf.features.internal.resolver.ResourceBuilder;
+import org.apache.karaf.features.internal.resolver.ResourceImpl;
+import org.apache.karaf.features.internal.resolver.ResourceUtils;
+import org.eclipse.equinox.region.RegionFilter;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Version;
+import org.osgi.resource.Capability;
+import org.osgi.resource.Requirement;
+import org.osgi.resource.Resource;
+
+import static org.apache.karaf.features.internal.resolver.ResourceUtils.TYPE_FEATURE;
+import static org.apache.karaf.features.internal.resolver.ResourceUtils.TYPE_SUBSYSTEM;
+import static org.apache.karaf.features.internal.resolver.ResourceUtils.addIdentityRequirement;
+import static org.apache.karaf.features.internal.util.MapUtils.addToMapSet;
+import static org.osgi.framework.namespace.IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE;
+import static org.osgi.framework.namespace.IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE;
+import static org.osgi.framework.namespace.IdentityNamespace.IDENTITY_NAMESPACE;
+
+public class Subsystem extends ResourceImpl {
+
+ private static final String ALL_FILTER = "(|(!(all=*))(all=*))";
+
+ private static final String SUBSYSTEM_FILTER = String.format("(%s=%s)", CAPABILITY_TYPE_ATTRIBUTE, TYPE_SUBSYSTEM);
+
+ private static final String FEATURE_FILTER = String.format("(%s=%s)", CAPABILITY_TYPE_ATTRIBUTE, TYPE_FEATURE);
+
+ private static final String SUBSYSTEM_OR_FEATURE_FILTER = String.format("(|%s%s)", SUBSYSTEM_FILTER, FEATURE_FILTER);
+
+ // Everything is visible
+ private static final Map<String, Set<String>> SHARE_ALL_POLICY =
+ Collections.singletonMap(
+ RegionFilter.VISIBLE_ALL_NAMESPACE,
+ Collections.singleton(ALL_FILTER));
+
+ // Nothing (but systems) is visible
+ private static final Map<String, Set<String>> SHARE_NONE_POLICY =
+ Collections.singletonMap(
+ IDENTITY_NAMESPACE,
+ Collections.singleton(SUBSYSTEM_FILTER));
+
+ private final String name;
+ private final boolean acceptDependencies;
+ private final Subsystem parent;
+ private final Feature feature;
+ private final List<Subsystem> children = new ArrayList<Subsystem>();
+ private final Map<String, Set<String>> importPolicy;
+ private final Map<String, Set<String>> exportPolicy;
+ private final List<Resource> installable = new ArrayList<Resource>();
+ private final Map<String, DependencyInfo> dependencies = new HashMap<String, DependencyInfo>();
+
+ public Subsystem(String name) {
+ super(name, TYPE_SUBSYSTEM, Version.emptyVersion);
+ this.name = name;
+ this.parent = null;
+ this.acceptDependencies = true;
+ this.feature = null;
+ this.importPolicy = SHARE_NONE_POLICY;
+ this.exportPolicy = SHARE_NONE_POLICY;
+ }
+
+ public Subsystem(String name, Feature feature, Subsystem parent) {
+ super(name, TYPE_SUBSYSTEM, Version.emptyVersion);
+ this.name = name;
+ this.parent = parent;
+ this.acceptDependencies = feature.getScoping() != null && feature.getScoping().acceptDependencies();
+ this.feature = feature;
+ if (feature.getScoping() != null) {
+ this.importPolicy = createPolicy(feature.getScoping().getImports());
+ this.importPolicy.put(IDENTITY_NAMESPACE, Collections.singleton(SUBSYSTEM_OR_FEATURE_FILTER));
+ this.exportPolicy = createPolicy(feature.getScoping().getExports());
+ this.exportPolicy.put(IDENTITY_NAMESPACE, Collections.singleton(SUBSYSTEM_OR_FEATURE_FILTER));
+ } else {
+ this.importPolicy = SHARE_ALL_POLICY;
+ this.exportPolicy = SHARE_ALL_POLICY;
+ }
+
+ Map<String, String> dirs = new HashMap<String, String>();
+ Map<String, Object> attrs = new HashMap<String, Object>();
+ attrs.put(IDENTITY_NAMESPACE, feature.getName());
+ attrs.put(CAPABILITY_TYPE_ATTRIBUTE, TYPE_FEATURE);
+ attrs.put(CAPABILITY_VERSION_ATTRIBUTE, new VersionRange(VersionTable.getVersion(feature.getVersion()), true));
+ Requirement requirement = new RequirementImpl(this, IDENTITY_NAMESPACE, dirs, attrs);
+ addRequirement(requirement);
+ }
+
+ public Subsystem(String name, Subsystem parent, boolean acceptDependencies) {
+ super(name, TYPE_SUBSYSTEM, Version.emptyVersion);
+ this.name = name;
+ this.parent = parent;
+ this.acceptDependencies = acceptDependencies;
+ this.feature = null;
+ this.importPolicy = SHARE_ALL_POLICY;
+ this.exportPolicy = SHARE_NONE_POLICY;
+ }
+
+ public List<Resource> getInstallable() {
+ return installable;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Subsystem getParent() {
+ return parent;
+ }
+
+ public Collection<Subsystem> getChildren() {
+ return children;
+ }
+
+ public Subsystem getChild(String name) {
+ for (Subsystem child : children) {
+ if (child.getName().equals(name)) {
+ return child;
+ }
+ }
+ return null;
+ }
+
+ public boolean isAcceptDependencies() {
+ return acceptDependencies;
+ }
+
+ public Map<String, Set<String>> getImportPolicy() {
+ return importPolicy;
+ }
+
+ public Map<String, Set<String>> getExportPolicy() {
+ return exportPolicy;
+ }
+
+ public Feature getFeature() {
+ return feature;
+ }
+
+ public Subsystem createSubsystem(String name, boolean acceptDependencies) {
+ if (feature != null) {
+ throw new UnsupportedOperationException("Can not create application subsystems inside a feature subsystem");
+ }
+ // Create subsystem
+ Subsystem as = new Subsystem(getName() + "/" + name, this, acceptDependencies);
+ children.add(as);
+ // Add a requirement to force its resolution
+ Capability identity = as.getCapabilities(IDENTITY_NAMESPACE).iterator().next();
+ Object bsn = identity.getAttributes().get(IDENTITY_NAMESPACE);
+ Requirement requirement = new RequirementImpl(this, IDENTITY_NAMESPACE,
+ Collections.<String,String>emptyMap(),
+ Collections.singletonMap(IDENTITY_NAMESPACE, bsn));
+ addRequirement(requirement);
+ // Add it to repo
+ installable.add(as);
+ return as;
+ }
+
+ public void addSystemResource(Resource resource) {
+ installable.add(resource);
+ }
+
+ public void requireFeature(String name, String range) {
+ ResourceUtils.addIdentityRequirement(this, name, TYPE_FEATURE, range);
+ }
+
+ @SuppressWarnings("InfiniteLoopStatement")
+ public void preResolve(Collection<Feature> features,
+ DownloadManager manager,
+ String featureResolutionRange) throws Exception {
+ for (Subsystem child : children) {
+ child.preResolve(features, manager, featureResolutionRange);
+ }
+ List<Requirement> processed = new ArrayList<Requirement>();
+ while (true) {
+ List<Requirement> requirements = getRequirements(IDENTITY_NAMESPACE);
+ requirements.removeAll(processed);
+ if (requirements.isEmpty()) {
+ break;
+ }
+ for (Requirement requirement : requirements) {
+ String name = (String) requirement.getAttributes().get(IDENTITY_NAMESPACE);
+ String type = (String) requirement.getAttributes().get(CAPABILITY_TYPE_ATTRIBUTE);
+ VersionRange range = (VersionRange) requirement.getAttributes().get(CAPABILITY_VERSION_ATTRIBUTE);
+ if (TYPE_FEATURE.equals(type)) {
+ for (Feature feature : features) {
+ if (feature.getName().equals(name)
+ && (range == null || range.contains(VersionTable.getVersion(feature.getVersion())))) {
+ if (feature != this.feature) {
+ String ssName = this.name + "#" + (feature.hasVersion() ? feature.getName() + "-" + feature.getVersion() : feature.getName());
+ Subsystem fs = getChild(ssName);
+ if (fs == null) {
+ fs = new Subsystem(ssName, feature, this);
+ fs.preResolve(features, manager, featureResolutionRange);
+ installable.add(fs);
+ children.add(fs);
+ }
+ }
+ }
+ }
+ }
+ processed.add(requirement);
+ }
+ }
+ if (feature != null) {
+ final Map<String, Resource> bundles = new ConcurrentHashMap<String, Resource>();
+ final Downloader downloader = manager.createDownloader();
+ final Map<BundleInfo, Boolean> infos = new HashMap<BundleInfo, Boolean>();
+ for (Conditional cond : feature.getConditional()) {
+ for (final BundleInfo bi : cond.getBundles()) {
+ infos.put(bi, false);
+ }
+ }
+ for (BundleInfo bi : feature.getBundles()) {
+ infos.put(bi, true);
+ }
+ for (Map.Entry<BundleInfo, Boolean> entry : infos.entrySet()) {
+ final BundleInfo bi = entry.getKey();
+ final String loc = bi.getLocation();
+ final boolean mandatory = entry.getValue();
+ downloader.download(loc, new DownloadCallback() {
+ @Override
+ public void downloaded(StreamProvider provider) throws Exception {
+ ResourceImpl res = createResource(loc, provider.getMetadata());
+ bundles.put(loc, res);
+ if (bi.isDependency()) {
+ addDependency(res, false);
+ } else {
+ doAddDependency(res, mandatory);
+ }
+ }
+ });
+ }
+ downloader.await();
+ for (Dependency dep : feature.getDependencies()) {
+ Subsystem ss = this;
+ while (!ss.isAcceptDependencies()) {
+ ss = ss.getParent();
+ }
+ ss.requireFeature(dep.getName(), dep.getVersion());
+ }
+ for (Conditional cond : feature.getConditional()) {
+ FeatureResource resCond = FeatureResource.build(feature, cond, featureResolutionRange, bundles);
+ addIdentityRequirement(this, resCond, false);
+ installable.add(resCond);
+ }
+
+ FeatureResource res = FeatureResource.build(feature, featureResolutionRange, bundles);
+ addIdentityRequirement(res, this);
+ installable.add(res);
+ }
+ // Compute dependencies
+ for (DependencyInfo info : dependencies.values()) {
+ installable.add(info.resource);
+ addIdentityRequirement(info.resource, this, info.mandatory);
+ }
+ }
+
+ void addDependency(ResourceImpl resource, boolean mandatory) {
+ if (isAcceptDependencies()) {
+ doAddDependency(resource, mandatory);
+ } else {
+ parent.addDependency(resource, mandatory);
+ }
+ }
+
+ private void doAddDependency(ResourceImpl resource, boolean mandatory) {
+ String id = Util.getSymbolicName(resource) + "|" + Util.getVersion(resource);
+ DependencyInfo info = dependencies.get(id);
+ if (info == null) {
+ info = new DependencyInfo();
+ dependencies.put(id, info);
+ }
+ info.resource = resource;
+ info.mandatory |= mandatory;
+ }
+
+ class DependencyInfo {
+ ResourceImpl resource;
+ boolean mandatory;
+ }
+
+ Map<String, Set<String>> createPolicy(List<? extends ScopeFilter> filters) {
+ Map<String, Set<String>> policy = new HashMap<String, Set<String>>();
+ for (ScopeFilter filter : filters) {
+ addToMapSet(policy, filter.getNamespace(), filter.getFilter());
+ }
+ return policy;
+ }
+
+ ResourceImpl createResource(String uri, Map<String, String> headers) throws Exception {
+ try {
+ return ResourceBuilder.build(uri, headers);
+ } catch (BundleException e) {
+ throw new Exception("Unable to create resource for bundle " + uri, e);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return getName();
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolveContext.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolveContext.java b/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolveContext.java
new file mode 100644
index 0000000..e5c6532
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolveContext.java
@@ -0,0 +1,188 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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.region;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.resolver.Util;
+import org.apache.karaf.features.internal.repository.StaticRepository;
+import org.eclipse.equinox.region.Region;
+import org.eclipse.equinox.region.RegionDigraph;
+import org.eclipse.equinox.region.RegionFilter;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+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.Wiring;
+import org.osgi.service.repository.Repository;
+import org.osgi.service.resolver.HostedCapability;
+import org.osgi.service.resolver.ResolveContext;
+
+public class SubsystemResolveContext extends ResolveContext {
+
+ private final Subsystem root;
+ private final RegionDigraph digraph;
+ private final CandidateComparator candidateComparator = new CandidateComparator();
+
+ private final Map<Resource, Subsystem> resToSub = new HashMap<Resource, Subsystem>();
+ private final Repository repository;
+
+
+ public SubsystemResolveContext(Subsystem root, RegionDigraph digraph) throws BundleException {
+ this.root = root;
+ this.digraph = digraph;
+
+ prepare(root);
+ repository = new StaticRepository(resToSub.keySet());
+ }
+
+ void prepare(Subsystem subsystem) {
+ resToSub.put(subsystem, subsystem);
+ for (Resource res : subsystem.getInstallable()) {
+ resToSub.put(res, subsystem);
+ }
+ for (Subsystem child : subsystem.getChildren()) {
+ prepare(child);
+ }
+ }
+
+ @Override
+ public Collection<Resource> getMandatoryResources() {
+ return Collections.<Resource>singleton(root);
+ }
+
+ @Override
+ public List<Capability> findProviders(Requirement requirement) {
+ List<Capability> caps = new ArrayList<Capability>();
+ Region requirerRegion = getRegion(requirement.getResource());
+ if (requirerRegion != null) {
+ Map<Requirement, Collection<Capability>> resMap =
+ repository.findProviders(Collections.singleton(requirement));
+ Collection<Capability> res = resMap != null ? resMap.get(requirement) : null;
+ if (res != null) {
+ caps.addAll(res);
+ }
+ // Use the digraph to prune non visible capabilities
+ Visitor visitor = new Visitor(caps);
+ requirerRegion.visitSubgraph(visitor);
+ Collection<Capability> allowed = visitor.getAllowed();
+ caps.retainAll(allowed);
+ // Handle cases where the same bundle is requested from both
+ // a subsystem and one of its ascendant. In such cases, we
+ // need to remove the one from the child if it can view
+ // the parent one
+ if (caps.size() > 1) {
+ Map<String, Resource> providers = new HashMap<String, Resource>();
+ for (Capability cap : caps) {
+ Resource resource = cap.getResource();
+ String id = Util.getSymbolicName(resource) + "|" + Util.getVersion(resource);
+ Resource prev = providers.get(id);
+ if (prev != null && prev != resource) {
+ String r1 = getRegion(prev).getName();
+ String r2 = getRegion(resource).getName();
+ int c = r1.compareTo(r2);
+ if (c == 0) {
+ // This should never happen because resource have been
+ // de-duplicated during the pre-resolution phase.
+ throw new IllegalStateException();
+ }
+ resource = c < 0 ? prev : resource;
+ }
+ providers.put(id, resource);
+ }
+ for (Iterator<Capability> it = caps.iterator(); it.hasNext();) {
+ Capability cap = it.next();
+ if (!providers.values().contains(cap.getResource())) {
+ it.remove();
+ }
+ }
+ }
+ // Sort caps
+ Collections.sort(caps, candidateComparator);
+ }
+ return caps;
+ }
+
+ private Subsystem getSubsystem(Resource resource) {
+ return resToSub.get(resource);
+ }
+
+ private Region getRegion(Resource resource) {
+ return digraph.getRegion(getSubsystem(resource).getName());
+ }
+
+ @Override
+ public int insertHostedCapability(List<Capability> capabilities, HostedCapability hostedCapability) {
+ int idx = Collections.binarySearch(capabilities, hostedCapability, candidateComparator);
+ if (idx < 0) {
+ idx = Math.abs(idx + 1);
+ }
+ capabilities.add(idx, hostedCapability);
+ return idx;
+ }
+
+ @Override
+ public boolean isEffective(Requirement requirement) {
+ String resolution = requirement.getDirectives().get(Constants.RESOLUTION_DIRECTIVE);
+ return requirement.getNamespace().equals(IdentityNamespace.IDENTITY_NAMESPACE)
+ || !Constants.RESOLUTION_OPTIONAL.equals(resolution);
+ }
+
+ @Override
+ public Map<Resource, Wiring> getWirings() {
+ return Collections.emptyMap();
+ }
+
+ class Visitor extends AbstractRegionDigraphVisitor<Capability> {
+
+ Visitor(Collection<Capability> candidates) {
+ super(candidates);
+ }
+
+ @Override
+ protected boolean contains(Region region, Capability candidate) {
+ return region.equals(getRegion(candidate.getResource()));
+ }
+
+ @Override
+ protected boolean isAllowed(Capability candidate, RegionFilter filter) {
+ if (filter.isAllowed(candidate.getNamespace(), candidate.getAttributes())) {
+ return true;
+ }
+ Resource resource = candidate.getResource();
+ List<Capability> identities = resource.getCapabilities(IdentityNamespace.IDENTITY_NAMESPACE);
+ if (identities != null && !identities.isEmpty()) {
+ Capability identity = identities.iterator().next();
+ Map<String, Object> attrs = new HashMap<String, Object>();
+ attrs.put(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE, identity.getAttributes().get(IdentityNamespace.IDENTITY_NAMESPACE));
+ attrs.put(Constants.BUNDLE_VERSION_ATTRIBUTE, identity.getAttributes().get(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE));
+ return filter.isAllowed(RegionFilter.VISIBLE_BUNDLE_NAMESPACE, attrs);
+ }
+ return false;
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolver.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolver.java b/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolver.java
new file mode 100644
index 0000000..8a98328
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/region/SubsystemResolver.java
@@ -0,0 +1,317 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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.region;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+import org.apache.felix.resolver.ResolverImpl;
+import org.apache.felix.resolver.Util;
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.Repository;
+import org.apache.karaf.features.internal.download.DownloadManager;
+import org.apache.karaf.features.internal.download.StreamProvider;
+import org.apache.karaf.features.internal.download.simple.SimpleDownloader;
+import org.apache.karaf.features.internal.resolver.CapabilitySet;
+import org.apache.karaf.features.internal.resolver.SimpleFilter;
+import org.apache.karaf.features.internal.resolver.Slf4jResolverLog;
+import org.eclipse.equinox.internal.region.StandardRegionDigraph;
+import org.eclipse.equinox.region.Region;
+import org.eclipse.equinox.region.RegionDigraph;
+import org.eclipse.equinox.region.RegionFilterBuilder;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.InvalidSyntaxException;
+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.Resolver;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.karaf.features.internal.resolver.ResourceUtils.TYPE_FEATURE;
+import static org.apache.karaf.features.internal.resolver.ResourceUtils.TYPE_SUBSYSTEM;
+import static org.apache.karaf.features.internal.util.MapUtils.invert;
+import static org.osgi.framework.namespace.IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE;
+import static org.osgi.framework.namespace.IdentityNamespace.IDENTITY_NAMESPACE;
+import static org.osgi.framework.namespace.IdentityNamespace.TYPE_BUNDLE;
+import static org.osgi.framework.namespace.IdentityNamespace.TYPE_FRAGMENT;
+
+public class SubsystemResolver {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(SubsystemResolver.class);
+
+ private DownloadManager manager;
+ private RegionDigraph digraph;
+ private Subsystem root;
+ private Map<Resource, List<Wire>> wiring;
+
+ public SubsystemResolver() {
+ this(new SimpleDownloader());
+ }
+
+ public SubsystemResolver(DownloadManager manager) {
+ this.manager = manager;
+ }
+
+ public Map<Resource, List<Wire>> resolve(
+ List<Repository> repositories,
+ Map<String, Set<String>> features,
+ Collection<? extends Resource> system,
+ String featureResolutionRange
+ ) throws Exception {
+ // Build subsystems on the fly
+ for (Map.Entry<String, Set<String>> entry : features.entrySet()) {
+ String[] parts = entry.getKey().split("/");
+ if (root == null) {
+ root = new Subsystem(parts[0]);
+ } else if (!root.getName().equals(parts[0])) {
+ throw new IllegalArgumentException("Can not use multiple roots: " + root.getName() + ", " + parts[0]);
+ }
+ Subsystem ss = root;
+ for (int i = 1; i < parts.length; i++) {
+ ss = getOrCreateChild(ss, parts[i]);
+ }
+ for (String feature : entry.getValue()) {
+ String name, range;
+ int idx = feature.indexOf('/');
+ if (idx >= 0) {
+ name = feature.substring(0, idx);
+ range = feature.substring(idx + 1);
+ } else {
+ name = feature;
+ range = null;
+ }
+ ss.requireFeature(name, range);
+ }
+ }
+ if (root == null) {
+ return Collections.emptyMap();
+ }
+ // Pre-resolve
+ List<Feature> allFeatures = new ArrayList<Feature>();
+ for (Repository repo : repositories) {
+ allFeatures.addAll(Arrays.asList(repo.getFeatures()));
+ }
+ root.preResolve(allFeatures, manager, featureResolutionRange);
+
+ // Add system resources
+ for (Resource res : system) {
+ root.addSystemResource(res);
+ }
+
+ // Populate digraph and resolve
+ digraph = new StandardRegionDigraph(null, null);
+ populateDigraph(digraph, root);
+
+ Resolver resolver = new ResolverImpl(new Slf4jResolverLog(LOGGER));
+ wiring = resolver.resolve(new SubsystemResolveContext(root, digraph));
+
+ // Fragments are always wired to their host only, so create fake wiring to
+ // the subsystem the host is wired to
+ associateFragments();
+
+ return wiring;
+ }
+
+ public Map<String, StreamProvider> getProviders() {
+ return manager.getProviders();
+ }
+
+ public RegionDigraph getDigraph() {
+ return digraph;
+ }
+
+ public Map<Resource, List<Wire>> getWiring() {
+ return wiring;
+ }
+
+ public Map<String, String> getFlatSubsystemsMap() {
+ Map<String, String> toFlatten = new HashMap<String, String>();
+ findSubsystemsToFlatten(root, toFlatten);
+ return toFlatten;
+ }
+
+ public Map<String, Set<Resource>> getBundlesPerRegions() {
+ return invert(getBundles());
+ }
+
+ public Map<Resource, String> getBundles() {
+ String filter = String.format("(&(%s=*)(|(%s=%s)(%s=%s)))",
+ IDENTITY_NAMESPACE,
+ CAPABILITY_TYPE_ATTRIBUTE, TYPE_BUNDLE,
+ CAPABILITY_TYPE_ATTRIBUTE, TYPE_FRAGMENT);
+ SimpleFilter sf = SimpleFilter.parse(filter);
+ return getResourceMapping(sf);
+ }
+
+ public Map<String, Set<Resource>> getFeaturesPerRegions() {
+ return invert(getFeatures());
+ }
+
+ public Map<Resource, String> getFeatures() {
+ SimpleFilter sf = createFilter(IDENTITY_NAMESPACE, "*",
+ CAPABILITY_TYPE_ATTRIBUTE, TYPE_FEATURE);
+ return getResourceMapping(sf);
+ }
+
+ public Map<String, Set<Resource>> getResourcesPerRegion(SimpleFilter resourceFilter) {
+ return invert(getResourceMapping(resourceFilter));
+ }
+
+ public Map<Resource, String> getResourceMapping(SimpleFilter resourceFilter) {
+ Map<String, String> flats = getFlatSubsystemsMap();
+ Map<Resource, List<Wire>> wiring = getWiring();
+ Map<Resource, String> resources = new HashMap<Resource, String>();
+ SimpleFilter sf = createFilter(IDENTITY_NAMESPACE, "*",
+ CAPABILITY_TYPE_ATTRIBUTE, TYPE_SUBSYSTEM);
+ for (Resource resource : wiring.keySet()) {
+ if (findMatchingCapability(resourceFilter, resource.getCapabilities(null)) != null) {
+ // Find the subsystem where this feature is installed
+ Wire wire = findMatchingWire(sf, wiring.get(resource));
+ if (wire != null) {
+ String region = (String) wire.getCapability().getAttributes().get(IDENTITY_NAMESPACE);
+ region = flats.get(region);
+ resources.put(resource, region);
+ }
+ }
+ }
+ return resources;
+ }
+
+ private void associateFragments() {
+ SimpleFilter sf = createFilter(IDENTITY_NAMESPACE, "*", CAPABILITY_TYPE_ATTRIBUTE, TYPE_SUBSYSTEM);
+ for (Map.Entry<Resource, List<Wire>> entry : wiring.entrySet()) {
+ final Resource resource = entry.getKey();
+ final Requirement requirement = getSubsystemRequirement(resource);
+ if (Util.isFragment(resource)) {
+ List<Wire> wires = entry.getValue();
+ final Resource host = wires.get(0).getProvider();
+ final Wire wire = findMatchingWire(sf, wiring.get(host));
+ if (wire != null) {
+ wires.add(new Wire() {
+ @Override
+ public Capability getCapability() {
+ return wire.getCapability();
+ }
+
+ @Override
+ public Requirement getRequirement() {
+ return requirement;
+ }
+
+ @Override
+ public Resource getProvider() {
+ return wire.getProvider();
+ }
+
+ @Override
+ public Resource getRequirer() {
+ return resource;
+ }
+ });
+ }
+ }
+ }
+ }
+
+ private Requirement getSubsystemRequirement(Resource resource) {
+ for (Requirement requirement : resource.getRequirements(null)) {
+ if (IDENTITY_NAMESPACE.equals(requirement.getNamespace())
+ && TYPE_SUBSYSTEM.equals(requirement.getAttributes().get(CAPABILITY_TYPE_ATTRIBUTE))) {
+ return requirement;
+ }
+ }
+ return null;
+ }
+
+ private Capability findMatchingCapability(SimpleFilter filter, Collection<Capability> caps) {
+ for (Capability cap : caps) {
+ if (CapabilitySet.matches(cap, filter)) {
+ return cap;
+ }
+ }
+ return null;
+ }
+
+ private Wire findMatchingWire(SimpleFilter filter, Collection<Wire> wires) {
+ for (Wire wire : wires) {
+ Capability cap = wire.getCapability();
+ if (CapabilitySet.matches(cap, filter)) {
+ return wire;
+ }
+ }
+ return null;
+ }
+
+ private SimpleFilter createFilter(String... s) {
+ Map<String, Object> attrs = new HashMap<String, Object>();
+ for (int i = 0; i < s.length - 1; i += 2) {
+ attrs.put(s[i], s[i+1]);
+ }
+ return SimpleFilter.convert(attrs);
+
+ }
+
+ private void findSubsystemsToFlatten(Subsystem subsystem, Map<String, String> toFlatten) {
+ Subsystem nonFlat = subsystem;
+ while (isFlat(nonFlat)) {
+ nonFlat = nonFlat.getParent();
+ }
+ toFlatten.put(subsystem.getName(), nonFlat.getName());
+ for (Subsystem child : subsystem.getChildren()) {
+ findSubsystemsToFlatten(child, toFlatten);
+ }
+ }
+
+ private boolean isFlat(Subsystem subsystem) {
+ return subsystem.getFeature() != null && subsystem.getFeature().getScoping() == null;
+ }
+
+ private Subsystem getOrCreateChild(Subsystem ss, String name) {
+ Subsystem child = ss.getChild(name);
+ return child != null ? child : ss.createSubsystem(name, true);
+ }
+
+ private void populateDigraph(RegionDigraph digraph, Subsystem subsystem) throws BundleException, InvalidSyntaxException {
+ Region region = digraph.createRegion(subsystem.getName());
+ if (subsystem.getParent() != null) {
+ Region parent = digraph.getRegion(subsystem.getParent().getName());
+ digraph.connect(region, createRegionFilterBuilder(digraph, subsystem.getImportPolicy()).build(), parent);
+ digraph.connect(parent, createRegionFilterBuilder(digraph, subsystem.getExportPolicy()).build(), region);
+ }
+ for (Subsystem child : subsystem.getChildren()) {
+ populateDigraph(digraph, child);
+ }
+ }
+
+ private RegionFilterBuilder createRegionFilterBuilder(RegionDigraph digraph, Map<String, Set<String>> sharingPolicy) throws InvalidSyntaxException {
+ RegionFilterBuilder result = digraph.createRegionFilterBuilder();
+ for (Map.Entry<String, Set<String>> entry : sharingPolicy.entrySet())
+ for (String filter : entry.getValue())
+ result.allow(entry.getKey(), filter);
+ return result;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/resolver/CandidateComparator.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/CandidateComparator.java b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/CandidateComparator.java
deleted file mode 100644
index ad4cc85..0000000
--- a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/CandidateComparator.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.resolver;
-
-import java.util.Comparator;
-
-import org.osgi.framework.Version;
-import org.osgi.framework.namespace.BundleNamespace;
-import org.osgi.framework.namespace.PackageNamespace;
-import org.osgi.framework.wiring.BundleCapability;
-import org.osgi.resource.Capability;
-
-public class CandidateComparator implements Comparator<Capability>
-{
- public int compare(Capability cap1, Capability cap2)
- {
- int c = 0;
- // Always prefer system bundle
- if (cap1 instanceof BundleCapability && !(cap2 instanceof BundleCapability)) {
- c = -1;
- } else if (!(cap1 instanceof BundleCapability) && cap2 instanceof BundleCapability) {
- c = 1;
- }
- // Compare revision capabilities.
- if ((c == 0) && cap1.getNamespace().equals(BundleNamespace.BUNDLE_NAMESPACE))
- {
- c = ((Comparable) cap1.getAttributes().get(BundleNamespace.BUNDLE_NAMESPACE))
- .compareTo(cap2.getAttributes().get(BundleNamespace.BUNDLE_NAMESPACE));
- if (c == 0)
- {
- Version v1 = (!cap1.getAttributes().containsKey(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE))
- ? Version.emptyVersion
- : (Version) cap1.getAttributes().get(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE);
- Version v2 = (!cap2.getAttributes().containsKey(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE))
- ? Version.emptyVersion
- : (Version) cap2.getAttributes().get(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE);
- // Compare these in reverse order, since we want
- // highest version to have priority.
- c = compareVersions(v2, v1);
- }
- }
- // Compare package capabilities.
- else if ((c == 0) && cap1.getNamespace().equals(PackageNamespace.PACKAGE_NAMESPACE))
- {
- c = ((Comparable) cap1.getAttributes().get(PackageNamespace.PACKAGE_NAMESPACE))
- .compareTo(cap2.getAttributes().get(PackageNamespace.PACKAGE_NAMESPACE));
- if (c == 0)
- {
- Version v1 = (!cap1.getAttributes().containsKey(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE))
- ? Version.emptyVersion
- : (Version) cap1.getAttributes().get(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE);
- Version v2 = (!cap2.getAttributes().containsKey(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE))
- ? Version.emptyVersion
- : (Version) cap2.getAttributes().get(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE);
- // Compare these in reverse order, since we want
- // highest version to have priority.
- c = compareVersions(v2, v1);
- // if same version, rather compare on the bundle version
- if (c == 0)
- {
- v1 = (!cap1.getAttributes().containsKey(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE))
- ? Version.emptyVersion
- : (Version) cap1.getAttributes().get(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE);
- v2 = (!cap2.getAttributes().containsKey(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE))
- ? Version.emptyVersion
- : (Version) cap2.getAttributes().get(BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE);
- // Compare these in reverse order, since we want
- // highest version to have priority.
- c = compareVersions(v2, v1);
- }
- }
- }
- // Compare feature capabilities
- else if ((c == 0) && cap1.getNamespace().equals(FeatureNamespace.FEATURE_NAMESPACE))
- {
- c = ((Comparable) cap1.getAttributes().get(FeatureNamespace.FEATURE_NAMESPACE))
- .compareTo(cap2.getAttributes().get(FeatureNamespace.FEATURE_NAMESPACE));
- if (c == 0)
- {
- Version v1 = (!cap1.getAttributes().containsKey(FeatureNamespace.CAPABILITY_VERSION_ATTRIBUTE))
- ? Version.emptyVersion
- : (Version) cap1.getAttributes().get(FeatureNamespace.CAPABILITY_VERSION_ATTRIBUTE);
- Version v2 = (!cap2.getAttributes().containsKey(FeatureNamespace.CAPABILITY_VERSION_ATTRIBUTE))
- ? Version.emptyVersion
- : (Version) cap2.getAttributes().get(FeatureNamespace.CAPABILITY_VERSION_ATTRIBUTE);
- // Compare these in reverse order, since we want
- // highest version to have priority.
- c = compareVersions(v2, v1);
- }
- }
- return c;
- }
-
- private int compareVersions(Version v1, Version v2) {
- int c = v1.getMajor() - v2.getMajor();
- if (c != 0) {
- return c;
- }
- c = v1.getMinor() - v2.getMinor();
- if (c != 0) {
- return c;
- }
- c = v1.getMicro() - v2.getMicro();
- if (c != 0) {
- return c;
- }
- String q1 = cleanQualifierForComparison(v1.getQualifier());
- String q2 = cleanQualifierForComparison(v2.getQualifier());
- return q1.compareTo(q2);
- }
-
- private String cleanQualifierForComparison(String qualifier) {
- return qualifier.replaceAll("(redhat-[0-9]{3})([0-9]{3})", "$1-$2");
- }
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/resolver/FeatureNamespace.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/FeatureNamespace.java b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/FeatureNamespace.java
deleted file mode 100644
index e211618..0000000
--- a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/FeatureNamespace.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.resolver;
-
-import java.util.List;
-
-import org.osgi.framework.Version;
-import org.osgi.resource.Capability;
-import org.osgi.resource.Namespace;
-import org.osgi.resource.Resource;
-
-/**
- */
-public final class FeatureNamespace extends Namespace {
-
- public static final String FEATURE_NAMESPACE = "karaf.feature";
-
- public static final String CAPABILITY_VERSION_ATTRIBUTE = "version";
-
- /**
- * The attribute value identifying the resource
- * {@link org.osgi.framework.namespace.IdentityNamespace#CAPABILITY_TYPE_ATTRIBUTE type} as an OSGi bundle.
- *
- * @see org.osgi.framework.namespace.IdentityNamespace#CAPABILITY_TYPE_ATTRIBUTE
- */
- public static final String TYPE_FEATURE = "karaf.feature";
-
- public static String getName(Resource resource)
- {
- List<Capability> caps = resource.getCapabilities(null);
- for (Capability cap : caps)
- {
- if (cap.getNamespace().equals(FEATURE_NAMESPACE))
- {
- return cap.getAttributes().get(FEATURE_NAMESPACE).toString();
- }
- }
- return null;
- }
-
- public static Version getVersion(Resource resource)
- {
- List<Capability> caps = resource.getCapabilities(null);
- for (Capability cap : caps)
- {
- if (cap.getNamespace().equals(FEATURE_NAMESPACE))
- {
- return (Version)
- cap.getAttributes().get(CAPABILITY_VERSION_ATTRIBUTE);
- }
- }
- return null;
- }
-
-
- private FeatureNamespace() {
- }
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/resolver/FeatureResource.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/FeatureResource.java b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/FeatureResource.java
index e3b0101..99e1253 100644
--- a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/FeatureResource.java
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/FeatureResource.java
@@ -16,11 +16,9 @@
*/
package org.apache.karaf.features.internal.resolver;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import org.apache.felix.utils.version.VersionRange;
import org.apache.felix.utils.version.VersionTable;
import org.apache.karaf.features.BundleInfo;
import org.apache.karaf.features.Conditional;
@@ -28,22 +26,21 @@ import org.apache.karaf.features.Dependency;
import org.apache.karaf.features.Feature;
import org.apache.karaf.features.internal.util.Macro;
import org.osgi.framework.BundleException;
-import org.osgi.framework.Constants;
-import org.osgi.framework.Version;
-import org.osgi.framework.namespace.IdentityNamespace;
-import org.osgi.resource.Capability;
import org.osgi.resource.Requirement;
import org.osgi.resource.Resource;
+import static org.apache.karaf.features.internal.resolver.ResourceUtils.TYPE_FEATURE;
+import static org.apache.karaf.features.internal.resolver.ResourceUtils.addIdentityRequirement;
+
/**
*/
public class FeatureResource extends ResourceImpl {
private final Feature feature;
- public static Resource build(Feature feature, Conditional conditional, String featureRange, Map<String, Resource> locToRes) throws BundleException {
+ public static FeatureResource build(Feature feature, Conditional conditional, String featureRange, Map<String, Resource> locToRes) throws BundleException {
Feature fcond = conditional.asFeature(feature.getName(), feature.getVersion());
- FeatureResource resource = (FeatureResource) build(fcond, featureRange, locToRes);
+ FeatureResource resource = build(fcond, featureRange, locToRes);
for (String cond : conditional.getCondition()) {
if (cond.startsWith("req:")) {
cond = cond.substring("req:".length());
@@ -66,29 +63,15 @@ public class FeatureResource extends ResourceImpl {
return resource;
}
- public static Resource build(Feature feature, String featureRange, Map<String, Resource> locToRes) throws BundleException {
+ public static FeatureResource build(Feature feature, String featureRange, Map<String, Resource> locToRes) throws BundleException {
FeatureResource resource = new FeatureResource(feature);
- Map<String, String> dirs = new HashMap<String, String>();
- Map<String, Object> attrs = new HashMap<String, Object>();
- attrs.put(FeatureNamespace.FEATURE_NAMESPACE, feature.getName());
- attrs.put(FeatureNamespace.CAPABILITY_VERSION_ATTRIBUTE, VersionTable.getVersion(feature.getVersion()));
- resource.addCapability(new CapabilityImpl(resource, FeatureNamespace.FEATURE_NAMESPACE, dirs, attrs));
for (BundleInfo info : feature.getBundles()) {
if (!info.isDependency()) {
Resource res = locToRes.get(info.getLocation());
if (res == null) {
throw new IllegalStateException("Resource not found for url " + info.getLocation());
}
- List<Capability> caps = res.getCapabilities(IdentityNamespace.IDENTITY_NAMESPACE);
- if (caps.size() != 1) {
- throw new IllegalStateException("Resource does not have a single " + IdentityNamespace.IDENTITY_NAMESPACE + " capability");
- }
- dirs = new HashMap<String, String>();
- attrs = new HashMap<String, Object>();
- attrs.put(IdentityNamespace.IDENTITY_NAMESPACE, caps.get(0).getAttributes().get(IdentityNamespace.IDENTITY_NAMESPACE));
- attrs.put(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE, caps.get(0).getAttributes().get(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE));
- attrs.put(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, new VersionRange((Version) caps.get(0).getAttributes().get(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE), true));
- resource.addRequirement(new RequirementImpl(resource, IdentityNamespace.IDENTITY_NAMESPACE, dirs, attrs));
+ addIdentityRequirement(resource, res);
}
}
for (Dependency dep : feature.getDependencies()) {
@@ -104,8 +87,6 @@ public class FeatureResource extends ResourceImpl {
}
protected static void addDependency(FeatureResource resource, Dependency dep, String featureRange) {
- Map<String, String> dirs;
- Map<String, Object> attrs;
String name = dep.getName();
String version = dep.getVersion();
if (version.equals("0.0.0")) {
@@ -113,17 +94,11 @@ public class FeatureResource extends ResourceImpl {
} else if (!version.startsWith("[") && !version.startsWith("(")) {
version = Macro.transform(featureRange, version);
}
- dirs = new HashMap<String, String>();
- attrs = new HashMap<String, Object>();
- attrs.put(FeatureNamespace.FEATURE_NAMESPACE, name);
- if (version != null) {
- attrs.put(FeatureNamespace.CAPABILITY_VERSION_ATTRIBUTE, new VersionRange(version));
- }
- resource.addRequirement(new RequirementImpl(resource, FeatureNamespace.FEATURE_NAMESPACE, dirs, attrs));
+ addIdentityRequirement(resource, name, TYPE_FEATURE, version);
}
public FeatureResource(Feature feature) {
- super(feature.getName(), FeatureNamespace.TYPE_FEATURE, VersionTable.getVersion(feature.getVersion()));
+ super(feature.getName(), TYPE_FEATURE, VersionTable.getVersion(feature.getVersion()));
this.feature = feature;
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/resolver/IdentityCapability.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/IdentityCapability.java b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/IdentityCapability.java
index cdc00d1..20e94fa 100644
--- a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/IdentityCapability.java
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/IdentityCapability.java
@@ -24,7 +24,7 @@ import org.osgi.framework.namespace.IdentityNamespace;
import org.osgi.resource.Capability;
import org.osgi.resource.Resource;
-class IdentityCapability extends BaseClause implements Capability
+public class IdentityCapability extends BaseClause implements Capability
{
private final Resource m_resource;
private final Map<String, String> m_dirs;
http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResolveContextImpl.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResolveContextImpl.java b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResolveContextImpl.java
deleted file mode 100644
index e2ff793..0000000
--- a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResolveContextImpl.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.resolver;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.osgi.framework.Constants;
-import org.osgi.resource.Capability;
-import org.osgi.resource.Requirement;
-import org.osgi.resource.Resource;
-import org.osgi.resource.Wiring;
-import org.osgi.service.repository.Repository;
-import org.osgi.service.resolver.HostedCapability;
-import org.osgi.service.resolver.ResolveContext;
-
-/**
-*/
-public class ResolveContextImpl extends ResolveContext {
-
- private final Set<Resource> mandatory;
- private final Set<Resource> optional;
- private final Repository repository;
- private final Map<Resource, Wiring> wirings;
- private final boolean resolveOptional;
-
- private final CandidateComparator candidateComparator = new CandidateComparator();
-
- public ResolveContextImpl(Set<Resource> mandatory,
- Set<Resource> optional,
- Repository repository,
- boolean resolveOptional) {
- this.mandatory = mandatory;
- this.optional = optional;
- this.repository = repository;
- this.wirings = new HashMap<Resource, Wiring>();
- this.resolveOptional = resolveOptional;
- }
-
- @Override
- public Collection<Resource> getMandatoryResources() {
- return mandatory;
- }
-
- @Override
- public Collection<Resource> getOptionalResources() {
- return optional;
- }
-
- @Override
- public List<Capability> findProviders(Requirement requirement) {
- List<Capability> caps = new ArrayList<Capability>();
- Map<Requirement, Collection<Capability>> resMap =
- repository.findProviders(Collections.singleton(requirement));
- Collection<Capability> res = resMap != null ? resMap.get(requirement) : null;
- if (res != null) {
- caps.addAll(res);
- }
- Collections.sort(caps, candidateComparator);
- return caps;
- }
- @Override
- public int insertHostedCapability(List capabilities, HostedCapability hostedCapability) {
- for (int i=0; i < capabilities.size(); i++) {
- Capability cap = (Capability) capabilities.get(i);
- if (candidateComparator.compare(hostedCapability, cap) <= 0) {
- capabilities.add(i, hostedCapability);
- return i;
- }
- }
- capabilities.add(hostedCapability);
- return capabilities.size() - 1;
- }
- @Override
- public boolean isEffective(Requirement requirement) {
- return resolveOptional ||
- !Constants.RESOLUTION_OPTIONAL.equals(requirement.getDirectives().get(Constants.RESOLUTION_DIRECTIVE));
- }
- @Override
- public Map<Resource, Wiring> getWirings() {
- return wirings;
- }
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResourceBuilder.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResourceBuilder.java b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResourceBuilder.java
index cb2c36a..941ed8c 100644
--- a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResourceBuilder.java
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResourceBuilder.java
@@ -35,12 +35,13 @@ import org.osgi.framework.wiring.BundleRevision;
import org.osgi.resource.Capability;
import org.osgi.resource.Requirement;
import org.osgi.resource.Resource;
+import org.osgi.service.repository.ContentNamespace;
public class ResourceBuilder {
public static final String RESOLUTION_DYNAMIC = "dynamic";
- public static Resource build(String uri, Map<String, String> headerMap)
+ public static ResourceImpl build(String uri, Map<String, String> headerMap)
throws BundleException {
// Verify that only manifest version 2 is specified.
@@ -74,8 +75,8 @@ public class ResourceBuilder {
ResourceImpl resource = new ResourceImpl(bundleSymbolicName, type, bundleVersion);
if (uri != null) {
Map<String, Object> attrs = new HashMap<String, Object>();
- attrs.put(UriNamespace.URI_NAMESPACE, uri);
- resource.addCapability(new CapabilityImpl(resource, UriNamespace.URI_NAMESPACE, Collections.<String, String>emptyMap(), attrs));
+ attrs.put(ContentNamespace.CAPABILITY_URL_ATTRIBUTE, uri);
+ resource.addCapability(new CapabilityImpl(resource, ContentNamespace.CONTENT_NAMESPACE, Collections.<String, String>emptyMap(), attrs));
}
// Add a bundle and host capability to all
http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResourceUtils.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResourceUtils.java b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResourceUtils.java
new file mode 100644
index 0000000..03d4fd9
--- /dev/null
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/ResourceUtils.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.features.internal.resolver;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.utils.version.VersionRange;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+import org.osgi.resource.Capability;
+import org.osgi.resource.Resource;
+
+import static org.osgi.framework.namespace.IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE;
+import static org.osgi.framework.namespace.IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE;
+import static org.osgi.framework.namespace.IdentityNamespace.IDENTITY_NAMESPACE;
+import static org.osgi.service.repository.ContentNamespace.CAPABILITY_URL_ATTRIBUTE;
+import static org.osgi.service.repository.ContentNamespace.CONTENT_NAMESPACE;
+
+public class ResourceUtils {
+
+ public static final String TYPE_SUBSYSTEM = "karaf.subsystem";
+
+ public static final String TYPE_FEATURE = "karaf.feature";
+
+ public static String getUri(Resource resource) {
+ List<Capability> caps = resource.getCapabilities(null);
+ for (Capability cap : caps) {
+ if (cap.getNamespace().equals(CONTENT_NAMESPACE)) {
+ return cap.getAttributes().get(CAPABILITY_URL_ATTRIBUTE).toString();
+ }
+ }
+ return null;
+ }
+
+ public static String getFeatureId(Resource resource) {
+ List<Capability> caps = resource.getCapabilities(null);
+ for (Capability cap : caps) {
+ if (cap.getNamespace().equals(IDENTITY_NAMESPACE)) {
+ Map<String, Object> attributes = cap.getAttributes();
+ if (TYPE_FEATURE.equals(attributes.get(CAPABILITY_TYPE_ATTRIBUTE))) {
+ String name = (String) attributes.get(IDENTITY_NAMESPACE);
+ Version version = (Version) attributes.get(CAPABILITY_VERSION_ATTRIBUTE);
+ return version != null ? name + "/" + version : name;
+ }
+ }
+ }
+ return null;
+ }
+
+ public static void addIdentityRequirement(ResourceImpl resource, String name, String type, String range) {
+ Map<String, String> dirs = new HashMap<String, String>();
+ Map<String, Object> attrs = new HashMap<String, Object>();
+ if (name != null) {
+ attrs.put(IDENTITY_NAMESPACE, name);
+ }
+ if (type != null) {
+ attrs.put(CAPABILITY_TYPE_ATTRIBUTE, type);
+ }
+ if (range != null) {
+ attrs.put(CAPABILITY_VERSION_ATTRIBUTE, new VersionRange(range));
+ }
+ resource.addRequirement(new RequirementImpl(resource, IDENTITY_NAMESPACE, dirs, attrs));
+ }
+
+ public static void addIdentityRequirement(ResourceImpl resource, Resource required) {
+ addIdentityRequirement(resource, required, true);
+ }
+
+ public static void addIdentityRequirement(ResourceImpl resource, Resource required, boolean mandatory) {
+ for (Capability cap : required.getCapabilities(null)) {
+ if (cap.getNamespace().equals(IDENTITY_NAMESPACE)) {
+ Map<String, Object> attributes = cap.getAttributes();
+ Map<String, String> dirs = new HashMap<String, String>();
+ dirs.put(Constants.RESOLUTION_DIRECTIVE, mandatory ? Constants.RESOLUTION_MANDATORY : Constants.RESOLUTION_OPTIONAL);
+ Map<String, Object> attrs = new HashMap<String, Object>();
+ attrs.put(IDENTITY_NAMESPACE, attributes.get(IDENTITY_NAMESPACE));
+ attrs.put(CAPABILITY_TYPE_ATTRIBUTE, attributes.get(CAPABILITY_TYPE_ATTRIBUTE));
+ Version version = (Version) attributes.get(CAPABILITY_VERSION_ATTRIBUTE);
+ if (version != null) {
+ attrs.put(CAPABILITY_VERSION_ATTRIBUTE, new VersionRange(version, true));
+ }
+ resource.addRequirement(new RequirementImpl(resource, IDENTITY_NAMESPACE, dirs, attrs));
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/resolver/UriNamespace.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/UriNamespace.java b/features/core/src/main/java/org/apache/karaf/features/internal/resolver/UriNamespace.java
deleted file mode 100644
index b5158bf..0000000
--- a/features/core/src/main/java/org/apache/karaf/features/internal/resolver/UriNamespace.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.features.internal.resolver;
-
-import java.util.List;
-
-import org.osgi.resource.Capability;
-import org.osgi.resource.Namespace;
-import org.osgi.resource.Resource;
-
-/**
- */
-public final class UriNamespace extends Namespace {
-
- public static final String URI_NAMESPACE = "karaf.uri";
-
- public static String getUri(Resource resource)
- {
- List<Capability> caps = resource.getCapabilities(null);
- for (Capability cap : caps)
- {
- if (cap.getNamespace().equals(UriNamespace.URI_NAMESPACE))
- {
- return cap.getAttributes().get(UriNamespace.URI_NAMESPACE).toString();
- }
- }
- return null;
- }
-
-
- private UriNamespace() {
- }
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2705ad88/features/core/src/main/java/org/apache/karaf/features/internal/service/FeatureConfigInstaller.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/FeatureConfigInstaller.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/FeatureConfigInstaller.java
index 0e9038d..258b44b 100644
--- a/features/core/src/main/java/org/apache/karaf/features/internal/service/FeatureConfigInstaller.java
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/FeatureConfigInstaller.java
@@ -45,6 +45,26 @@ public class FeatureConfigInstaller {
this.configAdmin = configAdmin;
}
+ public void installFeatureConfigs(Feature feature) throws IOException, InvalidSyntaxException {
+ for (String config : feature.getConfigurations().keySet()) {
+ Dictionary<String,String> props = new Hashtable<String, String>(feature.getConfigurations().get(config));
+ String[] pid = parsePid(config);
+ Configuration cfg = findExistingConfiguration(configAdmin, pid[0], pid[1]);
+ if (cfg == null) {
+ cfg = createConfiguration(configAdmin, pid[0], pid[1]);
+ String key = createConfigurationKey(pid[0], pid[1]);
+ props.put(CONFIG_KEY, key);
+ if (cfg.getBundleLocation() != null) {
+ cfg.setBundleLocation(null);
+ }
+ cfg.update(props);
+ }
+ }
+ for (ConfigFileInfo configFile : feature.getConfigurationFiles()) {
+ installConfigurationFile(configFile.getLocation(), configFile.getFinalname(), configFile.isOverride());
+ }
+ }
+
private String[] parsePid(String pid) {
int n = pid.indexOf('-');
if (n > 0) {
@@ -81,26 +101,6 @@ public class FeatureConfigInstaller {
return null;
}
- void installFeatureConfigs(Feature feature) throws IOException, InvalidSyntaxException {
- for (String config : feature.getConfigurations().keySet()) {
- Dictionary<String,String> props = new Hashtable<String, String>(feature.getConfigurations().get(config));
- String[] pid = parsePid(config);
- Configuration cfg = findExistingConfiguration(configAdmin, pid[0], pid[1]);
- if (cfg == null) {
- cfg = createConfiguration(configAdmin, pid[0], pid[1]);
- String key = createConfigurationKey(pid[0], pid[1]);
- props.put(CONFIG_KEY, key);
- if (cfg.getBundleLocation() != null) {
- cfg.setBundleLocation(null);
- }
- cfg.update(props);
- }
- }
- for (ConfigFileInfo configFile : feature.getConfigurationFiles()) {
- installConfigurationFile(configFile.getLocation(), configFile.getFinalname(), configFile.isOverride());
- }
- }
-
private String createConfigurationKey(String pid, String factoryPid) {
return factoryPid == null ? pid : pid + "-" + factoryPid;
}