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
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>
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/MetadataRepositoryIO.java2
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/io/MetadataParser.java250
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/io/MetadataWriter.java121
-rw-r--r--bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/io/XMLConstants.java32
-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
-rw-r--r--bundles/org.eclipse.equinox.p2.publisher.eclipse/META-INF/MANIFEST.MF2
-rw-r--r--bundles/org.eclipse.equinox.p2.publisher.eclipse/src/org/eclipse/equinox/p2/publisher/eclipse/BundlesAction.java91
-rw-r--r--bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/p2/publisher/AbstractPublisherAction.java2
-rw-r--r--bundles/org.eclipse.equinox.p2.repository/src/org/eclipse/equinox/internal/p2/persistence/XMLConstants.java16
-rw-r--r--bundles/org.eclipse.equinox.p2.repository/src/org/eclipse/equinox/internal/p2/persistence/XMLWriter.java82
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/director/AutomatedDirectorTest.java255
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/engine/PhaseSetTest.java33
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/metadata/RequirementToString.java13
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/metadata/expression/AllTests.java9
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/metadata/expression/FilterTest.java439
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/metadata/repository/SPIMetadataRepositoryTest.java20
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/planner/PropertyMatchRequirement.java111
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/publisher/actions/ActionTest.java23
-rw-r--r--bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/publisher/actions/BundlesActionTest.java109
27 files changed, 1315 insertions, 755 deletions
diff --git a/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/MetadataRepositoryIO.java b/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/MetadataRepositoryIO.java
index ed67c081a..4243ad59d 100644
--- a/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/MetadataRepositoryIO.java
+++ b/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/MetadataRepositoryIO.java
@@ -104,7 +104,7 @@ public class MetadataRepositoryIO {
// A format version number for metadata repository XML.
public static final Version COMPATIBLE_VERSION = Version.createOSGi(1, 0, 0);
- public static final Version CURRENT_VERSION = Version.createOSGi(1, 1, 0);
+ public static final Version CURRENT_VERSION = Version.createOSGi(1, 2, 0);
public static final VersionRange XML_TOLERANCE = new VersionRange(COMPATIBLE_VERSION, true, Version.createOSGi(2, 0, 0), false);
// Constants for processing Instructions
diff --git a/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/io/MetadataParser.java b/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/io/MetadataParser.java
index 20fc56a8d..024631745 100644
--- a/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/io/MetadataParser.java
+++ b/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/io/MetadataParser.java
@@ -12,11 +12,14 @@
*******************************************************************************/
package org.eclipse.equinox.internal.p2.metadata.repository.io;
+import static java.util.stream.Collectors.toList;
+
import java.net.URI;
import java.util.*;
import java.util.Map.Entry;
import org.eclipse.equinox.internal.p2.core.helpers.OrderedProperties;
-import org.eclipse.equinox.internal.p2.metadata.*;
+import org.eclipse.equinox.internal.p2.metadata.ArtifactKey;
+import org.eclipse.equinox.internal.p2.metadata.InstallableUnit;
import org.eclipse.equinox.internal.p2.persistence.XMLParser;
import org.eclipse.equinox.p2.metadata.*;
import org.eclipse.equinox.p2.metadata.MetadataFactory.*;
@@ -30,18 +33,6 @@ import org.xml.sax.ContentHandler;
public abstract class MetadataParser extends XMLParser implements XMLConstants {
static final ILicense[] NO_LICENSES = new ILicense[0];
- static final String ATTR_TYPE_LIST_HEAD = "List<"; //$NON-NLS-1$
- static final String ATTR_TYPE_STRING = String.class.getSimpleName();
- static final String ATTR_TYPE_INTEGER = Integer.class.getSimpleName();
- static final String ATTR_TYPE_LONG = Long.class.getSimpleName();
- static final String ATTR_TYPE_FLOAT = Float.class.getSimpleName();
- static final String ATTR_TYPE_DOUBLE = Double.class.getSimpleName();
- static final String ATTR_TYPE_BYTE = Byte.class.getSimpleName();
- static final String ATTR_TYPE_SHORT = Short.class.getSimpleName();
- static final String ATTR_TYPE_CHARACTER = Character.class.getSimpleName();
- static final String ATTR_TYPE_BOOLEAN = Boolean.class.getSimpleName();
- static final String ATTR_TYPE_VERSION = Version.class.getSimpleName();
-
public MetadataParser(BundleContext context, String bundleId) {
super(context, bundleId);
}
@@ -322,7 +313,7 @@ public abstract class MetadataParser extends XMLParser implements XMLConstants {
IProvidedCapability[] providedCapabilities = (providedCapabilitiesHandler == null ? new IProvidedCapability[0] : providedCapabilitiesHandler.getProvidedCapabilities());
currentUnit.setCapabilities(providedCapabilities);
- IRequirement[] requiredCapabilities = (requiredCapabilitiesHandler == null ? new IRequirement[0] : requiredCapabilitiesHandler.getRequiredCapabilities());
+ IRequirement[] requiredCapabilities = (requiredCapabilitiesHandler == null ? new IRequirement[0] : requiredCapabilitiesHandler.getRequirements());
currentUnit.setRequirements(requiredCapabilities);
IRequirement[] metaRequiredCapabilities = (metaRequiredCapabilitiesHandler == null ? new IRequirement[0] : metaRequiredCapabilitiesHandler.getMetaRequiredCapabilities());
currentUnit.setMetaRequirements(metaRequiredCapabilities);
@@ -389,7 +380,7 @@ public abstract class MetadataParser extends XMLParser implements XMLConstants {
@Override
protected void finished() {
if (children != null) {
- scopes.add(children.getRequiredCapabilities());
+ scopes.add(children.getRequirements());
}
}
}
@@ -517,7 +508,7 @@ public abstract class MetadataParser extends XMLParser implements XMLConstants {
private String namespace;
private String name;
private Version version;
- private ProvidedCapabilityAttributesHandler attributesHandler;
+ private ProvidedCapabilityPropertiesHandler propertiesHandler;
private List<IProvidedCapability> capabilities;
@@ -534,63 +525,68 @@ public abstract class MetadataParser extends XMLParser implements XMLConstants {
@Override
public void startElement(String elem, Attributes attributes) {
- if (elem.equals(CAPABILITY_ATTRIBUTES_ELEMENT)) {
- this.attributesHandler = new ProvidedCapabilityAttributesHandler(this, attributes);
- } else {
- invalidElement(elem, attributes);
+ switch (elem) {
+ case PROPERTIES_ELEMENT :
+ this.propertiesHandler = new ProvidedCapabilityPropertiesHandler(this, attributes);
+ break;
+ default :
+ invalidElement(elem, attributes);
+ break;
}
}
@Override
protected void finished() {
- Map<String, Object> capAttrs = (attributesHandler != null)
- ? attributesHandler.getAttributes()
+ Map<String, Object> properties = (propertiesHandler != null)
+ ? propertiesHandler.getProperties()
: new HashMap<>();
- capAttrs.put(namespace, name);
- capAttrs.put(ProvidedCapability.ATTRIBUTE_VERSION, version);
- IProvidedCapability cap = MetadataFactory.createProvidedCapability(namespace, capAttrs);
+ properties.put(namespace, name);
+ properties.put(IProvidedCapability.PROPERTY_VERSION, version);
+ IProvidedCapability cap = MetadataFactory.createProvidedCapability(namespace, properties);
capabilities.add(cap);
}
}
- protected class ProvidedCapabilityAttributesHandler extends AbstractMetadataHandler {
- private Map<String, Object> capAttributes;
+ protected class ProvidedCapabilityPropertiesHandler extends AbstractMetadataHandler {
+ private Map<String, Object> properties;
- public ProvidedCapabilityAttributesHandler(AbstractHandler parentHandler, Attributes attributes) {
- super(parentHandler, CAPABILITY_ATTRIBUTES_ELEMENT);
- // TODO add getOptionalSize(attributes, 4)
- this.capAttributes = new HashMap<>();
+ public ProvidedCapabilityPropertiesHandler(AbstractHandler parentHandler, Attributes attributes) {
+ super(parentHandler, PROPERTIES_ELEMENT);
+ this.properties = new HashMap<>(getOptionalSize(attributes, 2));
}
- public Map<String, Object> getAttributes() {
- return capAttributes;
+ public Map<String, Object> getProperties() {
+ return properties;
}
@Override
- public void startElement(String name, Attributes attributes) {
- if (name.equals(CAPABILITY_ATTRIBUTE_ELEMENT)) {
- new ProvidedCapabilityAttributeHandler(this, attributes, capAttributes);
- } else {
- invalidElement(name, attributes);
+ public void startElement(String elem, Attributes attributes) {
+ switch (elem) {
+ case PROPERTY_ELEMENT :
+ new ProvidedCapabilityPropertyHandler(this, attributes, properties);
+ break;
+ default :
+ invalidElement(elem, attributes);
+ break;
}
}
}
- protected class ProvidedCapabilityAttributeHandler extends AbstractMetadataHandler {
- public ProvidedCapabilityAttributeHandler(AbstractHandler parentHandler, Attributes attributes, Map<String, Object> capAttributes) {
- super(parentHandler, CAPABILITY_ATTRIBUTE_ELEMENT);
+ protected class ProvidedCapabilityPropertyHandler extends AbstractMetadataHandler {
+ public ProvidedCapabilityPropertyHandler(AbstractHandler parentHandler, Attributes attributes, Map<String, Object> properties) {
+ super(parentHandler, PROPERTY_ELEMENT);
- String[] values = parseRequiredAttributes(attributes, CAPABILITY_ATTRIBUTE_REQUIRED_ATTRIBUTES);
+ String[] values = parseAttributes(attributes, PROPERTY_ATTRIBUTES, PROPERTY_OPTIONAL_ATTRIBUTES);
String name = values[0];
String value = values[1];
- String type = values[2];
+ String type = values[2] == null ? PROPERTY_TYPE_STRING : values[2];
- if (type.startsWith(ATTR_TYPE_LIST_HEAD)) {
- capAttributes.put(name, parseList(type, value));
+ if (type.startsWith(PROPERTY_TYPE_LIST)) {
+ properties.put(name, parseList(type, value));
} else {
- capAttributes.put(name, parseScalar(type, value));
+ properties.put(name, parseScalar(type, value));
}
}
@@ -600,49 +596,53 @@ public abstract class MetadataParser extends XMLParser implements XMLConstants {
}
private List<Object> parseList(String type, String value) {
- String elType = type.substring(ATTR_TYPE_LIST_HEAD.length(), type.length() - 1);
-
- List<Object> res = new ArrayList<>();
- for (String el : value.split("\\s*,\\s*")) { //$NON-NLS-1$
- res.add(parseScalar(elType, el));
+ final String elType;
+ if (type.length() > PROPERTY_TYPE_LIST.length()) {
+ // Strip the leading "List<" and trailing ">"
+ elType = type.substring(PROPERTY_TYPE_LIST.length() + 1, type.length() - 1);
+ } else {
+ elType = PROPERTY_TYPE_STRING;
}
- return res;
+ return Arrays.stream(value.split("\\s*,\\s*")) //$NON-NLS-1$
+ .map(val -> parseScalar(elType, val))
+ .collect(toList());
}
private Object parseScalar(String type, String value) {
- if (ATTR_TYPE_STRING.equals(type)) {
+ if (PROPERTY_TYPE_STRING.equals(type)) {
return value;
}
- if (ATTR_TYPE_INTEGER.equals(type)) {
+ if (PROPERTY_TYPE_INTEGER.equals(type)) {
return Integer.parseInt(value);
}
- if (ATTR_TYPE_LONG.equals(type)) {
+ if (PROPERTY_TYPE_LONG.equals(type)) {
return Long.parseLong(value);
}
- if (ATTR_TYPE_FLOAT.equals(type)) {
+ if (PROPERTY_TYPE_FLOAT.equals(type)) {
return Float.parseFloat(value);
}
- if (ATTR_TYPE_DOUBLE.equals(type)) {
+ if (PROPERTY_TYPE_DOUBLE.equals(type)) {
return Double.parseDouble(value);
}
- if (ATTR_TYPE_BYTE.equals(type)) {
+ if (PROPERTY_TYPE_BYTE.equals(type)) {
return Byte.parseByte(value);
}
- if (ATTR_TYPE_SHORT.equals(type)) {
+ if (PROPERTY_TYPE_SHORT.equals(type)) {
return Short.parseShort(value);
}
- if (ATTR_TYPE_CHARACTER.equals(type)) {
+ if (PROPERTY_TYPE_CHARACTER.equals(type)) {
return value.charAt(0);
}
- if (ATTR_TYPE_BOOLEAN.equals(type)) {
+ if (PROPERTY_TYPE_BOOLEAN.equals(type)) {
return Boolean.parseBoolean(value);
}
- if (ATTR_TYPE_VERSION.equals(type)) {
+ if (PROPERTY_TYPE_VERSION.equals(type)) {
return Version.create(value);
}
- // TODO Throw what?
- return value.toString();
+
+ // String is the default
+ return value;
}
}
@@ -691,23 +691,29 @@ public abstract class MetadataParser extends XMLParser implements XMLConstants {
}
protected class RequirementsHandler extends AbstractMetadataHandler {
- private List<IRequirement> requiredCapabilities;
+ private List<IRequirement> requirements;
public RequirementsHandler(AbstractHandler parentHandler, Attributes attributes) {
super(parentHandler, REQUIREMENTS_ELEMENT);
- requiredCapabilities = new ArrayList<>(getOptionalSize(attributes, 4));
+ requirements = new ArrayList<>(getOptionalSize(attributes, 4));
}
- public IRequirement[] getRequiredCapabilities() {
- return requiredCapabilities.toArray(new IRequirement[requiredCapabilities.size()]);
+ public IRequirement[] getRequirements() {
+ return requirements.toArray(new IRequirement[requirements.size()]);
}
@Override
public void startElement(String name, Attributes attributes) {
- if (name.equals(REQUIREMENT_ELEMENT)) {
- new RequirementHandler(this, attributes, requiredCapabilities);
- } else {
- invalidElement(name, attributes);
+ switch (name) {
+ case REQUIREMENT_ELEMENT :
+ new RequirementHandler(this, attributes, requirements);
+ break;
+ case REQUIREMENT_PROPERTIES_ELEMENT :
+ new RequirementPropertiesHandler(this, attributes, requirements);
+ break;
+ default :
+ invalidElement(name, attributes);
+ break;
}
}
}
@@ -734,31 +740,34 @@ public abstract class MetadataParser extends XMLParser implements XMLConstants {
public RequirementHandler(AbstractHandler parentHandler, Attributes attributes, List<IRequirement> capabilities) {
super(parentHandler, REQUIREMENT_ELEMENT);
this.capabilities = capabilities;
+
+ // Version range requirement
if (attributes.getIndex(NAMESPACE_ATTRIBUTE) >= 0) {
- String[] values = parseAttributes(attributes, REQIURED_CAPABILITY_ATTRIBUTES, OPTIONAL_CAPABILITY_ATTRIBUTES);
+ String[] values = parseAttributes(attributes, REQIURED_CAPABILITY_ATTRIBUTES, REQUIRED_CAPABILITY_OPTIONAL_ATTRIBUTES);
namespace = values[0];
name = values[1];
range = checkVersionRange(REQUIREMENT_ELEMENT, VERSION_RANGE_ATTRIBUTE, values[2]);
- boolean isOptional = checkBoolean(REQUIREMENT_ELEMENT, CAPABILITY_OPTIONAL_ATTRIBUTE, values[3], false).booleanValue();
+ boolean isOptional = checkBoolean(REQUIREMENT_ELEMENT, REQUIRED_CAPABILITY_OPTIONAL_ATTRIBUTE, values[3], false).booleanValue();
min = isOptional ? 0 : 1;
- boolean isMultiple = checkBoolean(REQUIREMENT_ELEMENT, CAPABILITY_MULTIPLE_ATTRIBUTE, values[4], false).booleanValue();
+ boolean isMultiple = checkBoolean(REQUIREMENT_ELEMENT, REQUIRED_CAPABILITY_MULTIPLE_ATTRIBUTE, values[4], false).booleanValue();
max = isMultiple ? Integer.MAX_VALUE : 1;
- greedy = checkBoolean(REQUIREMENT_ELEMENT, CAPABILITY_GREED_ATTRIBUTE, values[5], true).booleanValue();
- } else {
- // Expression based requirement
- String[] values = parseAttributes(attributes, REQIUREMENT_ATTRIBUTES, OPTIONAL_REQUIREMENT_ATTRIBUTES);
+ greedy = checkBoolean(REQUIREMENT_ELEMENT, REQUIREMENT_GREED_ATTRIBUTE, values[5], true).booleanValue();
+ }
+ // IU match expression requirement
+ else {
+ String[] values = parseAttributes(attributes, REQUIRED_IU_MATCH_ATTRIBUTES, REQUIRED_IU_MATCH_OPTIONAL_ATTRIBUTES);
match = values[0];
matchParams = values[1];
min = values[2] == null ? 1 : checkInteger(REQUIREMENT_ELEMENT, MIN_ATTRIBUTE, values[2]);
max = values[3] == null ? 1 : checkInteger(REQUIREMENT_ELEMENT, MAX_ATTRIBUTE, values[3]);
- greedy = checkBoolean(REQUIREMENT_ELEMENT, CAPABILITY_GREED_ATTRIBUTE, values[4], true).booleanValue();
+ greedy = checkBoolean(REQUIREMENT_ELEMENT, REQUIREMENT_GREED_ATTRIBUTE, values[4], true).booleanValue();
}
}
@Override
public void startElement(String elem, Attributes attributes) {
- if (elem.equals(CAPABILITY_FILTER_ELEMENT)) {
- filterHandler = new TextHandler(this, CAPABILITY_FILTER_ELEMENT, attributes);
+ if (elem.equals(REQUIREMENT_FILTER_ELEMENT)) {
+ filterHandler = new TextHandler(this, REQUIREMENT_FILTER_ELEMENT, attributes);
} else if (elem.equals(REQUIREMENT_DESCRIPTION_ELEMENT)) {
descriptionHandler = new TextHandler(this, REQUIREMENT_DESCRIPTION_ELEMENT, attributes);
} else {
@@ -805,6 +814,83 @@ public abstract class MetadataParser extends XMLParser implements XMLConstants {
}
}
+ protected class RequirementPropertiesHandler extends AbstractHandler {
+ private List<IRequirement> requirements;
+
+ private String namespace;
+ private String match;
+ private int min;
+ private int max;
+ private boolean greedy;
+
+ private TextHandler filterHandler;
+ private TextHandler descriptionHandler;
+
+ public RequirementPropertiesHandler(AbstractHandler parentHandler, Attributes attributes, List<IRequirement> requirements) {
+ super(parentHandler, REQUIREMENT_PROPERTIES_ELEMENT);
+ this.requirements = requirements;
+
+ String[] values = parseAttributes(attributes, REQIURED_PROPERTIES_MATCH_ATTRIBUTES, REQIURED_PROPERTIES_MATCH_OPTIONAL_ATTRIBUTES);
+ namespace = values[0];
+ match = values[1];
+ min = (values[2] == null) ? 1 : checkInteger(REQUIREMENT_PROPERTIES_ELEMENT, MIN_ATTRIBUTE, values[2]);
+ max = (values[3] == null) ? 1 : checkInteger(REQUIREMENT_PROPERTIES_ELEMENT, MAX_ATTRIBUTE, values[3]);
+ greedy = checkBoolean(REQUIREMENT_PROPERTIES_ELEMENT, REQUIREMENT_GREED_ATTRIBUTE, values[4], true).booleanValue();
+ }
+
+ @Override
+ public void startElement(String elem, Attributes attributes) {
+ switch (elem) {
+ case REQUIREMENT_FILTER_ELEMENT :
+ filterHandler = new TextHandler(this, REQUIREMENT_FILTER_ELEMENT, attributes);
+ break;
+ case REQUIREMENT_DESCRIPTION_ELEMENT :
+ descriptionHandler = new TextHandler(this, REQUIREMENT_DESCRIPTION_ELEMENT, attributes);
+ break;
+ default :
+ invalidElement(elem, attributes);
+ break;
+ }
+ }
+
+ @Override
+ protected void finished() {
+ if (!isValidXML()) {
+ return;
+ }
+
+ IMatchExpression<IInstallableUnit> filter = null;
+ if (filterHandler != null) {
+ try {
+ filter = InstallableUnit.parseFilter(filterHandler.getText());
+ } catch (ExpressionParseException e) {
+ if (removeWhiteSpace(filterHandler.getText()).equals("(&(|)(|)(|))")) {//$NON-NLS-1$
+ // We could log this I guess
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ String description = (descriptionHandler != null) ? descriptionHandler.getText() : null;
+
+ IFilterExpression attrMatch = ExpressionUtil.parseLDAP(match);
+ IRequirement requirement = MetadataFactory.createRequirement(namespace, attrMatch, filter, min, max, greedy, description);
+ requirements.add(requirement);
+ }
+
+ private String removeWhiteSpace(String s) {
+ if (s == null)
+ return ""; //$NON-NLS-1$
+ StringBuffer builder = new StringBuffer();
+ for (int i = 0; i < s.length(); i++) {
+ if (s.charAt(i) != ' ')
+ builder.append(s.charAt(i));
+ }
+ return builder.toString();
+ }
+ }
+
protected class ArtifactsHandler extends AbstractHandler {
private List<IArtifactKey> artifacts;
diff --git a/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/io/MetadataWriter.java b/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/io/MetadataWriter.java
index 2b7686e35..f88d52bdd 100644
--- a/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/io/MetadataWriter.java
+++ b/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/io/MetadataWriter.java
@@ -14,11 +14,10 @@ package org.eclipse.equinox.internal.p2.metadata.repository.io;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.util.*;
-import java.util.Map.Entry;
import org.eclipse.core.runtime.*;
import org.eclipse.equinox.internal.p2.core.helpers.LogHelper;
-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.repository.Activator;
import org.eclipse.equinox.internal.p2.persistence.XMLWriter;
import org.eclipse.equinox.p2.metadata.*;
@@ -96,23 +95,23 @@ public class MetadataWriter extends XMLWriter implements XMLConstants {
private boolean hasOnlySimpleRequirements(IInstallableUnit iu) {
for (IRequirement r : iu.getRequirements())
- if (r.getMax() == 0 || !RequiredCapability.isSimpleRequirement(r.getMatches()))
+ if (r.getMax() == 0 || !RequiredCapability.isVersionRangeRequirement(r.getMatches()))
return false;
if (iu.getUpdateDescriptor() != null) {
for (IMatchExpression<IInstallableUnit> m : iu.getUpdateDescriptor().getIUsBeingUpdated()) {
- if (!RequiredCapability.isSimpleRequirement(m))
+ if (!RequiredCapability.isVersionRangeRequirement(m))
return false;
}
}
for (IRequirement r : iu.getMetaRequirements())
- if (r.getMax() == 0 || !RequiredCapability.isSimpleRequirement(r.getMatches()))
+ if (r.getMax() == 0 || !RequiredCapability.isVersionRangeRequirement(r.getMatches()))
return false;
if (iu instanceof IInstallableUnitFragment) {
for (IRequirement r : ((IInstallableUnitFragment) iu).getHost())
- if (!RequiredCapability.isSimpleRequirement(r.getMatches()))
+ if (!RequiredCapability.isVersionRangeRequirement(r.getMatches()))
return false;
}
@@ -120,11 +119,11 @@ public class MetadataWriter extends XMLWriter implements XMLConstants {
IInstallableUnitPatch iuPatch = (IInstallableUnitPatch) iu;
for (IRequirement[] rArr : iuPatch.getApplicabilityScope())
for (IRequirement r : rArr)
- if (!RequiredCapability.isSimpleRequirement(r.getMatches()))
+ if (!RequiredCapability.isVersionRangeRequirement(r.getMatches()))
return false;
IRequirement lifeCycle = iuPatch.getLifeCycle();
- if (lifeCycle != null && !RequiredCapability.isSimpleRequirement(lifeCycle.getMatches()))
+ if (lifeCycle != null && !RequiredCapability.isVersionRangeRequirement(lifeCycle.getMatches()))
return false;
}
return true;
@@ -167,50 +166,12 @@ public class MetadataWriter extends XMLWriter implements XMLConstants {
attribute(NAME_ATTRIBUTE, capability.getName());
attribute(VERSION_ATTRIBUTE, capability.getVersion());
- Map<String, Object> attrs = new HashMap<>(capability.getAttributes());
- attrs.remove(capability.getNamespace());
- attrs.remove(ProvidedCapability.ATTRIBUTE_VERSION);
+ Map<String, Object> props = new HashMap<>(capability.getProperties());
+ props.remove(capability.getNamespace());
+ props.remove(IProvidedCapability.PROPERTY_VERSION);
- if (!attrs.isEmpty()) {
- start(CAPABILITY_ATTRIBUTES_ELEMENT);
- attribute(COLLECTION_SIZE_ATTRIBUTE, attrs.size());
-
- for (Entry<String, Object> attr : attrs.entrySet()) {
- start(CAPABILITY_ATTRIBUTE_ELEMENT);
-
- String name = attr.getKey();
- Object val = attr.getValue();
- String type;
-
- if (Collection.class.isAssignableFrom(val.getClass())) {
- Collection<?> coll = (Collection<?>) val;
-
- String elType = coll.iterator().next().getClass().getSimpleName();
- type = String.format("List<%s>", elType); //$NON-NLS-1$
-
- StringBuilder valBuff = new StringBuilder();
- for (Iterator<?> iter = coll.iterator(); iter.hasNext();) {
- String el = iter.next().toString();
-
- valBuff.append(el);
- if (iter.hasNext()) {
- valBuff.append(","); //$NON-NLS-1$
- }
- }
-
- val = valBuff.toString();
- } else {
- type = val.getClass().getSimpleName();
- val = val.toString();
- }
-
- attribute(CAPABILITY_ATTRIBUTE_NAME_ATTRIBUTE, name);
- attribute(CAPABILITY_ATTRIBUTE_TYPE_ATTRIBUTE, type);
- attribute(CAPABILITY_ATTRIBUTE_VALUE_ATTRIBUTE, val);
-
- end(CAPABILITY_ATTRIBUTE_ELEMENT);
- }
- end(CAPABILITY_ATTRIBUTES_ELEMENT);
+ if (!props.isEmpty()) {
+ writeProperties(props);
}
end(PROVIDED_CAPABILITY_ELEMENT);
@@ -246,7 +207,7 @@ public class MetadataWriter extends XMLWriter implements XMLConstants {
throw new IllegalStateException();
IMatchExpression<IInstallableUnit> singleUD = descriptor.getIUsBeingUpdated().iterator().next();
start(UPDATE_DESCRIPTOR_ELEMENT);
- if (RequiredCapability.isSimpleRequirement(singleUD)) {
+ if (RequiredCapability.isVersionRangeRequirement(singleUD)) {
attribute(ID_ATTRIBUTE, RequiredCapability.extractName(singleUD));
attribute(VERSION_RANGE_ATTRIBUTE, RequiredCapability.extractRange(singleUD));
} else {
@@ -291,27 +252,59 @@ public class MetadataWriter extends XMLWriter implements XMLConstants {
}
protected void writeRequirement(IRequirement requirement) {
- start(REQUIREMENT_ELEMENT);
IMatchExpression<IInstallableUnit> match = requirement.getMatches();
- if (requirement.getMax() > 0 && RequiredCapability.isSimpleRequirement(match)) {
+
+ // A (namespace, name, version-range) type of requirement
+ if (requirement.getMax() > 0 && RequiredCapability.isVersionRangeRequirement(match)) {
+ start(REQUIREMENT_ELEMENT);
+
attribute(NAMESPACE_ATTRIBUTE, RequiredCapability.extractNamespace(match));
attribute(NAME_ATTRIBUTE, RequiredCapability.extractName(match));
attribute(VERSION_RANGE_ATTRIBUTE, RequiredCapability.extractRange(match));
- attribute(CAPABILITY_OPTIONAL_ATTRIBUTE, requirement.getMin() == 0, false);
- attribute(CAPABILITY_MULTIPLE_ATTRIBUTE, requirement.getMax() > 1, false);
- } else {
+ attribute(REQUIRED_CAPABILITY_OPTIONAL_ATTRIBUTE, requirement.getMin() == 0, false);
+ attribute(REQUIRED_CAPABILITY_MULTIPLE_ATTRIBUTE, requirement.getMax() > 1, false);
+ }
+ // A (namespace, attributes-match) type of requirement
+ else if (RequiredPropertiesMatch.isPropertiesMatchRequirement(match)) {
+ start(REQUIREMENT_PROPERTIES_ELEMENT);
+
+ attribute(NAMESPACE_ATTRIBUTE, RequiredPropertiesMatch.extractNamespace(match));
+ attribute(MATCH_ATTRIBUTE, RequiredPropertiesMatch.extractPropertiesMatch(match));
+
+ if (requirement.getMin() != 1) {
+ attribute(MIN_ATTRIBUTE, requirement.getMin());
+ }
+
+ if (requirement.getMax() != 1) {
+ attribute(MAX_ATTRIBUTE, requirement.getMax());
+ }
+ }
+ // A general match expression type of requirement
+ else {
+ start(REQUIREMENT_ELEMENT);
+
writeMatchExpression(match);
- if (requirement.getMin() != 1)
+
+ if (requirement.getMin() != 1) {
attribute(MIN_ATTRIBUTE, requirement.getMin());
- if (requirement.getMax() != 1)
+ }
+
+ if (requirement.getMax() != 1) {
attribute(MAX_ATTRIBUTE, requirement.getMax());
+ }
+ }
+
+ attribute(REQUIREMENT_GREED_ATTRIBUTE, requirement.isGreedy(), true);
+
+ if (requirement.getFilter() != null) {
+ writeTrimmedCdata(REQUIREMENT_FILTER_ELEMENT, requirement.getFilter().getParameters()[0].toString());
}
- attribute(CAPABILITY_GREED_ATTRIBUTE, requirement.isGreedy(), true);
- if (requirement.getFilter() != null)
- writeTrimmedCdata(CAPABILITY_FILTER_ELEMENT, requirement.getFilter().getParameters()[0].toString());
- if (requirement.getDescription() != null)
+
+ if (requirement.getDescription() != null) {
writeTrimmedCdata(REQUIREMENT_DESCRIPTION_ELEMENT, requirement.getDescription());
- end(REQUIREMENT_ELEMENT);
+ }
+
+ end();
}
private void writeMatchExpression(IMatchExpression<IInstallableUnit> match) {
diff --git a/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/io/XMLConstants.java b/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/io/XMLConstants.java
index 44db99925..621356e4a 100644
--- a/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/io/XMLConstants.java
+++ b/bundles/org.eclipse.equinox.p2.metadata.repository/src/org/eclipse/equinox/internal/p2/metadata/repository/io/XMLConstants.java
@@ -39,9 +39,7 @@ public interface XMLConstants extends org.eclipse.equinox.internal.p2.persistenc
public static final String REQUIREMENTS_ELEMENT = "requires"; //$NON-NLS-1$
public static final String HOST_REQUIREMENTS_ELEMENT = "hostRequirements"; //$NON-NLS-1$
public static final String META_REQUIREMENTS_ELEMENT = "metaRequirements"; //$NON-NLS-1$
- public static final String REQUIREMENT_ELEMENT = "required"; //$NON-NLS-1$
public static final String PROVIDED_CAPABILITIES_ELEMENT = "provides"; //$NON-NLS-1$
- public static final String PROVIDED_CAPABILITY_ELEMENT = "provided"; //$NON-NLS-1$
public static final String[] REQUIRED_PROVIDED_CAPABILITY_ATTRIBUTES = new String[] {NAMESPACE_ATTRIBUTE, NAME_ATTRIBUTE, VERSION_ATTRIBUTE};
public static final String TOUCHPOINT_TYPE_ELEMENT = "touchpoint"; //$NON-NLS-1$
public static final String TOUCHPOINT_DATA_ELEMENT = "touchpointData"; //$NON-NLS-1$
@@ -63,26 +61,26 @@ public interface XMLConstants extends org.eclipse.equinox.internal.p2.persistenc
public static final String[] OPTIONAL_IU_ATTRIBUTES = new String[] {SINGLETON_ATTRIBUTE};
public static final String GENERATION_ATTRIBUTE = "generation"; //$NON-NLS-1$
+ // Constants for the provided capability element
+ public static final String PROVIDED_CAPABILITY_ELEMENT = "provided"; //$NON-NLS-1$
+
// Constants for sub-elements of a required capability element
- public static final String CAPABILITY_FILTER_ELEMENT = "filter"; //$NON-NLS-1$
+ public static final String REQUIREMENT_ELEMENT = "required"; //$NON-NLS-1$
+ public static final String REQUIREMENT_PROPERTIES_ELEMENT = "requiredProperties"; //$NON-NLS-1$
+ public static final String REQUIREMENT_FILTER_ELEMENT = "filter"; //$NON-NLS-1$
public static final String REQUIREMENT_DESCRIPTION_ELEMENT = "description"; //$NON-NLS-1$
+ public static final String REQUIREMENT_GREED_ATTRIBUTE = "greedy"; //$NON-NLS-1$
- // Constants for attributes of a required capability element
- public static final String CAPABILITY_OPTIONAL_ATTRIBUTE = "optional"; //$NON-NLS-1$
- public static final String CAPABILITY_MULTIPLE_ATTRIBUTE = "multiple"; //$NON-NLS-1$
- public static final String CAPABILITY_GREED_ATTRIBUTE = "greedy"; //$NON-NLS-1$
+ public static final String REQUIRED_CAPABILITY_OPTIONAL_ATTRIBUTE = "optional"; //$NON-NLS-1$
+ public static final String REQUIRED_CAPABILITY_MULTIPLE_ATTRIBUTE = "multiple"; //$NON-NLS-1$
+ public static final String[] REQIURED_CAPABILITY_ATTRIBUTES = new String[] {NAMESPACE_ATTRIBUTE, NAME_ATTRIBUTE, VERSION_RANGE_ATTRIBUTE};
+ public static final String[] REQUIRED_CAPABILITY_OPTIONAL_ATTRIBUTES = new String[] {REQUIRED_CAPABILITY_OPTIONAL_ATTRIBUTE, REQUIRED_CAPABILITY_MULTIPLE_ATTRIBUTE, REQUIREMENT_GREED_ATTRIBUTE};
- public static final String CAPABILITY_ATTRIBUTES_ELEMENT = "attributes"; //$NON-NLS-1$
- public static final String CAPABILITY_ATTRIBUTE_ELEMENT = "attribute"; //$NON-NLS-1$
- public static final String CAPABILITY_ATTRIBUTE_NAME_ATTRIBUTE = "name"; //$NON-NLS-1$
- public static final String CAPABILITY_ATTRIBUTE_TYPE_ATTRIBUTE = "type"; //$NON-NLS-1$
- public static final String CAPABILITY_ATTRIBUTE_VALUE_ATTRIBUTE = "value"; //$NON-NLS-1$
- public static final String[] CAPABILITY_ATTRIBUTE_REQUIRED_ATTRIBUTES = new String[] {CAPABILITY_ATTRIBUTE_NAME_ATTRIBUTE, CAPABILITY_ATTRIBUTE_VALUE_ATTRIBUTE, CAPABILITY_ATTRIBUTE_TYPE_ATTRIBUTE};
+ public static final String[] REQIURED_PROPERTIES_MATCH_ATTRIBUTES = new String[] {NAMESPACE_ATTRIBUTE, MATCH_ATTRIBUTE};
+ public static final String[] REQIURED_PROPERTIES_MATCH_OPTIONAL_ATTRIBUTES = new String[] {MIN_ATTRIBUTE, MAX_ATTRIBUTE, REQUIREMENT_GREED_ATTRIBUTE};
- public static final String[] REQIURED_CAPABILITY_ATTRIBUTES = new String[] {NAMESPACE_ATTRIBUTE, NAME_ATTRIBUTE, VERSION_RANGE_ATTRIBUTE};
- public static final String[] REQIUREMENT_ATTRIBUTES = new String[] {MATCH_ATTRIBUTE};
- public static final String[] OPTIONAL_CAPABILITY_ATTRIBUTES = new String[] {CAPABILITY_OPTIONAL_ATTRIBUTE, CAPABILITY_MULTIPLE_ATTRIBUTE, CAPABILITY_GREED_ATTRIBUTE};
- public static final String[] OPTIONAL_REQUIREMENT_ATTRIBUTES = new String[] {MATCH_PARAMETERS_ATTRIBUTE, MIN_ATTRIBUTE, MAX_ATTRIBUTE, CAPABILITY_GREED_ATTRIBUTE};
+ public static final String[] REQUIRED_IU_MATCH_ATTRIBUTES = new String[] {MATCH_ATTRIBUTE};
+ public static final String[] REQUIRED_IU_MATCH_OPTIONAL_ATTRIBUTES = new String[] {MATCH_PARAMETERS_ATTRIBUTE, MIN_ATTRIBUTE, MAX_ATTRIBUTE, REQUIREMENT_GREED_ATTRIBUTE};
// Constants for attributes of an artifact key element
public static final String ARTIFACT_KEY_CLASSIFIER_ATTRIBUTE = "classifier"; //$NON-NLS-1$
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))
diff --git a/bundles/org.eclipse.equinox.p2.publisher.eclipse/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.p2.publisher.eclipse/META-INF/MANIFEST.MF
index 5ff218a9e..36dbe0f51 100644
--- a/bundles/org.eclipse.equinox.p2.publisher.eclipse/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.equinox.p2.publisher.eclipse/META-INF/MANIFEST.MF
@@ -39,6 +39,8 @@ Import-Package: org.eclipse.equinox.app;version="[1.0.0,2.0.0)",
org.eclipse.osgi.service.resolver;version="1.5.0",
org.eclipse.osgi.util;version="1.1.0",
org.osgi.framework;version="1.3.0",
+ org.osgi.framework.wiring;version="1.2.0",
+ org.osgi.resource;version="1.0.0",
org.osgi.service.application;version="1.1.0",
org.osgi.service.packageadmin;version="1.2.0"
Export-Package: org.eclipse.equinox.internal.p2.publisher.compatibility;x-internal:=true,
diff --git a/bundles/org.eclipse.equinox.p2.publisher.eclipse/src/org/eclipse/equinox/p2/publisher/eclipse/BundlesAction.java b/bundles/org.eclipse.equinox.p2.publisher.eclipse/src/org/eclipse/equinox/p2/publisher/eclipse/BundlesAction.java
index b3411b045..c2ec094be 100644
--- a/bundles/org.eclipse.equinox.p2.publisher.eclipse/src/org/eclipse/equinox/p2/publisher/eclipse/BundlesAction.java
+++ b/bundles/org.eclipse.equinox.p2.publisher.eclipse/src/org/eclipse/equinox/p2/publisher/eclipse/BundlesAction.java
@@ -12,6 +12,9 @@
******************************************************************************/
package org.eclipse.equinox.p2.publisher.eclipse;
+import static java.util.stream.Collectors.toList;
+import static java.util.stream.Collectors.toMap;
+
import java.io.*;
import java.util.*;
import java.util.Map.Entry;
@@ -28,7 +31,7 @@ import org.eclipse.equinox.p2.metadata.*;
import org.eclipse.equinox.p2.metadata.MetadataFactory.InstallableUnitDescription;
import org.eclipse.equinox.p2.metadata.MetadataFactory.InstallableUnitFragmentDescription;
import org.eclipse.equinox.p2.metadata.VersionRange;
-import org.eclipse.equinox.p2.metadata.expression.*;
+import org.eclipse.equinox.p2.metadata.expression.IMatchExpression;
import org.eclipse.equinox.p2.publisher.*;
import org.eclipse.equinox.p2.publisher.actions.*;
import org.eclipse.equinox.p2.query.IQueryResult;
@@ -43,6 +46,8 @@ import org.eclipse.osgi.util.NLS;
import org.eclipse.pde.internal.publishing.Activator;
import org.osgi.framework.BundleException;
import org.osgi.framework.Constants;
+import org.osgi.framework.wiring.BundleRequirement;
+import org.osgi.resource.Namespace;
/**
* Publish IUs for all of the bundles in a given set of locations or described by a set of
@@ -78,7 +83,6 @@ public class BundlesAction extends AbstractPublisherAction {
public static final String OSGI_BUNDLE_CLASSIFIER = "osgi.bundle"; //$NON-NLS-1$
public static final String CAPABILITY_NS_OSGI_BUNDLE = "osgi.bundle"; //$NON-NLS-1$
public static final String CAPABILITY_NS_OSGI_FRAGMENT = "osgi.fragment"; //$NON-NLS-1$
- public static final String CAPABILITY_ATTR_VERSION = "version"; //$NON-NLS-1$
public static final IProvidedCapability BUNDLE_CAPABILITY = MetadataFactory.createProvidedCapability(PublisherHelper.NAMESPACE_ECLIPSE_TYPE, TYPE_ECLIPSE_BUNDLE, Version.createOSGi(1, 0, 0));
public static final IProvidedCapability SOURCE_BUNDLE_CAPABILITY = MetadataFactory.createProvidedCapability(PublisherHelper.NAMESPACE_ECLIPSE_TYPE, TYPE_ECLIPSE_SOURCE, Version.createOSGi(1, 0, 0));
@@ -194,7 +198,7 @@ public class BundlesAction extends AbstractPublisherAction {
// Process generic requirements
ManifestElement[] rawRequireCapHeader = parseManifestHeader(Constants.REQUIRE_CAPABILITY, manifest, bd.getLocation());
for (GenericSpecification requiredCap : bd.getGenericRequires()) {
- addGenericRequirement(requirements, requiredCap, rawRequireCapHeader);
+ addRequirement(requirements, requiredCap, rawRequireCapHeader);
}
iu.setRequirements(requirements.toArray(new IRequirement[requirements.size()]));
@@ -223,7 +227,7 @@ public class BundlesAction extends AbstractPublisherAction {
int capNo = 0;
for (GenericDescription genericCap : bd.getGenericCapabilities()) {
- addGenericCapability(providedCapabilities, genericCap, iu, capNo);
+ addCapability(providedCapabilities, genericCap, iu, capNo);
capNo++;
}
@@ -301,36 +305,45 @@ public class BundlesAction extends AbstractPublisherAction {
reqsDeps.add(MetadataFactory.createRequirement(PublisherHelper.CAPABILITY_NS_JAVA_PACKAGE, importSpec.getName(), versionRange, null, optional, false, greedy));
}
- // TODO Handle all attributes and directives somehow? Especially the "effective" directive.
- protected void addGenericRequirement(List<IRequirement> reqsDeps, GenericSpecification requireCapSpec, ManifestElement[] rawRequiresPackageHeader) {
- String ns = requireCapSpec.getType();
- String ldap = requireCapSpec.getMatchingFilter();
- String matcher = "providedCapabilities.exists(pc | pc.namespace == '" + ns + "' && pc.attributes ~= filter('" + ldap + "'))"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
-
- IExpression expr = ExpressionUtil.parse(matcher);
- IMatchExpression<IInstallableUnit> matchExpr = ExpressionUtil.getFactory().matchExpression(expr);
-
- // Optional and greedy in order to be backward compatible.
- IRequirement requireCap = MetadataFactory.createRequirement(matchExpr, null, 0, 1, true);
-
- reqsDeps.add(requireCap);
- }
-
protected void addRequireBundleRequirement(List<IRequirement> reqsDeps, BundleSpecification requiredBundle, ManifestElement[] rawRequireBundleHeader) {
final boolean optional = requiredBundle.isOptional();
final boolean greedy;
- if (optional)
+ if (optional) {
greedy = INSTALLATION_GREEDY.equals(getInstallationDirective(requiredBundle.getName(), rawRequireBundleHeader));
- else
+ } else {
greedy = true;
+ }
reqsDeps.add(MetadataFactory.createRequirement(CAPABILITY_NS_OSGI_BUNDLE, requiredBundle.getName(), PublisherHelper.fromOSGiVersionRange(requiredBundle.getVersionRange()), null, optional ? 0 : 1, 1, greedy));
}
- protected void addGenericCapability(List<IProvidedCapability> caps, GenericDescription provideCapDesc, InstallableUnitDescription iu, int capNo) {
+ // TODO Handle the "effective:=" directive somehow?
+ protected void addRequirement(List<IRequirement> reqsDeps, GenericSpecification requireCapSpec, ManifestElement[] rawRequireCapabilities) {
+ BundleRequirement req = requireCapSpec.getRequirement();
+
+ String namespace = req.getNamespace();
+ Map<String, String> directives = req.getDirectives();
+
+ String capFilter = directives.get(Namespace.REQUIREMENT_FILTER_DIRECTIVE);
+ boolean optional = directives.get(Namespace.REQUIREMENT_RESOLUTION_DIRECTIVE) == Namespace.RESOLUTION_OPTIONAL;
+ boolean greedy = optional
+ ? INSTALLATION_GREEDY.equals(directives.get(INSTALLATION_DIRECTIVE))
+ : true;
+
+ IRequirement requireCap = MetadataFactory.createRequirement(namespace, capFilter, null, optional ? 0 : 1, 1, greedy);
+ reqsDeps.add(requireCap);
+ }
+
+ protected void addCapability(List<IProvidedCapability> caps, GenericDescription provideCapDesc, InstallableUnitDescription iu, int capNo) {
+ // Convert the values to String, Version, List of String or Version
+ Map<String, Object> capAttrs = provideCapDesc.getDeclaredAttributes()
+ .entrySet()
+ .stream()
+ .collect(toMap(Entry::getKey, e -> convertAttribute(e.getValue())));
+
+ // Resolve the namespace
String capNs = provideCapDesc.getType();
- Map<String, Object> capAttrs = new HashMap<>(provideCapDesc.getDeclaredAttributes());
- // Resolve the p2 name
+ // Resolve the mandatory p2 name
// By convention OSGi capabilities have an attribute named like the capability namespace.
// If this is not the case synthesize a unique name (e.g. "osgi.service" has an "objectClass" attribute instead).
// TODO If present but not a String log a warning somehow that it is ignored? Or fail the publication?
@@ -338,28 +351,32 @@ public class BundlesAction extends AbstractPublisherAction {
capNs,
(k, v) -> (v instanceof String) ? v : String.format("%s_%s-%s", iu.getId(), iu.getVersion(), capNo)); //$NON-NLS-1$
- // Convert all OSGi versions to P2 versions
- for (String key : new HashSet<>(capAttrs.keySet())) {
- Object val = capAttrs.get(key);
- if (!(val instanceof org.osgi.framework.Version)) {
- continue;
- }
- org.osgi.framework.Version osgiVer = (org.osgi.framework.Version) val;
- Version p2Ver = Version.createOSGi(osgiVer.getMajor(), osgiVer.getMinor(), osgiVer.getMicro(), osgiVer.getQualifier());
- capAttrs.put(key, p2Ver);
- }
-
- // Resolve the version
+ // Resolve the mandatory p2 version
// By convention versioned OSGi capabilities have a "version" attribute containing the OSGi Version object
// If this is not the case use an empty version (e.g. "osgi.ee" has a list of versions).
// TODO If present but not a Version log a warning somehow that it is ignored? Or fail the publication?
capAttrs.compute(
- CAPABILITY_ATTR_VERSION,
+ IProvidedCapability.PROPERTY_VERSION,
(k, v) -> (v instanceof Version) ? v : Version.emptyVersion);
caps.add(MetadataFactory.createProvidedCapability(capNs, capAttrs));
}
+ private Object convertAttribute(Object attr) {
+ if (attr instanceof Collection<?>) {
+ return ((Collection<?>) attr).stream().map(this::convertScalarAttribute).collect(toList());
+ }
+ return convertScalarAttribute(attr);
+ }
+
+ private Object convertScalarAttribute(Object attr) {
+ if (attr instanceof org.osgi.framework.Version) {
+ org.osgi.framework.Version osgiVer = (org.osgi.framework.Version) attr;
+ return Version.createOSGi(osgiVer.getMajor(), osgiVer.getMinor(), osgiVer.getMicro(), osgiVer.getQualifier());
+ }
+ return attr.toString();
+ }
+
static VersionRange computeUpdateRange(org.osgi.framework.Version base) {
VersionRange updateRange = null;
if (!base.equals(org.osgi.framework.Version.emptyVersion)) {
diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/p2/publisher/AbstractPublisherAction.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/p2/publisher/AbstractPublisherAction.java
index 71288480a..33822347f 100644
--- a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/p2/publisher/AbstractPublisherAction.java
+++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/p2/publisher/AbstractPublisherAction.java
@@ -395,7 +395,7 @@ public abstract class AbstractPublisherAction implements IPublisherAction {
}
IRequiredCapability requiredCapability = (IRequiredCapability) requirement;
- if (!RequiredCapability.isSimpleRequirement(requiredCapability.getMatches())) {
+ if (!RequiredCapability.isVersionRangeRequirement(requiredCapability.getMatches())) {
return null;
}
diff --git a/bundles/org.eclipse.equinox.p2.repository/src/org/eclipse/equinox/internal/p2/persistence/XMLConstants.java b/bundles/org.eclipse.equinox.p2.repository/src/org/eclipse/equinox/internal/p2/persistence/XMLConstants.java
index f1af9f142..de1601d90 100644
--- a/bundles/org.eclipse.equinox.p2.repository/src/org/eclipse/equinox/internal/p2/persistence/XMLConstants.java
+++ b/bundles/org.eclipse.equinox.p2.repository/src/org/eclipse/equinox/internal/p2/persistence/XMLConstants.java
@@ -11,6 +11,9 @@
*******************************************************************************/
package org.eclipse.equinox.internal.p2.persistence;
+import java.util.List;
+import org.eclipse.equinox.p2.metadata.Version;
+
public interface XMLConstants {
// Constants used in defining a default processing instruction
@@ -29,7 +32,20 @@ public interface XMLConstants {
public static final String PROPERTY_ELEMENT = "property"; //$NON-NLS-1$
public static final String PROPERTY_NAME_ATTRIBUTE = "name"; //$NON-NLS-1$
public static final String PROPERTY_VALUE_ATTRIBUTE = "value"; //$NON-NLS-1$
+ public static final String PROPERTY_TYPE_ATTRIBUTE = "type"; //$NON-NLS-1$
public static final String[] PROPERTY_ATTRIBUTES = new String[] {PROPERTY_NAME_ATTRIBUTE, PROPERTY_VALUE_ATTRIBUTE};
+ public static final String[] PROPERTY_OPTIONAL_ATTRIBUTES = new String[] {PROPERTY_TYPE_ATTRIBUTE};
+ public static final String PROPERTY_TYPE_LIST = List.class.getSimpleName();
+ public static final String PROPERTY_TYPE_STRING = String.class.getSimpleName();
+ public static final String PROPERTY_TYPE_INTEGER = Integer.class.getSimpleName();
+ public static final String PROPERTY_TYPE_LONG = Long.class.getSimpleName();
+ public static final String PROPERTY_TYPE_FLOAT = Float.class.getSimpleName();
+ public static final String PROPERTY_TYPE_DOUBLE = Double.class.getSimpleName();
+ public static final String PROPERTY_TYPE_BYTE = Byte.class.getSimpleName();
+ public static final String PROPERTY_TYPE_SHORT = Short.class.getSimpleName();
+ public static final String PROPERTY_TYPE_CHARACTER = Character.class.getSimpleName();
+ public static final String PROPERTY_TYPE_BOOLEAN = Boolean.class.getSimpleName();
+ public static final String PROPERTY_TYPE_VERSION = Version.class.getSimpleName();
// Constants for the names of common general attributes
public static final String ID_ATTRIBUTE = "id"; //$NON-NLS-1$
diff --git a/bundles/org.eclipse.equinox.p2.repository/src/org/eclipse/equinox/internal/p2/persistence/XMLWriter.java b/bundles/org.eclipse.equinox.p2.repository/src/org/eclipse/equinox/internal/p2/persistence/XMLWriter.java
index 6973a2f06..3a532f6ad 100644
--- a/bundles/org.eclipse.equinox.p2.repository/src/org/eclipse/equinox/internal/p2/persistence/XMLWriter.java
+++ b/bundles/org.eclipse.equinox.p2.repository/src/org/eclipse/equinox/internal/p2/persistence/XMLWriter.java
@@ -10,11 +10,11 @@
*******************************************************************************/
package org.eclipse.equinox.internal.p2.persistence;
+import static java.util.stream.Collectors.joining;
+
import java.io.*;
import java.nio.charset.StandardCharsets;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Stack;
+import java.util.*;
import org.eclipse.equinox.p2.metadata.Version;
public class XMLWriter implements XMLConstants {
@@ -220,28 +220,82 @@ public class XMLWriter implements XMLConstants {
this.pw.flush();
}
- public void writeProperties(Map<String, String> properties) {
+ public void writeProperties(Map<String, ?> properties) {
writeProperties(PROPERTIES_ELEMENT, properties);
}
- public void writeProperties(String propertiesElement, Map<String, String> properties) {
- if (properties != null && properties.size() > 0) {
- start(propertiesElement);
- attribute(COLLECTION_SIZE_ATTRIBUTE, properties.size());
- for (Entry<String, String> entry : properties.entrySet()) {
- writeProperty(entry.getKey(), entry.getValue());
- }
- end(propertiesElement);
+ public void writeProperties(String propertiesElement, Map<String, ?> properties) {
+ if (properties == null || properties.isEmpty()) {
+ return;
}
+
+ start(propertiesElement);
+ attribute(COLLECTION_SIZE_ATTRIBUTE, properties.size());
+ properties.forEach(this::writeProperty);
+ end();
}
- public void writeProperty(String name, String value) {
+ public void writeProperty(String name, Object value) {
+ String type;
+ String valueStr;
+
+ if (Collection.class.isAssignableFrom(value.getClass())) {
+ Collection<?> coll = (Collection<?>) value;
+
+ type = PROPERTY_TYPE_LIST;
+ String elType = resolvePropertyType(coll.iterator().next());
+ if (elType != null) {
+ type += String.format("<%s>", elType); //$NON-NLS-1$
+ }
+
+ valueStr = coll.stream().map(Object::toString).collect(joining(",")); //$NON-NLS-1$
+ } else {
+ type = resolvePropertyType(value);
+ valueStr = value.toString();
+ }
+
start(PROPERTY_ELEMENT);
attribute(PROPERTY_NAME_ATTRIBUTE, name);
- attribute(PROPERTY_VALUE_ATTRIBUTE, value);
+ attribute(PROPERTY_VALUE_ATTRIBUTE, valueStr);
+ attributeOptional(PROPERTY_TYPE_ATTRIBUTE, type);
end();
}
+ private String resolvePropertyType(Object value) {
+ if (value instanceof Integer) {
+ return PROPERTY_TYPE_INTEGER;
+ }
+ if (value instanceof Long) {
+ return PROPERTY_TYPE_LONG;
+ }
+ if (value instanceof Float) {
+ return PROPERTY_TYPE_FLOAT;
+ }
+ if (value instanceof Double) {
+ return PROPERTY_TYPE_DOUBLE;
+ }
+ if (value instanceof Byte) {
+ return PROPERTY_TYPE_BYTE;
+ }
+ if (value instanceof Short) {
+ return PROPERTY_TYPE_SHORT;
+ }
+ if (value instanceof Character) {
+ return PROPERTY_TYPE_CHARACTER;
+ }
+ if (value instanceof Boolean) {
+ return PROPERTY_TYPE_BOOLEAN;
+ }
+ if (value instanceof Version) {
+ return PROPERTY_TYPE_VERSION;
+ }
+
+ // Null is read back as String
+ // NOTE: Using string as default is needed for backward compatibility with properties that are always String like
+ // the IU properties
+ return null;
+ }
+
protected static String attributeImage(String name, String value) {
if (value == null) {
return ""; // optional attribute with no value //$NON-NLS-1$
diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/director/AutomatedDirectorTest.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/director/AutomatedDirectorTest.java
index f229b4e66..d726d6a5b 100644
--- a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/director/AutomatedDirectorTest.java
+++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/director/AutomatedDirectorTest.java
@@ -10,14 +10,16 @@ package org.eclipse.equinox.p2.tests.director;
import java.util.HashMap;
import java.util.Map;
-import junit.framework.Test;
-import junit.framework.TestSuite;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.equinox.internal.p2.core.helpers.LogHelper;
import org.eclipse.equinox.internal.p2.director.ProfileChangeRequest;
import org.eclipse.equinox.internal.provisional.p2.director.IDirector;
import org.eclipse.equinox.p2.engine.IProfile;
-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.Version;
import org.eclipse.equinox.p2.metadata.expression.IMatchExpression;
import org.eclipse.equinox.p2.tests.AbstractProvisioningTest;
@@ -25,20 +27,6 @@ import org.eclipse.equinox.p2.tests.AbstractProvisioningTest;
* Various automated tests of the {@link IDirector} API.
*/
public class AutomatedDirectorTest extends AbstractProvisioningTest {
- //private static Version version = Version.createOSGi(1, 0, 0);
-
- public static Test suite() {
- return new TestSuite(AutomatedDirectorTest.class);
- }
-
- public AutomatedDirectorTest() {
- super("");
- }
-
- public AutomatedDirectorTest(String name) {
- super(name);
- }
-
/**
* Tests installing an IU that has a filtered dependency on another IU. When
* the filter is satisfied, the dependency is active and the required IU should
@@ -46,26 +34,39 @@ public class AutomatedDirectorTest extends AbstractProvisioningTest {
* and the second IU should not be installed.
*/
public void testInstallFilteredCapability() {
- //The IU that is required
+ final String envKey = "filterKey";
+ final String envVal = "true";
+
+ // The IU that is required
IInstallableUnit requiredIU = createIU("required." + getName());
// The IU to be installed
- IMatchExpression<IInstallableUnit> filter = createFilter("FilterKey", "true");
- IRequirement capability = MetadataFactory.createRequirement(IInstallableUnit.NAMESPACE_IU_ID, requiredIU.getId(), ANY_VERSION, filter, false, false);
- IInstallableUnit toInstallIU = createIU("toInstall." + getName(), new IRequirement[] {capability});
+ IMatchExpression<IInstallableUnit> requirementFilter = createFilter(envKey, envVal);
+ IRequirement[] requires = new IRequirement[] {
+ MetadataFactory.createRequirement(IInstallableUnit.NAMESPACE_IU_ID, requiredIU.getId(), ANY_VERSION, requirementFilter, false, false)
+ };
+ IInstallableUnit toInstallIU = createIU("toInstall." + getName(), requires);
+ // Metadata repository
IInstallableUnit[] allUnits = new IInstallableUnit[] {requiredIU, toInstallIU};
createTestMetdataRepository(allUnits);
- IDirector director = createDirector();
- //Install into a profile in which the filter is satisfied
+ // Install into a profile in which the requirement filter is satisfied
Map<String, String> properties = new HashMap<>();
- properties.put(IProfile.PROP_ENVIRONMENTS, "FilterKey=true");
+ properties.put(IProfile.PROP_ENVIRONMENTS, envKey + "=" + envVal);
+
+ // Profile
IProfile satisfied = createProfile("Satisfied." + getName(), properties);
+
+ // Profile change request
ProfileChangeRequest request = new ProfileChangeRequest(satisfied);
request.add(toInstallIU);
+
+ // Provision
+ IDirector director = createDirector();
IStatus result = director.provision(request, null, null);
- assertTrue("1.0", result.isOK());
+
+ assertTrue(result.isOK());
assertProfileContains("1.1", satisfied, allUnits);
}
@@ -73,25 +74,41 @@ public class AutomatedDirectorTest extends AbstractProvisioningTest {
* Tests installing an IU that has an optional prerequisite that is available.
*/
public void testInstallOptionalAvailable() {
- String capabilityId = "test." + getName();
+ final String capabilityNamespace = "test.capability";
+ final String capabilityName = "test." + getName();
+ final Version capabilityVersion = DEFAULT_VERSION;
+
//The IU that exports the capability
- IInstallableUnit requiredIU = createIU("required." + getName(), new IProvidedCapability[] {MetadataFactory.createProvidedCapability("test.capability", capabilityId, DEFAULT_VERSION)});
+ IProvidedCapability[] provides = new IProvidedCapability[] {
+ MetadataFactory.createProvidedCapability(capabilityNamespace, capabilityName, capabilityVersion)
+ };
+ IInstallableUnit requiredIU = createIU("required." + getName(), provides);
//The IU that optionally requires the capability
- IRequirement required = MetadataFactory.createRequirement("test.capability", capabilityId, ANY_VERSION, null, /* optional=> */true, /* multiple=> */false, /* greedy=>*/false);
- IInstallableUnit toInstallIU = createIU("toInstall." + getName(), new IRequirement[] {required});
+ IRequirement[] requires = new IRequirement[] {
+ MetadataFactory.createRequirement(capabilityNamespace, capabilityName, ANY_VERSION, null, /* optional=> */true, /* multiple=> */false, /* greedy=>*/false)
+ };
+ IInstallableUnit toInstallIU = createIU("toInstall." + getName(), requires);
+ // Metadata repository
IInstallableUnit[] allUnits = new IInstallableUnit[] {toInstallIU, requiredIU};
- IInstallableUnit[] toInstallArray = new IInstallableUnit[] {toInstallIU};
createTestMetdataRepository(allUnits);
IProfile profile = createProfile("TestProfile." + getName());
- IDirector director = createDirector();
+
+ // Change request
ProfileChangeRequest request = new ProfileChangeRequest(profile);
+ IInstallableUnit[] toInstallArray = new IInstallableUnit[] {toInstallIU};
request.addInstallableUnits(toInstallArray);
+
+ // Provision
+ IDirector director = createDirector();
IStatus result = director.provision(request, null, null);
- if (!result.isOK())
+ if (!result.isOK()) {
LogHelper.log(result);
+ }
+
+ // The requiredIu is not installed, because the optional requirement is not greedy
assertTrue("1.0", result.isOK());
assertProfileContains("1.1", profile, toInstallArray);
}
@@ -100,21 +117,34 @@ public class AutomatedDirectorTest extends AbstractProvisioningTest {
* Tests installing an IU that has an optional prerequisite that is not available.
*/
public void testInstallOptionalUnavailable() {
- String capabilityId = "test." + getName();
- //no IU will be available that exports this capability
- IRequirement required = MetadataFactory.createRequirement("test.capability", capabilityId, ANY_VERSION, null, true, false);
- IInstallableUnit toInstallIU = createIU("toInstall." + getName(), new IRequirement[] {required});
+ final String capabilityNamespace = "test.capability";
+ final String capabilityName = "test." + getName();
+
+ // no IU will be available that exports this capability
+ IRequirement[] requires = new IRequirement[] {
+ MetadataFactory.createRequirement(capabilityNamespace, capabilityName, ANY_VERSION, null, /* optional=> */true, /* multiple=> */false)
+ };
+ IInstallableUnit toInstallIU = createIU("toInstall." + getName(), requires);
+ // Metadata repo
IInstallableUnit[] allUnits = new IInstallableUnit[] {toInstallIU};
createTestMetdataRepository(allUnits);
+ // Profile
IProfile profile = createProfile("TestProfile." + getName());
- IDirector director = createDirector();
+
+ // Change request
ProfileChangeRequest request = new ProfileChangeRequest(profile);
request.addInstallableUnits(allUnits);
+
+ // Provision
+ IDirector director = createDirector();
IStatus result = director.provision(request, null, null);
- if (!result.isOK())
+ if (!result.isOK()) {
LogHelper.log(result);
+ }
+
+ // The UI is installed because the requirement is optional
assertTrue("1.0", result.isOK());
assertProfileContains("1.1", profile, allUnits);
}
@@ -124,30 +154,50 @@ public class AutomatedDirectorTest extends AbstractProvisioningTest {
* the capability has a platform filter that is not satisfied.
*/
public void testInstallPlatformFilter() {
- //The IU that exports the capability
- String capabilityId = "test." + getName();
- IProvidedCapability[] provides = new IProvidedCapability[] {MetadataFactory.createProvidedCapability("test.capability", capabilityId, DEFAULT_VERSION)};
- IInstallableUnit requiredIU = createIU("required." + getName(), createFilter("osgi.os", "blort"), provides);
+ // Profile environment
+ final String osKey = "osgi.os";
+ final String osVal = "blort";
+
+ // Test capability
+ final String capabilityNamespace = "test.capability";
+ final String capabilityName = "test." + getName();
+ final Version capabilityVersion = DEFAULT_VERSION;
- IInstallableUnit toInstallIU = createIU("toInstall." + getName(), createRequiredCapabilities("test.capability", capabilityId, ANY_VERSION, (IMatchExpression<IInstallableUnit>) null));
+ // The IU that exports the capability
+ IProvidedCapability[] provides = new IProvidedCapability[] {MetadataFactory.createProvidedCapability(capabilityNamespace, capabilityName, capabilityVersion)};
+ IInstallableUnit requiredIU = createIU("required." + getName(), createFilter(osKey, osVal), provides);
+ // Installed IU
+ IInstallableUnit toInstallIU = createIU("toInstall." + getName(), createRequiredCapabilities(capabilityNamespace, capabilityName, ANY_VERSION, (IMatchExpression<IInstallableUnit>) null));
+
+ // Metadata repo
IInstallableUnit[] allUnits = new IInstallableUnit[] {requiredIU, toInstallIU};
- IInstallableUnit[] toInstallArray = new IInstallableUnit[] {toInstallIU};
createTestMetdataRepository(allUnits);
- IProfile profile = createProfile("TestProfile." + getName());
IDirector director = createDirector();
+
+ // Profile that does not satisfy the OS requirement
+ IProfile profile = createProfile("TestProfile." + getName());
+
+ // Request
ProfileChangeRequest request = new ProfileChangeRequest(profile);
+ IInstallableUnit[] toInstallArray = new IInstallableUnit[] {toInstallIU};
request.addInstallableUnits(toInstallArray);
+
+ // Provision - should fail since requireIU can't be installed on the current environment
IStatus result = director.provision(request, null, null);
assertTrue("1.0", !result.isOK());
- //try again with the filter satisfied
+ // New profile that satisfies the OS requirement
Map<String, String> properties = new HashMap<>();
- properties.put(IProfile.PROP_ENVIRONMENTS, "osgi.os=blort");
- IProfile profile2 = createProfile("TestProfile2." + getName(), properties);
- request = new ProfileChangeRequest(profile2);
+ properties.put(IProfile.PROP_ENVIRONMENTS, osKey + "=" + osVal);
+ profile = createProfile("TestProfile2." + getName(), properties);
+
+ // New request
+ request = new ProfileChangeRequest(profile);
request.addInstallableUnits(toInstallArray);
+
+ // New provisioning - should succeed
result = director.provision(request, null, null);
assertTrue("2.0", result.isOK());
}
@@ -156,27 +206,42 @@ public class AutomatedDirectorTest extends AbstractProvisioningTest {
* Tests installing an IU that has an unsatisfied platform filter
*/
public void testInstallPlatformFilterUnsatisfied() {
- //The IU to install
- IInstallableUnit toInstallIU = createIU("toInstall." + getName(), createFilter("osgi.os", "blort"), NO_PROVIDES);
+ // Profile environment
+ final String osKey = "osgi.os";
+ final String osVal = "blort";
+
+ // The IU to install that needs a concrete environment
+ IInstallableUnit toInstallIU = createIU("toInstall." + getName(), createFilter(osKey, osVal), NO_PROVIDES);
+
+ // Metadata repo
IInstallableUnit[] allUnits = new IInstallableUnit[] {toInstallIU};
- IInstallableUnit[] toInstallArray = new IInstallableUnit[] {toInstallIU};
createTestMetdataRepository(allUnits);
+ // Profile without a matching environment
IProfile profile = createProfile("TestProfile." + getName());
- IDirector director = createDirector();
+
+ // Change request
ProfileChangeRequest request = new ProfileChangeRequest(profile);
+ IInstallableUnit[] toInstallArray = new IInstallableUnit[] {toInstallIU};
request.addInstallableUnits(toInstallArray);
+
+ // Provisioning failure: incompatible environment
+ IDirector director = createDirector();
IStatus result = director.provision(request, null, null);
- assertTrue("1.0", !result.isOK());
+ assertTrue(!result.isOK());
- //try again with the filter satisfied
+ // Profile with matching environment
Map<String, String> properties = new HashMap<>();
- properties.put(IProfile.PROP_ENVIRONMENTS, "osgi.os=blort");
- IProfile profile2 = createProfile("TestProfile2." + getName(), properties);
- request = new ProfileChangeRequest(profile2);
+ properties.put(IProfile.PROP_ENVIRONMENTS, osKey + "=" + osVal);
+ profile = createProfile("TestProfile2." + getName(), properties);
+
+ // New change request
+ request = new ProfileChangeRequest(profile);
request.addInstallableUnits(toInstallArray);
+
+ // Provisioning success
result = director.provision(request, null, null);
- assertTrue("2.0", result.isOK());
+ assertTrue(result.isOK());
}
/**
@@ -184,24 +249,39 @@ public class AutomatedDirectorTest extends AbstractProvisioningTest {
* that the IU providing the capability is installed.
*/
public void testSimpleInstallRequired() {
- String capabilityId = "test." + getName();
+ // Test capability
+ String capabilityNamespace = "test.capability";
+ String capabilityName = "test." + getName();
+
//The IU that exports the capability
- IInstallableUnit requiredIU = createIU("required." + getName(), new IProvidedCapability[] {MetadataFactory.createProvidedCapability("test.capability", capabilityId, DEFAULT_VERSION)});
+ IProvidedCapability[] provides = new IProvidedCapability[] {
+ MetadataFactory.createProvidedCapability(capabilityNamespace, capabilityName, DEFAULT_VERSION)
+ };
+ IInstallableUnit requiredIU = createIU("required." + getName(), provides);
- IInstallableUnit toInstallIU = createIU("toInstall." + getName(), createRequiredCapabilities("test.capability", capabilityId, ANY_VERSION, (IMatchExpression<IInstallableUnit>) null));
+ // The IU that requires the capability
+ IRequirement[] requires = createRequiredCapabilities(capabilityNamespace, capabilityName, ANY_VERSION, (IMatchExpression<IInstallableUnit>) null);
+ IInstallableUnit toInstallIU = createIU("toInstall." + getName(), requires);
+ // Crate the metadata repo
IInstallableUnit[] allUnits = new IInstallableUnit[] {requiredIU, toInstallIU};
- IInstallableUnit[] toInstallArray = new IInstallableUnit[] {toInstallIU};
createTestMetdataRepository(allUnits);
+ // Provision
IProfile profile = createProfile("TestProfile." + getName());
- IDirector director = createDirector();
+ // Create the profile change request
ProfileChangeRequest request = new ProfileChangeRequest(profile);
+ IInstallableUnit[] toInstallArray = new IInstallableUnit[] {toInstallIU};
request.addInstallableUnits(toInstallArray);
+
+ // Provision
+ IDirector director = createDirector();
IStatus result = director.provision(request, null, null);
- if (!result.isOK())
+ if (!result.isOK()) {
LogHelper.log(result);
+ }
+
assertTrue("1.0", result.isOK());
assertProfileContains("1.1", profile, allUnits);
}
@@ -211,24 +291,34 @@ public class AutomatedDirectorTest extends AbstractProvisioningTest {
* specifying a version range (any version will do).
*/
public void testInstallRequiredNoVersion() {
- //The IU that is needed
+ // The IU that is needed
IInstallableUnit requiredIU = createIU("required." + getName());
- IRequirement capability = MetadataFactory.createRequirement(IInstallableUnit.NAMESPACE_IU_ID, requiredIU.getId(), null, null, false, false);
- IInstallableUnit toInstallIU = createIU("toInstall." + getName(), new IRequirement[] {capability});
+ // The IU that is installed
+ IRequirement[] requires = new IRequirement[] {
+ MetadataFactory.createRequirement(IInstallableUnit.NAMESPACE_IU_ID, requiredIU.getId(), null, null, false, false)
+ };
+ IInstallableUnit toInstallIU = createIU("toInstall." + getName(), requires);
+ // Metadata repo
IInstallableUnit[] allUnits = new IInstallableUnit[] {requiredIU, toInstallIU};
- IInstallableUnit[] toInstallArray = new IInstallableUnit[] {toInstallIU};
createTestMetdataRepository(allUnits);
+ // Profile
IProfile profile = createProfile("TestProfile." + getName());
- IDirector director = createDirector();
+ // Profile change request
ProfileChangeRequest request = new ProfileChangeRequest(profile);
+ IInstallableUnit[] toInstallArray = new IInstallableUnit[] {toInstallIU};
request.addInstallableUnits(toInstallArray);
+
+ // Provision
+ IDirector director = createDirector();
IStatus result = director.provision(request, null, null);
- if (!result.isOK())
+ if (!result.isOK()) {
LogHelper.log(result);
+ }
+
assertTrue("1.0", result.isOK());
assertProfileContains("1.1", profile, allUnits);
}
@@ -239,25 +329,34 @@ public class AutomatedDirectorTest extends AbstractProvisioningTest {
* capability on the IU namespace.
*/
public void testSimpleInstallRequiredIU() {
- //The IU that exports the capability
+ // The IU that is required. It exports it's identity capability by default.
IInstallableUnit requiredIU = createIU("required." + getName());
- IRequirement capability = MetadataFactory.createRequirement(IInstallableUnit.NAMESPACE_IU_ID, requiredIU.getId(), ANY_VERSION, null, false, false);
- IInstallableUnit toInstallIU = createIU("toInstall." + getName(), new IRequirement[] {capability});
+ // The IU that is installed
+ IRequirement[] requires = new IRequirement[] {
+ MetadataFactory.createRequirement(IInstallableUnit.NAMESPACE_IU_ID, requiredIU.getId(), ANY_VERSION, null, false, false)
+ };
+ IInstallableUnit toInstallIU = createIU("toInstall." + getName(), requires);
+ // Create the metadata repo
IInstallableUnit[] allUnits = new IInstallableUnit[] {requiredIU, toInstallIU};
- IInstallableUnit[] toInstallArray = new IInstallableUnit[] {toInstallIU};
createTestMetdataRepository(allUnits);
IProfile profile = createProfile("TestProfile." + getName());
- IDirector director = createDirector();
+ // Create the profile change request
ProfileChangeRequest request = new ProfileChangeRequest(profile);
+ IInstallableUnit[] toInstallArray = new IInstallableUnit[] {toInstallIU};
request.addInstallableUnits(toInstallArray);
+
+ // Provision
+ IDirector director = createDirector();
IStatus result = director.provision(request, null, null);
- if (!result.isOK())
+ if (!result.isOK()) {
LogHelper.log(result);
- assertTrue("1.0", result.isOK());
+ }
+
+ assertTrue(result.isOK());
assertProfileContains("1.1", profile, allUnits);
}
diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/engine/PhaseSetTest.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/engine/PhaseSetTest.java
index f085f9415..609d1d69a 100644
--- a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/engine/PhaseSetTest.java
+++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/engine/PhaseSetTest.java
@@ -12,21 +12,42 @@ package org.eclipse.equinox.p2.tests.engine;
import java.io.File;
import java.net.URI;
-import java.util.*;
+import java.util.EventObject;
+import java.util.HashMap;
+import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-import org.eclipse.core.runtime.*;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.equinox.internal.p2.director.ProfileChangeRequest;
-import org.eclipse.equinox.internal.p2.engine.*;
+import org.eclipse.equinox.internal.p2.engine.BeginOperationEvent;
+import org.eclipse.equinox.internal.p2.engine.CommitOperationEvent;
+import org.eclipse.equinox.internal.p2.engine.EngineSession;
+import org.eclipse.equinox.internal.p2.engine.InstallableUnitOperand;
+import org.eclipse.equinox.internal.p2.engine.Phase;
+import org.eclipse.equinox.internal.p2.engine.PhaseEvent;
+import org.eclipse.equinox.internal.p2.engine.PhaseSet;
+import org.eclipse.equinox.internal.p2.engine.ProfileEvent;
+import org.eclipse.equinox.internal.p2.engine.RollbackOperationEvent;
import org.eclipse.equinox.internal.p2.repository.DownloadProgressEvent;
import org.eclipse.equinox.internal.p2.touchpoint.natives.Util;
import org.eclipse.equinox.internal.provisional.p2.core.eventbus.ProvisioningListener;
import org.eclipse.equinox.internal.provisional.p2.repository.RepositoryEvent;
import org.eclipse.equinox.p2.core.ProvisionException;
-import org.eclipse.equinox.p2.engine.*;
+import org.eclipse.equinox.p2.engine.IEngine;
+import org.eclipse.equinox.p2.engine.IPhaseSet;
+import org.eclipse.equinox.p2.engine.IProfile;
+import org.eclipse.equinox.p2.engine.IProvisioningPlan;
+import org.eclipse.equinox.p2.engine.PhaseSetFactory;
+import org.eclipse.equinox.p2.engine.ProvisioningContext;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
-import org.eclipse.equinox.p2.query.*;
+import org.eclipse.equinox.p2.query.IQuery;
+import org.eclipse.equinox.p2.query.IQueryResult;
+import org.eclipse.equinox.p2.query.QueryUtil;
import org.eclipse.equinox.p2.repository.artifact.IArtifactRepository;
import org.eclipse.equinox.p2.tests.AbstractProvisioningTest;
import org.eclipse.equinox.p2.tests.TestActivator;
@@ -176,7 +197,7 @@ public class PhaseSetTest extends AbstractProvisioningTest {
getArtifactRepositoryManager().loadRepository(repoURI, null);
doProvisioning(repoURI, phaseSet, query, expectedCode, monitor);
// make sure the listener handles all event already that are dispatched asynchronously
- listener.latch.await(10, TimeUnit.SECONDS);
+ listener.latch.await(15, TimeUnit.SECONDS);
assertFalse("Engine still do provisioning after pausing.", listener.hasProvisioningEventAfterPaused);
pauseJob.join();
} finally {
diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/metadata/RequirementToString.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/metadata/RequirementToString.java
index 1ccc188bf..476d0daed 100644
--- a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/metadata/RequirementToString.java
+++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/metadata/RequirementToString.java
@@ -23,18 +23,23 @@ import org.eclipse.equinox.p2.metadata.expression.IMatchExpression;
public class RequirementToString extends TestCase {
public void testRequirementWithEmptyRange() {
IRequirement req = MetadataFactory.createRequirement("expectedNameSpace", "expectedName", VersionRange.emptyRange, null, false, false);
- assertEquals("expectedNameSpace expectedName 0.0.0", req.toString());
+ assertEquals("expectedNameSpace; expectedName 0.0.0", req.toString());
}
public void testStandardRequirement() {
IRequirement req = MetadataFactory.createRequirement("expectedNameSpace", "expectedName", new VersionRange("[1.0.0, 2.0.0)"), null, false, false);
- assertEquals("expectedNameSpace expectedName [1.0.0,2.0.0)", req.toString());
+ assertEquals("expectedNameSpace; expectedName [1.0.0,2.0.0)", req.toString());
+ }
+
+ public void testPropertiesRequirement() {
+ IRequirement req = MetadataFactory.createRequirement("expectedNameSpace", "(key=val)", null, 1, 1, true);
+ assertEquals("expectedNameSpace; (key=val)", req.toString());
}
public void testFancyRequirement() {
- Object[] expressionParameters = new Object[] {"expectedId1, expectedVersion1", "expectedId2, expectedVersion2"};
+ Object[] expressionParameters = new Object[] {"expectedId1", "expectedVersion1", "expectedId2", "expectedVersion2"};
IMatchExpression<IInstallableUnit> iuMatcher = ExpressionUtil.getFactory().<IInstallableUnit> matchExpression(ExpressionUtil.parse("(id == $0 && version == $1) || (id == $2 && version == $3)"), expressionParameters);
IRequirement req = MetadataFactory.createRequirement(iuMatcher, null, 1, 1, true);
- assertEquals("id == $0 && version == $1 || id == $2 && version == $3 expectedId1, expectedVersion1 expectedId2, expectedVersion2", req.toString().trim());
+ assertEquals("id == $0 && version == $1 || id == $2 && version == $3 (expectedId1, expectedVersion1, expectedId2, expectedVersion2)", req.toString().trim());
}
}
diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/metadata/expression/AllTests.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/metadata/expression/AllTests.java
index 27ebc00b8..8e5be56d7 100644
--- a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/metadata/expression/AllTests.java
+++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/metadata/expression/AllTests.java
@@ -4,13 +4,16 @@
* 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.equinox.p2.tests.metadata.expression;
-import junit.framework.*;
+import junit.framework.JUnit4TestAdapter;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
/**
* Performs all automated director tests.
@@ -20,7 +23,7 @@ public class AllTests extends TestCase {
public static Test suite() {
TestSuite suite = new TestSuite(AllTests.class.getName());
suite.addTestSuite(ExpressionTest.class);
- suite.addTestSuite(FilterTest.class);
+ suite.addTest(new JUnit4TestAdapter(FilterTest.class));
return suite;
}
diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/metadata/expression/FilterTest.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/metadata/expression/FilterTest.java
index 0d6895ac2..4a51833fb 100644
--- a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/metadata/expression/FilterTest.java
+++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/metadata/expression/FilterTest.java
@@ -10,19 +10,225 @@
*******************************************************************************/
package org.eclipse.equinox.p2.tests.metadata.expression;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
import java.math.BigDecimal;
import java.math.BigInteger;
-import java.util.*;
-import junit.framework.*;
-import org.eclipse.equinox.p2.metadata.expression.*;
-import org.osgi.framework.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.equinox.p2.metadata.Version;
+import org.eclipse.equinox.p2.metadata.expression.ExpressionParseException;
+import org.eclipse.equinox.p2.metadata.expression.ExpressionUtil;
+import org.eclipse.equinox.p2.metadata.expression.IFilterExpression;
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceReference;
+
+public class FilterTest {
+ @Test
+ public void testComparable() throws Exception {
+ IFilterExpression f1 = ExpressionUtil.parseLDAP("(comparable=42)");
+ Object comp;
+ Map<String, Object> hash = new HashMap<>();
+
+ comp = new SampleComparable("42");
+ hash.put("comparable", comp);
+ assertTrue("does not match filter", f1.match(hash));
+ assertTrue("does not match filter", f1.match(new DictionaryServiceReference(hash)));
+
+ comp = Long.valueOf(42);
+ hash.put("comparable", comp);
+ assertTrue("does not match filter", f1.match(hash));
+ assertTrue("does not match filter", f1.match(new DictionaryServiceReference(hash)));
+
+ IFilterExpression f2 = ExpressionUtil.parseLDAP("(comparable=42)");
+ hash = new Hashtable<>();
+
+ comp = new SampleComparable("42");
+ hash.put("comparable", comp);
+ assertTrue("does not match filter", f2.match(hash));
+ assertTrue("does not match filter", f2.match(new DictionaryServiceReference(hash)));
+
+ comp = Long.valueOf(42);
+ hash.put("comparable", comp);
+ assertTrue("does not match filter", f2.match(hash));
+ assertTrue("does not match filter", f2.match(new DictionaryServiceReference(hash)));
+
+ assertEquals("not equal", f1, f2);
+ }
+
+ @Test
+ public void testFilterEquality() {
+ Filter f1 = ExpressionUtil.parseLDAP("( a = bedroom )");
+ Filter f2 = ExpressionUtil.parseLDAP(" (a= bedroom ) ");
+ assertEquals("not equal", "(a= bedroom )", f1.toString());
+ assertEquals("not equal", "(a= bedroom )", f2.toString());
+ assertEquals("not equal", f1, f2);
+ assertEquals("not equal", f2, f1);
+ assertEquals("not equal", f1.hashCode(), f2.hashCode());
+
+ f1 = ExpressionUtil.parseLDAP("(status =\\28o*\\5c\\29\\2a)");
+ assertEquals("not equal", "(status=\\28o*\\5c\\29\\2a)", f1.toString());
+
+ f1 = ExpressionUtil.parseLDAP("(|(a=1)(&(a=1)(b=1)))");
+ f2 = ExpressionUtil.parseLDAP("(a=1)");
+
+ f1 = ExpressionUtil.parseLDAP("(|(&(os=macos)(ws=cocoa)(arch=x86))(&(ws=cocoa)(os=macos)(arch=ppc)))");
+ f2 = ExpressionUtil.parseLDAP("(&(os=macos)(ws=cocoa)(|(arch=x86)(arch=ppc)))");
+ assertEquals("not equal: f1:" + f1.toString() + ", f2:" + f1.toString(), f1, f2);
+
+ f1 = ExpressionUtil.parseLDAP("(&(|(x=a)(y=b)(z=a))(|(x=a)(y=b)(z=b)))");
+ f2 = ExpressionUtil.parseLDAP("(|(x=a)(y=b)(&(z=a)(z=b)))");
+ assertEquals("not equal: f1:" + f1.toString() + ", f2:" + f1.toString(), f1, f2);
+
+ f1 = ExpressionUtil.parseLDAP("(&(a=1)(|(a=1)(b=1)))");
+ f2 = ExpressionUtil.parseLDAP("(a=1)");
+
+ f1 = ExpressionUtil.parseLDAP("(|(a=1)(&(a=1)(b=1)))");
+ f2 = ExpressionUtil.parseLDAP("(a=1)");
+ assertEquals("not equal: f1:" + f1.toString() + ", f2:" + f1.toString(), f1, f2);
+ }
+
+ @Test
+ public void testFilterMatching() {
+ Dictionary<String, Object> props = new Hashtable<>();
+ props.put("room", "bedroom");
+ props.put("channel", Integer.valueOf(34));
+ props.put("status", "(on\\)*");
+ props.put("max record time", Long.valueOf(150));
+ props.put("canrecord", "true(x)");
+ props.put("shortvalue", Short.valueOf((short) 1000));
+ props.put("bytevalue", Byte.valueOf((byte) 10));
+ props.put("floatvalue", Float.valueOf(1.01f));
+ props.put("doublevalue", Double.valueOf(2.01));
+ props.put("charvalue", Character.valueOf('A'));
+ props.put("booleanvalue", Boolean.FALSE);
+ props.put("listvalue", Arrays.asList(1, 2, 3));
+ props.put("versionlistvalue", Arrays.asList(Version.create("1"), Version.create("2"), Version.create("3")));
+ props.put("weirdvalue", new Hashtable<>());
+ props.put("bigintvalue", new BigInteger("4123456"));
+ props.put("bigdecvalue", new BigDecimal("4.123456"));
+
+ assertMatch("(room=*)", props);
+ assertNoMatch("(rooom=*)", props);
+ assertMatch("(room=bedroom)", props);
+ assertMatch("(room~= B E D R O O M )", props);
+ assertNoMatch("(room=abc)", props);
+ assertMatch(" ( room >=aaaa)", props);
+ assertNoMatch("(room <=aaaa)", props);
+ assertMatch(" ( room =b*) ", props);
+ assertMatch(" ( room =*m) ", props);
+ assertMatch("(room=bed*room)", props);
+ assertMatch(" ( room =b*oo*m) ", props);
+ assertMatch(" ( room =*b*oo*m*) ", props);
+ assertNoMatch(" ( room =b*b* *m*) ", props);
+ assertMatch(" (& (room =bedroom) (channel = 34))", props);
+ assertNoMatch(" (& (room =b*) (room =*x) (channel=34))", props);
+ assertMatch("(| (room =bed*)(channel=222)) ", props);
+ assertMatch("(| (room =boom*)(channel=34)) ", props);
+ assertMatch(" (! (room =ab*b*oo*m*) ) ", props);
+ assertMatch(" (status =\\(o*\\\\\\)\\*) ", props);
+ assertMatch(" (status =\\28o*\\5c\\29\\2a) ", props);
+ assertMatch(" (status =\\28o*\\5C\\29\\2A) ", props);
+ assertMatch(" (canRecord =true\\(x\\)) ", props);
+ assertMatch("(max Record Time <=150) ", props);
+ assertMatch("(shortValue >= 100) ", props);
+ assertMatch(" ( & ( byteValue <= 100 ) ( byteValue >= 10 ) ) ", props);
+ assertMatch("(bigIntValue = 4123456) ", props);
+ assertMatch("(bigDecValue = 4.123456) ", props);
+ assertMatch("(floatValue >= 1.0) ", props);
+ assertMatch("(doubleValue <= 2.011) ", props);
+ assertMatch("(charValue ~= a) ", props);
+ assertMatch("(booleanValue = false) ", props);
+ assertMatch("(listvalue>=0)", props);
+ assertMatch("(listvalue=3)", props);
+ assertMatch("(!(listvalue>=4))", props);
+ assertMatch("(versionlistvalue>=0)", props);
+ assertMatch("(versionlistvalue=3)", props);
+ assertMatch("(!(versionlistvalue>=4))", props);
+ assertMatch("(& (| (room =d*m) (room =bed*) (room=abc)) (! (channel=999)))", props);
+ assertNoMatch("(room=bedroom)", null);
+ assertNoMatch("(weirdValue = 100) ", props);
+ }
+
+ @Test
+ public void testFilterParserErrors() {
+ assertParseError("()");
+ assertParseError("(=foo)");
+ assertParseError("(");
+ assertParseError("(abc = ))");
+ assertParseError("(& (abc = xyz) (& (345))");
+ assertParseError(" (room = b**oo!*m*) ) ");
+ assertParseError(" (room = b**oo)*m*) ) ");
+ assertParseError(" (room = *=b**oo*m*) ) ");
+ assertParseError(" (room = =b**oo*m*) ) ");
+ }
+
+ private void assertMatch(String query, Dictionary<String, Object> props) {
+ expectMatch(query, props, true);
+ }
+
+ private void assertNoMatch(String query, Dictionary<String, Object> props) {
+ expectMatch(query, props, false);
+ }
+
+ private void expectMatch(String query, Dictionary<String, Object> props, boolean match) {
+ Filter f = ExpressionUtil.parseLDAP(query);
+
+ // TODO Doing raw conversion here for simplicity; could convert to Dictionary<String, ?>
+ // but the filter impl must still handle cases where non String keys are used.
+ assertEquals(match, f.match(props));
+
+ ServiceReference ref = new DictionaryServiceReference((Map<String, ? extends Object>) props);
+ assertEquals(match, f.match(ref));
+ }
+
+ private void assertParseError(String query) {
+ try {
+ ExpressionUtil.parseLDAP(query);
+ fail("expected exception");
+ } catch (ExpressionParseException e) {
+ // Pass
+ }
+ }
+
+ private static class SampleComparable implements Comparable<SampleComparable> {
+ private int value = -1;
+
+ public SampleComparable(String value) {
+ this.value = Integer.parseInt(value);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof SampleComparable && value == ((SampleComparable) o).value;
+ }
+
+ @Override
+ public int compareTo(SampleComparable o) {
+ return value - o.value;
+ }
+
+ @Override
+ public String toString() {
+ return String.valueOf(value);
+ }
+ }
-public class FilterTest extends TestCase {
private static class DictionaryServiceReference implements ServiceReference {
private final Map<String, ? extends Object> dictionary;
-
+
private final String[] keys;
-
+
DictionaryServiceReference(Map<String, ? extends Object> dictionary) {
if (dictionary == null) {
this.dictionary = null;
@@ -42,17 +248,17 @@ public class FilterTest extends TestCase {
}
this.keys = keyList.toArray(new String[keyList.size()]);
}
-
+
@Override
public int compareTo(Object reference) {
throw new UnsupportedOperationException();
}
-
+
@Override
public Bundle getBundle() {
return null;
}
-
+
@Override
public Object getProperty(String k) {
for (int i = 0, length = keys.length; i < length; i++) {
@@ -63,230 +269,25 @@ public class FilterTest extends TestCase {
}
return null;
}
-
+
@Override
public String[] getPropertyKeys() {
return keys.clone();
}
-
+
@Override
public Bundle[] getUsingBundles() {
throw new UnsupportedOperationException();
}
-
+
@Override
public boolean isAssignableTo(Bundle bundle, String className) {
throw new UnsupportedOperationException();
}
-
+
@Override
public Dictionary<String, Object> getProperties() {
return new Hashtable<>(dictionary);
}
}
-
- private static class SampleComparable implements Comparable<SampleComparable> {
- private int value = -1;
-
- public SampleComparable(String value) {
- this.value = Integer.parseInt(value);
- }
-
- @Override
- public boolean equals(Object o) {
- return o instanceof SampleComparable && value == ((SampleComparable) o).value;
- }
-
- @Override
- public int compareTo(SampleComparable o) {
- return value - o.value;
- }
-
- @Override
- public String toString() {
- return String.valueOf(value);
- }
- }
-
- static final int ISTRUE = 1;
-
- static final int ISFALSE = 2;
-
- static final int ISILLEGAL = 3;
-
- public static Test suite() {
- return new TestSuite(FilterTest.class);
- }
-
- public void testComparable() throws Exception {
- IFilterExpression f1 = ExpressionUtil.parseLDAP("(comparable=42)"); //$NON-NLS-1$
- Object comp;
- Map<String, Object> hash = new HashMap<>();
-
- comp = new SampleComparable("42"); //$NON-NLS-1$
- hash.put("comparable", comp); //$NON-NLS-1$
- assertTrue("does not match filter", f1.match(hash)); //$NON-NLS-1$
- assertTrue("does not match filter", f1.match(new DictionaryServiceReference(hash))); //$NON-NLS-1$
-
- comp = Long.valueOf(42);
- hash.put("comparable", comp); //$NON-NLS-1$
- assertTrue("does not match filter", f1.match(hash)); //$NON-NLS-1$
- assertTrue("does not match filter", f1.match(new DictionaryServiceReference(hash))); //$NON-NLS-1$
-
- IFilterExpression f2 = ExpressionUtil.parseLDAP("(comparable=42)"); //$NON-NLS-1$
- hash = new Hashtable<>();
-
- comp = new SampleComparable("42"); //$NON-NLS-1$
- hash.put("comparable", comp); //$NON-NLS-1$
- assertTrue("does not match filter", f2.match(hash)); //$NON-NLS-1$
- assertTrue("does not match filter", f2.match(new DictionaryServiceReference(hash))); //$NON-NLS-1$
-
- comp = Long.valueOf(42);
- hash.put("comparable", comp); //$NON-NLS-1$
- assertTrue("does not match filter", f2.match(hash)); //$NON-NLS-1$
- assertTrue("does not match filter", f2.match(new DictionaryServiceReference(hash))); //$NON-NLS-1$
-
- assertEquals("not equal", f1, f2); //$NON-NLS-1$
- }
-
- public void testFilter() {
- Dictionary<String, Object> props = new Hashtable<>();
- props.put("room", "bedroom"); //$NON-NLS-1$ //$NON-NLS-2$
- props.put("channel", Integer.valueOf(34)); //$NON-NLS-1$
- props.put("status", "(on\\)*"); //$NON-NLS-1$//$NON-NLS-2$
- props.put("max record time", Long.valueOf(150)); //$NON-NLS-1$
- props.put("canrecord", "true(x)"); //$NON-NLS-1$ //$NON-NLS-2$
- props.put("shortvalue", Short.valueOf((short) 1000)); //$NON-NLS-1$
- props.put("bytevalue", Byte.valueOf((byte) 10)); //$NON-NLS-1$
- props.put("floatvalue", Float.valueOf(1.01f)); //$NON-NLS-1$
- props.put("doublevalue", Double.valueOf(2.01)); //$NON-NLS-1$
- props.put("charvalue", Character.valueOf('A')); //$NON-NLS-1$
- props.put("booleanvalue", Boolean.FALSE); //$NON-NLS-1$
- props.put("weirdvalue", new Hashtable<>()); //$NON-NLS-1$
- try {
- props.put("bigintvalue", new BigInteger("4123456")); //$NON-NLS-1$ //$NON-NLS-2$
- } catch (NoClassDefFoundError e) {
- // ignore
- }
- try {
- props.put("bigdecvalue", new BigDecimal("4.123456")); //$NON-NLS-1$ //$NON-NLS-2$
- } catch (NoClassDefFoundError e) {
- // ignore
- }
-
- testFilter("(room=*)", props, ISTRUE); //$NON-NLS-1$
- testFilter("(rooom=*)", props, ISFALSE); //$NON-NLS-1$
- testFilter("(room=bedroom)", props, ISTRUE); //$NON-NLS-1$
- testFilter("(room~= B E D R O O M )", props, ISTRUE); //$NON-NLS-1$
- testFilter("(room=abc)", props, ISFALSE); //$NON-NLS-1$
- testFilter(" ( room >=aaaa)", props, ISTRUE); //$NON-NLS-1$
- testFilter("(room <=aaaa)", props, ISFALSE); //$NON-NLS-1$
- testFilter(" ( room =b*) ", props, ISTRUE); //$NON-NLS-1$
- testFilter(" ( room =*m) ", props, ISTRUE); //$NON-NLS-1$
- testFilter("(room=bed*room)", props, ISTRUE); //$NON-NLS-1$
- testFilter(" ( room =b*oo*m) ", props, ISTRUE); //$NON-NLS-1$
- testFilter(" ( room =*b*oo*m*) ", props, ISTRUE); //$NON-NLS-1$
- testFilter(" ( room =b*b* *m*) ", props, ISFALSE); //$NON-NLS-1$
- testFilter(" (& (room =bedroom) (channel = 34))", props, ISTRUE); //$NON-NLS-1$
- testFilter(" (& (room =b*) (room =*x) (channel=34))", props, ISFALSE); //$NON-NLS-1$
- testFilter("(| (room =bed*)(channel=222)) ", props, ISTRUE); //$NON-NLS-1$
- testFilter("(| (room =boom*)(channel=34)) ", props, ISTRUE); //$NON-NLS-1$
- testFilter(" (! (room =ab*b*oo*m*) ) ", props, ISTRUE); //$NON-NLS-1$
- testFilter(" (status =\\(o*\\\\\\)\\*) ", props, ISTRUE); //$NON-NLS-1$
- testFilter(" (status =\\28o*\\5c\\29\\2a) ", props, ISTRUE); //$NON-NLS-1$
- testFilter(" (status =\\28o*\\5C\\29\\2A) ", props, ISTRUE); //$NON-NLS-1$
- testFilter(" (canRecord =true\\(x\\)) ", props, ISTRUE); //$NON-NLS-1$
- testFilter("(max Record Time <=150) ", props, ISTRUE); //$NON-NLS-1$
- testFilter("(shortValue >= 100) ", props, ISTRUE); //$NON-NLS-1$
- testFilter(" ( & ( byteValue <= 100 ) ( byteValue >= 10 ) ) ", props, ISTRUE); //$NON-NLS-1$
- testFilter("(bigIntValue = 4123456) ", props, ISTRUE); //$NON-NLS-1$
- testFilter("(bigDecValue = 4.123456) ", props, ISTRUE); //$NON-NLS-1$
- testFilter("(floatValue >= 1.0) ", props, ISTRUE); //$NON-NLS-1$
- testFilter("(doubleValue <= 2.011) ", props, ISTRUE); //$NON-NLS-1$
- testFilter("(charValue ~= a) ", props, ISTRUE); //$NON-NLS-1$
- testFilter("(booleanValue = false) ", props, ISTRUE); //$NON-NLS-1$
- testFilter("(& (| (room =d*m) (room =bed*) (room=abc)) (! (channel=999)))", props, ISTRUE); //$NON-NLS-1$
- testFilter("(room=bedroom)", null, ISFALSE); //$NON-NLS-1$
-
- testFilter("()", props, ISILLEGAL); //$NON-NLS-1$
- testFilter("(=foo)", props, ISILLEGAL); //$NON-NLS-1$
- testFilter("(", props, ISILLEGAL); //$NON-NLS-1$
- testFilter("(abc = ))", props, ISILLEGAL); //$NON-NLS-1$
- testFilter("(& (abc = xyz) (& (345))", props, ISILLEGAL); //$NON-NLS-1$
- testFilter(" (room = b**oo!*m*) ) ", props, ISILLEGAL); //$NON-NLS-1$
- testFilter(" (room = b**oo)*m*) ) ", props, ISILLEGAL); //$NON-NLS-1$
- testFilter(" (room = *=b**oo*m*) ) ", props, ISILLEGAL); //$NON-NLS-1$
- testFilter(" (room = =b**oo*m*) ) ", props, ISILLEGAL); //$NON-NLS-1$
-
- try {
- Filter f1 = ExpressionUtil.parseLDAP("( a = bedroom )"); //$NON-NLS-1$
- Filter f2 = ExpressionUtil.parseLDAP(" (a= bedroom ) "); //$NON-NLS-1$
- assertEquals("not equal", "(a= bedroom )", f1.toString()); //$NON-NLS-1$ //$NON-NLS-2$
- assertEquals("not equal", "(a= bedroom )", f2.toString()); //$NON-NLS-1$ //$NON-NLS-2$
- assertEquals("not equal", f1, f2); //$NON-NLS-1$
- assertEquals("not equal", f2, f1); //$NON-NLS-1$
- assertEquals("not equal", f1.hashCode(), f2.hashCode()); //$NON-NLS-1$
-
- f1 = ExpressionUtil.parseLDAP("(status =\\28o*\\5c\\29\\2a)");
- assertEquals("not equal", "(status=\\28o*\\5c\\29\\2a)", f1.toString()); //$NON-NLS-1$ //$NON-NLS-2$
-
- f1 = ExpressionUtil.parseLDAP("(|(a=1)(&(a=1)(b=1)))"); //$NON-NLS-1$
- f2 = ExpressionUtil.parseLDAP("(a=1)"); //$NON-NLS-1$
- System.out.println(f2.toString());
- System.out.println(f1.toString());
-
- f1 = ExpressionUtil.parseLDAP("(|(&(os=macos)(ws=cocoa)(arch=x86))(&(ws=cocoa)(os=macos)(arch=ppc)))"); //$NON-NLS-1$
- f2 = ExpressionUtil.parseLDAP("(&(os=macos)(ws=cocoa)(|(arch=x86)(arch=ppc)))"); //$NON-NLS-1$
- System.out.println(f2.toString());
- System.out.println(f1.toString());
- assertEquals("not equal", f1, f2); //$NON-NLS-1$
-
- f1 = ExpressionUtil.parseLDAP("(&(|(x=a)(y=b)(z=a))(|(x=a)(y=b)(z=b)))"); //$NON-NLS-1$
- f2 = ExpressionUtil.parseLDAP("(|(x=a)(y=b)(&(z=a)(z=b)))"); //$NON-NLS-1$
- System.out.println(f2.toString());
- System.out.println(f1.toString());
- assertEquals("not equal", f1, f2); //$NON-NLS-1$
-
- f1 = ExpressionUtil.parseLDAP("(&(a=1)(|(a=1)(b=1)))"); //$NON-NLS-1$
- f2 = ExpressionUtil.parseLDAP("(a=1)"); //$NON-NLS-1$
- System.out.println(f2.toString());
- System.out.println(f1.toString());
-
- f1 = ExpressionUtil.parseLDAP("(|(a=1)(&(a=1)(b=1)))"); //$NON-NLS-1$
- f2 = ExpressionUtil.parseLDAP("(a=1)"); //$NON-NLS-1$
- System.out.println(f2.toString());
- System.out.println(f1.toString());
- assertEquals("not equal", f1, f2); //$NON-NLS-1$
- } catch (IllegalArgumentException e) {
- fail("unexpected invalid syntax: " + e); //$NON-NLS-1$
- }
- testFilter("(weirdValue = 100) ", props, ISFALSE); //$NON-NLS-1$
-
- }
-
- private void testFilter(String query, Dictionary<String, Object> props, int expect) {
- final ServiceReference ref = new DictionaryServiceReference((Map<String, ? extends Object>) props);
- Filter f1;
- try {
- f1 = ExpressionUtil.parseLDAP(query);
-
- if (expect == ISILLEGAL) {
- fail("expected exception"); //$NON-NLS-1$
- }
- } catch (ExpressionParseException e) {
- System.out.println(e.toString());
- if (expect != ISILLEGAL) {
- fail("exception: " + e.toString()); //$NON-NLS-1$
- }
- return;
- }
-
- // TODO Doing raw conversion here for simplicity; could convert to Dictionary<String, ?>
- // but the filter impl must still handle cases where non String keys are used.
- boolean val = f1.match(props);
- assertEquals("wrong result", expect == ISTRUE, val); //$NON-NLS-1$
-
- val = f1.match(ref);
- assertEquals("wrong result", expect == ISTRUE, val); //$NON-NLS-1$
- }
}
diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/metadata/repository/SPIMetadataRepositoryTest.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/metadata/repository/SPIMetadataRepositoryTest.java
index 022b6549f..605143491 100644
--- a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/metadata/repository/SPIMetadataRepositoryTest.java
+++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/metadata/repository/SPIMetadataRepositoryTest.java
@@ -179,14 +179,14 @@ public class SPIMetadataRepositoryTest extends AbstractProvisioningTest {
class SPIProvidedCapability implements IProvidedCapability {
private final String namespace;
- private final Map<String, Object> attributes;
+ private final Map<String, Object> properties;
public SPIProvidedCapability(String namespace, String name, Version version) {
this.namespace = namespace;
- this.attributes = new HashMap<>();
- attributes.put(namespace, name);
- attributes.put(ProvidedCapability.ATTRIBUTE_VERSION, version);
+ this.properties = new HashMap<>();
+ properties.put(namespace, name);
+ properties.put(IProvidedCapability.PROPERTY_VERSION, version);
}
@Override
@@ -199,7 +199,7 @@ public class SPIMetadataRepositoryTest extends AbstractProvisioningTest {
if (!(namespace.equals(otherCapability.getNamespace()))) {
return false;
}
- if (!(attributes.equals(otherCapability.getAttributes()))) {
+ if (!(properties.equals(otherCapability.getProperties()))) {
return false;
}
return true;
@@ -207,12 +207,12 @@ public class SPIMetadataRepositoryTest extends AbstractProvisioningTest {
@Override
public String toString() {
- return namespace + "; " + attributes;
+ return namespace + "; " + properties;
}
@Override
public String getName() {
- return (String) attributes.get(namespace);
+ return (String) properties.get(namespace);
}
@Override
@@ -222,12 +222,12 @@ public class SPIMetadataRepositoryTest extends AbstractProvisioningTest {
@Override
public Version getVersion() {
- return (Version) attributes.get(ProvidedCapability.ATTRIBUTE_VERSION);
+ return (Version) properties.get(IProvidedCapability.PROPERTY_VERSION);
}
@Override
- public Map<String, Object> getAttributes() {
- return Collections.unmodifiableMap(attributes);
+ public Map<String, Object> getProperties() {
+ return Collections.unmodifiableMap(properties);
}
}
diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/planner/PropertyMatchRequirement.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/planner/PropertyMatchRequirement.java
new file mode 100644
index 000000000..4d709c93a
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/planner/PropertyMatchRequirement.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 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: IBM Corporation - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.equinox.p2.tests.planner;
+
+import static org.eclipse.core.runtime.IStatus.ERROR;
+import static org.eclipse.core.runtime.IStatus.OK;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.equinox.internal.p2.director.Explanation.MissingIU;
+import org.eclipse.equinox.internal.p2.director.ProfileChangeRequest;
+import org.eclipse.equinox.internal.provisional.p2.director.PlannerStatus;
+import org.eclipse.equinox.internal.provisional.p2.director.RequestStatus;
+import org.eclipse.equinox.p2.engine.IProfile;
+import org.eclipse.equinox.p2.engine.IProvisioningPlan;
+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.planner.IPlanner;
+import org.eclipse.equinox.p2.tests.AbstractProvisioningTest;
+
+public class PropertyMatchRequirement extends AbstractProvisioningTest {
+ private IInstallableUnit providerIu;
+ private IInstallableUnit consumerIu;
+
+ private IProfile profile;
+ private IPlanner planner;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ // A standard OSGi service representation
+ String osgiService = "osgi.service";
+ String objectClass = "objectClass";
+ List<String> objectClassList = Arrays.asList("org.example.A", "org.example.B", "org.example.C");
+
+ // Provider.
+ // TODO Check if p2 really needs a name. IProvidedCapability.equals() can differentiate by properties only.
+ Map<String, Object> capability = new HashMap<>();
+ capability.put(osgiService, "ignored-1");
+ capability.put(objectClass, objectClassList);
+
+ IProvidedCapability[] provides = new IProvidedCapability[] {
+ MetadataFactory.createProvidedCapability(osgiService, capability)
+ };
+ providerIu = createIU("provider", DEFAULT_VERSION, provides);
+
+ // Consumer
+ String requirement = String.format("(%s=%s)", objectClass, objectClassList.get(0));
+ IRequirement[] requires = new IRequirement[] {
+ MetadataFactory.createRequirement(osgiService, requirement, null, 1, 1, true)
+ };
+ consumerIu = createIU("consumer", DEFAULT_VERSION, requires);
+
+ // Planner
+ profile = createProfile("test." + getName());
+ planner = createPlanner();
+ }
+
+ public void testMandatoryPresent() {
+ createTestMetdataRepository(new IInstallableUnit[] {providerIu, consumerIu});
+
+ ProfileChangeRequest req = new ProfileChangeRequest(profile);
+ req.add(consumerIu);
+
+ // Must pass
+ IProvisioningPlan plan = planner.getProvisioningPlan(req, null, null);
+ assertEquals(OK, plan.getStatus().getSeverity());
+
+ // And both consumer and provider must be installed
+ assertInstallOperand(plan, consumerIu);
+ assertInstallOperand(plan, providerIu);
+ }
+
+ public void testMandatoryAbsent() {
+ createTestMetdataRepository(new IInstallableUnit[] {consumerIu});
+
+ ProfileChangeRequest req = new ProfileChangeRequest(profile);
+ req.add(consumerIu);
+
+ // Must fail
+ IProvisioningPlan plan = planner.getProvisioningPlan(req, null, null);
+ assertEquals(ERROR, plan.getStatus().getSeverity());
+
+ // With a good explanation
+ RequestStatus requestStatus = ((PlannerStatus) plan.getStatus()).getRequestStatus();
+ IRequirement consumerReq = consumerIu.getRequirements().iterator().next();
+ requestStatus.getExplanations()
+ .stream()
+ .filter(e -> e instanceof MissingIU)
+ .filter(e -> (((MissingIU) e).req.toString()).equals(consumerReq.toString()))
+ .findFirst()
+ .orElseGet(() -> {
+ fail("Did not find explanation for missing requirement: " + consumerReq);
+ return null;
+ });
+
+ // And the consumer must not be installed
+ assertNoOperand(plan, consumerIu);
+ }
+}
diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/publisher/actions/ActionTest.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/publisher/actions/ActionTest.java
index 058cca76c..faf51598b 100644
--- a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/publisher/actions/ActionTest.java
+++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/publisher/actions/ActionTest.java
@@ -27,15 +27,13 @@ import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.equinox.internal.p2.core.helpers.FileUtils;
+import org.eclipse.equinox.internal.p2.metadata.InstallableUnit;
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.Version;
import org.eclipse.equinox.p2.metadata.VersionRange;
-import org.eclipse.equinox.p2.metadata.expression.ExpressionUtil;
-import org.eclipse.equinox.p2.metadata.expression.IExpression;
-import org.eclipse.equinox.p2.metadata.expression.IMatchExpression;
import org.eclipse.equinox.p2.publisher.AbstractPublisherAction;
import org.eclipse.equinox.p2.publisher.IPublisherInfo;
import org.eclipse.equinox.p2.publisher.IPublisherResult;
@@ -92,18 +90,25 @@ public abstract class ActionTest extends AbstractProvisioningTest {
verifyRequirement(actual, namespace, name, range, null, 1, 1, true);
}
- protected void verifyRequirement(Collection<IRequirement> actual, String namespace, String name, VersionRange range, String filterStr, int minCard, int maxCard, boolean greedy) {
- IRequirement expected = MetadataFactory.createRequirement(namespace, name, range, null, minCard, maxCard, greedy);
+ protected void verifyRequirement(Collection<IRequirement> actual, String namespace, String name, VersionRange range, String envFilter, int minCard, int maxCard, boolean greedy) {
+ IRequirement expected = MetadataFactory.createRequirement(namespace, name, range, InstallableUnit.parseFilter(envFilter), minCard, maxCard, greedy);
verifyRequirement(actual, expected);
}
- protected void verifyRequirement(Collection<IRequirement> actual, String matchExpr, int minCard, int maxCard, boolean greedy) {
- IExpression expr = ExpressionUtil.parse(matchExpr);
- IMatchExpression<IInstallableUnit> matcher = ExpressionUtil.getFactory().matchExpression(expr);
- IRequirement expected = MetadataFactory.createRequirement(matcher, null, minCard, maxCard, greedy);
+ protected void verifyRequirement(Collection<IRequirement> actual, String namespace, String propsFilter, String envFilter, int minCard, int maxCard, boolean greedy) {
+ IRequirement expected = MetadataFactory.createRequirement(namespace, propsFilter, InstallableUnit.parseFilter(envFilter), minCard, maxCard, greedy);
verifyRequirement(actual, expected);
}
+ /**
+ * Safe to use only if actual and expected were created by the same method of {@link MetadataFactory}
+ * because match expressions are not safe to compare for equality.
+ *
+ * This must be guaranteed by all sub-class test cases
+ *
+ * @param actual
+ * @param expected
+ */
protected void verifyRequirement(Collection<IRequirement> actual, IRequirement expected) {
for (IRequirement act : actual) {
if (expected.getMatches().equals(act.getMatches())) {
diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/publisher/actions/BundlesActionTest.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/publisher/actions/BundlesActionTest.java
index af99bfe42..7e3ab0344 100644
--- a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/publisher/actions/BundlesActionTest.java
+++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/publisher/actions/BundlesActionTest.java
@@ -77,18 +77,19 @@ import org.eclipse.equinox.spi.p2.publisher.PublisherHelper;
public class BundlesActionTest extends ActionTest {
private static final String OSGI = PublisherHelper.OSGI_BUNDLE_CLASSIFIER;
private static final String OSGI_IDENTITY = "osgi.identity";
+ private static final String OSGI_EE = "osgi.ee";
private static final String JAVA_PACKAGE = "java.package";//$NON-NLS-1$
- private static final String JAVA_EE_1_4_REQ = "providedCapabilities.exists(pc | pc.namespace == 'osgi.ee' && pc.attributes ~= filter('(|(&(osgi.ee=JavaSE)(version=1.4))(&(osgi.ee=CDC/Foundation)(version=1.1)))'))";
- private static final String JAVA_EE_1_6_REQ = "providedCapabilities.exists(pc | pc.namespace == 'osgi.ee' && pc.attributes ~= filter('(&(osgi.ee=JavaSE)(version=1.6))'))";
+ private static final String JAVA_EE_1_4 = "(|(&(osgi.ee=JavaSE)(version=1.4))(&(osgi.ee=CDC/Foundation)(version=1.1)))";
+ private static final String JAVA_EE_1_6 = "(&(osgi.ee=JavaSE)(version=1.6))";
private static final String TEST1_IUD_NAME = "iud";//$NON-NLS-1$
private static final String TEST1_PROVZ_NAME = "iuz";//$NON-NLS-1$
private static final String TEST1_PROVBUNDLE_NAME = "test1";//$NON-NLS-1$
- private static final String TEST1_REQ_EE_FILTER = JAVA_EE_1_4_REQ;
+ private static final String TEST1_REQ_EE = JAVA_EE_1_4;
private static final String TEST2_REQ_A_NAME = "iua";//$NON-NLS-1$
private static final String TEST2_REQ_B_NAME = "iub";//$NON-NLS-1$
private static final String TEST2_REQ_C_NAME = "iuc";//$NON-NLS-1$
- private static final String TEST2_REQ_EE_FILTER = JAVA_EE_1_4_REQ;
+ private static final String TEST2_REQ_EE = JAVA_EE_1_4;
private static final String TEST2_PROV_Z_NAME = "iuz";//$NON-NLS-1$
private static final String TEST2_PROV_Y_NAME = "iuy";//$NON-NLS-1$
private static final String TEST2_PROV_X_NAME = "iux";//$NON-NLS-1$
@@ -99,9 +100,9 @@ public class BundlesActionTest extends ActionTest {
private static final String TEST4_REQ_PACKAGE_OPTGREEDY_NAME = "iuf";//$NON-NLS-1$
private static final String TEST4_REQ_BUNDLE_OPTIONAL_NAME = "iug";//$NON-NLS-1$
private static final String TEST4_REQ_BUNDLE_OPTGREEDY_NAME = "iuh";//$NON-NLS-1$
- private static final String TEST5_REQ_EE_FILTER = JAVA_EE_1_4_REQ;
+ private static final String TEST5_REQ_EE = JAVA_EE_1_4;
private static final String TEST5_PROV_BUNDLE_NAME = "test5";//$NON-NLS-1$
- private static final String TESTDYN_REQ_EE_FILTER = JAVA_EE_1_6_REQ;
+ private static final String TESTDYN_REQ_EE = JAVA_EE_1_6;
private static final File TEST_BASE = new File(TestActivator.getTestDataFolder(), "BundlesActionTest");//$NON-NLS-1$
private static final File TEST_FILE1 = new File(TEST_BASE, TEST1_PROVBUNDLE_NAME);
@@ -173,32 +174,32 @@ public class BundlesActionTest extends ActionTest {
bundlesAction.perform(info, results, new NullProgressMonitor());
Collection<IInstallableUnit> ius = results.getIUs(null, null);
- assertEquals("1.0", 1, ius.size());
+ assertEquals(1, ius.size());
info = new PublisherInfo();
results = new PublisherResult();
bundlesAction = new BundlesAction(new File[] {foo});
bundlesAction.perform(info, results, new NullProgressMonitor());
ius = results.getIUs(null, null);
- assertEquals("2.0", 1, ius.size());
+ assertEquals(1, ius.size());
QueryableArray queryableArray = new QueryableArray(ius.toArray(new IInstallableUnit[ius.size()]));
IQueryResult<IInstallableUnit> result = queryableArray.query(QueryUtil.createIUQuery("foo"), null);
- assertEquals("3.1", 1, queryResultSize(result));
+ assertEquals(1, queryResultSize(result));
IInstallableUnit iu = result.iterator().next();
TranslationSupport utils = new TranslationSupport();
utils.setTranslationSource(queryableArray);
- assertEquals("3.2", "English Foo", utils.getIUProperty(iu, IInstallableUnit.PROP_NAME));
+ assertEquals("English Foo", utils.getIUProperty(iu, IInstallableUnit.PROP_NAME));
bundlesAction = new BundlesAction(new File[] {foo_fragment});
bundlesAction.perform(info, results, new NullProgressMonitor());
ius = results.getIUs(null, null);
- assertEquals("2.0", 3, ius.size());
+ assertEquals(3, ius.size());
queryableArray = new QueryableArray(ius.toArray(new IInstallableUnit[ius.size()]));
result = queryableArray.query(QueryUtil.createIUQuery("foo"), null);
- assertEquals("2.1", 1, queryResultSize(result));
+ assertEquals(1, queryResultSize(result));
iu = result.iterator().next();
utils.setTranslationSource(queryableArray);
- assertEquals("2.2", "German Foo", utils.getIUProperty(iu, IInstallableUnit.PROP_NAME, Locale.GERMAN.toString()));
+ assertEquals("German Foo", utils.getIUProperty(iu, IInstallableUnit.PROP_NAME, Locale.GERMAN.toString()));
}
private void verifyBundlesAction() throws Exception {
@@ -217,7 +218,7 @@ public class BundlesActionTest extends ActionTest {
IArtifactDescriptor[] descriptors = artifactRepository.getArtifactDescriptors(key2);
// Should have one canonical and one packed
- assertTrue("1.0", descriptors.length == 2);
+ assertEquals(2, descriptors.length);
int packedIdx;
int canonicalIdx;
@@ -244,18 +245,18 @@ public class BundlesActionTest extends ActionTest {
}
private void verifyBundle1() {
- ArrayList<IInstallableUnit> ius = new ArrayList<>(publisherResult.getIUs(TEST1_PROVBUNDLE_NAME, IPublisherResult.ROOT));
- assertTrue(ius.size() == 1);
+ List<IInstallableUnit> ius = new ArrayList<>(publisherResult.getIUs(TEST1_PROVBUNDLE_NAME, IPublisherResult.ROOT));
+ assertEquals(1, ius.size());
IInstallableUnit bundle1IU = ius.get(0);
- assertNotNull("1.0", bundle1IU);
- assertEquals("1.1", bundle1IU.getVersion(), BUNDLE1_VERSION);
+ assertNotNull(bundle1IU);
+ assertEquals(bundle1IU.getVersion(), BUNDLE1_VERSION);
// check required capabilities
- Collection<IRequirement> requiredCapability = bundle1IU.getRequirements();
- verifyRequirement(requiredCapability, TEST1_IU_D_NAMESPACE, TEST1_IUD_NAME, TEST1_IU_D_VERSION_RANGE);
- verifyRequirement(requiredCapability, TEST1_REQ_EE_FILTER, 0, 1, true);
- assertEquals("2.0", 2, requiredCapability.size());
+ Collection<IRequirement> requirements = bundle1IU.getRequirements();
+ verifyRequirement(requirements, TEST1_IU_D_NAMESPACE, TEST1_IUD_NAME, TEST1_IU_D_VERSION_RANGE);
+ verifyRequirement(requirements, OSGI_EE, TEST1_REQ_EE, null, 1, 1, true);
+ assertEquals(2, requirements.size());
// check provided capabilities
Collection<IProvidedCapability> providedCapabilities = bundle1IU.getProvidedCapabilities();
@@ -264,7 +265,7 @@ public class BundlesActionTest extends ActionTest {
verifyProvidedCapability(providedCapabilities, OSGI, TEST1_PROVBUNDLE_NAME, BUNDLE1_VERSION);
verifyProvidedCapability(providedCapabilities, TEST1_PROV_Z_NAMESPACE, TEST1_PROVZ_NAME, TEST2_PROVZ_VERSION);
verifyProvidedCapability(providedCapabilities, PublisherHelper.NAMESPACE_ECLIPSE_TYPE, "source", Version.create("1.0.0"));//$NON-NLS-1$//$NON-NLS-2$
- assertEquals("2.1", 5, providedCapabilities.size());
+ assertEquals(5, providedCapabilities.size());
Collection<ITouchpointData> data = bundle1IU.getTouchpointData();
boolean found = false;
@@ -277,27 +278,27 @@ public class BundlesActionTest extends ActionTest {
found = true;
}
}
- assertTrue("3.0", found);
+ assertTrue(found);
}
private void verifyBundle2() {
- ArrayList<IInstallableUnit> ius = new ArrayList<>(publisherResult.getIUs(TEST2_PROV_BUNDLE_NAME, IPublisherResult.ROOT));
- assertTrue(ius.size() == 1);
- IInstallableUnit bundle2IU = ius.get(0);
+ List<IInstallableUnit> ius = new ArrayList<>(publisherResult.getIUs(TEST2_PROV_BUNDLE_NAME, IPublisherResult.ROOT));
+ assertEquals(1, ius.size());
- assertNotNull(bundle2IU);
- assertEquals(bundle2IU.getVersion(), BUNDLE2_VERSION);
+ IInstallableUnit bundleIu = ius.get(0);
+ assertNotNull(bundleIu);
+ assertEquals(bundleIu.getVersion(), BUNDLE2_VERSION);
// check required capabilities
- Collection<IRequirement> requirements = bundle2IU.getRequirements();
+ Collection<IRequirement> requirements = bundleIu.getRequirements();
verifyRequirement(requirements, TEST2_IU_A_NAMESPACE, TEST2_REQ_A_NAME, TEST2_IU_A_VERSION_RANGE);
verifyRequirement(requirements, TEST2_IU_B_NAMESPACE, TEST2_REQ_B_NAME, TEST2_IU_B_VERSION_RANGE);
verifyRequirement(requirements, TEST2_IU_C_NAMESPACE, TEST2_REQ_C_NAME, TEST2_IU_C_VERSION_RANGE);
- verifyRequirement(requirements, TEST2_REQ_EE_FILTER, 0, 1, true);
- assertTrue(requirements.size() == 4 /*number of tested elements*/);
+ verifyRequirement(requirements, OSGI_EE, TEST2_REQ_EE, null, 1, 1, true);
+ assertEquals(4, requirements.size());
// check provided capabilities
- Collection<IProvidedCapability> providedCapabilities = bundle2IU.getProvidedCapabilities();
+ Collection<IProvidedCapability> providedCapabilities = bundleIu.getProvidedCapabilities();
verifyProvidedCapability(providedCapabilities, PROVBUNDLE_NAMESPACE, TEST2_PROV_BUNDLE_NAME, PROVBUNDLE2_VERSION);
verifyProvidedCapability(providedCapabilities, OSGI, TEST2_PROV_BUNDLE_NAME, BUNDLE2_VERSION);
verifyProvidedCapability(providedCapabilities, OSGI_IDENTITY, TEST2_PROV_BUNDLE_NAME, BUNDLE2_VERSION);
@@ -308,11 +309,11 @@ public class BundlesActionTest extends ActionTest {
assertEquals(7, providedCapabilities.size()); /*number of tested elements*/
// check %bundle name is correct
- Map<String, String> prop = bundle2IU.getProperties();
+ Map<String, String> prop = bundleIu.getProperties();
assertTrue(prop.get("org.eclipse.equinox.p2.name").toString().equalsIgnoreCase("%bundleName"));//$NON-NLS-1$//$NON-NLS-2$
assertTrue(prop.get("org.eclipse.equinox.p2.provider").toString().equalsIgnoreCase("%providerName"));//$NON-NLS-1$//$NON-NLS-2$
- Collection<ITouchpointData> data = bundle2IU.getTouchpointData();
+ Collection<ITouchpointData> data = bundleIu.getTouchpointData();
boolean found = false;
for (ITouchpointData td : data) {
ITouchpointInstruction configure = td.getInstruction("configure");
@@ -323,18 +324,17 @@ public class BundlesActionTest extends ActionTest {
found = true;
}
}
- assertFalse("3.0", found);
-
+ assertFalse(found);
}
private void verifyBundle3() {
// also a regression test for bug 393051: manifest headers use uncommon (but valid) capitalization
ArrayList<IInstallableUnit> ius = new ArrayList<>(publisherResult.getIUs(TEST3_PROV_BUNDLE_NAME, IPublisherResult.ROOT));
+ assertEquals(1, ius.size());
- assertTrue(ius.size() == 1);
- IInstallableUnit bundle3IU = ius.get(0);
+ IInstallableUnit bundleIu = ius.get(0);
- IUpdateDescriptor updateDescriptor = bundle3IU.getUpdateDescriptor();
+ IUpdateDescriptor updateDescriptor = bundleIu.getUpdateDescriptor();
String name = RequiredCapability.extractName(updateDescriptor.getIUsBeingUpdated().iterator().next());
VersionRange range = RequiredCapability.extractRange(updateDescriptor.getIUsBeingUpdated().iterator().next());
String description = updateDescriptor.getDescription();
@@ -349,36 +349,31 @@ public class BundlesActionTest extends ActionTest {
private void verifyBundle4() {
ArrayList<IInstallableUnit> ius = new ArrayList<>(publisherResult.getIUs(TEST4_PROV_BUNDLE_NAME, IPublisherResult.ROOT));
- assertTrue(ius.size() == 1);
- IInstallableUnit bundle4IU = ius.get(0);
+ assertEquals(1, ius.size());
- assertNotNull("1.0", bundle4IU);
- assertEquals("1.1", bundle4IU.getVersion(), BUNDLE4_VERSION);
+ IInstallableUnit bundleIu = ius.get(0);
+ assertNotNull(bundleIu);
+ assertEquals(bundleIu.getVersion(), BUNDLE4_VERSION);
// check required capabilities
- Collection<IRequirement> requirements = bundle4IU.getRequirements();
+ Collection<IRequirement> requirements = bundleIu.getRequirements();
verifyRequirement(requirements, JAVA_PACKAGE, TEST4_REQ_PACKAGE_OPTIONAL_NAME, DEFAULT_VERSION_RANGE, null, 0, 1, false);
verifyRequirement(requirements, JAVA_PACKAGE, TEST4_REQ_PACKAGE_OPTGREEDY_NAME, DEFAULT_VERSION_RANGE, null, 0, 1, true);
verifyRequirement(requirements, OSGI, TEST4_REQ_BUNDLE_OPTIONAL_NAME, DEFAULT_VERSION_RANGE, null, 0, 1, false);
verifyRequirement(requirements, OSGI, TEST4_REQ_BUNDLE_OPTGREEDY_NAME, DEFAULT_VERSION_RANGE, null, 0, 1, true);
- assertEquals("2.0", 4, requirements.size());
+ assertEquals(4, requirements.size());
}
private void verifyBundle5() {
ArrayList<IInstallableUnit> ius = new ArrayList<>(publisherResult.getIUs(TEST5_PROV_BUNDLE_NAME, IPublisherResult.ROOT));
- assertTrue(ius.size() == 1);
+ assertEquals(1, ius.size());
+
IInstallableUnit bundle5IU = ius.get(0);
Collection<IRequirement> requirements = bundle5IU.getRequirements();
- verifyRequirement(requirements, TEST5_REQ_EE_FILTER, 0, 1, true);
- assertTrue(requirements.size() == 2);
- IRequirement requirement = requirements.iterator().next();
-
- int min = requirement.getMin();
- int max = requirement.getMax();
-
- assertTrue(min == 6);
- assertTrue(max == 7);
+ verifyRequirement(requirements, OSGI_EE, TEST5_REQ_EE, null, 1, 1, true);
+ verifyRequirement(requirements, "bar", "foo", VersionRange.emptyRange, null, 6, 7, true);
+ assertEquals(2, requirements.size());
}
@Override
@@ -491,7 +486,7 @@ public class BundlesActionTest extends ActionTest {
IInstallableUnit iu = BundlesAction.createBundleIU(BundlesAction.createBundleDescription(testData), null, new PublisherInfo());
Collection<IRequirement> requirements = iu.getRequirements();
- verifyRequirement(requirements, TESTDYN_REQ_EE_FILTER, 0, 1, true);
+ verifyRequirement(requirements, OSGI_EE, TESTDYN_REQ_EE, null, 1, 1, true);
assertEquals(1, requirements.size());
}

Back to the top