Having just updated to this commit and looked through the new code, is it
possible that this component is no longer buildable on Java 5?
> + @Test
> + public void testCapabilityHeader() throws Exception {
> + String s =
> + "com.acme.dictionary; effective:=resolve; from:String=nl; to=de;
> version:Version=3.4.0.test;somedir:=test, " +
> + "com.acme.dictionary; filter:=\"(&(width>=1000)(height>=1000))\",
> " +
>
+
"com.acme.ip2location;country:List<String>=\"nl,be,fr,uk\";version:Version=1.3;long:Long="
+ Long.MAX_VALUE + ";d:Double=\"2.2250738585072012e-308\"";
> +
> + List<GenericMetadata> capabilities =
> ManifestHeaderProcessor.parseCapabilityString(s);
> + testCapabilitiesOrRequirements(capabilities);
> + }
Isn't d:Double=\"2.2250738585072012e-308\"" going to send Java 5 into an
infinite loop when it tries to parse that double, or am I remembering the magic
number wrong? I don't have a Java 5 to test with, but I think it will break...
Regards,
Tim Ward
-------------------
Apache Aries PMC member & Enterprise OSGi advocate
Enterprise OSGi in Action (http://www.manning.com/cummins)
-------------------
> Subject: svn commit: r1204471 - in /aries/trunk/util/util-r42/src:
> main/java/org/apache/aries/util/manifest/ManifestHeaderProcessor.java
> test/java/org/apache/aries/util/manifest/ManifestHeaderProcessorTest.java
> Date: Mon, 21 Nov 2011 12:35:04 +0000
> To: [email protected]
> From: [email protected]
>
> Author: davidb
> Date: Mon Nov 21 12:35:04 2011
> New Revision: 1204471
>
> URL: http://svn.apache.org/viewvc?rev=1204471&view=rev
> Log:
> Enhance ManifestHeaderProcessor to support Provide-Capability and
> Require-Capability style headers. The functionality can be found in:
> ManifestHeaderProcessor.parseCapabilityString()
> ManifestHeaderProcessor.parseRequirementString()
> Currently the implementation of both is exactly the same under the hood, but
> I introduced them as separate methods to make make usage feel more naturally.
> It will also allow fixes to them individually in the future if needed.
>
> Modified:
>
> aries/trunk/util/util-r42/src/main/java/org/apache/aries/util/manifest/ManifestHeaderProcessor.java
>
> aries/trunk/util/util-r42/src/test/java/org/apache/aries/util/manifest/ManifestHeaderProcessorTest.java
>
> Modified:
> aries/trunk/util/util-r42/src/main/java/org/apache/aries/util/manifest/ManifestHeaderProcessor.java
> URL:
> http://svn.apache.org/viewvc/aries/trunk/util/util-r42/src/main/java/org/apache/aries/util/manifest/ManifestHeaderProcessor.java?rev=1204471&r1=1204470&r2=1204471&view=diff
> ==============================================================================
> ---
> aries/trunk/util/util-r42/src/main/java/org/apache/aries/util/manifest/ManifestHeaderProcessor.java
> (original)
> +++
> aries/trunk/util/util-r42/src/main/java/org/apache/aries/util/manifest/ManifestHeaderProcessor.java
> Mon Nov 21 12:35:04 2011
> @@ -31,6 +31,7 @@ import java.util.regex.Pattern;
> import org.apache.aries.util.ManifestHeaderUtils;
> import org.apache.aries.util.VersionRange;
> import org.osgi.framework.Constants;
> +import org.osgi.framework.Version;
>
>
> public class ManifestHeaderProcessor
> @@ -41,6 +42,31 @@ public class ManifestHeaderProcessor
> private static final String GREATER_EQ_OP = ">=";
>
> /**
> + * A GenericMetadata is either a Generic Capability or a Generic
> Requirement
> + */
> + public static class GenericMetadata {
> + private final String namespace;
> + private final Map<String, Object> attributes = new HashMap<String,
> Object>();
> + private final Map<String, String> directives = new HashMap<String,
> String>();
> +
> + public GenericMetadata(String namespace) {
> + this.namespace = namespace;
> + }
> +
> + public String getNamespace() {
> + return namespace;
> + }
> +
> + public Map<String, Object> getAttributes() {
> + return attributes;
> + }
> +
> + public Map<String, String> getDirectives() {
> + return directives;
> + }
> + }
> +
> + /**
> * A simple class to associate two types.
> *
> * @param <N> The type for the 'Name'
> @@ -49,7 +75,7 @@ public class ManifestHeaderProcessor
> public static class NameValuePair {
> private String name;
> private Map<String,String> attributes;
> -
> +
> public NameValuePair(String name, Map<String,String> value)
> {
> this.name = name;
> @@ -63,7 +89,7 @@ public class ManifestHeaderProcessor
> {
> this.name = name;
> }
> -
> +
> public Map<String,String> getAttributes()
> {
> return attributes;
> @@ -72,7 +98,7 @@ public class ManifestHeaderProcessor
> {
> this.attributes = value;
> }
> -
> +
> @Override
> public String toString(){
> return "{"+name.toString()+"::"+attributes.toString()+"}";
> @@ -102,9 +128,9 @@ public class ManifestHeaderProcessor
> return true;
> }
> }
> -
> +
> /**
> - * Intended to provide a standard way to add Name/Value's to
> + * Intended to provide a standard way to add Name/Value's to
> * aggregations of Name/Value's.
> *
> * @param <N> Type of 'Name'
> @@ -121,17 +147,17 @@ public class ManifestHeaderProcessor
>
> /**
> * Map of Name -> Value.
> - *
> + *
> * @param <N> Type of 'Name'
> * @param <V> Type of 'Value'
> */
> public static class NameValueMap extends HashMap<String,
> Map<String,String>> implements NameValueCollection, Map<String,
> Map<String,String>>{
> private static final long serialVersionUID = -6446338858542599141L;
> -
> +
> public void addToCollection(String n, Map<String,String> v){
> this.put(n,v);
> }
> -
> +
> @Override
> public String toString(){
> StringBuilder sb = new StringBuilder();
> @@ -146,19 +172,19 @@ public class ManifestHeaderProcessor
> return sb.toString();
> }
> }
> -
> +
> /**
> * List of Name/Value
> *
> * @param <N> Type of 'Name'
> * @param <V> Type of 'Value'
> */
> - public static class NameValueList extends ArrayList<NameValuePair>
> implements NameValueCollection, List<NameValuePair> {
> + public static class NameValueList extends ArrayList<NameValuePair>
> implements NameValueCollection, List<NameValuePair> {
> private static final long serialVersionUID = 1808636823825029983L;
> -
> +
> public void addToCollection(String n, Map<String,String> v){
> this.add(new NameValuePair(n,v));
> - }
> + }
> @Override
> public String toString(){
> StringBuffer sb = new StringBuffer();
> @@ -167,18 +193,18 @@ public class ManifestHeaderProcessor
> for(NameValuePair nvp : this){
> if(!first)sb.append(",");
> first=false;
> - sb.append(nvp.toString());
> + sb.append(nvp.toString());
> }
> sb.append("}");
> return sb.toString();
> }
> }
> -
> +
> /**
> - *
> + *
> * Splits a delimiter separated string, tolerating presence of non
> separator commas
> * within double quoted segments.
> - *
> + *
> * Eg.
> * com.ibm.ws.eba.helloWorldService;version="[1.0.0, 1.0.0]" &
> * com.ibm.ws.eba.helloWorldService;version="1.0.0"
> @@ -191,23 +217,23 @@ public class ManifestHeaderProcessor
> public static List<String> split(String value, String delimiter)
> {
> return ManifestHeaderUtils.split(value, delimiter);
> - }
> -
> -
> + }
> +
> +
> /**
> * Internal method to parse headers with the format<p>
> - * [Name](;[Name])*(;[attribute-name]=[attribute-value])*<br>
> + * [Name](;[Name])*(;[attribute-name]=[attribute-value])*<br>
> * Eg.<br>
> * rumplestiltskin;thing=value;other=something<br>
> * littleredridinghood
> * bundle1;bundle2;other=things
> * bundle1;bundle2
> - *
> + *
> * @param s data to parse
> - * @return a list of NameValuePair, with the Name being the name
> component,
> - * and the Value being a NameValueMap of key->value mappings.
> + * @return a list of NameValuePair, with the Name being the name component,
> + * and the Value being a NameValueMap of key->value mappings.
> */
> - private static List<NameValuePair>
> genericNameWithNameValuePairProcess(String s){
> + private static List<NameValuePair>
> genericNameWithNameValuePairProcess(String s){
> String name;
> Map<String,String> params = null;
> List<NameValuePair> nameValues = new ArrayList<NameValuePair>();
> @@ -217,19 +243,19 @@ public class ManifestHeaderProcessor
> name = s;
> params = new HashMap<String, String>();
> pkgs.add(name);
> - }else{
> + }else{
> name = s.substring(0,index).trim();
> String tail = s.substring(index+1).trim();
> -
> +
> pkgs.add(name); // add the first package
> StringBuilder parameters = new StringBuilder();
> -
> -
> +
> +
> // take into consideration of multiple packages separated by ';'
> // while they share the same attributes or directives
> List<String> tailParts = split(tail, ";");
> boolean firstParameter =false;
> -
> +
> for (String part : tailParts) {
> // if it is not a parameter and no parameter appears in front of it,
> it must a package
> if (!!!(part.contains("="))) {
> @@ -238,30 +264,30 @@ public class ManifestHeaderProcessor
> if (!!!(firstParameter))
> pkgs.add(part);
> } else {
> - if (!!!(firstParameter))
> + if (!!!(firstParameter))
> firstParameter = true;
>
> parameters.append(part + ";");
> }
> - }
> -
> + }
> +
> if (parameters.length() != 0) {
> //remove the final ';' if there is one
> if (parameters.toString().endsWith(";")) {
> -
> +
> parameters = parameters.deleteCharAt(parameters.length() -1);
> - }
> -
> + }
> +
> params = genericNameValueProcess(parameters.toString());
> }
> -
> +
> }
> for (String pkg : pkgs) {
> nameValues.add(new NameValuePair(pkg,params));
> - }
> -
> + }
> +
> return nameValues;
> -
> +
> }
>
> /**
> @@ -271,68 +297,68 @@ public class ManifestHeaderProcessor
> * thing=value;other=something<br>
> * <p>
> * Note. Directives (name:=value) are represented in the map with name
> suffixed by ':'
> - *
> + *
> * @param s data to parse
> * @return a NameValueMap, with attribute-name -> attribute-value.
> */
> private static Map<String,String> genericNameValueProcess(String s){
> - Map<String,String> params = new HashMap<String,String>();
> + Map<String,String> params = new HashMap<String,String>();
> List<String> parameters = split(s, ";");
> for(String parameter : parameters) {
> List<String> parts = split(parameter,"=");
> - // do a check, otherwise we might get NPE
> + // do a check, otherwise we might get NPE
> if (parts.size() ==2) {
> String second = parts.get(1).trim();
> if (second.startsWith("\"") && second.endsWith("\""))
> second = second.substring(1,second.length()-1);
> -
> +
> String first = parts.get(0).trim();
> -
> - // make sure for directives we clear out any space as in "directive
> :=value"
> +
> + // make sure for directives we clear out any space as in "directive
> :=value"
> if (first.endsWith(":")) {
> first = first.substring(0, first.length()-1).trim()+":";
> }
> -
> +
> params.put(first, second);
> }
> }
>
> return params;
> }
> -
> +
> /**
> - * Processes an import/export style header.. <p>
> + * Processes an import/export style header.. <p>
> * pkg1;attrib=value;attrib=value,pkg2;attrib=value,pkg3;attrib=value
> - *
> + *
> * @param out The collection to add each package name + attrib map to.
> * @param s The data to parse
> */
> private static void genericImportExportProcess(NameValueCollection out,
> String s){
> List<String> packages = split(s, ",");
> - for(String pkg : packages){
> + for(String pkg : packages){
> List<NameValuePair> ps = genericNameWithNameValuePairProcess(pkg);
> for (NameValuePair p : ps) {
> out.addToCollection(p.getName(), p.getAttributes());
> }
> - }
> + }
> }
> -
> +
> /**
> * Parse an export style header.<p>
> * pkg1;attrib=value;attrib=value,pkg2;attrib=value,pkg3;attrib=value2
> * <p>
> * Result is returned as a list, as export does allow duplicate package
> exports.
> - *
> + *
> * @param list The data to parse.
> - * @return List of NameValuePairs, where each Name in the list is an
> exported package,
> - * with its associated Value being a NameValueMap of any
> attributes declared.
> + * @return List of NameValuePairs, where each Name in the list is an
> exported package,
> + * with its associated Value being a NameValueMap of any
> attributes declared.
> */
> public static List<NameValuePair> parseExportString(String s){
> NameValueList retval = new NameValueList();
> genericImportExportProcess(retval, s);
> return retval;
> }
> -
> +
> /**
> * Parse an export style header in a list.<p>
> * pkg1;attrib=value;attrib=value
> @@ -340,54 +366,144 @@ public class ManifestHeaderProcessor
> * pkg3;attrib=value2
> * <p>
> * Result is returned as a list, as export does allow duplicate package
> exports.
> - *
> + *
> * @param list The data to parse.
> - * @return List of NameValuePairs, where each Name in the list is an
> exported package,
> - * with its associated Value being a NameValueMap of any
> attributes declared.
> + * @return List of NameValuePairs, where each Name in the list is an
> exported package,
> + * with its associated Value being a NameValueMap of any
> attributes declared.
> */
> public static List<NameValuePair> parseExportList(List<String> list){
> NameValueList retval = new NameValueList();
> - for(String pkg : list){
> + for(String pkg : list){
> List<NameValuePair> ps = genericNameWithNameValuePairProcess(pkg);
> for (NameValuePair p : ps) {
> retval.addToCollection(p.getName(), p.getAttributes());
> }
> - }
> + }
> return retval;
> }
> -
> +
> /**
> * Parse an import style header.<p>
> * pkg1;attrib=value;attrib=value,pkg2;attrib=value,pkg3;attrib=value
> * <p>
> * Result is returned as a set, as import does not allow duplicate package
> imports.
> - *
> + *
> * @param s The data to parse.
> - * @return Map of NameValuePairs, where each Key in the Map is an imported
> package,
> - * with its associated Value being a NameValueMap of any
> attributes declared.
> - */
> + * @return Map of NameValuePairs, where each Key in the Map is an imported
> package,
> + * with its associated Value being a NameValueMap of any
> attributes declared.
> + */
> public static Map<String, Map<String, String>> parseImportString(String s){
> NameValueMap retval = new NameValueMap();
> genericImportExportProcess(retval, s);
> - return retval;
> + return retval;
> + }
> +
> + /**
> + * Parse a generic capability header. For example<br/>
> + *
> com.acme.myns;mylist:List<String>="nl,be,fr,uk";myver:Version=1.3;long:Long="1234";d:Double="3.14";myattr=xyz,
> + * com.acme.myns;myattr=abc
> + * @param s The header to be parsed
> + * @return A list of GenericMetadata objects each representing an
> individual capability. The values in the attribute map
> + * are of the specified datatype.
> + */
> + public static List<GenericMetadata> parseCapabilityString(String s) {
> + return parseGenericMetadata(s);
> }
> -
> +
> + /**
> + * Parse a generic capability header. For example<br/>
> + *
> com.acme.myns;mylist:List<String>="nl,be,fr,uk";myver:Version=1.3;long:Long="1234";d:Double="3.14";myattr=xyz,
> + * com.acme.myns;myattr=abc
> + * @param s The header to be parsed
> + * @return A list of GenericMetadata objects each representing an
> individual capability. The values in the attribute map
> + * are of the specified datatype.
> + */
> + public static List<GenericMetadata> parseRequirementString(String s) {
> + return parseGenericMetadata(s);
> + }
> +
> + private static List<GenericMetadata> parseGenericMetadata(String s) {
> + List<GenericMetadata> capabilities = new ArrayList<GenericMetadata>();
> +
> + List<String> entries = split(s, ",");
> + for(String e : entries){
> + List<NameValuePair> nvpList = genericNameWithNameValuePairProcess(e);
> +
> + for(NameValuePair nvp : nvpList) {
> + String namespace = nvp.getName();
> + GenericMetadata cap = new GenericMetadata(namespace);
> + capabilities.add(cap);
> +
> + Map<String, String> attrMap = nvp.getAttributes();
> + for (Map.Entry<String, String> entry : attrMap.entrySet()) {
> + String k = entry.getKey();
> + String v = entry.getValue();
> + if (k.contains(":")) {
> + if (k.endsWith(":")) {
> + // a directive
> + cap.getDirectives().put(k.substring(0, k.length() - 1), v);
> + } else {
> + // an attribute with its datatype specified
> + parseTypedAttribute(k, v, cap);
> + }
> + } else {
> + // ordinary (String) attribute
> + cap.getAttributes().put(k, v);
> + }
> + }
> + }
> + }
> +
> + return capabilities;
> + }
> +
> + private static void parseTypedAttribute(String k, String v,
> GenericMetadata cap) {
> + int idx = k.indexOf(':');
> + String name = k.substring(0, idx);
> + String type = k.substring(idx + 1);
> +
> + if (type.startsWith("List<") && type.endsWith(">")) {
> + String subtype = type.substring("List<".length(), type.length() -
> 1).trim();
> + List<Object> l = new ArrayList<Object>();
> + for (String s : v.split(",")) {
> + l.add(getTypedValue(k, subtype, s));
> + }
> + cap.getAttributes().put(name, l);
> + } else {
> + cap.getAttributes().put(name, getTypedValue(k, type.trim(), v));
> + }
> + }
> +
> + private static Object getTypedValue(String k, String type, String v) {
> + if ("String".equals(type)) {
> + return v;
> + } else if ("Long".equals(type)) {
> + return Long.parseLong(v);
> + } else if ("Double".equals(type)) {
> + return Double.parseDouble(v);
> + } else if ("Version".equals(type)) {
> + return Version.parseVersion(v);
> + }
> + throw new IllegalArgumentException(k + "=" + v);
> + }
> +
> +
> /**
> * Parse a bundle symbolic name.<p>
> * bundlesymbolicname;attrib=value;attrib=value
> * <p>
> - *
> + *
> * @param s The data to parse.
> - * @return NameValuePair with Name being the BundleSymbolicName,
> - * and Value being any attribs declared for the name.
> - */
> + * @return NameValuePair with Name being the BundleSymbolicName,
> + * and Value being any attribs declared for the name.
> + */
> public static NameValuePair parseBundleSymbolicName(String s){
> return genericNameWithNameValuePairProcess(s).get(0); // should just
> return the first one
> }
> -
> +
> /**
> - * Parse a version range..
> - *
> + * Parse a version range..
> + *
> * @param s
> * @return VersionRange object.
> * @throws IllegalArgumentException if the String could not be parsed as a
> VersionRange
> @@ -395,10 +511,10 @@ public class ManifestHeaderProcessor
> public static VersionRange parseVersionRange(String s) throws
> IllegalArgumentException{
> return new VersionRange(s);
> }
> -
> +
> /**
> - * Parse a version range and indicate if the version is an exact version
> - *
> + * Parse a version range and indicate if the version is an exact version
> + *
> * @param s
> * @param exactVersion
> * @return VersionRange object.
> @@ -415,7 +531,7 @@ public class ManifestHeaderProcessor
> * Filter strings generated by this method will therefore tend to break
> the
> * standard OSGi Filter class. The OBR stanza can be stripped out later
> if
> * required.
> - *
> + *
> * @param attribs
> * @return filter string
> */
> @@ -537,10 +653,10 @@ public class ManifestHeaderProcessor
> * include a stanza of the form, (mandatory:<*mandatoryAttribute) Filter
> * strings generated by this method will therefore tend to break the
> standard
> * OSGi Filter class. The OBR stanza can be stripped out later if required.
> - *
> + *
> * We may wish to consider relocating this method since VersionRange has
> its
> * own top level class.
> - *
> + *
> * @param type
> * @param name
> * @param attribs
> @@ -655,8 +771,8 @@ public class ManifestHeaderProcessor
>
> return result;
> }
> -
> - public static Map<String,String> parseFilter(String filter)
> +
> + public static Map<String,String> parseFilter(String filter)
> {
> Map<String,String> result;
> if (filter.startsWith("(&")) {
> @@ -666,6 +782,5 @@ public class ManifestHeaderProcessor
> }
> return result;
> }
> -
> }
>
>
> Modified:
> aries/trunk/util/util-r42/src/test/java/org/apache/aries/util/manifest/ManifestHeaderProcessorTest.java
> URL:
> http://svn.apache.org/viewvc/aries/trunk/util/util-r42/src/test/java/org/apache/aries/util/manifest/ManifestHeaderProcessorTest.java?rev=1204471&r1=1204470&r2=1204471&view=diff
> ==============================================================================
> ---
> aries/trunk/util/util-r42/src/test/java/org/apache/aries/util/manifest/ManifestHeaderProcessorTest.java
> (original)
> +++
> aries/trunk/util/util-r42/src/test/java/org/apache/aries/util/manifest/ManifestHeaderProcessorTest.java
> Mon Nov 21 12:35:04 2011
> @@ -27,15 +27,16 @@ import static org.junit.Assert.assertTru
> import static org.junit.Assert.fail;
>
> import java.util.ArrayList;
> +import java.util.Arrays;
> import java.util.HashMap;
> import java.util.List;
> import java.util.Map;
>
> import org.apache.aries.util.VersionRange;
> -import org.apache.aries.util.manifest.ManifestHeaderProcessor;
> -import org.apache.aries.util.manifest.ManifestHeaderProcessor.NameValueMap;
> +import
> org.apache.aries.util.manifest.ManifestHeaderProcessor.GenericMetadata;
> import org.apache.aries.util.manifest.ManifestHeaderProcessor.NameValuePair;
> import org.junit.Test;
> +import org.osgi.framework.Version;
>
> public class ManifestHeaderProcessorTest
> {
> @@ -44,10 +45,10 @@ public class ManifestHeaderProcessorTest
> HashMap<String, String> attrs = new HashMap<String, String>();
> attrs.put("some", "value");
> NameValuePair nvp = new NameValuePair("key", attrs);
> -
> +
> assertEquals("The name value pair is not set properly.", nvp.getName(),
> "key");
> assertEquals("The value is not set properly.",
> nvp.getAttributes().get("some"), "value");
> -
> +
> attrs = new HashMap<String, String>();
> attrs.put("some", "value");
> NameValuePair anotherNvp = new NameValuePair("key", attrs);
> @@ -59,58 +60,58 @@ public class ManifestHeaderProcessorTest
> nvp.setAttributes(attrs);
> assertEquals("The name value pair is not set properly.", nvp.getName(),
> "newKey");
> assertEquals("The value is not set properly.",
> nvp.getAttributes().get("some"), "newValue");
> -
> +
> Map<String,String> nvm1 = new HashMap<String,String>();
> nvm1.put("a","b");
> nvm1.put("c","d");
> -
> +
> Map<String,String> nvm2 = new HashMap<String,String>();
> nvm2.put("c","d");
> nvm2.put("a","b");
> assertEquals("The maps are not equal.", nvm1, nvm2);
> nvm2.put("e","f");
> assertNotSame("The maps are the same.", nvm1, nvm2);
> -
> +
> NameValuePair nvp1 = new NameValuePair("one",nvm1);
> NameValuePair nvp2 = new NameValuePair("one",nvm2);
> -
> +
> assertNotSame("The pairs are identical ",nvp1,nvp2);
> nvm1.put("e","f");
> assertEquals("The pairs are not equal.", nvp1,nvp2);
> -
> +
> List<NameValuePair> bundleInfoList1 = new ArrayList<NameValuePair>();
> bundleInfoList1.add(nvp1);
>
> List<NameValuePair> bundleInfoList2 = new ArrayList<NameValuePair>();
> bundleInfoList2.add(nvp1);
> -
> +
> bundleInfoList1.removeAll(bundleInfoList2);
> assertEquals("The List should be empty", bundleInfoList1.isEmpty(),
> true);
> -
> -
> +
> +
> assertNotSame("The two objects of NameValuePair is not equal.", nvp,
> anotherNvp);
> }
>
> -
> +
> /**
> * Test the Bundle manifest header entry of
> * Bundle-SymbolicName: com.acme.foo;singleton:=true
> */
> @Test
> - public void testParseBundleSymbolicName()
> + public void testParseBundleSymbolicName()
> {
> String bundleSymbolicNameEntry =
> "com.acme.foo;singleton:=true;fragment-attachment:=always";
> NameValuePair nvp =
> ManifestHeaderProcessor.parseBundleSymbolicName(bundleSymbolicNameEntry);
> assertEquals("The symbolic name is wrong.", nvp.getName(),
> "com.acme.foo");
> assertEquals("The value is wrong.", "true",
> nvp.getAttributes().get("singleton:") );
> assertEquals("The directive is wrong.", "always",
> nvp.getAttributes().get("fragment-attachment:") );
> -
> +
> String bundleSymbolicNameEntry2 = "com.acme.foo";
> NameValuePair nvp2 =
> ManifestHeaderProcessor.parseBundleSymbolicName(bundleSymbolicNameEntry2);
> assertEquals("The symbolic name is wrong.", nvp2.getName(),
> "com.acme.foo");
> }
> -
> -
> +
> +
>
> /**
> * Test the import package and import service
> @@ -120,9 +121,9 @@ public class ManifestHeaderProcessorTest
> public void testParseImportString()
> {
> String importPackage =
> "com.acme.foo,come.acm.e.bar;version=\"[1.23,1.24.5]\";resolution:=mandatory;company=\"ACME\",a.b.c;version=1.2.3;company=com";
> -
> +
> Map<String, Map<String, String>> importPackageReturn =
> ManifestHeaderProcessor.parseImportString(importPackage);
> -
> +
> assertTrue("The package is not set.",
> importPackageReturn.containsKey("com.acme.foo"));
> assertTrue("The package is not set.",
> importPackageReturn.containsKey("come.acm.e.bar"));
> assertTrue("The package is not set.",
> importPackageReturn.containsKey("come.acm.e.bar"));
> @@ -133,12 +134,12 @@ public class ManifestHeaderProcessorTest
> assertEquals("The directive is not set correctly.", "ACME",
> importPackageReturn.get("come.acm.e.bar").get("company"));
> assertEquals("The directive is not set correctly.", "1.2.3",
> importPackageReturn.get("a.b.c").get("version"));
> assertEquals("The directive is not set correctly.", "com",
> importPackageReturn.get("a.b.c").get("company"));
> -
> +
> importPackage="com.acme.foo";
> -
> +
> assertTrue("The package is not set.",
> importPackageReturn.containsKey("com.acme.foo"));
> assertTrue("The package should not contain any attributes.",
> importPackageReturn.get("com.acme.foo").isEmpty());
> -
> +
> importPackage="com.acme.foo;com.acme.bar;version=2";
> Map<String, Map<String, String>> importPackageReturn2 =
> ManifestHeaderProcessor.parseImportString(importPackage);
> assertTrue("The package is not set.",
> importPackageReturn2.containsKey("com.acme.foo"));
> @@ -146,31 +147,31 @@ public class ManifestHeaderProcessorTest
> assertEquals("The directive is not set correctly.", "2",
> importPackageReturn2.get("com.acme.foo").get("version"));
> assertEquals("The directive is not set correctly.", "2",
> importPackageReturn2.get("com.acme.bar").get("version"));
> }
> -
> +
> @Test
> public void testParseExportString()
> {
> String exportPackage =
> "com.acme.foo,com.acme.bar;version=1,com.acme.bar;version=2;uses:=\"a.b.c,d.e.f\";security=false;mandatory:=security";
> -
> +
> List<NameValuePair> exportPackageReturn =
> ManifestHeaderProcessor.parseExportString(exportPackage);
> -
> +
> int i =0;
> assertEquals("The number of the packages is wrong.", 3,
> exportPackageReturn.size());
> for (NameValuePair nvp : exportPackageReturn) {
> if (nvp.getName().equals("com.acme.foo")) {
> i++;
> -
> +
> assertTrue("The directive or attribute should not be set.",
> nvp.getAttributes().isEmpty() );
> } else if ((nvp.getName().equals("com.acme.bar")) &&
> ("2".equals(nvp.getAttributes().get("version")))) {
> -
> -
> +
> +
> i++;
> assertEquals("The directive is wrong.", "a.b.c,d.e.f",
> nvp.getAttributes().get("uses:"));
> assertEquals("The directive is wrong.", "false",
> nvp.getAttributes().get("security"));
> assertEquals("The directive is wrong.", "security",
> nvp.getAttributes().get("mandatory:"));
> } else if ((nvp.getName().equals("com.acme.bar")) &&
> ("1".equals(nvp.getAttributes().get("version")))) {
> i++;
> -
> +
> assertNull("The directive is wrong.",
> nvp.getAttributes().get("uses:"));
> assertNull("The directive is wrong.",
> nvp.getAttributes().get("security"));
> assertNull("The directive is wrong.",
> nvp.getAttributes().get("mandatory:"));
> @@ -178,90 +179,90 @@ public class ManifestHeaderProcessorTest
> }
> // make sure all three packages stored
> assertEquals("The names of the packages are wrong.", 3, i);
> -
> +
> exportPackage = "com.acme.foo";
> -
> +
> exportPackageReturn =
> ManifestHeaderProcessor.parseExportString(exportPackage);
> -
> +
> int k =0;
> assertEquals("The number of the packages is wrong.", 1,
> exportPackageReturn.size());
> for (NameValuePair nvp : exportPackageReturn) {
> if (nvp.getName().equals("com.acme.foo")) {
> k++;
> -
> +
> assertTrue("The directive or attribute should not be set.",
> nvp.getAttributes().isEmpty() );
> - }
> + }
> }
> assertEquals("The names of the packages are wrong.", 1, k);
> -
> +
> // test multiple packages separated by ;
> -
> +
> exportPackage =
> "com.acme.foo;com.acme.bar;version=\"2\";resolution:=optional";
> -
> +
> exportPackageReturn =
> ManifestHeaderProcessor.parseExportString(exportPackage);
> -
> +
> k =0;
> assertEquals("The number of the packages is wrong.", 2,
> exportPackageReturn.size());
> for (NameValuePair nvp : exportPackageReturn) {
> if (nvp.getName().equals("com.acme.foo")) {
> k++;
> -
> +
> assertEquals("The attribute is wrong.", "2",
> nvp.getAttributes().get("version") );
> assertEquals("The attribute is wrong.", "optional",
> nvp.getAttributes().get("resolution:"));
> } else if (nvp.getName().equals("com.acme.bar")) {
> k++;
> -
> +
> assertEquals("The attribute is wrong.", "2",
> nvp.getAttributes().get("version") );
> assertEquals("The attribute is wrong.", "optional",
> nvp.getAttributes().get("resolution:"));
> }
> }
> assertEquals("The names of the packages are wrong.", 2, k);
> -
> +
> exportPackageReturn =
> ManifestHeaderProcessor.parseExportString("some.export.with.space.in;directive
> := spacey");
> assertEquals(exportPackageReturn.toString(), "spacey",
> exportPackageReturn.get(0).getAttributes().get("directive:"));
> }
> -
> +
> @Test
> public void testExportMandatoryAttributes() {
> String exportPackage =
> "com.acme.foo,com.acme.bar;version=2;company=dodo;security=false;mandatory:=\"security,company\"";
> -
> +
> List<NameValuePair> exportPackageReturn =
> ManifestHeaderProcessor.parseExportString(exportPackage);
> -
> +
> int i =0;
> assertEquals("The number of the packages is wrong.", 2,
> exportPackageReturn.size());
> for (NameValuePair nvp : exportPackageReturn) {
> if (nvp.getName().equals("com.acme.foo")) {
> i++;
> -
> +
> assertTrue("The directive or attribute should not be set.",
> nvp.getAttributes().isEmpty() );
> } else if ((nvp.getName().equals("com.acme.bar")) &&
> ("2".equals(nvp.getAttributes().get("version")))) {
> -
> -
> +
> +
> i++;
> assertEquals("The directive is wrong.", "dodo",
> nvp.getAttributes().get("company"));
> assertEquals("The directive is wrong.", "false",
> nvp.getAttributes().get("security"));
> assertEquals("The directive is wrong.", "security,company",
> nvp.getAttributes().get("mandatory:"));
> - }
> + }
> }
> // make sure all three packages stored
> assertEquals("The names of the packages are wrong.", 2, i);
> -
> +
> }
> -
> +
> private String createExpectedFilter(Map<String, String> values, String
> ... parts)
> {
> StringBuilder builder = new StringBuilder(parts[0]);
> -
> +
> for (Map.Entry<String, String> entry : values.entrySet()) {
> if ("version".equals(entry.getKey())) builder.append(parts[2]);
> else if ("company".equals(entry.getKey())) builder.append(parts[1]);
> }
> -
> +
> builder.append(parts[3]);
> -
> +
> return builder.toString();
> }
> -
> +
> /**
> * Test the filter generated correctly
> * @throws Exception
> @@ -275,49 +276,49 @@ public class ManifestHeaderProcessorTest
> String filter =
> ManifestHeaderProcessor.generateFilter("symbolic-name", "com.ibm.foo",
> valueMap);
> String expected = createExpectedFilter(valueMap,
> "(&(symbolic-name=com.ibm.foo)", "(company=com)",
> "(version>=1.2.0)(version<=2.3.0)", "(mandatory:<*company))");
> assertEquals("The filter is wrong.", expected, filter );
> -
> -
> +
> +
> valueMap.clear();
> -
> +
> valueMap.put("version", "(1.2, 2.3]");
> valueMap.put("resulution:", "mandatory");
> valueMap.put("company", "com");
> filter = ManifestHeaderProcessor.generateFilter("symbolic-name",
> "com.ibm.foo", valueMap);
> expected = createExpectedFilter(valueMap,
> "(&(symbolic-name=com.ibm.foo)", "(company=com)",
> "(version>=1.2.0)(version<=2.3.0)(!(version=1.2.0))",
> "(mandatory:<*company))");
> assertEquals("The filter is wrong.", expected, filter );
> -
> +
> valueMap.clear();
> -
> +
> valueMap.put("version", "(1.2, 2.3)");
> valueMap.put("resulution:", "mandatory");
> valueMap.put("company", "com");
> filter = ManifestHeaderProcessor.generateFilter("symbolic-name",
> "com.ibm.foo", valueMap);
> expected = createExpectedFilter(valueMap,
> "(&(symbolic-name=com.ibm.foo)", "(company=com)",
> "(version>=1.2.0)(version<=2.3.0)(!(version=1.2.0))(!(version=2.3.0))",
> "(mandatory:<*company))");
> assertEquals("The filter is wrong.", expected, filter );
> -
> +
> valueMap.clear();
> -
> +
> valueMap.put("version", "1.2");
> valueMap.put("resulution:", "mandatory");
> valueMap.put("company", "com");
> filter = ManifestHeaderProcessor.generateFilter("symbolic-name",
> "com.ibm.foo", valueMap);
> expected = createExpectedFilter(valueMap,
> "(&(symbolic-name=com.ibm.foo)", "(company=com)", "(version>=1.2.0)",
> "(mandatory:<*company))");
> assertEquals("The filter is wrong.", expected, filter );
> -
> +
> valueMap.clear();
> -
> +
> valueMap.put("resulution:", "mandatory");
> valueMap.put("company", "com");
> filter = ManifestHeaderProcessor.generateFilter("symbolic-name",
> "com.ibm.foo", valueMap);
> expected = createExpectedFilter(valueMap,
> "(&(symbolic-name=com.ibm.foo)", "(company=com)", "",
> "(mandatory:<*company))");
> assertEquals("The filter is wrong.", expected, filter );
> }
> -
> +
> /**
> * Test the version range created correctly
> * @throws Exception
> */
> -
> +
> @Test
> public void testVersionRange() throws Exception {
> String version1 = "[1.2.3, 4.5.6]";
> @@ -332,51 +333,51 @@ public class ManifestHeaderProcessorTest
> String version10=null;
> String version11="";
> String version12="\"[1.2.3, 4.5.6]\"";
> -
> +
> VersionRange vr = ManifestHeaderProcessor.parseVersionRange(version1);
> assertEquals("The value is wrong", "1.2.3",
> vr.getMinimumVersion().toString());
> assertFalse("The value is wrong", vr.isMinimumExclusive());
> assertEquals("The value is wrong", "4.5.6",
> vr.getMaximumVersion().toString());
> assertFalse("The value is wrong", vr.isMaximumExclusive());
> -
> +
> vr = ManifestHeaderProcessor.parseVersionRange(version2);
> assertEquals("The value is wrong", "1.0.0",
> vr.getMinimumVersion().toString());
> assertTrue("The value is wrong", vr.isMinimumExclusive());
> assertEquals("The value is wrong", "2.0.0",
> vr.getMaximumVersion().toString());
> assertFalse("The value is wrong", vr.isMaximumExclusive());
> -
> +
> vr = ManifestHeaderProcessor.parseVersionRange(version3);
> -
> +
> assertEquals("The value is wrong", "2.0.0",
> vr.getMinimumVersion().toString());
> assertFalse("The value is wrong", vr.isMinimumExclusive());
> assertEquals("The value is wrong", "4.0.0",
> vr.getMaximumVersion().toString());
> assertTrue("The value is wrong", vr.isMaximumExclusive());
> -
> +
> vr = ManifestHeaderProcessor.parseVersionRange(version4);
> -
> +
> assertEquals("The value is wrong", "1.0.0",
> vr.getMinimumVersion().toString());
> assertTrue("The value is wrong", vr.isMinimumExclusive());
> assertEquals("The value is wrong", "2.0.0",
> vr.getMaximumVersion().toString());
> assertTrue("The value is wrong", vr.isMaximumExclusive());
> -
> +
> vr = ManifestHeaderProcessor.parseVersionRange(version5);
> assertEquals("The value is wrong", "2.0.0",
> vr.getMinimumVersion().toString());
> assertFalse("The value is wrong", vr.isMinimumExclusive());
> assertNull("The value is wrong", vr.getMaximumVersion());
> assertFalse("The value is wrong", vr.isMaximumExclusive());
> -
> +
> vr = ManifestHeaderProcessor.parseVersionRange(version6);
> assertEquals("The value is wrong", "2.3.0",
> vr.getMinimumVersion().toString());
> assertFalse("The value is wrong", vr.isMinimumExclusive());
> assertNull("The value is wrong", vr.getMaximumVersion());
> assertFalse("The value is wrong", vr.isMaximumExclusive());
> -
> +
> vr = ManifestHeaderProcessor.parseVersionRange(version7);
> assertEquals("The value is wrong", "1.2.3.q",
> vr.getMinimumVersion().toString());
> assertFalse("The value is wrong", vr.isMinimumExclusive());
> assertEquals("The value is wrong", "2.3.4.p",
> vr.getMaximumVersion().toString());
> assertTrue("The value is wrong", vr.isMaximumExclusive());
> -
> +
> vr = ManifestHeaderProcessor.parseVersionRange(version8);
> assertEquals("The value is wrong", "1.2.2.5",
> vr.getMinimumVersion().toString());
> assertFalse("The value is wrong", vr.isMinimumExclusive());
> @@ -388,7 +389,7 @@ public class ManifestHeaderProcessorTest
> } catch (Exception e){
> exception = true;
> }
> -
> +
> assertTrue("The value is wrong", exception);
> boolean exceptionNull = false;
> try {
> @@ -403,15 +404,15 @@ public class ManifestHeaderProcessorTest
> assertFalse("The value is wrong", vr.isMinimumExclusive());
> assertNull("The value is wrong", vr.getMaximumVersion());
> assertFalse("The value is wrong", vr.isMaximumExclusive());
> -
> -
> +
> +
> vr = ManifestHeaderProcessor.parseVersionRange(version12);
> assertEquals("The value is wrong", "1.2.3",
> vr.getMinimumVersion().toString());
> assertFalse("The value is wrong", vr.isMinimumExclusive());
> assertEquals("The value is wrong", "4.5.6",
> vr.getMaximumVersion().toString());
> - assertFalse("The value is wrong", vr.isMaximumExclusive());
> + assertFalse("The value is wrong", vr.isMaximumExclusive());
> }
> -
> +
> @Test
> public void testInvalidVersions() throws Exception
> {
> @@ -421,7 +422,7 @@ public class ManifestHeaderProcessorTest
> } catch (IllegalArgumentException e) {
> // assertEquals(MessageUtil.getMessage("APPUTILS0009E", "a"),
> e.getMessage());
> }
> -
> +
> try {
> ManifestHeaderProcessor.parseVersionRange("[1.0.0,1.0.1]", true);
> assertTrue("Should have thrown an exception", false);
> @@ -437,18 +438,18 @@ public class ManifestHeaderProcessorTest
> List<String> result = ManifestHeaderProcessor.split(export, ",");
> assertEquals("The result is wrong.", export, result.get(0));
> assertEquals("The result is wrong.", 1, result.size());
> -
> +
> String aString =
> "com.acme.foo;weirdAttr=\"one;two;three\";weirdDir:=\"1;2;3\"";
> result = ManifestHeaderProcessor.split(aString, ";");
> assertEquals("The result is wrong.", "com.acme.foo", result.get(0));
> assertEquals("The result is wrong.", "weirdAttr=\"one;two;three\"",
> result.get(1));
> assertEquals("The result is wrong.", "weirdDir:=\"1;2;3\"",
> result.get(2));
> -
> +
> assertEquals("The result is wrong.", 3, result.size());
> -
> -
> -
> -
> +
> +
> +
> +
> String pkg1 = "com.ibm.ws.eba.example.helloIsolation;version=\"1.0.0\"
> ";
> String pkg2 =
> "com.ibm.ws.eba.helloWorldService;version=\"[1.0.0,1.0.0]\"";
> String pkg3 = " com.ibm.ws.eba.helloWorldService;version=\"1.0.0\"";
> @@ -459,47 +460,47 @@ public class ManifestHeaderProcessorTest
> String appContent3 = pkg1 + ", " + pkg3 + ", " + pkg2;
> String appContent4 = pkg1 + ", " + pkg3 + ", " + pkg4;
> String appContent5 = pkg1 + ", " + pkg3 + ", " + pkg5;
> -
> +
> List<String> splitList = ManifestHeaderProcessor.split(appContent1,
> ",");
> assertEquals(pkg1.trim(), splitList.get(0));
> assertEquals(pkg2.trim(), splitList.get(1));
> assertEquals(pkg3.trim(), splitList.get(2));
> -
> +
> splitList = ManifestHeaderProcessor.split(appContent2, ",");
> assertEquals(pkg2.trim(), splitList.get(0));
> assertEquals(pkg1.trim(), splitList.get(1));
> assertEquals(pkg3.trim(), splitList.get(2));
> -
> +
> splitList = ManifestHeaderProcessor.split(appContent3, ",");
> assertEquals(pkg1.trim(), splitList.get(0));
> assertEquals(pkg3.trim(), splitList.get(1));
> assertEquals(pkg2.trim(), splitList.get(2));
> -
> +
> splitList = ManifestHeaderProcessor.split(appContent4, ",");
> assertEquals(pkg1.trim(), splitList.get(0));
> assertEquals(pkg3.trim(), splitList.get(1));
> assertEquals(pkg4.trim(), splitList.get(2));
> -
> +
> splitList = ManifestHeaderProcessor.split(appContent5, ",");
> assertEquals(pkg1.trim(), splitList.get(0));
> assertEquals(pkg3.trim(), splitList.get(1));
> - assertEquals(pkg5.trim(), splitList.get(2));
> + assertEquals(pkg5.trim(), splitList.get(2));
> }
> -
> +
> @Test
> public void testParseFilter()
> {
> Map<String,String> attrs =
> ManifestHeaderProcessor.parseFilter("(package=com.ibm.test)");
> assertEquals("com.ibm.test", attrs.get("package"));
> -
> +
> attrs =
> ManifestHeaderProcessor.parseFilter("(&(package=com.ibm.test)(attr=value))");
> assertEquals("com.ibm.test", attrs.get("package"));
> assertEquals("value", attrs.get("attr"));
> assertEquals(2, attrs.size());
> -
> +
> attrs = ManifestHeaderProcessor.parseFilter("(&(version>=1.0.0))");
> assertEquals("1.0.0", attrs.get("version"));
> -
> +
> attrs =
> ManifestHeaderProcessor.parseFilter("(&(version>=1.0.0)(version<=2.0.0))");
> assertEquals("[1.0.0,2.0.0]", attrs.get("version"));
>
> @@ -509,9 +510,9 @@ public class ManifestHeaderProcessorTest
> attrs =
> ManifestHeaderProcessor.parseFilter("(&(!(version=2.0.0))(!(version=1.0.0))(version>=1.0.0)(version<=2.0.0))");
> assertEquals("(1.0.0,2.0.0)", attrs.get("version"));
> }
> -
> +
> @Test
> - public void testExactVersion() throws Exception
> + public void testExactVersion() throws Exception
> {
> VersionRange vr;
> try {
> @@ -520,30 +521,102 @@ public class ManifestHeaderProcessorTest
> } catch (IllegalArgumentException e) {
> // expected
> }
> -
> +
> vr = ManifestHeaderProcessor.parseVersionRange("[1.0.0, 1.0.0]", true);
> assertTrue(vr.isExactVersion());
> -
> +
> try {
> vr = ManifestHeaderProcessor.parseVersionRange("(1.0.0, 1.0.0]",
> true);
> fail("should not get here 2");
> } catch (IllegalArgumentException e) {
> // expected
> }
> -
> +
> try {
> vr = ManifestHeaderProcessor.parseVersionRange("[1.0.0, 1.0.0)",
> true);
> fail("should not get here 3");
> } catch (IllegalArgumentException e) {
> // expected
> }
> -
> +
> vr = ManifestHeaderProcessor.parseVersionRange("[1.0.0, 2.0.0]");
> assertFalse(vr.isExactVersion());
> -
> +
> vr = ManifestHeaderProcessor.parseVersionRange("[1.0.0, 1.0.0]");
> assertTrue(vr.isExactVersion());
> -
> -
> +
> +
> + }
> +
> + @Test
> + public void testCapabilityHeader() throws Exception {
> + String s =
> + "com.acme.dictionary; effective:=resolve; from:String=nl; to=de;
> version:Version=3.4.0.test;somedir:=test, " +
> + "com.acme.dictionary; filter:=\"(&(width>=1000)(height>=1000))\",
> " +
> +
> "com.acme.ip2location;country:List<String>=\"nl,be,fr,uk\";version:Version=1.3;long:Long="
> + Long.MAX_VALUE + ";d:Double=\"2.2250738585072012e-308\"";
> +
> + List<GenericMetadata> capabilities =
> ManifestHeaderProcessor.parseCapabilityString(s);
> + testCapabilitiesOrRequirements(capabilities);
> + }
> +
> + @Test
> + public void testRequirementHeader() throws Exception {
> + String s =
> + "com.acme.dictionary; effective:=resolve; from:String=nl; to=de;
> version:Version=3.4.0.test;somedir:=test, " +
> + "com.acme.dictionary; filter:=\"(&(width>=1000)(height>=1000))\",
> " +
> +
> "com.acme.ip2location;country:List<String>=\"nl,be,fr,uk\";version:Version=1.3;long:Long="
> + Long.MAX_VALUE + ";d:Double=\"2.2250738585072012e-308\"";
> +
> + List<GenericMetadata> capabilities =
> ManifestHeaderProcessor.parseRequirementString(s);
> + testCapabilitiesOrRequirements(capabilities);
> + }
> +
> + private void testCapabilitiesOrRequirements(List<GenericMetadata>
> metadata) {
> + assertEquals(3, metadata.size());
> +
> + boolean found1 = false, found2 = false, found3 = false;
> + for (GenericMetadata cap : metadata) {
> + if ("com.acme.dictionary".equals(cap.getNamespace()) &&
> cap.getDirectives().containsKey("effective")) {
> + testDictionaryCapability1(cap);
> + found1 = true;
> + } else if ("com.acme.dictionary".equals(cap.getNamespace()) &&
> cap.getDirectives().containsKey("filter")) {
> + testDictionaryCapability2(cap);
> + found2 = true;
> + } else if ("com.acme.ip2location".equals(cap.getNamespace())) {
> + testIP2LocationCapability(cap);
> + found3 = true;
> + }
> + }
> +
> + assertTrue(found1);
> + assertTrue(found2);
> + assertTrue(found3);
> + }
> +
> + private void testDictionaryCapability1(GenericMetadata cap) {
> + assertEquals(2, cap.getDirectives().size());
> + assertEquals("resolve", cap.getDirectives().get("effective"));
> + assertEquals("test", cap.getDirectives().get("somedir"));
> +
> + assertEquals(3, cap.getAttributes().size());
> + assertEquals("nl", cap.getAttributes().get("from"));
> + assertEquals("de", cap.getAttributes().get("to"));
> + assertEquals(new Version(3, 4, 0, "test"),
> cap.getAttributes().get("version"));
> + }
> +
> + private void testDictionaryCapability2(GenericMetadata cap) {
> + assertEquals(1, cap.getDirectives().size());
> + assertEquals("(&(width>=1000)(height>=1000))",
> cap.getDirectives().get("filter"));
> +
> + assertEquals(0, cap.getAttributes().size());
> + }
> +
> + private void testIP2LocationCapability(GenericMetadata cap) {
> + assertEquals(0, cap.getDirectives().size());
> + assertEquals(4, cap.getAttributes().size());
> +
> + assertEquals(new Version(1, 3, 0), cap.getAttributes().get("version"));
> + assertEquals(Arrays.asList("nl", "be", "fr", "uk"),
> cap.getAttributes().get("country"));
> + assertEquals(Long.MAX_VALUE, cap.getAttributes().get("long"));
> + assertEquals(0, new
> Double("2.2250738585072012e-308").compareTo((Double)
> cap.getAttributes().get("d")));
> }
> }
>
>