You are viewing a plain text version of this content. The canonical link for it is here.
Posted to woden-dev@ws.apache.org by jk...@apache.org on 2007/01/07 05:56:09 UTC

svn commit: r493645 - in /incubator/woden/trunk/java: src/org/apache/woden/wsdl20/extensions/http/HTTPLocation.java test/org/apache/woden/wsdl20/extensions/http/HTTPLocationTest.java

Author: jkaputin
Date: Sat Jan  6 20:56:08 2007
New Revision: 493645

URL: http://svn.apache.org/viewvc?view=rev&rev=493645
Log:
WODEN-86 finished implementing behaviour of this class
including methods to substitute values for local
names and query the values. Added unit tests.

Modified:
    incubator/woden/trunk/java/src/org/apache/woden/wsdl20/extensions/http/HTTPLocation.java
    incubator/woden/trunk/java/test/org/apache/woden/wsdl20/extensions/http/HTTPLocationTest.java

Modified: incubator/woden/trunk/java/src/org/apache/woden/wsdl20/extensions/http/HTTPLocation.java
URL: http://svn.apache.org/viewvc/incubator/woden/trunk/java/src/org/apache/woden/wsdl20/extensions/http/HTTPLocation.java?view=diff&rev=493645&r1=493644&r2=493645
==============================================================================
--- incubator/woden/trunk/java/src/org/apache/woden/wsdl20/extensions/http/HTTPLocation.java (original)
+++ incubator/woden/trunk/java/src/org/apache/woden/wsdl20/extensions/http/HTTPLocation.java Sat Jan  6 20:56:08 2007
@@ -53,15 +53,19 @@
  * The specification of the WSDL 2.0 HTTP Binding extensions does not explicitly state how to
  * interpret extraneous, unmatched curly braces, so this class adopts the following strategy:
  * <p>
- * If multiple left braces precede a right brace, pair the right most one with the right brace
- * and treat the others as unmatched left braces.
+ * If multiple single left braces precede a right brace, pair the right most one with the right 
+ * brace and treat the others as unmatched left braces.
  * <pre>
- *   e.g. "{ { {..}" 
+ *   e.g. "{..{..{xxxx}" 
  * </pre>
- * If multiple right braces follow a left brace, pair the left most one with the left brace
- * and treat the others as unmatched right braces.
+ * If multiple single right braces follow a left brace, pair the left most one with the left 
+ * brace and treat the others as unmatched right braces.
  * <pre>
- *   e.g. "{..} } }" 
+ *   e.g. "{xxxx}..}..}" 
+ * </pre>
+ * Double left or right braces take precedence over potentially matching pairs of single braces.
+ * <pre>
+ *   e.g. "{xxxx}}}" is evaluated as {xxxx,}},} not as {xxxx},}} 
  * </pre>
  * 
  * @author John Kaputin (jkaputin@apache.org)
@@ -75,6 +79,7 @@
     private List fValidatedList = new Vector(); //identifies syntax errors in the template
     private List fParsedList = new Vector();    //working list for value substitution
     
+    private final String emptyString = "".intern();
     private final String leftBrace = "{".intern();
     private final String rightBrace = "}".intern();
     private final String doubleLeftBraces = "{{".intern();
