Author: jkaputin
Date: Thu Jan 4 06:02:03 2007
New Revision: 492571
URL: http://svn.apache.org/viewvc?view=rev&rev=492571
Log:
WODEN-86 Added behaviour to instantiate an object from
a string, parse and validate the string and to
derive a new location string based on the current
state of the object. Work-in-progress with 'get'
and 'substitute' methods declared but not yet implemented.
Modified:
incubator/woden/trunk/java/src/org/apache/woden/wsdl20/extensions/http/HTTPLocation.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=492571&r1=492570&r2=492571
==============================================================================
---
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
Thu Jan 4 06:02:03 2007
@@ -1,5 +1,5 @@
/**
- * Copyright 2006 Apache Software Foundation
+ * Copyright 2006,2007 Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,125 +15,124 @@
*/
package org.apache.woden.wsdl20.extensions.http;
-import java.net.URI;
-import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Vector;
import org.apache.woden.types.NCName;
/**
- * This class represents the value of the {http location} property from the
- * HTTP extensions to the WSDL <code>BindingOperation</code> component.
- * This property may be used as a template in which local names of elements
+ * This class represents the {http location} extension property of the
+ * <code>BindingOperation</code> component and the <code>whttp:location</code>
extension
+ * attribute of the WSDL binding <operation> element, as defined by the
+ * WSDL 2.0 HTTP binding extensions.
+ *
+ * The HTTP location may be used as a template in which local names of
elements
* from the instance data of the message to be serialized in request IRI are
* cited by enclosing the element name within curly braces (e.g.
"temperature/{town}").
- * The curly brace-enclosed element name is substituted with the value of that
+ * A curly brace-enclosed element name is substituted with the value of that
* element from the instance data when the request IRI is constructed.
* <p>
- * This class can verify that any such templated value is in a form that will
- * allow it to be converted to a URI after substitution has taken place.
- * It can return the original value of the property, as defined in the WSDL.
- * It can also return a template value substituted with instance data.
+ * This class has a single constructor which takes a String argument
representing
+ * the original value of the HTTP location, which may be templated with the
curly
+ * brace syntax described above. An object of this class represents only that
HTTP
+ * location string (i.e. the location template cannot be modified). The class
does have
+ * methods to substitute element values for local names and to return the
derived HTTP
+ * location after substitution has occurred.
+ * <p>
+ * This class performs syntax validation of the original HTTP location
template, checking that
+ * any single left and right curly braces are used correctly as pairs
enclosing a String that
+ * is of the correct format to represent an element local name (i.e. of type
xs:NCName).
+ * It also handles the double curly brace syntax defined by this extension to
represent
+ * literal single curly braces in the derived location value. For example,
+ * "abc{{def" becomes "abc{def" in the derived location and this literal left
brace is
+ * not used for matching purposes with a right curly brace.
+ * <p>
+ * 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>
- * TODO are further methods required to access templated local names and/or
perform value substitution?
- * <br>For example:
+ * 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.
* <pre>
- * String[] getLocalNames()
- * String getLocalName(int position)
- * void substituteValue(int position, String value)
- * int countOccurrences(String localName)
- * void substituteValue(String localName, int occurrence, String value)
- * void substituteValues(String localName, String[] values)
+ * e.g. "{ { {..}"
+ * </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.
+ * <pre>
+ * e.g. "{..} } }"
* </pre>
*
* @author John Kaputin ([EMAIL PROTECTED])
*/
public class HTTPLocation {
- private String fLocation;
+ private String fLocationTemplate;
+ private String fDerivedLocation = null;
+ boolean fValid = true;
- private String leftBrace = "{".intern();
- private String rightBrace = "}".intern();
+ private List fValidatedList = new Vector(); //identifies syntax errors in
the template
+ private List fParsedList = new Vector(); //working list for value
substitution
- public HTTPLocation(String httpLocation) {
- fLocation = httpLocation;
- }
+ private final String leftBrace = "{".intern();
+ private final String rightBrace = "}".intern();
+ private final String doubleLeftBraces = "{{".intern();
+ private final String doubleRightBraces = "}}".intern();
+ private final List curlyBraces = Arrays.asList(new String[] {
+ leftBrace, rightBrace, doubleLeftBraces, doubleRightBraces});
/**
- * Validates that the value of the {http location} property is in a form
- * that can be converted to a URI when constructing the request, assuming
- * that any required template substitution has taken place.
- * It first checks that any curly braces appear as matched pairs,
- * left and right, enclosing a string value that could represent the local
- * name of an element (i.e. an NCName).
- * It then checks that a java.net.URI object can be created from the
property
- * value by simulating template substitution to eliminate any curly braces.
- * Note that this method just checks the format of the {http location}
value,
- * but not the validity of any substituted values.
- *
+ * This constructor creates an HTTPLocation object from the specified
String. This
+ * String is the original value of the {http location} property, prior to
any template
+ * substitution of element local names enclosed in curly braces with
element values.
+ * If the property was parsed from a WSDL document, this will be the value
of the
+ * <code>whttp:location</code> attribute within a binding operation
element.
+ * <p>
+ * The location template String argument must not be null.
+ *
+ * @param location the String value of the http location
*/
- public boolean isTemplateValid() {
-
- boolean valid = true;
-
- //step 1: check all curly braces match and enclose an NCName string.
-
- int left, right, temp = 0;
-
- while(valid) {
- left = fLocation.indexOf(leftBrace, temp);
- if(left != -1) {
- right = fLocation.indexOf(rightBrace, left);
- if(right != -1) {
- String localName = fLocation.substring(left+1, right);
- if(NCName.isValid(localName)) {
- //we have matching curly braces enclosing a valid
NCName
- temp = right+1;
- continue;
- } else {
- valid = false; //invalid local name string
- }
- } else {
- valid = false; //unmatched left curly brace
- }
- } else {
- right = fLocation.indexOf(rightBrace, temp);
- if(right == -1) {
- break;
- } else {
- valid = false; //unmatched right curly brace
- }
- }
- }
+ public HTTPLocation(String location) {
+ fLocationTemplate = location;
- //step 2: simulate substitution to eliminate curly braces
- // and pass the resulting string to the URI constuctor.
-
- if (valid) {
- String substituted = fLocation.replace('{', 'X');
- substituted = substituted.replace('}', 'X');
- try {
- new URI(substituted);
- } catch (URISyntaxException e) {
- valid = false;
+ if(fLocationTemplate != null) {
+ 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;
}
-
- //step 3: return the result of these checks
- return valid;
}
/**
- * Returns the original value of the {http location} property,
- * prior to any template substitution.
+ * Returns true if the format of the the {http location} property prior to
any
+ * template substitution is valid, otherwise false.
+ *
+ * TODO add more javadoc
+ *
+ */
+ public boolean isTemplateValid() {
+ return fValid;
+ }
+
+ /**
+ * Returns the original value of the HTTP location, prior to any template
+ * substitution of element local names enclosed in curly braces with
element values.
+ * If the property was parsed from a WSDL document, this will be the value
of the
+ * <code>whttp:location</code> attribute within a binding operation
element.
*/
public String getLocationTemplate() {
- return fLocation;
+ return fLocationTemplate;
}
/**
* Takes a String array containing the instance data values to be
substituted
* for curly brace-enclosed local names in the HTTP location template and
returns
- * the a String representing the substituted template.
+ * a String representing the substituted template.
* The array values correspond positionally to the local names in the
template.
* <p>
* If the HTTP location template is not valid, this method will return
null;
@@ -143,6 +142,7 @@
* than there are values in the String array, the unmatched local names
will remain
* enclosed in curly braces in the returned string.
*
+ * TODO remove this method as it is now replaced by the method
substitute(String[] values), which changes the object state and conforms to
naming convention for other substitution methods.
*/
public String getLocationSubstituted(String[] values) {
if(!isTemplateValid()) {
@@ -155,18 +155,414 @@
for(int i=0; i<values.length; i++) {
next = values[i];
- left = fLocation.indexOf(leftBrace, temp);
+ left = fLocationTemplate.indexOf(leftBrace, temp);
if(left == -1) {
break; //there are no more templated local names
}
- substituted.append(fLocation.substring(temp, left));
+ substituted.append(fLocationTemplate.substring(temp, left));
substituted.append(next);
- right = fLocation.indexOf(rightBrace, left+1);
+ right = fLocationTemplate.indexOf(rightBrace, left+1);
temp = right+1;
}
- substituted.append(fLocation.substring(temp));
+ substituted.append(fLocationTemplate.substring(temp));
return substituted.toString();
}
+
+ /**
+ * Returns a String array containing the element local names that appear
+ * enclosed in curly braces in the location template, in the order that
they
+ * appear in the template. Note that if a local name appears multiple
times in
+ * the template, multiple corresponding occurrences will be present in the
array.
+ *
+ * @return a String array containing all element local names from the
template
+ */
+ public String[] getLocalNames() {
+ return null; //TODO implement this method
+ }
+
+ /**
+ * Returns a String array containing the distinct element local names that
appear
+ * enclosed in curly braces in the location template, in the order that
they appear
+ * in the template. If a local name appears multiple times in the template,
+ * only the first occurrence will be present in the array.
+ *
+ * @return a String array containing the distinct element local names from
the template
+ */
+ public String[] getDistinctLocalNames() {
+ return null; //TODO implement this method
+ }
+
+ /**
+ * Counts the number of element local names enclosed in curly braces
within the location template.
+ * This is equal to <code>getLocalNames().length</code>.
+ *
+ * @return the number of occurrences of <code>localName</code>
+ */
+ public int countLocalNames() {
+ return 0; //TODO implement this method
+ }
+
+ /**
+ * Counts the occurrences of the specified element local name enclosed in
curly braces
+ * within the location template.
+ * A null argument will return zero.
+ *
+ * @param localName the local name of an element from the instance data of
the message
+ * @return the number of occurrences of <code>localName</code>
+ */
+ public int countOccurrences(String localName) {
+ return 0; //TODO implement this method
+ }
+
+ //TODO public void substitute(String localName, int occurrence, String
value) {}, required?
+
+ /**
+ * 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
+ * will be substituted. It does not handle multiple substitution.
+ *
+ * @param localName the local name of an element from the instance data of
the message
+ * @param value the value to be substitute for <code>localName</code>
+ */
+ public void substitute(String localName, String value) {
+
+ fDerivedLocation = null;
+
+ }
+
+ /**
+ * Substitute either the first occurrence or all occurrences of the
specified element local name
+ * and its enclosing curly braces within the location template with the
specified String value
+ * of that element.
+ * If the <code>allOccurrences</code> argument is <it>false</it> only the
first occurrence
+ * of the specified local name will be substituted (this is the same
behaviour as the method
+ * <code>substitute(String localName, String value)</code>). If it is true
+ * then all occurrences will be substituted with the specified value.
+ *
+ * @param localName the local name of an element from the instance data of
the message
+ * @param value the value to be substitute for <code>localName</code>
+ * @param allOccurrences indicates whether to substitute all occurrences
of <code>localName</code>
+ * or just the first
+ *
+ * //TODO determine if this method is actually needed and if not, remove
it.
+ */
+ public void substitute(String localName, String value, boolean
allOccurrences) {
+
+ fDerivedLocation = null;
+
+ }
+
+ /**
+ * Substitute the occurrences of the specified element local name and its
enclosing curly braces
+ * within the location template with the values contained in the specified
String array, in the
+ * order they appear.
+ * The size of the array should be equal to the number of occurrences of
the local name appearing
+ * within the template (i.e. equal to the result of the
<code>countOccurrences(String localName)</code>
+ * method).
+ * If it is shorter, any additional local name occurrences in the template
will be ignored.
+ * If it is longer, any additional values in the array will be ignored.
+ * <p>
+ * A null element in the array will remove any previously substituted
value for the
+ * corresponding occurrence of the local name within the template.
+ *
+ * @param localName the local name of an element from the instance data of
the message
+ * @param values a String array containing the values to be substituted
for occurrences of
+ * <code>localName</code>, in order.
+ */
+ public void substitute(String localName, String[] values) {
+
+ fDerivedLocation = null;
+
+ }
+
+ /**
+ * Substitute the element local names and their enclosing curly braces
within the location
+ * template with the values contained in the specified String array, in
the order they appear.
+ * The size of the array should be equal to the number of local names
appearing within the
+ * template (i.e. equal to the result of the
<code>countLocalNames()</code> method).
+ * If it is shorter, any additional local names in the template will be
ignored.
+ * If it is longer, any additional values in the array will be ignored.
+ * <p>
+ * A null element in the array will remove any previously substituted
value for the
+ * corresponding local name within the template.
+ *
+ * @param values a String array containing the values to be substituted
for any occurrences of an
+ * element local name within the template, in order.
+ */
+ public void substitute(String[] values) {
+
+ fDerivedLocation = null;
+ }
+
+ /**
+ * Return the String value associated with the specified element local
name.
+ * If template substitution has already happened via any of the
+ * <code>substitute</code> methods, this String should represent the value
of
+ * some element from the instance data of the message. If substitution has
not
+ * yet happened, a null value is returned.
+ * <p>
+ * Note, this method assumes a single occurrence of the specified local
name
+ * within the template. If the local name appears multiple times in the
template,
+ * the method returns the value associated with the first occurrence of
this
+ * local name.
+ *
+ * @param localName the local name of an element from the instance data of
the message
+ * @return the String value associated with <code>localName</code>
+ */
+ public String getValue(String localName) {
+ return null; //TODO implement this method
+ }
+
+ /**
+ * Returns a String array containing the values associated with occurrences
+ * of the specified element local name, in the order they appear within
the template.
+ * If template substitution has already happened via any of the
+ * <code>substitute</code> methods, each String should represent the value
of
+ * some element from the instance data of the message. If substitution has
not
+ * yet happened for some occurrence of the local name, the corresponding
+ * array element will be null.
+ *
+ * @param localName the local name of an element from the instance data of
the message
+ * @return an array of String values associated with occurrences of
<code>localName</code>
+ */
+ public String[] getValues(String localName) {
+ return null; //TODO implement this method
+ }
+
+ /**
+ * Returns a String array containing the values associated with all
element local names,
+ * in the order they appear within the template.
+ * If template substitution has already happened via any of the
+ * <code>substitute</code> methods, each String should represent the value
of
+ * some element from the instance data of the message. If substitution has
not
+ * yet happened for a local name, the corresponding array element will be
null.
+ *
+ * @return an array of String values associated with element local names
within the template
+ */
+ public String[] getValues() {
+ return null; //TODO implement this method
+ }
+
+ /**
+ * Returns a String representing the HTTP Location template with any
element name/value
+ * substitution that has taken place via the <code>substitute</code>
methods.
+ * If any element local name has not yet been substituted with a value
then that
+ * local name will appear in the String in its original template form,
enclosed in
+ * curly braces.
+ * <p>
+ * If the HTTP Location does not contain any curly brace template syntax
then substitution
+ * is not applicable and this method will return the same String value as
the
+ * <code>getLocationTemplate()</code> method.
+ */
+ public String toString() {
+
+ if(fDerivedLocation != null) {
+ return fDerivedLocation;
+ }
+
+ StringBuffer buffer = new StringBuffer();
+ Iterator it = fParsedList.iterator();
+
+ while(it.hasNext()) {
+ Object currToken = it.next();
+ if(currToken instanceof String[]) {
+ String[] nameValue = (String[])currToken;
+ if(nameValue[1] == null) {
+ //no value substitution, so append the original curly
brace-enclosed string
+ buffer.append(leftBrace);
+ buffer.append(nameValue[0]);
+ buffer.append(rightBrace);
+ } else {
+ //append the substituted element value
+ buffer.append(nameValue[1]);
+ }
+ } else {
+ buffer.append(currToken);
+ }
+ }
+
+ fDerivedLocation = buffer.toString();
+
+ return fDerivedLocation;
+ }
+
+ /*
+ * Scan location char by char left to right. Add {, }, {{ or }} or any
+ * string between these add as tokens in a new ordered list. Return this
new
+ * tokenized list to be used as input to the template validation step.
+ */
+ private List tokenizeTemplate() {
+
+ StringBuffer buffer = new StringBuffer();
+ int len = fLocationTemplate.length();
+ char currChar;
+ int lastPos = len-1;
+ List tokens = new Vector();
+
+ for(int i=0; i<len; i++) {
+ currChar = fLocationTemplate.charAt(i);
+ if(currChar == '{') {
+ if(buffer.length() > 0) {
+ tokens.add(buffer.toString());
+ buffer = new StringBuffer();
+ }
+ if(i < lastPos && fLocationTemplate.charAt(i+1) == '{') {
+ tokens.add(doubleLeftBraces);
+ i++; //move loop position to the 2nd left curly brace
+ } else {
+ tokens.add(leftBrace);
+ }
+ } else if(currChar == '}') {
+ if(buffer.length() > 0) {
+ tokens.add(buffer.toString());
+ buffer = new StringBuffer();
+ }
+ if(i < lastPos && fLocationTemplate.charAt(i+1) == '}') {
+ tokens.add(doubleRightBraces);
+ i++; //move loop position to the 2nd right curly brace
+ } else {
+ tokens.add(rightBrace);
+ }
+
+ } else {
+ buffer.append(currChar);
+ }
+ }
+
+ if(buffer.length() > 0) {
+ tokens.add(buffer.toString());
+ }
+
+ return tokens;
+ }
+
+ /*
+ * Identify matching pairs of left and right curly braces with a string in
between and check
+ * that the string between them is of type xs:NCName (i.e. the type
required for an element
+ * local name).
+ * 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 right braces follow a left brace, pair the left most one
with the left brace
+ * and treat the others as unmatched right braces.
+ * Any unmatched left or right braces are added to the output list. Their
presence in this list
+ * can be used later to identify this type of error.
+ *
+ * Replace valid curly brace-enclosed strings with a 2 element String
array in the output list.
+ * The first element is the local name string and the second element,
initialized to null,
+ * represents the element value.
+ * If the enclosed string is not of type NCName, add it to the output list
as a single string
+ * with its enclosing left and right braces (e.g. "{invalid:name}"). This
type of string can be
+ * used later to identify this type of error.
+ *
+ * Any double curly braces '{{' or '}}' are copied directly to the output
list.
+ * Any other strings in the input list are also copied directly to the
output list.
+ *
+ * This output list of valid and in-error items can be used to identify
particular types of
+ * errors present in the template and is also used as input to the final
parsing step.
+ *
+ */
+ private void validateTemplate(List tokenizedList) {
+
+ if(tokenizedList.size() == 0) {
+ fValid = false;
+ return;
+ }
+
+ boolean valid = true;
+ List tokens = new Vector();
+ int size = tokenizedList.size();
+ ListIterator it = tokenizedList.listIterator();
+
+ while(it.hasNext()) {
+ Object 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);
+ if(!curlyBraces.contains(nextToken) && nextNextToken ==
rightBrace) {
+ //we have a string enclosed by a pair of left and
right curly braces
+ if(NCName.isValid(nextToken)) {
+ String[] nameValue = new String[] {nextToken,
null};
+ tokens.add(nameValue);
+ } else {
+ valid = false; //invalid format for a local name
+ StringBuffer buffer = new StringBuffer(leftBrace);
+ buffer.append(nextToken);
+ buffer.append(rightBrace);
+ tokens.add(buffer.toString());
+ }
+ it.next(); //local name
+ it.next(); //right curly brace
+ } else {
+ //TODO handle a string containing double curly brace
as an invalid local name, not an unmatched left brace.
+ valid = false; //left brace not followed by a name and
a right brace
+ tokens.add(leftBrace);
+ }
+ }
+ } else if(currToken == rightBrace) {
+ //right brace not preceded by a name and a left brace
+ valid = false;
+ tokens.add(rightBrace);
+ } else {
+ //This token is double left or double right curly braces or
some string
+ //other than a single curly brace.
+ tokens.add(currToken);
+ }
+
+ } //end while loop
+
+ fValid = valid;
+ fValidatedList = tokens;
+ }
+
+ /*
+ * Create a final parsed list of items from the location template, which
can be used
+ * for value substitution and for creating the external representation of
the
+ * location after substitution. The output list will contain either the 2
element
+ * string arrays representing templated local names or strings
concatenating any
+ * other content that appears between templated names. These string
concatentations
+ * will include any double curly braces, replaced by a single brace. They
will also
+ * include any invalid curly brace-enclosed strings (e.g.
"{invalid:name}").
+ */
+ private void parseTemplate() {
+
+ StringBuffer buffer = new StringBuffer();
+ List tokens = new Vector();
+ Iterator it = fValidatedList.iterator();
+
+ while(it.hasNext()) {
+ Object 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.
+ if(buffer.length() > 0) {
+ tokens.add(buffer.toString());
+ buffer = new StringBuffer();
+ }
+ tokens.add(currToken);
+ } else if(currToken == doubleLeftBraces) {
+ buffer.append(leftBrace);
+ } else if(currToken == doubleRightBraces) {
+ buffer.append(rightBrace);
+ } else {
+ //just append this to any previous string content
+ buffer.append(currToken);
+ }
+ }
+
+ if(buffer.length() > 0) {
+ tokens.add(buffer.toString());
+ }
+
+ fParsedList = tokens;
+ }
+
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]