diff options
author | Thomas Watson | 2014-02-17 15:26:41 +0000 |
---|---|---|
committer | Thomas Watson | 2014-02-17 19:23:15 +0000 |
commit | 1eabbd02085722c331e805b868894ac3022078ee (patch) | |
tree | 0465e2a8d1b6864867818a5eb6f3deba91d86ae3 | |
parent | 87138c2bce46ece8c89bd465a6e00e99eee3cbe8 (diff) | |
download | rt.equinox.framework-1eabbd02085722c331e805b868894ac3022078ee.tar.gz rt.equinox.framework-1eabbd02085722c331e805b868894ac3022078ee.tar.xz rt.equinox.framework-1eabbd02085722c331e805b868894ac3022078ee.zip |
Bug 426492 - Missing dependency message from Equinox got worseI20140218-0800
6 files changed, 214 insertions, 431 deletions
diff --git a/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/FilterParser.java b/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/FilterParser.java deleted file mode 100644 index 8a9251d05..000000000 --- a/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/FilterParser.java +++ /dev/null @@ -1,416 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012 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 - Initial API and implementation - ******************************************************************************/ -package org.eclipse.osgi.compatibility.state; - -import java.util.*; -import org.osgi.framework.InvalidSyntaxException; -import org.osgi.framework.Version; - -public class FilterParser { - static class Range { - private char leftRule = 0; - private Version leftVersion; - private Version rightVersion; - private char rightRule = 0; - private Collection<Version> excludes = new ArrayList<Version>(0); - - public String toString() { - if (rightVersion == null) { - return leftVersion.toString(); - } - return leftRule + leftVersion.toString() + ',' + rightVersion.toString() + rightRule; - } - - void addExclude(Version exclude) { - this.excludes.add(exclude); - setLeft(leftRule, leftVersion); - setRight(rightRule, rightVersion); - } - - boolean setLeft(char leftRule, Version leftVersion) { - if (this.leftVersion != null && this.leftVersion != leftVersion) - return false; - this.leftRule = excludes.contains(leftVersion) ? '(' : leftRule; - this.leftVersion = leftVersion; - return true; - } - - boolean setRight(char rightRule, Version rightVersion) { - if (this.rightVersion != null && this.rightVersion != rightVersion) - return false; - this.rightRule = excludes.contains(rightVersion) ? ')' : rightRule; - this.rightVersion = rightVersion; - return true; - } - } - - public static class FilterComponent { - /* filter operators */ - public static final int EQUAL = 1; - public static final int APPROX = 2; - public static final int GREATER = 3; - public static final int LESS = 4; - public static final int AND = 7; - public static final int OR = 8; - public static final int NOT = 9; - - private final int op; - private final String attr; - private final String value; - private final List<FilterComponent> nested; - - public FilterComponent(int op, List<FilterComponent> nested) { - this.op = op; - this.attr = null; - this.value = null; - this.nested = nested; - } - - public FilterComponent(int op, String attr, String value) { - this.op = op; - this.attr = attr; - this.value = value; - this.nested = Collections.emptyList(); - } - - public int getOp() { - return op; - } - - public String getAttr() { - return attr; - } - - public String getValue() { - return value; - } - - public List<FilterComponent> getNested() { - return nested; - } - - public Map<String, String> getStandardOSGiAttributes(String... versions) { - if (op != AND && op != EQUAL) - throw new IllegalStateException("Invalid filter for Starndard OSGi Attributes: " + op); //$NON-NLS-1$ - Map<String, String> result = new HashMap<String, String>(); - Map<String, Range> versionAttrs = new HashMap<String, Range>(); - if (versions != null) { - for (String versionAttr : versions) { - versionAttrs.put(versionAttr, null); - } - } - addAttributes(result, versionAttrs, false); - for (Map.Entry<String, Range> entry : versionAttrs.entrySet()) { - Range range = entry.getValue(); - if (range != null) { - result.put(entry.getKey(), range.toString()); - } - } - - return result; - } - - private void addAttributes(Map<String, String> attributes, Map<String, Range> versionAttrs, boolean not) { - if (op == EQUAL) { - if (!versionAttrs.containsKey(attr)) { - attributes.put(attr, value); - } else { - // this is an exact range e.g. [value,value] - Range currentRange = versionAttrs.get(attr); - if (currentRange != null) { - if (not) { - // this is an expanded for of the filter, e.g.: - // [1.0,2.0) -> (&(version>=1.0)(version<=2.0)(!(version=2.0))) - currentRange.addExclude(new Version(value)); - } else { - throw new IllegalStateException("Invalid range for: " + attr); //$NON-NLS-1$ - } - } - currentRange = new Range(); - Version version = new Version(value); - currentRange.setLeft('[', version); - currentRange.setRight(']', version); - versionAttrs.put(attr, currentRange); - } - } else if (op == LESS) { - if (!versionAttrs.containsKey(attr)) - throw new IllegalStateException("Invalid attribute: " + attr); //$NON-NLS-1$ - Range currentRange = versionAttrs.get(attr); - if (currentRange == null) { - currentRange = new Range(); - versionAttrs.put(attr, currentRange); - } - if (not) { - // this must be a range start "(value" - if (!currentRange.setLeft('(', new Version(value))) - throw new IllegalStateException("range start is already processed for attribute: " + attr); //$NON-NLS-1$ - } else { - // this must be a range end "value]" - if (!currentRange.setRight(']', new Version(value))) - throw new IllegalStateException("range end is already processed for attribute: " + attr); //$NON-NLS-1$ - } - } else if (op == GREATER) { - if (!versionAttrs.containsKey(attr)) - throw new IllegalStateException("Invalid attribute: " + attr); //$NON-NLS-1$ - Range currentRange = versionAttrs.get(attr); - if (currentRange == null) { - currentRange = new Range(); - versionAttrs.put(attr, currentRange); - } - if (not) { - // this must be a range end "value)" - if (!currentRange.setRight(')', new Version(value))) - throw new IllegalStateException("range end is already processed for attribute: " + attr); //$NON-NLS-1$ - } else { - // this must be a range start "[value" - if (!currentRange.setLeft('[', new Version(value))) - throw new IllegalStateException("range start is already processed for attribute: " + attr); //$NON-NLS-1$ - } - } else if (op == AND) { - for (FilterComponent component : nested) { - component.addAttributes(attributes, versionAttrs, false); - } - } else if (op == NOT) { - nested.get(0).addAttributes(attributes, versionAttrs, true); - } else { - throw new IllegalStateException("Invalid filter for standard OSGi requirements: " + op); //$NON-NLS-1$ - } - } - } - - private final String filterstring; - private final char[] filterChars; - private int pos; - - public FilterParser(String filterstring) { - this.filterstring = filterstring; - filterChars = filterstring.toCharArray(); - pos = 0; - } - - public FilterComponent parse() throws InvalidSyntaxException { - FilterComponent filter; - try { - filter = parse_filter(); - } catch (ArrayIndexOutOfBoundsException e) { - throw new InvalidSyntaxException("Filter ended abruptly", filterstring, e); //$NON-NLS-1$ - } - - if (pos != filterChars.length) { - throw new InvalidSyntaxException("Extraneous trailing characters: " + filterstring.substring(pos), filterstring); //$NON-NLS-1$ - } - return filter; - } - - private FilterComponent parse_filter() throws InvalidSyntaxException { - FilterComponent filter; - skipWhiteSpace(); - - if (filterChars[pos] != '(') { - throw new InvalidSyntaxException("Missing '(': " + filterstring.substring(pos), filterstring); //$NON-NLS-1$ - } - - pos++; - - filter = parse_filtercomp(); - - skipWhiteSpace(); - - if (filterChars[pos] != ')') { - throw new InvalidSyntaxException("Missing ')': " + filterstring.substring(pos), filterstring); //$NON-NLS-1$ - } - - pos++; - - skipWhiteSpace(); - - return filter; - } - - private FilterComponent parse_filtercomp() throws InvalidSyntaxException { - skipWhiteSpace(); - - char c = filterChars[pos]; - - switch (c) { - case '&' : { - pos++; - return parse_and(); - } - case '|' : { - pos++; - return parse_or(); - } - case '!' : { - pos++; - return parse_not(); - } - } - return parse_item(); - } - - private FilterComponent parse_and() throws InvalidSyntaxException { - int lookahead = pos; - skipWhiteSpace(); - - if (filterChars[pos] != '(') { - pos = lookahead - 1; - return parse_item(); - } - - List<FilterComponent> operands = new ArrayList<FilterComponent>(10); - - while (filterChars[pos] == '(') { - FilterComponent child = parse_filter(); - operands.add(child); - } - - return new FilterComponent(FilterComponent.AND, operands); - } - - private FilterComponent parse_or() throws InvalidSyntaxException { - int lookahead = pos; - skipWhiteSpace(); - - if (filterChars[pos] != '(') { - pos = lookahead - 1; - return parse_item(); - } - - List<FilterComponent> operands = new ArrayList<FilterComponent>(10); - - while (filterChars[pos] == '(') { - FilterComponent child = parse_filter(); - operands.add(child); - } - - return new FilterComponent(FilterComponent.OR, operands); - } - - private FilterComponent parse_not() throws InvalidSyntaxException { - int lookahead = pos; - skipWhiteSpace(); - - if (filterChars[pos] != '(') { - pos = lookahead - 1; - return parse_item(); - } - - List<FilterComponent> operands = new ArrayList<FilterComponent>(1); - FilterComponent child = parse_filter(); - operands.add(child); - - return new FilterComponent(FilterComponent.NOT, operands); - } - - private FilterComponent parse_item() throws InvalidSyntaxException { - String attr = parse_attr(); - - skipWhiteSpace(); - - switch (filterChars[pos]) { - case '~' : { - if (filterChars[pos + 1] == '=') { - pos += 2; - return new FilterComponent(FilterComponent.APPROX, attr, parse_value()); - } - break; - } - case '>' : { - if (filterChars[pos + 1] == '=') { - pos += 2; - return new FilterComponent(FilterComponent.GREATER, attr, parse_value()); - } - break; - } - case '<' : { - if (filterChars[pos + 1] == '=') { - pos += 2; - return new FilterComponent(FilterComponent.LESS, attr, parse_value()); - } - break; - } - case '=' : { - pos++; - return new FilterComponent(FilterComponent.EQUAL, attr, parse_value()); - } - } - - throw new InvalidSyntaxException("Invalid operator: " + filterstring.substring(pos), filterstring); //$NON-NLS-1$ - } - - private String parse_attr() throws InvalidSyntaxException { - skipWhiteSpace(); - - int begin = pos; - int end = pos; - - char c = filterChars[pos]; - - while (c != '~' && c != '<' && c != '>' && c != '=' && c != '(' && c != ')') { - pos++; - - if (!Character.isWhitespace(c)) { - end = pos; - } - - c = filterChars[pos]; - } - - int length = end - begin; - - if (length == 0) { - throw new InvalidSyntaxException("Missing attr: " + filterstring.substring(pos), filterstring); //$NON-NLS-1$ - } - - return new String(filterChars, begin, length); - } - - private String parse_value() throws InvalidSyntaxException { - StringBuffer sb = new StringBuffer(filterChars.length - pos); - - parseloop: while (true) { - char c = filterChars[pos]; - - switch (c) { - case ')' : { - break parseloop; - } - - case '(' : { - throw new InvalidSyntaxException("Invalid value: " + filterstring.substring(pos), filterstring); //$NON-NLS-1$ - } - - case '\\' : { - pos++; - c = filterChars[pos]; - /* fall through into default */ - } - - default : { - sb.append(c); - pos++; - break; - } - } - } - - if (sb.length() == 0) { - throw new InvalidSyntaxException("Missing value: " + filterstring.substring(pos), filterstring); //$NON-NLS-1$ - } - - return sb.toString(); - } - - private void skipWhiteSpace() { - for (int length = filterChars.length; (pos < length) && Character.isWhitespace(filterChars[pos]);) { - pos++; - } - } -} diff --git a/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/StateConverter.java b/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/StateConverter.java index dbf45aba4..426607bef 100644 --- a/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/StateConverter.java +++ b/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/StateConverter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2013 IBM Corporation and others. All rights reserved. + * Copyright (c) 2013, 2014 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 @@ -11,7 +11,7 @@ package org.eclipse.osgi.compatibility.state; import java.util.*; import java.util.Map.Entry; -import org.eclipse.osgi.compatibility.state.FilterParser.FilterComponent; +import org.eclipse.osgi.internal.framework.FilterImpl; import org.eclipse.osgi.service.resolver.*; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.Version; @@ -156,14 +156,13 @@ class StateConverter { String filter = directives.remove(Namespace.REQUIREMENT_FILTER_DIRECTIVE); if (filter == null) throw new IllegalArgumentException("No filter directive found:" + requirement); //$NON-NLS-1$ - FilterParser parser = new FilterParser(filter); - FilterComponent component = null; + FilterImpl parser; try { - component = parser.parse(); + parser = FilterImpl.newInstance(filter); } catch (InvalidSyntaxException e) { throw new IllegalArgumentException("Invalid filter directive", e); //$NON-NLS-1$ } - Map<String, String> matchingAttributes = component.getStandardOSGiAttributes(versions); + Map<String, String> matchingAttributes = parser.getStandardOSGiAttributes(versions); String name = matchingAttributes.remove(namespace); if (name == null) throw new IllegalArgumentException("Invalid requirement: " + requirement); //$NON-NLS-1$ diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/Module.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/Module.java index bc5f295ac..bc21bbd3e 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/Module.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/Module.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2013 IBM Corporation and others. + * Copyright (c) 2012, 2014 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 @@ -421,7 +421,7 @@ public abstract class Module implements BundleReference, BundleStartLevel, Compa return; if (getState().equals(State.INSTALLED)) { String reportMessage = report.getResolutionReportMessage(getCurrentRevision()); - throw new BundleException(Msg.Module_ResolveError + reportMessage, BundleException.RESOLVE_ERROR, e); + throw new BundleException(Msg.Module_ResolveError + reportMessage, BundleException.RESOLVE_ERROR); } } diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleResolutionReport.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleResolutionReport.java index 3e66c4f0e..359d9db75 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleResolutionReport.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleResolutionReport.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2013 IBM Corporation and others. + * Copyright (c) 2013, 2014 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 @@ -11,8 +11,12 @@ package org.eclipse.osgi.container; import java.util.*; +import org.eclipse.osgi.internal.framework.FilterImpl; import org.eclipse.osgi.internal.messages.Msg; import org.eclipse.osgi.report.resolution.ResolutionReport; +import org.osgi.framework.Constants; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.namespace.*; import org.osgi.framework.wiring.BundleRevision; import org.osgi.resource.*; import org.osgi.service.resolver.ResolutionException; @@ -112,7 +116,7 @@ public class ModuleResolutionReport implements ResolutionReport { private static void printResolutionEntry(StringBuilder result, String prepend, ResolutionReport.Entry entry, Map<Resource, List<ResolutionReport.Entry>> reportEntries, Set<BundleRevision> visited) { switch (entry.getType()) { case MISSING_CAPABILITY : - result.append(prepend).append(Msg.ModuleResolutionReport_UnresolvedReq).append(entry.getData()).append('\n'); + result.append(prepend).append(Msg.ModuleResolutionReport_UnresolvedReq).append(printRequirement(entry.getData())).append('\n'); break; case SINGLETON_SELECTION : result.append(prepend).append(Msg.ModuleResolutionReport_AnotherSingleton).append(entry.getData()).append('\n'); @@ -127,8 +131,8 @@ public class ModuleResolutionReport implements ResolutionReport { Capability unresolvedCapability = unresolvedCapabilities.iterator().next(); // make sure this is not a case of importing and exporting the same package if (!unresolvedRequirement.getKey().getResource().equals(unresolvedCapability.getResource())) { - result.append(prepend).append(Msg.ModuleResolutionReport_UnresolvedReq).append(unresolvedRequirement.getKey()).append('\n'); - result.append(prepend).append(" -> ").append(unresolvedCapability).append('\n'); //$NON-NLS-1$ + result.append(prepend).append(Msg.ModuleResolutionReport_UnresolvedReq).append(printRequirement(unresolvedRequirement.getKey())).append('\n'); + result.append(prepend).append(" -> ").append(printCapability(unresolvedCapability)).append('\n'); //$NON-NLS-1$ result.append(getResolutionReport0(prepend + " ", (ModuleRevision) unresolvedCapability.getResource(), reportEntries, visited)); //$NON-NLS-1$ } } @@ -147,6 +151,57 @@ public class ModuleResolutionReport implements ResolutionReport { } } + private static Object printCapability(Capability cap) { + if (PackageNamespace.PACKAGE_NAMESPACE.equals(cap.getNamespace())) { + return Constants.EXPORT_PACKAGE + ": " + createOSGiCapability(cap); //$NON-NLS-1$ + } else if (BundleNamespace.BUNDLE_NAMESPACE.equals(cap.getNamespace())) { + return Constants.BUNDLE_SYMBOLICNAME + ": " + createOSGiCapability(cap); //$NON-NLS-1$ + } else if (HostNamespace.HOST_NAMESPACE.equals(cap.getNamespace())) { + return Constants.BUNDLE_SYMBOLICNAME + ": " + createOSGiCapability(cap); //$NON-NLS-1$ + } + return Constants.PROVIDE_CAPABILITY + ": " + cap.toString(); //$NON-NLS-1$ + } + + private static String createOSGiCapability(Capability cap) { + Map<String, Object> attributes = new HashMap<String, Object>(cap.getAttributes()); + Map<String, String> directives = cap.getDirectives(); + String name = (String) attributes.remove(cap.getNamespace()); + return name + ModuleRevision.toString(attributes, false, true) + ModuleRevision.toString(directives, true, true); + } + + private static String printRequirement(Object data) { + if (!(data instanceof Requirement)) { + return String.valueOf(data); + } + Requirement req = (Requirement) data; + if (PackageNamespace.PACKAGE_NAMESPACE.equals(req.getNamespace())) { + return Constants.IMPORT_PACKAGE + ": " + createOSGiRequirement(req, PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE, PackageNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE); //$NON-NLS-1$ + } else if (BundleNamespace.BUNDLE_NAMESPACE.equals(req.getNamespace())) { + return Constants.REQUIRE_BUNDLE + ": " + createOSGiRequirement(req, BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE); //$NON-NLS-1$ + } else if (HostNamespace.HOST_NAMESPACE.equals(req.getNamespace())) { + return Constants.FRAGMENT_HOST + ": " + createOSGiRequirement(req, HostNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE); //$NON-NLS-1$ + } + return Constants.REQUIRE_CAPABILITY + ": " + req.toString(); //$NON-NLS-1$ + } + + private static String createOSGiRequirement(Requirement requirement, String... versions) { + Map<String, String> directives = new HashMap<String, String>(requirement.getDirectives()); + String filter = directives.remove(Namespace.REQUIREMENT_FILTER_DIRECTIVE); + if (filter == null) + throw new IllegalArgumentException("No filter directive found:" + requirement); //$NON-NLS-1$ + FilterImpl filterImpl; + try { + filterImpl = FilterImpl.newInstance(filter); + } catch (InvalidSyntaxException e) { + throw new IllegalArgumentException("Invalid filter directive", e); //$NON-NLS-1$ + } + Map<String, String> matchingAttributes = filterImpl.getStandardOSGiAttributes(versions); + String name = matchingAttributes.remove(requirement.getNamespace()); + if (name == null) + throw new IllegalArgumentException("Invalid requirement: " + requirement); //$NON-NLS-1$ + return name + ModuleRevision.toString(matchingAttributes, false, true) + ModuleRevision.toString(directives, true, true); + } + @Override public String getResolutionReportMessage(Resource resource) { return getResolutionReport0(null, (ModuleRevision) resource, getEntries(), null); diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleRevision.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleRevision.java index 5951e5e4f..b8e452fc4 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleRevision.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleRevision.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2013 IBM Corporation and others. + * Copyright (c) 2012, 2014 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 @@ -197,6 +197,10 @@ public final class ModuleRevision implements BundleRevision { } static <V> String toString(Map<String, V> map, boolean directives) { + return toString(map, directives, false); + } + + static <V> String toString(Map<String, V> map, boolean directives, boolean stringsOnly) { if (map.size() == 0) return ""; //$NON-NLS-1$ String assignment = directives ? ":=" : "="; //$NON-NLS-1$ //$NON-NLS-2$ @@ -221,7 +225,7 @@ public final class ModuleRevision implements BundleRevision { sb.append('"'); } else { String type = ""; //$NON-NLS-1$ - if (!(value instanceof String)) { + if (!(value instanceof String) && !stringsOnly) { String className = value.getClass().getName(); type = ":" + className.substring(className.lastIndexOf('.') + 1); //$NON-NLS-1$ } diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/FilterImpl.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/FilterImpl.java index 1977c3426..4e012d889 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/FilterImpl.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/FilterImpl.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2003, 2013 IBM Corporation and others. + * Copyright (c) 2003, 2014 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 @@ -1765,4 +1765,145 @@ public class FilterImpl implements Filter /* since Framework 1.1 */{ return null; } } + + static class Range { + private char leftRule = 0; + private Version leftVersion; + private Version rightVersion; + private char rightRule = 0; + private Collection<Version> excludes = new ArrayList<Version>(0); + + public String toString() { + if (rightVersion == null) { + return leftVersion.toString(); + } + return leftRule + leftVersion.toString() + ',' + rightVersion.toString() + rightRule; + } + + void addExclude(Version exclude) { + this.excludes.add(exclude); + setLeft(leftRule, leftVersion); + setRight(rightRule, rightVersion); + } + + boolean setLeft(char leftRule, Version leftVersion) { + if (this.leftVersion != null && this.leftVersion != leftVersion) + return false; + this.leftRule = excludes.contains(leftVersion) ? '(' : leftRule; + this.leftVersion = leftVersion; + return true; + } + + boolean setRight(char rightRule, Version rightVersion) { + if (this.rightVersion != null && this.rightVersion != rightVersion) + return false; + this.rightRule = excludes.contains(rightVersion) ? ')' : rightRule; + this.rightVersion = rightVersion; + return true; + } + } + + public Map<String, String> getStandardOSGiAttributes(String... versions) { + if (op != AND && op != EQUAL && op != SUBSTRING && op != PRESENT) + throw new IllegalArgumentException("Invalid filter for Starndard OSGi Attributes: " + op); //$NON-NLS-1$ + Map<String, String> result = new HashMap<String, String>(); + Map<String, Range> versionAttrs = new HashMap<String, Range>(); + if (versions != null) { + for (String versionAttr : versions) { + versionAttrs.put(versionAttr, null); + } + } + addAttributes(result, versionAttrs, false); + for (Map.Entry<String, Range> entry : versionAttrs.entrySet()) { + Range range = entry.getValue(); + if (range != null) { + result.put(entry.getKey(), range.toString()); + } + } + + return result; + } + + private void addAttributes(Map<String, String> attributes, Map<String, Range> versionAttrs, boolean not) { + if (op == EQUAL) { + if (!versionAttrs.containsKey(attr)) { + attributes.put(attr, (String) value); + } else { + // this is an exact range e.g. [value,value] + Range currentRange = versionAttrs.get(attr); + if (currentRange != null) { + if (not) { + // this is an expanded form of the filter, e.g.: + // [1.0,2.0) -> (&(version>=1.0)(version<=2.0)(!(version=2.0))) + currentRange.addExclude(new Version((String) value)); + } else { + throw new IllegalStateException("Invalid range for: " + attr); //$NON-NLS-1$ + } + } else { + currentRange = new Range(); + Version version = new Version((String) value); + currentRange.setLeft('[', version); + currentRange.setRight(']', version); + versionAttrs.put(attr, currentRange); + } + } + } else if (op == SUBSTRING || op == PRESENT) { + if (value == null) { + attributes.put(attr, "*"); //$NON-NLS-1$ + } else { + StringBuilder builder = new StringBuilder(); + for (String component : (String[]) value) { + if (component == null) { + builder.append('*'); + } else { + builder.append(component); + } + } + attributes.put(attr, builder.toString()); + } + + } else if (op == LESS) { + if (!versionAttrs.containsKey(attr)) + throw new IllegalStateException("Invalid attribute: " + attr); //$NON-NLS-1$ + Range currentRange = versionAttrs.get(attr); + if (currentRange == null) { + currentRange = new Range(); + versionAttrs.put(attr, currentRange); + } + if (not) { + // this must be a range start "(value" + if (!currentRange.setLeft('(', new Version((String) value))) + throw new IllegalStateException("range start is already processed for attribute: " + attr); //$NON-NLS-1$ + } else { + // this must be a range end "value]" + if (!currentRange.setRight(']', new Version((String) value))) + throw new IllegalStateException("range end is already processed for attribute: " + attr); //$NON-NLS-1$ + } + } else if (op == GREATER) { + if (!versionAttrs.containsKey(attr)) + throw new IllegalStateException("Invalid attribute: " + attr); //$NON-NLS-1$ + Range currentRange = versionAttrs.get(attr); + if (currentRange == null) { + currentRange = new Range(); + versionAttrs.put(attr, currentRange); + } + if (not) { + // this must be a range end "value)" + if (!currentRange.setRight(')', new Version((String) value))) + throw new IllegalStateException("range end is already processed for attribute: " + attr); //$NON-NLS-1$ + } else { + // this must be a range start "[value" + if (!currentRange.setLeft('[', new Version((String) value))) + throw new IllegalStateException("range start is already processed for attribute: " + attr); //$NON-NLS-1$ + } + } else if (op == AND) { + for (FilterImpl component : (FilterImpl[]) value) { + component.addAttributes(attributes, versionAttrs, false); + } + } else if (op == NOT) { + ((FilterImpl) value).addAttributes(attributes, versionAttrs, true); + } else { + throw new IllegalStateException("Invalid filter for standard OSGi requirements: " + op); //$NON-NLS-1$ + } + } } |