Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTodor Boev2018-01-03 12:48:52 -0500
committerAlexander Kurtakov2018-01-16 13:56:02 -0500
commita7a99e1fa49938a8f62d44d5c443d38981afeace (patch)
tree8d9152f0908a5030f2a93a818d6bb0b07facb946 /bundles/org.eclipse.equinox.p2.metadata
parentf539d2ad9b77c9a9f03b9f4cdad08c5847dc8025 (diff)
downloadrt.equinox.p2-a7a99e1fa49938a8f62d44d5c443d38981afeace.tar.gz
rt.equinox.p2-a7a99e1fa49938a8f62d44d5c443d38981afeace.tar.xz
rt.equinox.p2-a7a99e1fa49938a8f62d44d5c443d38981afeace.zip
Bug 528387 - Dedicated xml elements for generic requirementsI20180119-0110I20180118-2000I20180117-2000
- Renamed IProvidedCapability.getAttributes() to getProperties(). This is in sync with other parts of p2 that use "properties" for such data. E.g. the IU properties. - Extended content.xml read/write with a new serialization format for requirements with the "requiredProperties" element. It is used to build an IRequirement that has a standard match expression that applies an LDAP filter to the capability properties. It was not possible to extend the existing "required" element in a way that will make old p2 builds ignore the extended version. - Extended the content.xml read/write shared properties handling logic with "type" attribute. Older p2 builds will ignore it and use strings. Also the "type" attribute only appears in the "properties" extension of "provides" which will be ignored by old p2 builds to begin with. - Some additional cleanup to the content.xml read/write - Increased the current content.xml format version from 1.1.0 to 1.2.0. Old p2 builds declare compatibility with [1.0.0, 2). - Made the handling of the property types supported by a capability safer. E.g. unknown types are converted to Strings. E.g. ProvidedCapability verifies that only supported types are used. - Made the handling of generic requirements reflect the real semantics. E.g. with correct handling of the resolution:=optional|mandatory flag rather than to declare everything optional to avoid breakages in older p2 builds. This is possible because the "requiredProperties" element is completely ignored by older builds. E.g. now if an extender or service is missing provisioning will fail as it is supposed to. - Added factory methods to MetadataFactory for LDAP based requirements. - Added a planner test for LDAP requirements - Cleaned up the AutomatedDirectorTest - Cleaned up some LDAP matching test cases. Change-Id: Ifff77b3ea4c9cea33fd236ed101b1f33c173891d Signed-off-by: Todor Boev <rinsvind@gmail.com>
Diffstat (limited to 'bundles/org.eclipse.equinox.p2.metadata')
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/ProvidedCapability.java125
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/RequiredCapability.java51
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/RequiredPropertiesMatch.java84
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/Requirement.java14
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/CoercingComparator.java4
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/index/CapabilityIndex.java4
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/messages.properties2
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/IProvidedCapability.java39
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/MetadataFactory.java137
9 files changed, 307 insertions, 153 deletions
diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/ProvidedCapability.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/ProvidedCapability.java
index 13eb67642..31297abf8 100644
--- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/ProvidedCapability.java
+++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/ProvidedCapability.java
@@ -9,10 +9,14 @@
* IBM Corporation - initial API and implementation
* EclipseSource - ongoing development
* SAP - ongoing development
+ * Todor Boev
*******************************************************************************/
package org.eclipse.equinox.internal.p2.metadata;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.eclipse.core.runtime.Assert;
@@ -31,44 +35,65 @@ public class ProvidedCapability implements IProvidedCapability, IMemberProvider
public static final String MEMBER_NAME = "name"; //$NON-NLS-1$
/** Used for fast access from P2 queries to the {@link #getVersion} method */
public static final String MEMBER_VERSION = "version"; //$NON-NLS-1$
- /** Used for fast access from P2 queries to the {@link #getAttributes} method */
- public static final String MEMBER_ATTRIBUTES = "attributes"; //$NON-NLS-1$
-
- // TODO Move this to IProvidedCapability?
- // The "version" attribute is part of the public contract of getVersion() and getAttributes()
- public static final String ATTRIBUTE_VERSION = "version"; //$NON-NLS-1$
+ /** Used for fast access from P2 queries to the {@link #getProperties} method */
+ public static final String MEMBER_PROPERTIES = "properties"; //$NON-NLS-1$
private final String namespace;
- private final Map<String, Object> attributes;
+ private final Map<String, Object> properties;
- public ProvidedCapability(String namespace, Map<String, Object> attrs) {
+ public ProvidedCapability(String namespace, Map<String, Object> props) {
Assert.isNotNull(namespace, NLS.bind(Messages.provided_capability_namespace_not_defined, null));
this.namespace = namespace;
- Assert.isNotNull(attrs);
- Assert.isTrue(!attrs.isEmpty());
+ Assert.isNotNull(props);
+ Assert.isTrue(!props.isEmpty());
+
+ assertValidPropertyTypes(props);
- this.attributes = new HashMap<>(attrs);
+ Map<String, Object> resolvedProps = new HashMap<>(props);
// Verify the name
- Assert.isTrue(attributes.containsKey(namespace) && (attributes.get(namespace) instanceof String), NLS.bind(Messages.provided_capability_name_not_defined, namespace));
+ Assert.isTrue(resolvedProps.containsKey(namespace) && (resolvedProps.get(namespace) instanceof String), NLS.bind(Messages.provided_capability_name_not_defined, namespace));
// Verify the version
- Object version = attributes.get(ATTRIBUTE_VERSION);
+ Object version = resolvedProps.get(PROPERTY_VERSION);
if (version != null) {
- Assert.isTrue(attributes.get(ATTRIBUTE_VERSION) instanceof Version);
+ Assert.isTrue(props.get(PROPERTY_VERSION) instanceof Version);
} else {
- attributes.put(ATTRIBUTE_VERSION, Version.emptyVersion);
+ resolvedProps.put(PROPERTY_VERSION, Version.emptyVersion);
}
+
+ this.properties = Collections.unmodifiableMap(props);
}
public ProvidedCapability(String namespace, String name, Version version) {
Assert.isNotNull(namespace, NLS.bind(Messages.provided_capability_namespace_not_defined, null));
Assert.isNotNull(name, NLS.bind(Messages.provided_capability_name_not_defined, namespace));
this.namespace = namespace;
- this.attributes = new HashMap<>();
- attributes.put(namespace, name);
- attributes.put(ATTRIBUTE_VERSION, version == null ? Version.emptyVersion : version);
+ this.properties = new HashMap<>();
+ properties.put(namespace, name);
+ properties.put(PROPERTY_VERSION, version == null ? Version.emptyVersion : version);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder str = new StringBuilder();
+ str.append(namespace);
+
+ for (Entry<String, Object> attr : properties.entrySet()) {
+ String key = attr.getKey();
+ Object val = attr.getValue();
+ String type = val.getClass().getSimpleName();
+
+ str.append("; ").append(key).append(":").append(type).append("=").append(val); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ return str.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ return namespace.hashCode() * properties.hashCode();
}
@Override
@@ -87,7 +112,7 @@ public class ProvidedCapability implements IProvidedCapability, IMemberProvider
return false;
}
- if (!(attributes.equals(otherCapability.getAttributes()))) {
+ if (!(properties.equals(otherCapability.getProperties()))) {
return false;
}
@@ -101,38 +126,17 @@ public class ProvidedCapability implements IProvidedCapability, IMemberProvider
@Override
public String getName() {
- return (String) attributes.get(namespace);
+ return (String) properties.get(namespace);
}
@Override
public Version getVersion() {
- return (Version) attributes.get(ATTRIBUTE_VERSION);
+ return (Version) properties.get(PROPERTY_VERSION);
}
@Override
- public Map<String, Object> getAttributes() {
- return attributes;
- }
-
- @Override
- public int hashCode() {
- return namespace.hashCode() * attributes.hashCode();
- }
-
- @Override
- public String toString() {
- StringBuilder str = new StringBuilder();
- str.append(namespace);
-
- for (Entry<String, Object> attr : attributes.entrySet()) {
- String key = attr.getKey();
- Object val = attr.getValue();
- String type = val.getClass().getSimpleName();
-
- str.append("; ").append(key).append(":").append(type).append("=").append(val); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- }
-
- return str.toString();
+ public Map<String, Object> getProperties() {
+ return properties;
}
@Override
@@ -141,13 +145,36 @@ public class ProvidedCapability implements IProvidedCapability, IMemberProvider
case MEMBER_NAMESPACE :
return namespace;
case MEMBER_NAME :
- return attributes.get(namespace);
+ return properties.get(namespace);
case MEMBER_VERSION :
- return attributes.get(ATTRIBUTE_VERSION);
- case MEMBER_ATTRIBUTES :
- return attributes;
+ return properties.get(PROPERTY_VERSION);
+ case MEMBER_PROPERTIES :
+ return properties;
default :
- throw new IllegalArgumentException("No such member: " + memberName); //$NON-NLS-1$
+ throw new IllegalArgumentException(String.format("No such member: %s", memberName)); //$NON-NLS-1$
+ }
+ }
+
+ private void assertValidPropertyTypes(Map<String, Object> props) {
+ props.forEach(this::assertValidValueType);
+ }
+
+ private void assertValidValueType(String key, Object prop) {
+ if (prop instanceof List<?>) {
+ int idx = 0;
+ for (Object scalar : (List<?>) prop) {
+ assertValidScalarType(String.format("%s[%s]", key, idx++), scalar); //$NON-NLS-1$
+ }
+ } else {
+ assertValidScalarType(key, prop);
}
}
+
+ private void assertValidScalarType(String key, Object scalar) {
+ Arrays.asList(Version.class, String.class, Long.class, Integer.class, Short.class, Byte.class, Double.class, Float.class, Boolean.class, Character.class)
+ .stream()
+ .filter(t -> t.isAssignableFrom(scalar.getClass()))
+ .findFirst()
+ .orElseThrow(() -> new IllegalArgumentException(String.format("Invalid type %s of property %s", scalar.getClass(), key))); //$NON-NLS-1$
+ }
}
diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/RequiredCapability.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/RequiredCapability.java
index cd8f8dac8..c08af575d 100644
--- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/RequiredCapability.java
+++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/RequiredCapability.java
@@ -39,27 +39,14 @@ import org.eclipse.equinox.p2.metadata.expression.IMatchExpression;
* @see IInstallableUnit#NAMESPACE_IU_ID
*/
public class RequiredCapability extends Requirement implements IRequiredCapability {
- private static final IExpression simpleMatchExpression;
-
- static {
- IExpressionFactory factory = ExpressionUtil.getFactory();
-
- IExpression xVar = factory.variable("cap"); //$NON-NLS-1$
-
- IExpression name = factory.member(xVar, MEMBER_NAME);
- IExpression nameEqual = factory.equals(name, factory.indexedParameter(0));
-
- IExpression namespace = factory.member(xVar, MEMBER_NAMESPACE);
- IExpression namespaceEqual = factory.equals(namespace, factory.indexedParameter(1));
-
- IExpression version = factory.member(xVar, MEMBER_VERSION);
- IExpression versionInRange = factory.matches(version, factory.indexedParameter(2));
-
- IExpression pvMember = factory.member(factory.thisVariable(), MEMBER_PROVIDED_CAPABILITIES);
-
- // Place nameEqual first to eliminate quickly most non-matching candidates
- simpleMatchExpression = factory.exists(pvMember, factory.lambda(xVar, factory.and(nameEqual, namespaceEqual, versionInRange)));
- }
+ /**
+ * Argument $0 must evaluate to a String
+ * Argument $1 must evaluate to a String
+ * Argument $2 must evaluate to a {@link VersionRange}
+ */
+ private static final IExpression VERSION_RANGE_MATCH = ExpressionUtil.parse(
+ String.format("%s.exists(cap | cap.%s == $0 && cap.%s == $1 && cap.%s ~= $2)", //$NON-NLS-1$
+ MEMBER_PROVIDED_CAPABILITIES, MEMBER_NAME, MEMBER_NAMESPACE, MEMBER_VERSION));
/**
* TODO Remove. This is a private impl class. Users must call the analogous MetadataFactory.createRequirement()
@@ -104,17 +91,11 @@ public class RequiredCapability extends Requirement implements IRequiredCapabili
public String toString() {
StringBuilder result = new StringBuilder();
- // Namespace
result.append(getNamespace());
- result.append(' ');
-
- // Name
+ result.append("; "); //$NON-NLS-1$
result.append(getName());
- result.append(' ');
-
- // Version range
- VersionRange range = getRange();
- result.append(range);
+ result.append(" "); //$NON-NLS-1$
+ result.append(getRange());
return result.toString();
}
@@ -124,7 +105,7 @@ public class RequiredCapability extends Requirement implements IRequiredCapabili
Assert.isNotNull(name);
Object resolvedRange = (range != null) ? range : VersionRange.emptyRange;
IExpressionFactory factory = ExpressionUtil.getFactory();
- return factory.matchExpression(simpleMatchExpression, name, namespace, resolvedRange);
+ return factory.matchExpression(VERSION_RANGE_MATCH, name, namespace, resolvedRange);
}
public static String extractNamespace(IMatchExpression<IInstallableUnit> matchExpression) {
@@ -144,7 +125,7 @@ public class RequiredCapability extends Requirement implements IRequiredCapabili
}
public static boolean isVersionStrict(IMatchExpression<IInstallableUnit> matchExpression) {
- if (!isSimpleRequirement(matchExpression)) {
+ if (!isVersionRangeRequirement(matchExpression)) {
return false;
}
@@ -153,12 +134,12 @@ public class RequiredCapability extends Requirement implements IRequiredCapabili
return range.getMinimum().equals(range.getMaximum());
}
- public static boolean isSimpleRequirement(IMatchExpression<IInstallableUnit> matchExpression) {
- return simpleMatchExpression.equals(ExpressionUtil.getOperand(matchExpression));
+ public static boolean isVersionRangeRequirement(IMatchExpression<IInstallableUnit> matchExpression) {
+ return VERSION_RANGE_MATCH.equals(ExpressionUtil.getOperand(matchExpression));
}
private static void assertValid(IMatchExpression<IInstallableUnit> matchExpression) {
- if (!isSimpleRequirement(matchExpression)) {
+ if (!isVersionRangeRequirement(matchExpression)) {
throw new IllegalArgumentException();
}
}
diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/RequiredPropertiesMatch.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/RequiredPropertiesMatch.java
new file mode 100644
index 000000000..a108fadc0
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/RequiredPropertiesMatch.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2017 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Todor Boev
+ *******************************************************************************/
+package org.eclipse.equinox.internal.p2.metadata;
+
+import static org.eclipse.equinox.internal.p2.metadata.InstallableUnit.MEMBER_PROVIDED_CAPABILITIES;
+import static org.eclipse.equinox.internal.p2.metadata.ProvidedCapability.MEMBER_NAMESPACE;
+import static org.eclipse.equinox.internal.p2.metadata.ProvidedCapability.MEMBER_PROPERTIES;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.equinox.p2.metadata.IInstallableUnit;
+import org.eclipse.equinox.p2.metadata.IProvidedCapability;
+import org.eclipse.equinox.p2.metadata.IRequirement;
+import org.eclipse.equinox.p2.metadata.expression.ExpressionUtil;
+import org.eclipse.equinox.p2.metadata.expression.IExpression;
+import org.eclipse.equinox.p2.metadata.expression.IExpressionFactory;
+import org.eclipse.equinox.p2.metadata.expression.IFilterExpression;
+import org.eclipse.equinox.p2.metadata.expression.IMatchExpression;
+
+/**
+ * A required capability match represents some external constraint on an {@link IInstallableUnit}.
+ * <p>
+ * This is a flavor of the general {@link IRequirement} that searches for
+ * a capability that has {@link IProvidedCapability#getProperties() properties} that match a given expression.
+ * I.e. this is much more limited that an arbitrary match expression executed over all metadata of the IU.
+ */
+public class RequiredPropertiesMatch extends Requirement {
+ /**
+ * Argument $0 must evaluate to a String
+ * Argument $2 must evaluate to an expression compatible with the match operator "~="
+ */
+ private static final IExpression PROPERTIES_MATCH = ExpressionUtil.parse(
+ String.format("%s.exists(cap | cap.%s == $0 && cap.%s ~= $1)", //$NON-NLS-1$
+ MEMBER_PROVIDED_CAPABILITIES, MEMBER_NAMESPACE, MEMBER_PROPERTIES));
+
+ public RequiredPropertiesMatch(String namespace, IFilterExpression attrFilter, IMatchExpression<IInstallableUnit> envFilter, int min, int max, boolean greedy, String description) {
+ super(createMatchExpressionFromFilter(namespace, attrFilter), envFilter, min, max, greedy, description);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder result = new StringBuilder();
+
+ result.append(extractNamespace(getMatches()));
+ result.append("; "); //$NON-NLS-1$
+ result.append(extractPropertiesMatch(getMatches()));
+
+ return result.toString();
+ }
+
+ public static IMatchExpression<IInstallableUnit> createMatchExpressionFromFilter(String namespace, IFilterExpression attrFilter) {
+ Assert.isNotNull(namespace);
+ Assert.isNotNull(attrFilter);
+ IExpressionFactory factory = ExpressionUtil.getFactory();
+ return factory.matchExpression(PROPERTIES_MATCH, namespace, attrFilter);
+ }
+
+ public static String extractNamespace(IMatchExpression<IInstallableUnit> matchExpression) {
+ assertValid(matchExpression);
+ return (String) matchExpression.getParameters()[0];
+ }
+
+ public static IFilterExpression extractPropertiesMatch(IMatchExpression<IInstallableUnit> matchExpression) {
+ assertValid(matchExpression);
+ return (IFilterExpression) matchExpression.getParameters()[1];
+ }
+
+ public static boolean isPropertiesMatchRequirement(IMatchExpression<IInstallableUnit> matchExpression) {
+ return PROPERTIES_MATCH.equals(ExpressionUtil.getOperand(matchExpression));
+ }
+
+ private static void assertValid(IMatchExpression<IInstallableUnit> matchExpression) {
+ if (!isPropertiesMatchRequirement(matchExpression)) {
+ throw new IllegalArgumentException();
+ }
+ }
+}
diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/Requirement.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/Requirement.java
index 036721c5f..5fe660e82 100644
--- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/Requirement.java
+++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/Requirement.java
@@ -11,7 +11,11 @@
*******************************************************************************/
package org.eclipse.equinox.internal.p2.metadata;
-import org.eclipse.equinox.p2.metadata.*;
+import org.eclipse.equinox.p2.metadata.IInstallableUnit;
+import org.eclipse.equinox.p2.metadata.IProvidedCapability;
+import org.eclipse.equinox.p2.metadata.IRequirement;
+import org.eclipse.equinox.p2.metadata.MetadataFactory;
+import org.eclipse.equinox.p2.metadata.VersionRange;
import org.eclipse.equinox.p2.metadata.expression.IMatchExpression;
import org.eclipse.equinox.p2.metadata.expression.IMemberProvider;
@@ -66,10 +70,14 @@ public class Requirement implements IRequirement, IMemberProvider {
// Parameters
Object[] params = matchExpression.getParameters();
if (params.length > 0) {
- result.append(' ');
+ result.append(" ("); //$NON-NLS-1$
for (int i = 0; i < params.length; i++) {
- result.append(params[i]).append(' ');
+ if (i > 0) {
+ result.append(", "); //$NON-NLS-1$
+ }
+ result.append(params[i]);
}
+ result.append(')');
}
return result.toString();
diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/CoercingComparator.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/CoercingComparator.java
index 6cb8008f7..c6d31687d 100644
--- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/CoercingComparator.java
+++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/CoercingComparator.java
@@ -229,8 +229,6 @@ public abstract class CoercingComparator<T> {
Version coerce(Object v) {
if (v instanceof Version)
return (Version) v;
- if (v instanceof String)
- return Version.create((String) v);
if (v instanceof String) {
try {
return Version.create((String) v);
@@ -333,7 +331,7 @@ public abstract class CoercingComparator<T> {
* @return The coercing comparator
*/
@SuppressWarnings("unchecked")
- public static <V extends Object> CoercingComparator<V> getComparator(V value, Object v2) {
+ public static <V> CoercingComparator<V> getComparator(V value, Object v2) {
Class<V> vClass = (Class<V>) value.getClass();
CoercingComparator<?>[] carr = coercers;
int idx = carr.length;
diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/index/CapabilityIndex.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/index/CapabilityIndex.java
index d7b2b3cac..8d89b2d13 100644
--- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/index/CapabilityIndex.java
+++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/index/CapabilityIndex.java
@@ -110,7 +110,7 @@ public class CapabilityIndex extends Index<IInstallableUnit> {
// index usage query
//
IMatchExpression<IInstallableUnit> rm = ((IRequirement) rhsObj).getMatches();
- return RequiredCapability.isSimpleRequirement(rm) ? concatenateUnique(queriedKeys, rm.getParameters()[0]) : getRequirementIDs(rm.createContext(), ((Unary) rm).operand, queriedKeys);
+ return RequiredCapability.isVersionRangeRequirement(rm) ? concatenateUnique(queriedKeys, rm.getParameters()[0]) : getRequirementIDs(rm.createContext(), ((Unary) rm).operand, queriedKeys);
}
@Override
@@ -185,7 +185,7 @@ public class CapabilityIndex extends Index<IInstallableUnit> {
// index usage query
//
IMatchExpression<IInstallableUnit> rm = ((IRequirement) rhsObj).getMatches();
- queriedKeys = RequiredCapability.isSimpleRequirement(rm) ? concatenateUnique(queriedKeys, rm.getParameters()[0]) : getRequirementIDs(rm.createContext(), ((Unary) rm).operand, queriedKeys);
+ queriedKeys = RequiredCapability.isVersionRangeRequirement(rm) ? concatenateUnique(queriedKeys, rm.getParameters()[0]) : getRequirementIDs(rm.createContext(), ((Unary) rm).operand, queriedKeys);
break;
default :
diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/messages.properties b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/messages.properties
index aa3b72b2e..ac979c288 100644
--- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/messages.properties
+++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/messages.properties
@@ -60,7 +60,7 @@ premature_end_of_format=Premature end of format
premature_end_of_format_expected_0=Premature end of format, "{0}" expected
premature_EOS_0=Premature end of string in "{0}"
provided_capability_name_not_defined=the name of provided capability "{0}" is not defined
-provided_capability_namespace_not_defined=the namespace of the provided capabilty is not defined
+provided_capability_namespace_not_defined=the namespace of the provided capability is not defined
range_defined_more_then_once=Range defined more then once
range_max_cannot_be_less_then_range_min=The range maximum must not be less then its minimum
range_max_cannot_be_zero=The range maximum cannot be zero
diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/IProvidedCapability.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/IProvidedCapability.java
index de61165eb..7cf08a170 100644
--- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/IProvidedCapability.java
+++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/IProvidedCapability.java
@@ -6,11 +6,13 @@
*
* Contributors:
* EclipseSource - initial API and implementation
- * IBM - ongoing development
+* IBM - ongoing development
+* Todor Boev
******************************************************************************/
package org.eclipse.equinox.p2.metadata;
import java.util.Map;
+import org.eclipse.equinox.p2.metadata.expression.IFilterExpression;
/**
* Describes a capability that is exposed by an installable unit. These capabilities
@@ -29,45 +31,56 @@ import java.util.Map;
*/
public interface IProvidedCapability {
/**
+ * The name of the property under which the capability version is stored.
+ *
+ * Can be used with {@link #getProperties()}. The same value can be obtained with {@link #getVersion()}
+ *
+ * @since 2.4
+ */
+ String PROPERTY_VERSION = "version"; //$NON-NLS-1$
+
+ /**
*
* @return String the namespace of this capability.
* @noreference This method is not intended to be referenced by clients.
*/
- public String getNamespace();
+ String getNamespace();
/**
*
- * @return String the attribute stored under a key equal to {@link #getNamespace()} attribute of this capability.
+ * @return String the attribute stored under a key equal to the {@link #getNamespace()} attribute of this capability.
* @noreference This method is not intended to be referenced by clients.
*/
- public String getName();
+ String getName();
/**
*
- * @return String the special <code>version</code> attribute of this capability.
+ * @return String the special {@link #PROPERTY_VERSION} attribute of this capability.
* @noreference This method is not intended to be referenced by clients.
*/
- public Version getVersion();
+ Version getVersion();
/**
+ * A full description of this capability including the name and the version.
+ * <p>
+ * Such a description can be used to match this capability with an {@link IFilterExpression LDAP filter} for example.
*
- * @return A full description of this capability
+ * @return An unmodifiable map
* @noreference This method is not intended to be referenced by clients.
* @since 2.4
*/
- public Map<String, Object> getAttributes();
+ Map<String, Object> getProperties();
/**
* Returns whether this provided capability is equal to the given object.
*
* This method returns <i>true</i> if:
* <ul>
- * <li> Both this object and the given object are of type IProvidedCapability
- * <li> The result of <b>getNamespace()</b> on both objects are equal
- * <li> The result of <b>getAttributes()</b> on both objects are equal
+ * <li>Both this object and the given object are of type IProvidedCapability</li>
+ * <li>The result of {@link #getNamespace()} on both objects are equal</li>
+ * <li>The result of {@link #getProperties()} on both objects are equal</li>
* </ul>
*/
@Override
- public boolean equals(Object other);
-
+ boolean equals(Object other);
} \ No newline at end of file
diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/MetadataFactory.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/MetadataFactory.java
index e3f89b18d..6c9d91a77 100644
--- a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/MetadataFactory.java
+++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/p2/metadata/MetadataFactory.java
@@ -30,6 +30,7 @@ import org.eclipse.equinox.internal.p2.metadata.InstallableUnitPatch;
import org.eclipse.equinox.internal.p2.metadata.License;
import org.eclipse.equinox.internal.p2.metadata.ProvidedCapability;
import org.eclipse.equinox.internal.p2.metadata.RequiredCapability;
+import org.eclipse.equinox.internal.p2.metadata.RequiredPropertiesMatch;
import org.eclipse.equinox.internal.p2.metadata.Requirement;
import org.eclipse.equinox.internal.p2.metadata.RequirementChange;
import org.eclipse.equinox.internal.p2.metadata.ResolvedInstallableUnit;
@@ -37,6 +38,8 @@ import org.eclipse.equinox.internal.p2.metadata.TouchpointData;
import org.eclipse.equinox.internal.p2.metadata.TouchpointInstruction;
import org.eclipse.equinox.internal.p2.metadata.TouchpointType;
import org.eclipse.equinox.internal.p2.metadata.UpdateDescriptor;
+import org.eclipse.equinox.p2.metadata.expression.ExpressionUtil;
+import org.eclipse.equinox.p2.metadata.expression.IFilterExpression;
import org.eclipse.equinox.p2.metadata.expression.IMatchExpression;
/**
@@ -461,11 +464,29 @@ public final class MetadataFactory {
* Returns a {@link IProvidedCapability} with the given values.
*
* @param namespace The capability namespace
- * @param attributes The description of the capability
+ * @param properties The description of the capability
* @since 2.4
*/
- public static IProvidedCapability createProvidedCapability(String namespace, Map<String, Object> attributes) {
- return new ProvidedCapability(namespace, attributes);
+ public static IProvidedCapability createProvidedCapability(String namespace, Map<String, Object> properties) {
+ return new ProvidedCapability(namespace, properties);
+ }
+
+ /**
+ * Create and return a new requirement ({@link IRequirement}) with the specified values.
+ *
+ * @param namespace the namespace for the requirement. Must not be <code>null</code>.
+ * @param name the name for the requirement. Must not be <code>null</code>.
+ * @param range the version range. A value of <code>null</code> is equivalent to {@link VersionRange#emptyRange} and matches all versions.
+ * @param filter The filter used to evaluate whether this capability is applicable in the
+ * current environment, or <code>null</code> to indicate this capability is always applicable
+ * @param optional <code>true</code> if this requirement is optional, and <code>false</code> otherwise.
+ * @param multiple <code>true</code> if this requirement can be satisfied by multiple provided capabilities, or <code>false</code>
+ * if it requires exactly one match
+ * @param greedy <code>true</code> if the requirement should be considered greedy and <code>false</code> otherwise
+ * @return the requirement
+ */
+ public static IRequirement createRequirement(String namespace, String name, VersionRange range, String filter, boolean optional, boolean multiple, boolean greedy) {
+ return new RequiredCapability(namespace, name, range, InstallableUnit.parseFilter(filter), optional ? 0 : 1, multiple ? Integer.MAX_VALUE : 1, greedy, null);
}
/**
@@ -507,87 +528,81 @@ public final class MetadataFactory {
/**
* Create and return a new requirement ({@link IRequirement}) with the specified values.
*
- * @param requirement the match expression
+ * @param namespace the namespace for the requirement. Must not be <code>null</code>.
+ * @param name the name for the requirement. Must not be <code>null</code>.
+ * @param range the version range. A value of <code>null</code> is equivalent to {@link VersionRange#emptyRange} and matches all versions.
* @param filter The filter used to evaluate whether this capability is applicable in the
* current environment, or <code>null</code> to indicate this capability is always applicable
* @param minCard minimum cardinality
* @param maxCard maximum cardinality
* @param greedy <code>true</code> if the requirement should be considered greedy and <code>false</code> otherwise
+ * @param description a <code>String</code> description of the requirement, or <code>null</code>
* @return the requirement
*/
- public static IRequirement createRequirement(IMatchExpression<IInstallableUnit> requirement, IMatchExpression<IInstallableUnit> filter, int minCard, int maxCard, boolean greedy) {
- // IRequiredCapability is simply a requirement with a match expression derived from a (namespace, name, version) tripet.
- // However the xml format also requires that maxCard > 1 or it is serialized in the generic format.
- // When parsing back from xml try to convert to an IRequiredCapability to retain the representation prior to serialization
- if (RequiredCapability.isSimpleRequirement(requirement)) {
- String namespace = RequiredCapability.extractNamespace(requirement);
- String name = RequiredCapability.extractName(requirement);
- VersionRange range = RequiredCapability.extractRange(requirement);
- return new RequiredCapability(namespace, name, range, filter, minCard, maxCard, greedy, null);
- }
+ public static IRequirement createRequirement(String namespace, String name, VersionRange range, IMatchExpression<IInstallableUnit> filter, int minCard, int maxCard, boolean greedy, String description) {
+ return new RequiredCapability(namespace, name, range, filter, minCard, maxCard, greedy, description);
+ }
- return new Requirement(requirement, filter, minCard, maxCard, greedy, null);
+ /**
+ *
+ * @param namespace
+ * @param propsFilter filter applied on {@link IProvidedCapability#getProperties()} of every {@link IInstallableUnit#getProvidedCapabilities()}
+ * @param envFilter matcher over {@link IInstallableUnit#getProperties()}
+ * @param minCard
+ * @param maxCard
+ * @param greedy
+ * @return the requirement
+ * @since 2.4
+ */
+ public static IRequirement createRequirement(String namespace, String propsFilter, IMatchExpression<IInstallableUnit> envFilter, int minCard, int maxCard, boolean greedy) {
+ IFilterExpression attrFilterExpr = ExpressionUtil.parseLDAP(propsFilter);
+ return new RequiredPropertiesMatch(namespace, attrFilterExpr, envFilter, minCard, maxCard, greedy, null);
}
/**
- * Create and return a new requirement ({@link IRequirement}) with the specified values.
*
- * @param namespace the namespace for the requirement. Must not be <code>null</code>.
- * @param name the name for the requirement. Must not be <code>null</code>.
- * @param range the version range. A value of <code>null</code> is equivalent to {@link VersionRange#emptyRange} and matches all versions.
- * @param filter The filter used to evaluate whether this capability is applicable in the
- * current environment, or <code>null</code> to indicate this capability is always applicable
- * @param optional <code>true</code> if this requirement is optional, and <code>false</code> otherwise.
- * @param multiple <code>true</code> if this requirement can be satisfied by multiple provided capabilities, or <code>false</code>
- * if it requires exactly one match
- * @param greedy <code>true</code> if the requirement should be considered greedy and <code>false</code> otherwise
+ * @param namespace
+ * @param propsFilter
+ * @param envFilter
+ * @param minCard
+ * @param maxCard
+ * @param greedy
+ * @param description
* @return the requirement
+ * @since 2.4
*/
- public static IRequirement createRequirement(String namespace, String name, VersionRange range, String filter, boolean optional, boolean multiple, boolean greedy) {
- return new RequiredCapability(namespace, name, range, InstallableUnit.parseFilter(filter), optional ? 0 : 1, multiple ? Integer.MAX_VALUE : 1, greedy, null);
+ public static IRequirement createRequirement(String namespace, IFilterExpression propsFilter, IMatchExpression<IInstallableUnit> envFilter, int minCard, int maxCard, boolean greedy, String description) {
+ return new RequiredPropertiesMatch(namespace, propsFilter, envFilter, minCard, maxCard, greedy, null);
}
/**
* Create and return a new requirement ({@link IRequirement}) with the specified values.
*
- * @param namespace the namespace for the requirement. Must not be <code>null</code>.
- * @param name the name for the requirement. Must not be <code>null</code>.
- * @param range the version range. A value of <code>null</code> is equivalent to {@link VersionRange#emptyRange} and matches all versions.
- * @param filter The filter used to evaluate whether this capability is applicable in the
+ * @param requirement the match expression
+ * @param envFilter The filter used to evaluate whether this capability is applicable in the
* current environment, or <code>null</code> to indicate this capability is always applicable
* @param minCard minimum cardinality
* @param maxCard maximum cardinality
* @param greedy <code>true</code> if the requirement should be considered greedy and <code>false</code> otherwise
- * @param description a <code>String</code> description of the requirement, or <code>null</code>
* @return the requirement
*/
- public static IRequirement createRequirement(String namespace, String name, VersionRange range, IMatchExpression<IInstallableUnit> filter, int minCard, int maxCard, boolean greedy, String description) {
- return new RequiredCapability(namespace, name, range, filter, minCard, maxCard, greedy, description);
+ public static IRequirement createRequirement(IMatchExpression<IInstallableUnit> requirement, IMatchExpression<IInstallableUnit> envFilter, int minCard, int maxCard, boolean greedy) {
+ return createRequirementInternal(requirement, envFilter, minCard, maxCard, greedy, null);
}
/**
* Create and return a new requirement ({@link IRequirement}) with the specified values.
*
* @param requirement the match expression
- * @param filter the filter, or <code>null</code>
+ * @param envFilter the filter, or <code>null</code>
* @param minCard minimum cardinality
* @param maxCard maximum cardinality
* @param greedy <code>true</code> if the requirement should be considered greedy and <code>false</code> otherwise
* @param description a <code>String</code> description of the requirement, or <code>null</code>
* @return the requirement
*/
- public static IRequirement createRequirement(IMatchExpression<IInstallableUnit> requirement, IMatchExpression<IInstallableUnit> filter, int minCard, int maxCard, boolean greedy, String description) {
- // IRequiredCapability is simply a requirement with a match expression derived from a (namespace, name, version) tripet.
- // However the xml format also requires that maxCard > 1 or it is serialized in the generic format.
- // When parsing back from xml try to convert to an IRequiredCapability to retain the representation prior to serialization
- if (RequiredCapability.isSimpleRequirement(requirement)) {
- String namespace = RequiredCapability.extractNamespace(requirement);
- String name = RequiredCapability.extractName(requirement);
- VersionRange range = RequiredCapability.extractRange(requirement);
- return new RequiredCapability(namespace, name, range, filter, minCard, maxCard, greedy, description);
- }
-
- return new Requirement(requirement, filter, minCard, maxCard, greedy, description);
+ public static IRequirement createRequirement(IMatchExpression<IInstallableUnit> requirement, IMatchExpression<IInstallableUnit> envFilter, int minCard, int maxCard, boolean greedy, String description) {
+ return createRequirementInternal(requirement, envFilter, minCard, maxCard, greedy, description);
}
/**
@@ -737,6 +752,14 @@ public final class MetadataFactory {
}
}
+ /**
+ *
+ * @param descriptors
+ * @param severity
+ * @param description
+ * @param location
+ * @return A new update descriptor
+ */
public static IUpdateDescriptor createUpdateDescriptor(Collection<IMatchExpression<IInstallableUnit>> descriptors, int severity, String description, URI location) {
return new UpdateDescriptor(descriptors, severity, description, location);
}
@@ -770,6 +793,26 @@ public final class MetadataFactory {
return createUpdateDescriptor(descriptors, severity, description, location);
}
+ private static IRequirement createRequirementInternal(IMatchExpression<IInstallableUnit> requirement, IMatchExpression<IInstallableUnit> envFilter, int minCard, int maxCard, boolean greedy, String description) {
+ // IRequiredCapability is simply a requirement with a match expression derived from a (namespace, name, version) tripet.
+ // However the xml format also requires that maxCard > 1 or it is serialized in the generic format.
+ // When parsing back from xml try to convert to an IRequiredCapability to retain the representation prior to serialization
+ if (RequiredCapability.isVersionRangeRequirement(requirement)) {
+ String namespace = RequiredCapability.extractNamespace(requirement);
+ String name = RequiredCapability.extractName(requirement);
+ VersionRange range = RequiredCapability.extractRange(requirement);
+ return new RequiredCapability(namespace, name, range, envFilter, minCard, maxCard, greedy, description);
+ }
+
+ if (RequiredPropertiesMatch.isPropertiesMatchRequirement(requirement)) {
+ String namespace = RequiredPropertiesMatch.extractNamespace(requirement);
+ IFilterExpression attrMatch = RequiredPropertiesMatch.extractPropertiesMatch(requirement);
+ return new RequiredPropertiesMatch(namespace, attrMatch, envFilter, minCard, maxCard, greedy, description);
+ }
+
+ return new Requirement(requirement, envFilter, minCard, maxCard, greedy, description);
+ }
+
private static ITouchpointType getCachedTouchpointType(String id, Version version) {
for (int i = 0; i < typeCache.length; i++) {
if (typeCache[i] != null && typeCache[i].getId().equals(id) && typeCache[i].getVersion().equals(version))

Back to the top