You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@aries.apache.org by Timothy Ward <ti...@apache.org> on 2011/11/25 19:36:52 UTC

RE: 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

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: commits@aries.apache.org
> From: davidb@apache.org
> 
> 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")));
>      }
>  }
> 
> 
 		 	   		  

Re: 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

Posted by David Bosschaert <da...@gmail.com>.
Should be fixed in r1209121.

David

On 1 December 2011 15:11, David Bosschaert <da...@gmail.com> wrote:
> Sorry for the late reply. I missed this response earlier on.
>
> Yes, I used the famously problematic double constant. LOL of course
> that breaks older compilers. I'll change it into something else. Sorry
> about that.
>
> Cheers,
>
> David
>
> On 1 December 2011 14:07, Timothy Ward <ti...@apache.org> wrote:
>>
>> In which case I think we should change those tests to use a different constant!
>>
>> Regards
>>
>> Tim Ward
>> -------------------
>> Apache Aries PMC member & Enterprise OSGi advocate
>> Enterprise OSGi in Action (http://www.manning.com/cummins)
>> -------------------
>>
>>
>>> From: hughesj@apache.org
>>> Date: Thu, 1 Dec 2011 13:59:31 +0000
>>> Subject: Re: 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
>>> To: dev@aries.apache.org
>>>
>>> On 25 November 2011 18:36, Timothy Ward <ti...@apache.org> wrote:
>>> >
>>> > 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...
>>>
>>> Yes. That's what it does for me (on an old level of java 6 without the fix).
>>>
>>> >
>>> > 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: commits@aries.apache.org
>>> >> From: davidb@apache.org
>>> >>
>>> >> 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")));
>>> >>      }
>>> >>  }
>>> >>
>>> >>
>>> >
>>

Re: 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

Posted by David Bosschaert <da...@gmail.com>.
Sorry for the late reply. I missed this response earlier on.

Yes, I used the famously problematic double constant. LOL of course
that breaks older compilers. I'll change it into something else. Sorry
about that.

Cheers,

David

On 1 December 2011 14:07, Timothy Ward <ti...@apache.org> wrote:
>
> In which case I think we should change those tests to use a different constant!
>
> Regards
>
> Tim Ward
> -------------------
> Apache Aries PMC member & Enterprise OSGi advocate
> Enterprise OSGi in Action (http://www.manning.com/cummins)
> -------------------
>
>
>> From: hughesj@apache.org
>> Date: Thu, 1 Dec 2011 13:59:31 +0000
>> Subject: Re: 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
>> To: dev@aries.apache.org
>>
>> On 25 November 2011 18:36, Timothy Ward <ti...@apache.org> wrote:
>> >
>> > 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...
>>
>> Yes. That's what it does for me (on an old level of java 6 without the fix).
>>
>> >
>> > 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: commits@aries.apache.org
>> >> From: davidb@apache.org
>> >>
>> >> 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")));
>> >>      }
>> >>  }
>> >>
>> >>
>> >
>

RE: 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

Posted by Timothy Ward <ti...@apache.org>.
In which case I think we should change those tests to use a different constant!

Regards

Tim Ward
-------------------
Apache Aries PMC member & Enterprise OSGi advocate
Enterprise OSGi in Action (http://www.manning.com/cummins)
-------------------


> From: hughesj@apache.org
> Date: Thu, 1 Dec 2011 13:59:31 +0000
> Subject: Re: 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
> To: dev@aries.apache.org
> 
> On 25 November 2011 18:36, Timothy Ward <ti...@apache.org> wrote:
> >
> > 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...
> 
> Yes. That's what it does for me (on an old level of java 6 without the fix).
> 
> >
> > 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: commits@aries.apache.org
> >> From: davidb@apache.org
> >>
> >> 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")));
> >>      }
> >>  }
> >>
> >>
> >
 		 	   		  

Re: 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

Posted by Jeremy Hughes <hu...@apache.org>.
On 25 November 2011 18:36, Timothy Ward <ti...@apache.org> wrote:
>
> 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...

Yes. That's what it does for me (on an old level of java 6 without the fix).

>
> 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: commits@aries.apache.org
>> From: davidb@apache.org
>>
>> 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")));
>>      }
>>  }
>>
>>
>