You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by jw...@apache.org on 2015/09/29 04:06:33 UTC
svn commit: r1705795 - in /aries/trunk/subsystem:
subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/
subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/defect/
Author: jwross
Date: Tue Sep 29 02:06:33 2015
New Revision: 1705795
URL: http://svn.apache.org/viewvc?rev=1705795&view=rev
Log:
ARIES-1419 Provide-Capability header parser does not support typed attributes.
Add support for the cardinality directive in Require-Capability.
Add support for the cardinality directive to Subsystem-ImportService. Although the specification only references the filter directive
in conjunction with this header, the same directives used with Require-Capability in the osgi.service namespace (i.e. resolution,
effective, and cardinality) are necessary because Subsystem-ImportService serves a similar role.
Fix Require-Capability grammar, which should allow typed attributes.
Add test.
Move the typed parameter parsing to the abstract clause class to be used by both Require-Capability and Provide-Capability.
Require-Capability must use a typed parameter rather than the attribute factory when converting a requirement into a clause.
Support attributes in the require capability requirement.
Support lists of scalars in typed attributes. Support requirement to header clause conversion. Override toString in order to include the type information.
Added:
aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/CardinalityDirective.java
aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/defect/Aries1419Test.java
Modified:
aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/AbstractClause.java
aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/DirectiveFactory.java
aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/Grammar.java
aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/Patterns.java
aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/ProvideCapabilityHeader.java
aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/RequireCapabilityHeader.java
aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/RequireCapabilityRequirement.java
aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/SubsystemImportServiceHeader.java
aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/TypedAttribute.java
Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/AbstractClause.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/AbstractClause.java?rev=1705795&r1=1705794&r2=1705795&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/AbstractClause.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/AbstractClause.java Tue Sep 29 02:06:33 2015
@@ -47,6 +47,34 @@ public abstract class AbstractClause imp
}
return parameters;
}
+
+ protected static Map<String, Parameter> parseTypedParameters(String clause) {
+ Map<String, Parameter> parameters = new HashMap<String, Parameter>();
+ Matcher matcher = Patterns.TYPED_PARAMETER.matcher(clause);
+ while (matcher.find()) {
+ if (":=".equals(matcher.group(2))) {
+ // This is a directive.
+ parameters.put(matcher.group(1), DirectiveFactory.createDirective(matcher.group(1), removeQuotes(matcher.group(3))));
+ }
+ else if (":".equals(matcher.group(5))) {
+ // This is a typed attribute with a declared version.
+ parameters.put(matcher.group(4), new TypedAttribute(matcher.group(4), removeQuotes(matcher.group(7)), matcher.group(6)));
+ }
+ else {
+ // This is a typed attribute without a declared version.
+ parameters.put(matcher.group(4), new TypedAttribute(matcher.group(4), removeQuotes(matcher.group(7)), "String"));
+ }
+ }
+ return parameters;
+ }
+
+ protected static String removeQuotes(String value) {
+ if (value == null)
+ return null;
+ if (value.startsWith("\"") && value.endsWith("\""))
+ return value.substring(1, value.length() - 1);
+ return value;
+ }
protected static String parsePath(String clause, Pattern pattern, boolean replaceAllWhitespace) {
Matcher matcher = pattern.matcher(clause);
Added: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/CardinalityDirective.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/CardinalityDirective.java?rev=1705795&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/CardinalityDirective.java (added)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/CardinalityDirective.java Tue Sep 29 02:06:33 2015
@@ -0,0 +1,51 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.aries.subsystem.core.archive;
+
+import org.osgi.resource.Namespace;
+
+public class CardinalityDirective extends AbstractDirective {
+ public static final String NAME = Namespace.REQUIREMENT_CARDINALITY_DIRECTIVE;
+ public static final String VALUE_MULTIPLE = Namespace.CARDINALITY_MULTIPLE;
+ public static final String VALUE_SINGLE = Namespace.CARDINALITY_SINGLE;
+
+ public static final CardinalityDirective MULTIPLE = new CardinalityDirective(VALUE_MULTIPLE);
+ public static final CardinalityDirective SINGLE = new CardinalityDirective(VALUE_SINGLE);
+
+ public static final CardinalityDirective DEFAULT = SINGLE;
+
+ public static CardinalityDirective getInstance(String value) {
+ if (VALUE_SINGLE.equals(value))
+ return SINGLE;
+ if (VALUE_MULTIPLE.equals(value))
+ return MULTIPLE;
+ return new CardinalityDirective(value);
+ }
+
+ public CardinalityDirective() {
+ this(VALUE_SINGLE);
+ }
+
+ public CardinalityDirective(String value) {
+ super(NAME, value);
+ }
+
+ public boolean isMultiple() {
+ return MULTIPLE == this || VALUE_MULTIPLE.equals(getValue());
+ }
+
+ public boolean isSingle() {
+ return SINGLE == this || VALUE_SINGLE.equals(getValue());
+ }
+}
Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/DirectiveFactory.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/DirectiveFactory.java?rev=1705795&r1=1705794&r2=1705795&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/DirectiveFactory.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/DirectiveFactory.java Tue Sep 29 02:06:33 2015
@@ -29,6 +29,8 @@ public class DirectiveFactory {
return ProvisionPolicyDirective.getInstance(value);
if (ReferenceDirective.NAME.equals(name))
return ReferenceDirective.getInstance(value);
+ if (CardinalityDirective.NAME.equals(name))
+ return CardinalityDirective.getInstance(value);
return new GenericDirective(name, value);
}
}
Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/Grammar.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/Grammar.java?rev=1705795&r1=1705794&r2=1705795&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/Grammar.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/Grammar.java Tue Sep 29 02:06:33 2015
@@ -116,8 +116,6 @@ public interface Grammar {
public static final String IMPORTPACKAGE = IMPORT + "(?:\\,\\s*" + IMPORT + ")*";
public static final String NAMESPACE = SYMBOLICNAME;
- public static final String REQUIREMENT = NAMESPACE + "(?:;\\s*(?:" + PARAMETER + "))*";
- public static final String REQUIRE_CAPABILITY = REQUIREMENT + "(?:,\\s*(?:" + REQUIREMENT + "))*";
public static final String BUNDLE_DESCRIPTION = SYMBOLICNAME + "(?:;\\s*(?:" + PARAMETER + "))*";
public static final String REQUIRE_BUNDLE = BUNDLE_DESCRIPTION + "(?:,\\s*(?:" + BUNDLE_DESCRIPTION + "))*";
@@ -129,6 +127,8 @@ public interface Grammar {
public static final String LIST = "List<(?:" + SCALAR + ")>";
public static final String TYPE = "(?:" + SCALAR + ")|" + LIST;
public static final String TYPED_ATTR = EXTENDED + "(?:\\:" + TYPE + ")?=(?:" + ARGUMENT + ')';
+ public static final String REQUIREMENT = NAMESPACE + "(?:;\\s*(?:(?:" + DIRECTIVE + ")|(?:" + TYPED_ATTR + ")))*";
+ public static final String REQUIRE_CAPABILITY = REQUIREMENT + "(?:,\\s*(?:" + REQUIREMENT + "))*";
public static final String CAPABILITY = NAMESPACE + "(?:;\\s*(?:(?:" + DIRECTIVE + ")|(?:" + TYPED_ATTR + ")))*";
public static final String PROVIDE_CAPABILITY = CAPABILITY + "(?:,\\s*(?:" + CAPABILITY + "))*";
Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/Patterns.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/Patterns.java?rev=1705795&r1=1705794&r2=1705795&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/Patterns.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/Patterns.java Tue Sep 29 02:06:33 2015
@@ -18,4 +18,6 @@ public class Patterns {
private static final String DIRECTIVE = '(' + Grammar.EXTENDED + ")(:=)(" + Grammar.ARGUMENT + ')';
private static final String TYPED_ATTR = '(' + Grammar.EXTENDED + ")(?:(\\:)(" + Grammar.TYPE + "))?=(" + Grammar.ARGUMENT + ')';
public static final Pattern TYPED_PARAMETER = Pattern.compile("(?:(?:" + DIRECTIVE + ")|(?:" + TYPED_ATTR + "))(?=;|\\z)");
+
+ public static final Pattern SCALAR_LIST = Pattern.compile("List(?:<(String|Long|Double|Version)>)?");
}
Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/ProvideCapabilityHeader.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/ProvideCapabilityHeader.java?rev=1705795&r1=1705794&r2=1705795&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/ProvideCapabilityHeader.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/ProvideCapabilityHeader.java Tue Sep 29 02:06:33 2015
@@ -14,47 +14,25 @@
package org.apache.aries.subsystem.core.archive;
import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Collection;
import java.util.List;
-import java.util.regex.Matcher;
import org.osgi.framework.Constants;
import org.osgi.resource.Resource;
public class ProvideCapabilityHeader extends AbstractClauseBasedHeader<ProvideCapabilityHeader.Clause> implements CapabilityHeader<ProvideCapabilityHeader.Clause> {
public static class Clause extends AbstractClause {
- public static final String DIRECTIVE_EFFECTIVE = Constants.EFFECTIVE_DIRECTIVE;
+ public static final String DIRECTIVE_EFFECTIVE = EffectiveDirective.NAME;
public static final String DIRECTIVE_USES = Constants.USES_DIRECTIVE;
- private static String removeQuotes(String value) {
- if (value == null)
- return null;
- if (value.startsWith("\"") && value.endsWith("\""))
- return value.substring(1, value.length() - 1);
- return value;
- }
+ private static final Collection<Parameter> defaultParameters = generateDefaultParameters(
+ EffectiveDirective.DEFAULT);
public Clause(String clause) {
super(
parsePath(clause, Patterns.NAMESPACE, false),
- new HashMap<String, Parameter>(),
- generateDefaultParameters(
- EffectiveDirective.DEFAULT));
- Matcher matcher = Patterns.TYPED_PARAMETER.matcher(clause);
- while (matcher.find()) {
- if (":=".equals(matcher.group(2))) {
- // This is a directive.
- parameters.put(matcher.group(1), DirectiveFactory.createDirective(matcher.group(1), removeQuotes(matcher.group(3))));
- }
- else if (":".equals(matcher.group(5))) {
- // This is a typed attribute with a declared version.
- parameters.put(matcher.group(4), new TypedAttribute(matcher.group(4), removeQuotes(matcher.group(7)), matcher.group(6)));
- }
- else {
- // This is a typed attribute without a declared version.
- parameters.put(matcher.group(4), new TypedAttribute(matcher.group(4), removeQuotes(matcher.group(7)), TypedAttribute.Type.String));
- }
- }
+ parseTypedParameters(clause),
+ defaultParameters);
}
public String getNamespace() {
Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/RequireCapabilityHeader.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/RequireCapabilityHeader.java?rev=1705795&r1=1705794&r2=1705795&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/RequireCapabilityHeader.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/RequireCapabilityHeader.java Tue Sep 29 02:06:33 2015
@@ -25,19 +25,22 @@ import org.osgi.resource.Resource;
public class RequireCapabilityHeader extends AbstractClauseBasedHeader<RequireCapabilityHeader.Clause> implements RequirementHeader<RequireCapabilityHeader.Clause> {
public static class Clause extends AbstractClause {
- public static final String DIRECTIVE_EFFECTIVE = Constants.EFFECTIVE_DIRECTIVE;
- public static final String DIRECTIVE_FILTER = Constants.FILTER_DIRECTIVE;
- public static final String DIRECTIVE_RESOLUTION = Constants.RESOLUTION_DIRECTIVE;
+ public static final String DIRECTIVE_CARDINALITY = CardinalityDirective.NAME;
+ public static final String DIRECTIVE_EFFECTIVE = EffectiveDirective.NAME;
+ public static final String DIRECTIVE_FILTER = FilterDirective.NAME;
+ public static final String DIRECTIVE_RESOLUTION = ResolutionDirective.NAME;
private static final Collection<Parameter> defaultParameters = generateDefaultParameters(
- EffectiveDirective.RESOLVE,
- ResolutionDirective.MANDATORY);
+ EffectiveDirective.DEFAULT,
+ ResolutionDirective.MANDATORY,
+ CardinalityDirective.DEFAULT);
public Clause(String clause) {
super(
parsePath(clause, Patterns.NAMESPACE, false),
- parseParameters(clause, false),
+ parseTypedParameters(clause),
defaultParameters);
+
}
public Clause(String path, Map<String, Parameter> parameters, Collection<Parameter> defaultParameters) {
@@ -54,7 +57,7 @@ public class RequireCapabilityHeader ext
Map<String, Parameter> parameters = new HashMap<String, Parameter>(attributes.size() + directives.size());
for (Map.Entry<String, Object> entry : attributes.entrySet()) {
String key = entry.getKey();
- parameters.put(key, AttributeFactory.createAttribute(key, String.valueOf(entry.getValue())));
+ parameters.put(key, new TypedAttribute(key, entry.getValue()));
}
for (Map.Entry<String, String> entry : directives.entrySet()) {
String key = entry.getKey();
Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/RequireCapabilityRequirement.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/RequireCapabilityRequirement.java?rev=1705795&r1=1705794&r2=1705795&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/RequireCapabilityRequirement.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/RequireCapabilityRequirement.java Tue Sep 29 02:06:33 2015
@@ -24,21 +24,27 @@ import org.osgi.resource.Resource;
public class RequireCapabilityRequirement extends AbstractRequirement {
public static final String DIRECTIVE_FILTER = Namespace.REQUIREMENT_FILTER_DIRECTIVE;
+ private final Map<String, Object> attributes;
private final Map<String, String> directives;
private final String namespace;
private final Resource resource;
public RequireCapabilityRequirement(RequireCapabilityHeader.Clause clause, Resource resource) {
namespace = clause.getNamespace();
+ attributes = new HashMap<String, Object>(clause.getAttributes().size());
+ for (Attribute attribute : clause.getAttributes()) {
+ attributes.put(attribute.getName(), attribute.getValue());
+ }
directives = new HashMap<String, String>(clause.getDirectives().size());
- for (Directive directive : clause.getDirectives())
+ for (Directive directive : clause.getDirectives()) {
directives.put(directive.getName(), directive.getValue());
+ }
this.resource = resource;
}
@Override
public Map<String, Object> getAttributes() {
- return Collections.emptyMap();
+ return Collections.unmodifiableMap(attributes);
}
@Override
Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/SubsystemImportServiceHeader.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/SubsystemImportServiceHeader.java?rev=1705795&r1=1705794&r2=1705795&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/SubsystemImportServiceHeader.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/SubsystemImportServiceHeader.java Tue Sep 29 02:06:33 2015
@@ -27,13 +27,15 @@ import org.osgi.service.subsystem.Subsys
public class SubsystemImportServiceHeader extends AbstractClauseBasedHeader<SubsystemImportServiceHeader.Clause> implements RequirementHeader<SubsystemImportServiceHeader.Clause> {
public static class Clause extends AbstractClause {
- public static final String DIRECTIVE_EFFECTIVE = Constants.EFFECTIVE_DIRECTIVE;
- public static final String DIRECTIVE_FILTER = Constants.FILTER_DIRECTIVE;
- public static final String DIRECTIVE_RESOLUTION = Constants.RESOLUTION_DIRECTIVE;
+ public static final String DIRECTIVE_CARDINALITY = CardinalityDirective.NAME;
+ public static final String DIRECTIVE_EFFECTIVE = EffectiveDirective.NAME;
+ public static final String DIRECTIVE_FILTER = FilterDirective.NAME;
+ public static final String DIRECTIVE_RESOLUTION = ResolutionDirective.NAME;
private static final Collection<Parameter> defaultParameters = generateDefaultParameters(
EffectiveDirective.ACTIVE,
- ResolutionDirective.MANDATORY);
+ ResolutionDirective.MANDATORY,
+ CardinalityDirective.SINGLE);
public Clause(String clause) {
super(
Modified: aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/TypedAttribute.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/TypedAttribute.java?rev=1705795&r1=1705794&r2=1705795&view=diff
==============================================================================
--- aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/TypedAttribute.java (original)
+++ aries/trunk/subsystem/subsystem-core/src/main/java/org/apache/aries/subsystem/core/archive/TypedAttribute.java Tue Sep 29 02:06:33 2015
@@ -13,41 +13,144 @@
*/
package org.apache.aries.subsystem.core.archive;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+
import org.osgi.framework.Version;
public class TypedAttribute extends AbstractAttribute {
- public static enum Type {
- Double,
- Long,
- String,
- Version
- }
-
- private static Object parseValue(String value, Type type) {
- switch (type) {
- case Double:
- return Double.valueOf(value);
- case Long:
- return Long.valueOf(value);
- case Version:
- return Version.parseVersion(value);
- default:
- return value;
+ private static final String DOUBLE = "Double";
+ private static final String LIST = "List";
+ private static final String LIST_DOUBLE = "List<Double>";
+ private static final String LIST_LONG = "List<Long>";
+ private static final String LIST_STRING = "List<String>";
+ private static final String LIST_VERSION = "List<Version>";
+ private static final String LONG = "Long";
+ private static final String STRING = "String";
+ private static final String VERSION = "Version";
+
+ private static Object parseScalar(String value, String type) {
+ if (STRING.equals(type)) {
+ return value;
+ }
+ if (VERSION.equals(type)) {
+ return Version.parseVersion(value);
+ }
+ if (LONG.equals(type)) {
+ return Long.valueOf(value);
}
+ if (DOUBLE.equals(type)) {
+ return Double.valueOf(value);
+ }
+ return null;
}
- private final Type type;
+ private static Object parseList(String value, String type) {
+ if (!type.startsWith(LIST)) {
+ return null;
+ }
+ String scalar;
+ if (type.length() == LIST.length()) {
+ scalar = STRING;
+ }
+ else {
+ Matcher matcher = Patterns.SCALAR_LIST.matcher(type);
+ if (!matcher.matches()) {
+ return null;
+ }
+ scalar = matcher.group(1);
+ }
+ String[] values = value.split(",");
+ List<Object> result = new ArrayList<Object>(values.length);
+ for (String s : values) {
+ result.add(parseScalar(s, scalar));
+ }
+ return result;
+ }
- public TypedAttribute(String name, String value, String type) {
- this(name, value, Type.valueOf(type));
+ private static Object parseValue(String value, String type) {
+ if (type == null) {
+ return value;
+ }
+ Object result = parseScalar(value, type);
+ if (result == null) {
+ result = parseList(value, type);
+ }
+ return result;
}
- public TypedAttribute(String name, String value, Type type) {
+ private final String type;
+
+ public TypedAttribute(String name, String value, String type) {
super(name, parseValue(value, type));
this.type = type;
}
- public Type getType() {
- return type;
+ public TypedAttribute(String name, Object value) {
+ super(name, value);
+ if (value instanceof String) {
+ type = STRING;
+ }
+ else if (value instanceof List) {
+ @SuppressWarnings("rawtypes")
+ List list = (List)value;
+ if (list.isEmpty()) {
+ type = LIST;
+ }
+ else {
+ Object o = list.get(0);
+ if (o instanceof String) {
+ type = LIST_STRING;
+ }
+ else if (o instanceof Version) {
+ type = LIST_VERSION;
+ }
+ else if (o instanceof Long) {
+ type = LIST_LONG;
+ }
+ else if (o instanceof Double) {
+ type = LIST_DOUBLE;
+ }
+ else {
+ throw new IllegalArgumentException(name + '=' + value);
+ }
+ }
+ }
+ else if (value instanceof Version) {
+ type = VERSION;
+ }
+ else if (value instanceof Long) {
+ type = LONG;
+ }
+ else if (value instanceof Double) {
+ type = DOUBLE;
+ }
+ else {
+ throw new IllegalArgumentException(name + '=' + value);
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder()
+ .append(getName())
+ .append(':')
+ .append(type)
+ .append("=\"");
+ if (type.startsWith(LIST)) {
+ @SuppressWarnings("rawtypes")
+ List list = (List)getValue();
+ if (!list.isEmpty()) {
+ builder.append(list.get(0));
+ }
+ for (int i = 1; i < list.size(); i++) {
+ builder.append(',').append(list.get(i));
+ }
+ }
+ else {
+ builder.append(getValue());
+ }
+ return builder.append('"').toString();
}
}
Added: aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/defect/Aries1419Test.java
URL: http://svn.apache.org/viewvc/aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/defect/Aries1419Test.java?rev=1705795&view=auto
==============================================================================
--- aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/defect/Aries1419Test.java (added)
+++ aries/trunk/subsystem/subsystem-itests/src/test/java/org/apache/aries/subsystem/itests/defect/Aries1419Test.java Tue Sep 29 02:06:33 2015
@@ -0,0 +1,172 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.subsystem.itests.defect;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.aries.subsystem.core.archive.RequireCapabilityHeader;
+import org.apache.aries.subsystem.core.internal.BasicSubsystem;
+import org.apache.aries.subsystem.itests.SubsystemTest;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.service.subsystem.Subsystem;
+import org.osgi.service.subsystem.SubsystemConstants;
+import org.osgi.service.subsystem.SubsystemException;
+
+import aQute.bnd.osgi.Constants;
+
+/*
+ * https://issues.apache.org/jira/browse/ARIES-1419
+ *
+ * Provide-Capability header parser does not support typed attributes.
+ */
+public class Aries1419Test extends SubsystemTest {
+ /*
+ * Subsystem-SymbolicName: application.a.esa
+ *
+ * Included In Archive
+ * bundle.a.jar
+ */
+ private static final String APPLICATION_A = "application.a.esa";
+ /*
+ * Subsystem-SymbolicName: application.b.esa
+ *
+ * Included In Archive
+ * bundle.c.jar
+ */
+ private static final String APPLICATION_B = "application.b.esa";
+ /*
+ * Bundle-SymbolicName: bundle.a.jar
+ * Require-Capability: "a;resolution:=optional;filter:=\"(b=c)\";d=e;
+ * f:String=g;h:Long=21474836470;i:Double=3.4028234663852886E39;
+ * j:Version=2.1;k:List=\"foo,bar,acme\";l:List<Version>=\"1.1,2.2,3.3\""
+ */
+ private static final String BUNDLE_A = "bundle.a.jar";
+ /*
+ * Bundle-SymbolicName: bundle.b.jar
+ * Provide-Capability: "a;d=e;f:String=g;h:Long=21474836470;
+ * i:Double=3.4028234663852886E39;j:Version=2.1;k:List=\"foo,bar,acme\";
+ * l:List<Version>=\"1.1,2.2,3.3\""
+ */
+ private static final String BUNDLE_B = "bundle.b.jar";
+ /*
+ * Bundle-SymbolicName: bundle.c.jar
+ * Require-Capability: "a;filter:="(d=e)"
+ */
+ private static final String BUNDLE_C = "bundle.c.jar";
+
+ private static boolean createdTestFiles;
+
+ @Before
+ public void createTestFiles() throws Exception {
+ if (createdTestFiles)
+ return;
+ createBundleA();
+ createBundleB();
+ createBundleC();
+ createApplicationA();
+ createApplicationB();
+ createdTestFiles = true;
+ }
+
+ private void createBundleA() throws IOException {
+ createBundle(
+ name(BUNDLE_A),
+ requireCapability("a;resolution:=optional;filter:=\"(b=c)\""
+ + ";d=e;f:String=g;h:Long=21474836470;i:Double=3.4028234663852886E39"
+ + ";j:Version=2.1;k:List=\"foo,bar,acme\";l:List<Version>=\"1.1,2.2,3.3\""));
+ }
+
+ private void createBundleB() throws IOException {
+ createBundle(
+ name(BUNDLE_B),
+ provideCapability("a;b=c;d=e;f:String=g;h:Long=21474836470"
+ + ";i:Double=3.4028234663852886E39;j:Version=2.1;"
+ + "k:List=\"foo,bar,acme\";l:List<Version>=\"1.1,2.2,3.3\""));
+ }
+
+ private void createBundleC() throws IOException {
+ createBundle(
+ name(BUNDLE_C),
+ requireCapability("a;filter:=\"(&(b=c)(d=e)(f=g)(h<=21474836470)"
+ + "(!(i>=3.4028234663852886E40))(&(j>=2)(!(version>=3)))"
+ + "(|(k=foo)(k=bar)(k=acme))(&(l=1.1.0)(l=2.2)))\""));
+ }
+
+ private static void createApplicationA() throws IOException {
+ createApplicationAManifest();
+ createSubsystem(APPLICATION_A, BUNDLE_A);
+ }
+
+ private static void createApplicationAManifest() throws IOException {
+ Map<String, String> attributes = new HashMap<String, String>();
+ attributes.put(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME, APPLICATION_A);
+ createManifest(APPLICATION_A + ".mf", attributes);
+ }
+
+ private static void createApplicationB() throws IOException {
+ createApplicationBManifest();
+ createSubsystem(APPLICATION_B, BUNDLE_C);
+ }
+
+ private static void createApplicationBManifest() throws IOException {
+ Map<String, String> attributes = new HashMap<String, String>();
+ attributes.put(SubsystemConstants.SUBSYSTEM_SYMBOLICNAME, APPLICATION_B);
+ createManifest(APPLICATION_B + ".mf", attributes);
+ }
+
+ @Test
+ public void testRequireCapability() throws Exception {
+ Subsystem applicationA = installSubsystemFromFile(APPLICATION_A);
+ try {
+ Bundle bundleA = getConstituentAsBundle(applicationA, BUNDLE_A, null, null);
+ String expectedStr = bundleA.getHeaders().get(Constants.REQUIRE_CAPABILITY);
+ RequireCapabilityHeader expected = new RequireCapabilityHeader(expectedStr);
+ Map<String, String> headers = ((BasicSubsystem)applicationA).getDeploymentHeaders();
+ String actualStr = headers.get(Constants.REQUIRE_CAPABILITY);
+ RequireCapabilityHeader actual = new RequireCapabilityHeader(actualStr);
+ assertEquals("Wrong header", expected, actual);
+ }
+ finally {
+ uninstallSubsystemSilently(applicationA);
+ }
+ }
+
+ @Test
+ public void testProvideCapability() throws Exception {
+ Bundle bundleB = installBundleFromFile(BUNDLE_B);
+ try {
+ Subsystem applicationB = installSubsystemFromFile(APPLICATION_B);
+ uninstallSubsystemSilently(applicationB);
+ }
+ catch (SubsystemException e) {
+ e.printStackTrace();
+ fail("Subsystem should have installed");
+ }
+ finally {
+ uninstallSilently(bundleB);
+ }
+ }
+}