@@ -96,15 +101,18 @@
     public HTTPLocation(String location) {
         fLocationTemplate = location;
         
-        if(fLocationTemplate != null) {
+        if(location == null) {
+            //TODO throw NPE with suitable error message
+            fValid = false;
+        } else if(location.equals(emptyString)) {
+            fValidatedList.add(emptyString);
+            fParsedList.add(emptyString);
+        } else {
             List tokenizedList = tokenizeTemplate();
             validateTemplate(tokenizedList);
             if(fValidatedList.size() > 0) {
                 parseTemplate();
             }
-        } else {
-            //TODO decide whether to throw NPE or simply flag location template as invalid
-            fValid = false;
         }
     }
     
@@ -178,7 +186,23 @@
      * @return a String array containing all element local names from the template
      */
     public String[] getLocalNames() {
-        return null; //TODO implement this method
+        
+        List names = new Vector();
+        Object next;
+        String[] elem;
+        
+        Iterator it = fParsedList.iterator();
+        while(it.hasNext()) {
+            next = it.next();
+            if(next instanceof String[]) {
+                elem = (String[]) next;
+                names.add(elem[0]);
+            }
+        }
+        
+        String[] array = new String[names.size()];
+        names.toArray(array);
+        return array;
     }
     
     /**
@@ -190,7 +214,26 @@
      * @return a String array containing the distinct element local names from the template
      */
     public String[] getDistinctLocalNames() {
-        return null; //TODO implement this method
+        
+        List names = new Vector();
+        Object next;
+        String[] elem;
+        
+        Iterator it = fParsedList.iterator();
+        while(it.hasNext()) {
+            next = it.next();
+            if(next instanceof String[]) {
+                elem = (String[]) next;
+                String name = elem[0];
+                if(!names.contains(name)) {
+                    names.add(name);
+                }
+            }
+        }
+        
+        String[] array = new String[names.size()];
+        names.toArray(array);
+        return array;
     }
     
     /**
@@ -200,7 +243,19 @@
      * @return the number of occurrences of <code>localName</code>
      */
     public int countLocalNames() {
-        return 0; //TODO implement this method
+        
+        Object next;
+        int count = 0;
+        
+        Iterator it = fParsedList.iterator();
+        while(it.hasNext()) {
+            next = it.next();
+            if(next instanceof String[]) {
+                count++;
+            }
+        }
+        
+        return count;
     }
     
     /**
@@ -212,7 +267,25 @@
      * @return the number of occurrences of <code>localName</code>
      */
     public int countOccurrences(String localName) {
-        return 0; //TODO implement this method
+        
+        int count = 0;
+        Object next;
+        String[] elem;
+        
+        if(localName != null) {
+            Iterator it = fParsedList.iterator();
+            while(it.hasNext()) {
+                next = it.next();
+                if(next instanceof String[]) {
+                    elem = (String[]) next;
+                    if (elem[0].equals(localName)) {
+                        count++;
+                    }
+                }
+            }
+        }
+        
+        return count;
     }
     
     //TODO public void substitute(String localName, int occurrence, String value) {}, required?
@@ -221,7 +294,7 @@
      * Substitute the specified element local name and its enclosing curly braces within the
      * location template with the specified String value of that element. 
      * Note, this method assumes a single occurrence only of the specified local name, so if 
-     * the the local name appears multiple times in the template only the first occurrence 
+     * if the local name appears multiple times in the template only the first occurrence 
      * will be substituted. It does not handle multiple substitution.
      * 
      * @param localName the local name of an element from the instance data of the message
@@ -229,8 +302,7 @@
      */
     public void substitute(String localName, String value) {
         
-        fDerivedLocation = null;
-        
+        substitute(localName, value, false);
     }
     
     /**
@@ -251,7 +323,27 @@
      */
     public void substitute(String localName, String value, boolean allOccurrences) {
         
-        fDerivedLocation = null;
+        if(localName == null) {
+            //TODO throw NPE?
+            return;
+        }
+        fDerivedLocation = null; //flush the cached value
+        
+        Object next;
+        String[] elem;
+        Iterator it = fParsedList.iterator();
+        while(it.hasNext()) {
+            next = it.next();
+            if(next instanceof String[]) {
+                elem = (String[])next;
+                if(elem[0].equals(localName)) {
+                    elem[1] = value;
+                    if(!allOccurrences) {
+                        break;
+                    }
+                }
+            }
+        }
         
     }
 
@@ -274,7 +366,26 @@
      */
     public void substitute(String localName, String[] values) {
         
-        fDerivedLocation = null;
+        if(localName == null || values == null) {
+            //TODO throw NPE?
+            return;
+        }
+        fDerivedLocation = null; //flush the cached value
+        
+        Object next;
+        String[] elem;
+        int i = 0;
+        Iterator it = fParsedList.iterator();
+        while(it.hasNext() && i<values.length) {
+            next = it.next();
+            if(next instanceof String[]) {
+                elem = (String[])next;
+                if(elem[0].equals(localName)) {
+                    elem[1] = values[i];
+                    i++;
+                }
+            }
+        }
 
     }
     
@@ -294,8 +405,25 @@
      */
     public void substitute(String[] values) {
         
-        fDerivedLocation = null;
+        if(values == null) {
+            //TODO throw NPE?
+            return;
+        }
+        fDerivedLocation = null; //flush the cached value
 
+        Object next;
+        String[] elem;
+        int i = 0;
+        Iterator it = fParsedList.iterator();
+        while(it.hasNext() && i<values.length) {
+            next = it.next();
+            if(next instanceof String[]) {
+                elem = (String[])next;
+                elem[1] = values[i];
+                i++;
+            }
+        }
+        
     }
 
     /**
@@ -314,7 +442,26 @@
      * @return the String value associated with <code>localName</code>
      */
     public String getValue(String localName) {
-        return null; //TODO implement this method
+        
+        Object next;
+        String[] elem;
+        String value = null;
+      
+        if(localName != null) {
+            Iterator it = fParsedList.iterator();
+            while (it.hasNext()) {
+                next = it.next();
+                if (next instanceof String[]) {
+                    elem = (String[]) next;
+                    if (elem[0].equals(localName)) {
+                        value = elem[1];
+                        break;
+                    }
+                }
+            }
+        }
+        
+        return value;
     }
     
     /**
@@ -330,7 +477,27 @@
      * @return an array of String values associated with occurrences of <code>localName</code>
      */
     public String[] getValues(String localName) {
-        return null; //TODO implement this method
+        
+        List values = new Vector();
+        Object next;
+        String[] elem;
+        
+        if(localName != null) {
+            Iterator it = fParsedList.iterator();
+            while (it.hasNext()) {
+                next = it.next();
+                if (next instanceof String[]) {
+                    elem = (String[]) next;
+                    if (elem[0].equals(localName)) {
+                        values.add(elem[1]);
+                    }
+                }
+            }
+        }
+        
+        String[] array = new String[values.size()];
+        values.toArray(array);
+        return array;
     }
     
     /**
@@ -344,7 +511,23 @@
      * @return an array of String values associated with element local names within the template
      */
     public String[] getValues() {
-        return null; //TODO implement this method
+        
+        List values = new Vector();
+        Object next;
+        String[] elem;
+        
+        Iterator it = fParsedList.iterator();
+        while (it.hasNext()) {
+            next = it.next();
+            if (next instanceof String[]) {
+                elem = (String[]) next;
+                values.add(elem[1]);
+            }
+        }
+        
+        String[] array = new String[values.size()];
+        values.toArray(array);
+        return array;
     }
     
     /**
@@ -365,12 +548,14 @@
         }
         
         StringBuffer buffer = new StringBuffer();
+        Object currToken;
+        String[] nameValue;
         Iterator it = fParsedList.iterator();
         
         while(it.hasNext()) {
-            Object currToken = it.next();
+            currToken = it.next();
             if(currToken instanceof String[]) {
-                String[] nameValue = (String[])currToken;
+                nameValue = (String[])currToken;
                 if(nameValue[1] == null) {
                     //no value substitution, so append the original curly brace-enclosed string
                     buffer.append(leftBrace);
@@ -467,26 +652,24 @@
      */
     private void validateTemplate(List tokenizedList) {
         
-        if(tokenizedList.size() == 0) {
-            fValid = false;
-            return;
-        }
-        
         boolean valid = true;
         List tokens = new Vector();
+        Object currToken;
+        String nextToken;
+        Object nextNextToken;
         int size = tokenizedList.size();
         ListIterator it = tokenizedList.listIterator();
         
         while(it.hasNext()) {
-            Object currToken = it.next();
+            currToken = it.next();
             int currIndex = it.previousIndex();
             if(currToken == leftBrace) {
                 if(size-currIndex < 3) {
                     valid = false; //left brace not followed by a name and a right brace
                     tokens.add(leftBrace);
                 } else {
-                    String nextToken = (String)tokenizedList.get(currIndex+1);
-                    Object nextNextToken = tokenizedList.get(currIndex+2);
+                    nextToken = (String)tokenizedList.get(currIndex+1);
+                    nextNextToken = tokenizedList.get(currIndex+2);
                     if(!curlyBraces.contains(nextToken) && nextNextToken == rightBrace) {
                         //we have a string enclosed by a pair of left and right curly braces
                         if(NCName.isValid(nextToken)) {
@@ -535,11 +718,12 @@
     private void parseTemplate() {
         
         StringBuffer buffer = new StringBuffer();
+        Object currToken;
         List tokens = new Vector();
         Iterator it = fValidatedList.iterator();
         
         while(it.hasNext()) {
-            Object currToken = it.next();
+            currToken = it.next();
             if(currToken instanceof String[]) {
                 //This is a templated local name, so output any previously concatentated
                 //string content then output this string array.

Modified: incubator/woden/trunk/java/test/org/apache/woden/wsdl20/extensions/http/HTTPLocationTest.java
URL: http://svn.apache.org/viewvc/incubator/woden/trunk/java/test/org/apache/woden/wsdl20/extensions/http/HTTPLocationTest.java?view=diff&rev=493645&r1=493644&r2=493645
==============================================================================
--- incubator/woden/trunk/java/test/org/apache/woden/wsdl20/extensions/http/HTTPLocationTest.java (original)
+++ incubator/woden/trunk/java/test/org/apache/woden/wsdl20/extensions/http/HTTPLocationTest.java Sat Jan  6 20:56:08 2007
@@ -28,11 +28,6 @@
  */
 public class HTTPLocationTest extends TestCase 
 {
-    private String httpLoc0 = "?op=Cancel";
-    private String httpLoc1 = "/temperature/{town}";
-    private String httpLoc2 = "?op=Quote;key={symbol};amt={amount}";
-    private String httpLoc3 = "?first={FirstName};middle={MiddleName};last={LastName}";
-    
     public static Test suite()
     {
         return new TestSuite(HTTPLocationTest.class);
@@ -54,82 +49,581 @@
         super.tearDown();
     }
     
-    public void test1ArgCtor() throws Exception
+    public void testCtor() throws Exception
     {
-        HTTPLocation loc = new HTTPLocation(httpLoc1);
+        HTTPLocation loc;
+        
+        //empty string
+        loc = new HTTPLocation("");
+        assertNotNull(loc);
+        
+        //no curly braces
+        loc = new HTTPLocation("/temperature/");
+        assertNotNull(loc);
+        
+        //one local name
+        loc = new HTTPLocation("/temperature/{town}/");
+        assertNotNull(loc);
+        
+        //multiple local names
+        loc = new HTTPLocation("/temperature/{town}/{state}/{country}");
+        assertNotNull(loc);
+        
+        //with double curly braces
+        loc = new HTTPLocation("{{XXX}}/temperature/{town}/{{{state}}}/{country}");
+        assertNotNull(loc);
+        
+        //invalid template
+        loc = new HTTPLocation("{{XXX}}/te}mp}erature/{town}/{state}/{coun{try}");
         assertNotNull(loc);
         
     }
     
-    public void testGetHttpLocationTemplate() throws Exception
+    public void testGetLocationTemplate() throws Exception
     {
-        HTTPLocation loc = new HTTPLocation(httpLoc1);
-        assertEquals(httpLoc1, loc.getLocationTemplate());
+        HTTPLocation loc;
+        
+        //after ctor
+        loc = new HTTPLocation("/temperature/{town}");
+        assertEquals("/temperature/{town}", loc.getLocationTemplate());
+        
+        //after substitution ... template still has its original value
+        loc = new HTTPLocation("/temperature/{town}");
+        loc.substitute("town","London");
+        assertEquals("/temperature/{town}", loc.getLocationTemplate());
+        
+        
     }
     
     public void testIsTemplateValid() throws Exception
     {
+        HTTPLocation loc;
+        boolean result;
         
-        HTTPLocation loc = new HTTPLocation(httpLoc0);
-        boolean result = loc.isTemplateValid();
+        //empty string
+        loc = new HTTPLocation("");
+        result = loc.isTemplateValid();
         assertTrue(result);
         
-        loc = new HTTPLocation(httpLoc1);
+        //no curly braces
+        loc = new HTTPLocation("/temperature/");
         result = loc.isTemplateValid();
         assertTrue(result);
         
-        loc = new HTTPLocation(httpLoc2);
+        //one local name
+        loc = new HTTPLocation("/temperature/{town}/");
         result = loc.isTemplateValid();
         assertTrue(result);
         
-        loc = new HTTPLocation(httpLoc3);
+        //multiple local names
+        loc = new HTTPLocation("/temperature/{town}/{state}/{country}");
         result = loc.isTemplateValid();
         assertTrue(result);
         
-        loc = new HTTPLocation("/foo/{bar{"); //unmatched left brace
+        //with double curly braces
+        loc = new HTTPLocation("{{XXX}}/temperature/{town}/}}{state}{{/{country};Tic{{Tac{{Toe");
+        result = loc.isTemplateValid();
+        assertTrue(result);
+
+        //invalid .. unmatched left braces
+        
+        loc = new HTTPLocation("/foo/{bar{");
         result = loc.isTemplateValid();
         assertFalse(result);
         
-        loc = new HTTPLocation("/foo/{bar"); //unmatched left brace
+        loc = new HTTPLocation("/foo/{bar");
         result = loc.isTemplateValid();
         assertFalse(result);
         
-        loc = new HTTPLocation("/foo/bar{"); //unmatched left brace
+        loc = new HTTPLocation("/foo/bar{");
         result = loc.isTemplateValid();
         assertFalse(result);
         
-        loc = new HTTPLocation("/foo/}bar}"); //unmatched right brace
+        loc = new HTTPLocation("/f{oo/{bar}");
         result = loc.isTemplateValid();
         assertFalse(result);
         
-        loc = new HTTPLocation("/foo/}bar"); //unmatched right brace
+        loc = new HTTPLocation("{/f{oo/{bar}");
         result = loc.isTemplateValid();
         assertFalse(result);
         
-        loc = new HTTPLocation("/foo/bar}"); //unmatched right brace
+        loc = new HTTPLocation("/foo/{bar}/man{");
         result = loc.isTemplateValid();
         assertFalse(result);
         
-        loc = new HTTPLocation("/foo/{b{ar}"); //unmatched left brace
+        /* One might expect the template "{{{state}}}" to be parsed as {{,{state},}} where inner 
+         * most braces are matched as a pair enclosing the string "state", but in the 
+         * Woden implementation the double curly braces take precedence so it is parsed as 
+         * {{,{,state,}},} which flags the template as invalid. The WSDL 2.0 spec is silent on the 
+         * precedence of double curly braces over pairs of matching single braces.
+         */
+        loc = new HTTPLocation("{{{state}}}");
         result = loc.isTemplateValid();
         assertFalse(result);
+
+        //invalid .. unmatched right braces
         
-        loc = new HTTPLocation("/foo/{ba}r}"); //unmatched left brace
+        loc = new HTTPLocation("/foo/}bar}");
         result = loc.isTemplateValid();
         assertFalse(result);
         
-        loc = new HTTPLocation("/foo/{bar}"); //valid local name
+        loc = new HTTPLocation("/foo/}bar");
         result = loc.isTemplateValid();
-        assertTrue(result);
+        assertFalse(result);
+        
+        loc = new HTTPLocation("/foo/bar}");
+        result = loc.isTemplateValid();
+        assertFalse(result);
+        
+        loc = new HTTPLocation("/f}oo/{bar}");
+        result = loc.isTemplateValid();
+        assertFalse(result);
+        
+        loc = new HTTPLocation("}/f}oo/{bar}");
+        result = loc.isTemplateValid();
+        assertFalse(result);
+        
+        loc = new HTTPLocation("/foo/{bar}/man}");
+        result = loc.isTemplateValid();
+        assertFalse(result);
         
-        loc = new HTTPLocation("/foo/{ba:r}"); //invalid local name
+        /* ditto the previous comment about double curly braces taking precedence over a 
+         * potentially matching pair of single curly braces. The template "{state}}}" is
+         * parsed as {,state,}},} not as {state},}}.
+         * 
+         */
+        loc = new HTTPLocation("{state}}}");
         result = loc.isTemplateValid();
         assertFalse(result);
+
+        //invalid local name ... not of type xs:NCName
+        
+        loc = new HTTPLocation("/foo/{bar:man}");
+        result = loc.isTemplateValid();
+        assertFalse(result);
+    }
+    
+    public void testGetLocalNames() {
+        HTTPLocation loc;
+        String[] actual;
+        String[] expected;
+        boolean result;
+        
+        loc = new HTTPLocation("?op=EchoInt");
+        actual = loc.getLocalNames();
+        expected = new String[] {};
+        result = arraysEqual(expected,actual);
+        assertTrue(result);
+        
+        loc = new HTTPLocation("?op=EchoInt;first={fname}");
+        actual = loc.getLocalNames();
+        expected = new String[] {"fname"};
+        result = arraysEqual(expected,actual);
+        assertTrue(result);
+        
+        loc = new HTTPLocation("?op=EchoInt;first={fname};middle={mname};last={lname}");
+        actual = loc.getLocalNames();
+        expected = new String[] {"fname","mname","lname"};
+        result = arraysEqual(expected,actual);
+        assertTrue(result);
+        
+    }
+    
+    public void testGetDistinctLocalNames() {
+        HTTPLocation loc;
+        String[] actual;
+        String[] expected;
+        boolean result;
+        
+        loc = new HTTPLocation("?op=EchoInt");
+        actual = loc.getDistinctLocalNames();
+        expected = new String[] {};
+        result = arraysEqual(expected,actual);
+        assertTrue(result);
+        
+        loc = new HTTPLocation("?op=EchoInt;first={fname}");
+        actual = loc.getDistinctLocalNames();
+        expected = new String[] {"fname"};
+        result = arraysEqual(expected,actual);
+        assertTrue(result);
+        
+        loc = new HTTPLocation("?op=EchoInt;first={fname};middle={mname};last={lname}");
+        actual = loc.getDistinctLocalNames();
+        expected = new String[] {"fname","mname","lname"};
+        result = arraysEqual(expected,actual);
+        assertTrue(result);
+        
+        loc = new HTTPLocation("?op=EchoInt;first={fname};middle={fname};last={lname}");
+        actual = loc.getDistinctLocalNames();
+        expected = new String[] {"fname","lname"};
+        result = arraysEqual(expected,actual);
+        assertTrue(result);
+        
+        loc = new HTTPLocation("?op=EchoInt;first={fname};middle={mname};last={fname}");
+        actual = loc.getDistinctLocalNames();
+        expected = new String[] {"fname","mname"};
+        result = arraysEqual(expected,actual);
+        assertTrue(result);
+        
+        loc = new HTTPLocation("?op=EchoInt;first={fname};middle={fname};last={fname}");
+        actual = loc.getDistinctLocalNames();
+        expected = new String[] {"fname"};
+        result = arraysEqual(expected,actual);
+        assertTrue(result);
+        
+    }
+
+    
+    public void testCountLocalNames() {
+        HTTPLocation loc;
+        int count;
+        
+        loc = new HTTPLocation("?op=EchoInt");
+        count = loc.countLocalNames();
+        assertEquals(0,count);
+        
+        loc = new HTTPLocation("?op=EchoInt;first={fname}");
+        count = loc.countLocalNames();
+        assertEquals(1,count);
+        
+        loc = new HTTPLocation("?op=EchoInt;first={fname};middle={mname};last={lname}");
+        count = loc.countLocalNames();
+        assertEquals(3,count);
+        
+        loc = new HTTPLocation("?op=EchoInt;first={fname};middle={mname};last={fname}");
+        count = loc.countLocalNames();
+        assertEquals(3,count);
+        
+    }
+    
+    public void testCountOccurrences() {
+        HTTPLocation loc;
+        int count;
+        String localName = "fname";
+        
+        loc = new HTTPLocation("?op=EchoInt");
+        count = loc.countOccurrences(localName);
+        assertEquals(0,count);
+        
+        loc = new HTTPLocation("?op=EchoInt;first={fname}");
+        count = loc.countOccurrences(localName);
+        assertEquals(1,count);
+        
+        loc = new HTTPLocation("?op=EchoInt;first={fname};middle={mname};last={lname}");
+        count = loc.countOccurrences(localName);
+        assertEquals(1,count);
+        
+        loc = new HTTPLocation("?op=EchoInt;first={fname};middle={mname};last={fname}");
+        count = loc.countOccurrences(localName);
+        assertEquals(2,count);
+        
+        loc = new HTTPLocation("?op=EchoInt;first={fname};middle={fname};last={fname}");
+        count = loc.countOccurrences(localName);
+        assertEquals(3,count);
+        
+        loc = new HTTPLocation("?op=EchoInt;first={lname};middle={lname};last={lname}");
+        count = loc.countOccurrences(localName);
+        assertEquals(0,count);
+        
+    }
+    
+    public void testSubstitute_StringString() {
+        HTTPLocation loc;
+        String actual;
+        
+        loc = new HTTPLocation("?op=EchoInt");
+        loc.substitute("fname", "Dougal"); //no effect
+        actual = loc.toString();
+        assertEquals("?op=EchoInt", actual);
+
+        loc = new HTTPLocation("?op=EchoInt;first={fname}");
+        loc.substitute("fname", "Dougal");
+        actual = loc.toString();
+        assertEquals("?op=EchoInt;first=Dougal", actual);
+
+        loc = new HTTPLocation("?op=EchoInt;first={fname};middle={mname};last={lname}");
+        loc.substitute("fname", "Dougal");
+        loc.substitute("lname", "Smith");
+        actual = loc.toString();
+        assertEquals("?op=EchoInt;first=Dougal;middle={mname};last=Smith", actual);
+
+        loc = new HTTPLocation("?op=EchoInt;first={fname};middle={mname};last={mname}");
+        loc.substitute("mname", "Dougal");
+        actual = loc.toString();
+        assertEquals("?op=EchoInt;first={fname};middle=Dougal;last={mname}", actual);
+
+    }
+    
+    public void testSubstitute_StringStringBoolean() {
+        HTTPLocation loc;
+        String actual;
+        
+        loc = new HTTPLocation("?op=EchoInt");
+        loc.substitute("fname", "Dougal", false); //no effect
+        actual = loc.toString();
+        assertEquals("?op=EchoInt", actual);
+
+        loc = new HTTPLocation("?op=EchoInt;first={fname}");
+        loc.substitute("fname", "Dougal", false);
+        actual = loc.toString();
+        assertEquals("?op=EchoInt;first=Dougal", actual);
+
+        loc = new HTTPLocation("?op=EchoInt;first={fname}");
+        loc.substitute("fname", "Dougal", true);
+        actual = loc.toString();
+        assertEquals("?op=EchoInt;first=Dougal", actual);
+
+        loc = new HTTPLocation("?op=EchoInt;first={fname};middle={mname};last={lname}");
+        loc.substitute("mname", "Dougal", true);
+        actual = loc.toString();
+        assertEquals("?op=EchoInt;first={fname};middle=Dougal;last={lname}", actual);
+
+        loc = new HTTPLocation("?op=EchoInt;first={fname};middle={mname};last={mname}");
+        loc.substitute("mname", "Dougal", false);
+        actual = loc.toString();
+        assertEquals("?op=EchoInt;first={fname};middle=Dougal;last={mname}", actual);
+
+        loc = new HTTPLocation("?op=EchoInt;first={fname};middle={mname};last={mname}");
+        loc.substitute("mname", "Dougal", true);
+        actual = loc.toString();
+        assertEquals("?op=EchoInt;first={fname};middle=Dougal;last=Dougal", actual);
+
+        loc = new HTTPLocation("?op=EchoInt;first={fname};middle={mname};last={lname}");
+        loc.substitute(null, "Dougal", true); //arg1 null so ignored
+        actual = loc.toString();
+        assertEquals("?op=EchoInt;first={fname};middle={mname};last={lname}", actual);
+
+        loc = new HTTPLocation("?op=EchoInt;first={fname};middle={mname};last={mname}");
+        loc.substitute("mname", "Dougal", true);
+        loc.substitute("mname", null, false); //1st value 'Dougal' removed
+        actual = loc.toString();
+        assertEquals("?op=EchoInt;first={fname};middle={mname};last=Dougal", actual);
+
+        loc = new HTTPLocation("?op=EchoInt;first={fname};middle={mname};last={mname}");
+        loc.substitute("mname", "Dougal", true);
+        loc.substitute("mname", null, true); //both values 'Dougal' removed
+        actual = loc.toString();
+        assertEquals("?op=EchoInt;first={fname};middle={mname};last={mname}", actual);
+
+    }
+
+    public void testSubstitute_StringStringArray() {
+        HTTPLocation loc;
+        String actual;
+        
+        loc = new HTTPLocation("?op=EchoInt");
+        loc.substitute("fname", new String[] {"Dougal"}); //no effect
+        actual = loc.toString();
+        assertEquals("?op=EchoInt", actual);
+
+        loc = new HTTPLocation("?op=EchoInt;first={fname}");
+        loc.substitute("fname", new String[] {"Dougal"}); //1 to 1
+        actual = loc.toString();
+        assertEquals("?op=EchoInt;first=Dougal", actual);
+
+        loc = new HTTPLocation("?op=EchoInt;first={fname};middle={mname};last={lname}");
+        loc.substitute("fname", new String[] {"Dougal","Malcolm"});  //array > template
+        actual = loc.toString();
+        assertEquals("?op=EchoInt;first=Dougal;middle={mname};last={lname}", actual);
+
+        loc = new HTTPLocation("?op=EchoInt;first={fname};middle={fname};last={lname}");
+        loc.substitute("fname", new String[] {"Dougal","Malcolm"});  //array = template
+        actual = loc.toString();
+        assertEquals("?op=EchoInt;first=Dougal;middle=Malcolm;last={lname}", actual);
+
+        loc = new HTTPLocation("?op=EchoInt;first={fname};middle={fname};last={fname}");
+        loc.substitute("fname", new String[] {"Dougal","Malcolm"});  //array < template
+        actual = loc.toString();
+        assertEquals("?op=EchoInt;first=Dougal;middle=Malcolm;last={fname}", actual);
+
+        loc = new HTTPLocation("?op=EchoInt;first={fname};middle={fname};last={fname}");
+        loc.substitute("fname", new String[] {"Dougal","Malcolm","MacDonald","McDouglas"});  //array > template
+        actual = loc.toString();
+        assertEquals("?op=EchoInt;first=Dougal;middle=Malcolm;last=MacDonald", actual);
+
+    }
+    
+    public void testSubstitute_StringArray() {
+        HTTPLocation loc;
+        String actual;
+        
+        loc = new HTTPLocation("?op=EchoInt");
+        loc.substitute(new String[] {"Dougal"}); //no effect
+        actual = loc.toString();
+        assertEquals("?op=EchoInt", actual);
+
+        loc = new HTTPLocation("?op=EchoInt;first={fname}");
+        loc.substitute(new String[] {"Dougal"}); //1 to 1
+        actual = loc.toString();
+        assertEquals("?op=EchoInt;first=Dougal", actual);
+
+        loc = new HTTPLocation("?op=EchoInt;first={fname};middle={mname};last={lname}");
+        loc.substitute(new String[] {"Dougal","Malcolm"});  //array < template
+        actual = loc.toString();
+        assertEquals("?op=EchoInt;first=Dougal;middle=Malcolm;last={lname}", actual);
+
+        loc = new HTTPLocation("?op=EchoInt;first={fname};middle={mname};last={lname}");
+        loc.substitute(new String[] {"Dougal","Malcolm","MacDonald"});  //array = template
+        actual = loc.toString();
+        assertEquals("?op=EchoInt;first=Dougal;middle=Malcolm;last=MacDonald", actual);
+
+        loc = new HTTPLocation("?op=EchoInt;first={fname};middle={mname};last={lname}");
+        loc.substitute(new String[] {"Dougal","Malcolm","MacDonald","McDouglas"});  //array > template
+        actual = loc.toString();
+        assertEquals("?op=EchoInt;first=Dougal;middle=Malcolm;last=MacDonald", actual);
+
+    }
+    
+    public void testGetValue_String() {
+        HTTPLocation loc;
+        String actual;
+        
+        loc = new HTTPLocation("?op=EchoInt");
+        actual = loc.getValue("fname"); //no effect
+        assertNull(actual);
+
+        loc = new HTTPLocation("?op=EchoInt;first={fname}");
+        actual = loc.getValue("fname");
+        assertNull(actual);
+        loc.substitute(new String[] {"Dougal"});
+        actual = loc.getValue("fname");
+        assertEquals("Dougal",actual);
+        
+        loc = new HTTPLocation("?op=EchoInt;first={fname};middle={mname};last={mname}");
+        loc.substitute(new String[] {"Dougal","Malcolm","MacDonald"});
+        actual = loc.getValue("mname");
+        assertEquals("Malcolm",actual);
+        
+    }
+    
+    public void testGetValues_String() {
+        HTTPLocation loc;
+        String[] actual;
+        String[] expected;
+        boolean result;
+        
+        loc = new HTTPLocation("?op=EchoInt");
+        actual = loc.getValues("fname"); //no effect
+        expected = new String[] {};
+        result = arraysEqual(expected,actual);
+        assertTrue(result);
+
+        loc = new HTTPLocation("?op=EchoInt;first={fname}");
+        actual = loc.getValues("fname");
+        expected = new String[] {(String)null};
+        result = arraysEqual(expected,actual);
+        assertTrue(result);
+
+        loc = new HTTPLocation("?op=EchoInt;first={fname}");
+        actual = loc.getValues("mname");
+        expected = new String[] {};
+        result = arraysEqual(expected,actual);
+        assertTrue(result);
+
+        loc = new HTTPLocation("?op=EchoInt;first={fname}");
+        loc.substitute("fname", "Dougal");
+        actual = loc.getValues("fname");
+        expected = new String[] {"Dougal"};
+        result = arraysEqual(expected,actual);
+        assertTrue(result);
+
+        loc = new HTTPLocation("?op=EchoInt;first={fname};middle={fname};last={mname}");
+        loc.substitute("fname", new String[] {"Dougal","Malcolm"});
+        actual = loc.getValues("fname");
+        expected = new String[] {"Dougal","Malcolm"};
+        result = arraysEqual(expected,actual);
+        assertTrue(result);
+
+    }
+    
+    public void testGetValues() {
+        HTTPLocation loc;
+        String[] actual;
+        String[] expected;
+        boolean result;
+        
+        loc = new HTTPLocation("?op=EchoInt");
+        actual = loc.getValues(); //no effect
+        expected = new String[] {};
+        result = arraysEqual(expected,actual);
+        assertTrue(result);
+
+        loc = new HTTPLocation("?op=EchoInt;first={fname}");
+        actual = loc.getValues();
+        expected = new String[] {(String)null};
+        result = arraysEqual(expected,actual);
+        assertTrue(result);
+
+        loc = new HTTPLocation("?op=EchoInt;first={fname}");
+        loc.substitute("fname", "Dougal");
+        actual = loc.getValues();
+        expected = new String[] {"Dougal"};
+        result = arraysEqual(expected,actual);
+        assertTrue(result);
+
+        loc = new HTTPLocation("?op=EchoInt;first={fname};middle={mname};last={fname}");
+        loc.substitute("fname", new String[] {"Dougal","Malcolm"});
+        actual = loc.getValues();
+        expected = new String[] {"Dougal",null,"Malcolm"};
+        result = arraysEqual(expected,actual);
+        assertTrue(result);
         
     }
     
-    public void testGetHttpLocationSubstituted() throws Exception
+    public void testToString() {
+        
+        //toString() has been significantly tested by the testSubstituteXXX methods
+        
+        HTTPLocation loc;
+        String actual;
+        
+        loc = new HTTPLocation("?op={{EchoInt}};f}{irst{{}}={fname};middle}={mname};last{={lname};{{");
+        loc.substitute(new String[] {"Dougal","Malcolm","MacDonald","McDouglas"});  //array > template
+        actual = loc.toString();
+        assertEquals("?op={EchoInt};f}{irst{}=Dougal;middle}=Malcolm;last{=MacDonald;{", actual);
+        
+    }
+    
+    private boolean arraysEqual(String[] a1, String[] a2) {
+        boolean result = true;
+        Object o1, o2;
+        
+        if(a1.length != a2.length) {
+            result = false;
+        } else {
+            for(int i=0; i<a1.length; i++) {
+                o1 = a1[i];
+                o2 = a2[i];
+                if(o1 == null && o2 == null) {
+                    continue;
+                }
+                if(o1 == null || o2 == null) {
+                    result = false;
+                    break;
+                }
+                if(!a1[i].equals(a2[i])) {
+                    result = false;
+                    break;
+                }
+            }
+        }
+        
+        return result;
+    }
+    
+    
+    
+    
+    
+    //TODO remove this test method when the getLocationSubtituted method is removed.
+    public void testGetLocationSubstituted() throws Exception
     {
+        String httpLoc0 = "?op=Cancel";
+        String httpLoc1 = "/temperature/{town}";
+        String httpLoc2 = "?op=Quote;key={symbol};amt={amount}";
+        String httpLoc3 = "?first={FirstName};middle={MiddleName};last={LastName}";
+        
+
         String[] values0 = new String[] {};
         String[] values1 = new String[] {"ONE"};
         String[] values2 = new String[] {"ONE","TWO"};



---------------------------------------------------------------------
To unsubscribe, e-mail: woden-dev-unsubscribe@ws.apache.org
For additional commands, e-mail: woden-dev-help@ws.apache.org