Index: java/org/apache/commons/httpclient/HttpConnection.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpConnection.java,v retrieving revision 1.55 diff -u -r1.55 HttpConnection.java --- java/org/apache/commons/httpclient/HttpConnection.java 10 Apr 2003 23:36:36 -0000 1.55 +++ java/org/apache/commons/httpclient/HttpConnection.java 16 Apr 2003 18:25:39 -0000 @@ -63,7 +63,6 @@ package org.apache.commons.httpclient; -import java.io.FilterOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; Index: java/org/apache/commons/httpclient/HttpConstants.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpConstants.java,v retrieving revision 1.9 diff -u -r1.9 HttpConstants.java --- java/org/apache/commons/httpclient/HttpConstants.java 10 Apr 2003 17:18:49 -0000 1.9 +++ java/org/apache/commons/httpclient/HttpConstants.java 16 Apr 2003 18:25:41 -0000 @@ -1,5 +1,5 @@ /* - * $Header: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpConstants.java,v 1.9 2003/04/10 17:18:49 olegk Exp $ + * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpConstants.java,v 1.9 2003/04/10 17:18:49 olegk Exp $ * $Revision: 1.9 $ * $Date: 2003/04/10 17:18:49 $ * @@ -70,7 +70,7 @@ /** - * DOCUMENT ME! + * HTTP content conversion routines. * * @author Oleg Kalnichevski * @author Mike Bowler Index: java/org/apache/commons/httpclient/methods/EntityEnclosingMethod.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/EntityEnclosingMethod.java,v retrieving revision 1.14 diff -u -r1.14 EntityEnclosingMethod.java --- java/org/apache/commons/httpclient/methods/EntityEnclosingMethod.java 1 Apr 2003 19:04:19 -0000 1.14 +++ java/org/apache/commons/httpclient/methods/EntityEnclosingMethod.java 16 Apr 2003 18:25:44 -0000 @@ -67,10 +67,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.io.OutputStream; -import java.io.Reader; -import java.io.UnsupportedEncodingException; import org.apache.commons.httpclient.ChunkedOutputStream; import org.apache.commons.httpclient.ContentLengthInputStream; @@ -114,8 +111,16 @@ private byte[] buffer = null; /** The unbuffered request body, if any. */ - private InputStream requestBodyStream = null; + private InputStream requestStream = null; + /** The request body as string, if any. */ + private String requestString = null; + + /** for optimization purpose, the generated request body may be + * cached when the method is being executed. + */ + private byte[] contentCache = null; + /** Counts how often the request was sent to the server. */ private int repeatCount = 0; @@ -179,15 +184,65 @@ /** * Returns true if there is a request body to be sent. - * 'Expect: 100-continue' handshake may not be used if request - * body is not present + * + *
This method must be overwritten by sub-classes that implement + * alternative request content input methods + *
* * @return boolean * * @since 2.0beta1 */ protected boolean hasRequestContent() { - return (this.requestBodyStream != null) || (this.buffer != null); + LOG.trace("enter EntityEnclosingMethod.hasRequestContent()"); + return (this.buffer != null) || + (this.requestStream != null) || + (this.requestString != null); + } + + /** + * Clears request body + * + *This method must be overwritten by sub-classes that implement + * alternative request content input methods + *
+ * + * @since 2.0beta1 + */ + protected void clearRequestBody() { + LOG.trace("enter EntityEnclosingMethod.clearRequestBody()"); + this.requestStream = null; + this.requestString = null; + this.buffer = null; + this.contentCache = null; + } + + + /** + * Generates request body. + * + * @return request body as an array of bytes. If the request content + * has not been set, returns null. + * + *This method must be overwritten by sub-classes that implement + * alternative request content input methods + *
+ * + * @since 2.0beta1 + */ + protected byte[] generateRequestBody() { + LOG.trace("enter EntityEnclosingMethod.renerateRequestBody()"); + if (this.requestStream != null) { + bufferContent(); + } + + if (this.buffer != null) { + return this.buffer; + } else if (this.requestString != null) { + return HttpConstants.getContentBytes(this.requestString, getRequestCharSet()); + } else { + return null; + } } /** @@ -256,9 +311,10 @@ if (this.requestContentLength != CONTENT_LENGTH_AUTO) { return this.requestContentLength; } - bufferContent(); - - return (this.buffer == null) ? 0 : this.buffer.length; + if (this.contentCache == null) { + this.contentCache = generateRequestBody(); + } + return (this.contentCache == null) ? 0 : this.contentCache.length; } /** @@ -268,21 +324,23 @@ */ public void setRequestBody(InputStream body) { LOG.trace("enter EntityEnclosingMethod.setRequestBody(InputStream)"); - this.requestBodyStream = body; - this.buffer = null; + clearRequestBody(); + this.requestStream = body; } /** * Gets the request body as a stream. + * Calling this method will cause the content to be buffered. * * @return The request body {@link java.io.InputStream} if it has been set. */ public InputStream getRequestBody() { LOG.trace("enter EntityEnclosingMethod.getRequestBody()"); - if (this.buffer != null) { - return new ByteArrayInputStream(this.buffer); + byte [] content = generateRequestBody(); + if (content != null) { + return new ByteArrayInputStream(content); } else { - return this.requestBodyStream; + return new ByteArrayInputStream(new byte[] {}); } } @@ -293,17 +351,13 @@ */ public void setRequestBody(String body) { LOG.trace("enter EntityEnclosingMethod.setRequestBody(String)"); - - if (body == null) { - this.requestBodyStream = null; - this.buffer = null; - return; - } - this.buffer = HttpConstants.getContentBytes(body, getRequestCharSet()); + clearRequestBody(); + this.requestString = body; } /** * Gets the request body as a String. + * Calling this method will cause the content to be buffered. * * @return the request body as a string * @@ -311,25 +365,12 @@ */ public String getRequestBodyAsString() throws IOException { LOG.trace("enter EntityEnclosingMethod.getRequestBodyAsString()"); - - Reader instream = null; - try { - instream = new InputStreamReader(getRequestBody(), getRequestCharSet()); - } catch (UnsupportedEncodingException e) { - if (LOG.isWarnEnabled()) { - LOG.warn("Unsupported encoding: " + e.getMessage()); - } - instream = new InputStreamReader(getRequestBody()); - } - - StringBuffer buffer = new StringBuffer(); - char[] tmp = new char[4096]; - int l = 0; - while ((l = instream.read(tmp)) >= 0) { - buffer.append(tmp, 0, l); + byte [] content = generateRequestBody(); + if (content != null) { + return HttpConstants.getContentString(content, getRequestCharSet()); + } else { + return null; } - - return buffer.toString(); } @@ -350,19 +391,38 @@ LOG.trace( "enter EntityEnclosingMethod.writeRequestBody(HttpState, HttpConnection)"); + if (!hasRequestContent()) { + LOG.debug("Request body has not been specified"); + return true; + } + int contentLength = getRequestContentLength(); if ((contentLength == CONTENT_LENGTH_CHUNKED) && !isHttp11()) { throw new HttpException( "Chunked transfer encoding not allowed for HTTP/1.0"); } - InputStream instream = getRequestBody(); + + InputStream instream = null; + if (this.requestStream != null) { + LOG.debug("Using unbuffered request body"); + instream = this.requestStream; + } else { + if (this.contentCache == null) { + this.contentCache = generateRequestBody(); + } + if (this.contentCache != null) { + LOG.debug("Using buffered request body"); + instream = new ByteArrayInputStream(this.contentCache); + } + } + if (instream == null) { LOG.debug("Request body is empty"); return true; } - if ((this.repeatCount > 0) && (this.buffer == null)) { + if ((this.repeatCount > 0) && (this.contentCache == null)) { throw new HttpException( "Unbuffered entity enclosing request can not be repeated."); } @@ -405,39 +465,37 @@ */ public void recycle() { LOG.trace("enter EntityEnclosingMethod.recycle()"); + clearRequestBody(); this.requestContentLength = CONTENT_LENGTH_AUTO; - this.requestBodyStream = null; - this.buffer = null; this.repeatCount = 0; super.recycle(); } /** - * Buffers the request body and calculates the content length. If the - * method was called earlier it returns immediately. + * Buffers request body input stream. */ - protected void bufferContent() { + private void bufferContent() { LOG.trace("enter EntityEnclosingMethod.bufferContent()"); if (this.buffer != null) { + // Already been buffered return; } - if (this.requestBodyStream == null) { - return; - } - try { - ByteArrayOutputStream tmp = new ByteArrayOutputStream(); - byte[] data = new byte[4096]; - int l = 0; - while ((l = this.requestBodyStream.read(data)) >= 0) { - tmp.write(data, 0, l); + if (this.requestStream != null) { + try { + ByteArrayOutputStream tmp = new ByteArrayOutputStream(); + byte[] data = new byte[4096]; + int l = 0; + while ((l = this.requestStream.read(data)) >= 0) { + tmp.write(data, 0, l); + } + this.buffer = tmp.toByteArray(); + this.requestStream = null; + } catch (IOException e) { + LOG.error(e.getMessage(), e); + this.buffer = null; + this.requestStream = null; } - this.buffer = tmp.toByteArray(); - this.requestBodyStream = null; - } catch (IOException e) { - LOG.error(e.getMessage(), e); - this.buffer = null; - this.requestBodyStream = null; } } } Index: java/org/apache/commons/httpclient/methods/PostMethod.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/PostMethod.java,v retrieving revision 1.40 diff -u -r1.40 PostMethod.java --- java/org/apache/commons/httpclient/methods/PostMethod.java 4 Apr 2003 02:37:03 -0000 1.40 +++ java/org/apache/commons/httpclient/methods/PostMethod.java 16 Apr 2003 18:25:47 -0000 @@ -63,11 +63,11 @@ package org.apache.commons.httpclient.methods; import java.io.IOException; -import java.io.InputStream; import java.util.Iterator; import java.util.Vector; import org.apache.commons.httpclient.HttpConnection; +import org.apache.commons.httpclient.HttpConstants; import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.HttpState; import org.apache.commons.httpclient.NameValuePair; @@ -113,25 +113,14 @@ /** Log object for this class. */ private static final Log LOG = LogFactory.getLog(PostMethod.class); - /** Custom content encoding. */ - private static final int CUSTOM_CONTENT = 0; - - /** URL encoded content. */ - private static final int URL_ENCODED_CONTENT = 1; - - /** My content encoding. */ - private int contentEncoding = CUSTOM_CONTENT; - /** The Content-Type for www-form-urlcoded. */ public static final String FORM_URL_ENCODED_CONTENT_TYPE = "application/x-www-form-urlencoded"; /** * The buffered request body consisting ofNameValuePairs.
- * @deprecated Parameters will not be buffered in the future but converted
- * into an InputStream immediately.
*/
- private Vector deprecated_parameters = new Vector();
+ private Vector params = new Vector();
// ----------------------------------------------------------- Constructors
@@ -195,6 +184,96 @@
return "POST";
}
+
+ /**
+ * Returns true if there is a request body to be sent.
+ *
+ * This method must be overwritten by sub-classes that implement + * alternative request content input methods + *
+ * + * @return boolean + * + * @since 2.0beta1 + */ + protected boolean hasRequestContent() { + LOG.trace("enter PostMethod.hasRequestContent()"); + if (!this.params.isEmpty()) { + return true; + } else { + return super.hasRequestContent(); + } + } + + /** + * Clears request body + * + *This method must be overwritten by sub-classes that implement + * alternative request content input methods + *
+ * + * @since 2.0beta1 + */ + protected void clearRequestBody() { + LOG.trace("enter PostMethod.clearRequestBody()"); + this.params.clear(); + super.clearRequestBody(); + } + + + /** + * Generates request body. + * + * @return request body as an array of bytes. If the request content + * has not been set, returns null. + * + *This method must be overwritten by sub-classes that implement + * alternative request content input methods + *
+ * + * @since 2.0beta1 + */ + protected byte[] generateRequestBody() { + LOG.trace("enter PostMethod.renerateRequestBody()"); + if (!this.params.isEmpty()) { + String charset = getRequestCharSet(); + StringBuffer buff = new StringBuffer(); + + for (int i = 0; i < this.params.size(); i++) { + if (i > 0) { + buff.append("&"); + } + NameValuePair parameter = (NameValuePair)this.params.get(i); + String queryName = null; + try { + queryName = URIUtil.encodeWithinQuery(parameter.getName(), charset); + } catch (URIException e) { + if (LOG.isWarnEnabled()) { + LOG.warn("Encosing error: " + e.toString()); + } + queryName = parameter.getName(); + } + + buff.append(queryName).append("="); + String queryValue = null; + + try { + queryValue = URIUtil.encodeWithinQuery(parameter.getValue(), charset); + } catch (URIException e) { + if (LOG.isWarnEnabled()) { + LOG.warn("Encosing error: " + e.toString()); + } + queryValue = parameter.getValue(); + } + buff.append(queryValue); + } + return HttpConstants.getContentBytes(buff.toString()); + } else { + return super.generateRequestBody(); + } + } + + /** * Set the value of parameter with parameterName to parameterValue. Does * not preserve the initial insertion order. @@ -203,8 +282,6 @@ * @param parameterValue value of the parameter * * @since 2.0 - * - * @deprecated use {@link #setRequestBody(NameValuePair[])}. */ public void setParameter(String parameterName, String parameterValue) { LOG.trace("enter PostMethod.setParameter(String, String)"); @@ -224,8 +301,6 @@ * * @since 2.0 * - * @deprecated use {@link #getRequestBody()} or - * {@link #getRequestBodyAsString()}. */ public NameValuePair getParameter(String paramName) { LOG.trace("enter PostMethod.getParameter(String)"); @@ -234,7 +309,7 @@ return null; } - Iterator iter = deprecated_parameters.iterator(); + Iterator iter = this.params.iterator(); while (iter.hasNext()) { NameValuePair parameter = (NameValuePair) iter.next(); @@ -256,14 +331,12 @@ * * @since 2.0 * - * @deprecated use {@link #getRequestBody()} or - * {@link #getRequestBodyAsString()}. */ public NameValuePair[] getParameters() { LOG.trace("enter PostMethod.getParameters()"); - int numPairs = deprecated_parameters.size(); - Object[] objectArr = deprecated_parameters.toArray(); + int numPairs = this.params.size(); + Object[] objectArr = this.params.toArray(); NameValuePair[] nvPairArr = new NameValuePair[numPairs]; for (int i = 0; i < numPairs; i++) { @@ -282,8 +355,6 @@ * @throws IllegalArgumentException if either argument is null * * @since 1.0 - * - * @deprecated use {@link #setRequestBody(NameValuePair[])}. */ public void addParameter(String paramName, String paramValue) throws IllegalArgumentException { @@ -292,10 +363,9 @@ if ((paramName == null) || (paramValue == null)) { throw new IllegalArgumentException( "Arguments to addParameter(String, String) cannot be null"); - } else { - deprecated_parameters.add(new NameValuePair(paramName, paramValue)); } - setRequestBody(getParameters()); + super.clearRequestBody(); + this.params.add(new NameValuePair(paramName, paramValue)); } /** @@ -307,8 +377,6 @@ * null values * * @since 2.0 - * - * @deprecated use {@link #setRequestBody(NameValuePair[])}. */ public void addParameter(NameValuePair param) throws IllegalArgumentException { @@ -316,9 +384,8 @@ if (param == null) { throw new IllegalArgumentException("NameValuePair may not be null"); - } else { - addParameter(param.getName(), param.getValue()); } + addParameter(param.getName(), param.getValue()); } /** @@ -328,8 +395,6 @@ * @param parameters The array of parameters to add. * * @since 2.0 - * - * @deprecated use {@link #setRequestBody(NameValuePair[])}. */ public void addParameters(NameValuePair[] parameters) { LOG.trace("enter PostMethod.addParameters(NameValuePair[])"); @@ -356,8 +421,6 @@ * @throws IllegalArgumentException When the parameter name passed is null * * @since 2.0 - * - * @deprecated use {@link #setRequestBody(NameValuePair[])}. */ public boolean removeParameter(String paramName) throws IllegalArgumentException { @@ -368,7 +431,7 @@ "Argument passed to removeParameter(String) cannot be null"); } boolean removed = true; - Iterator iter = deprecated_parameters.iterator(); + Iterator iter = this.params.iterator(); while (iter.hasNext()) { NameValuePair pair = (NameValuePair) iter.next(); @@ -378,7 +441,6 @@ removed = true; } } - setRequestBody(getParameters()); return removed; } @@ -395,8 +457,6 @@ * @throws IllegalArgumentException when param name or value are null * * @since 2.0 - * - * @deprecated use {@link #setRequestBody(NameValuePair[])}. */ public boolean removeParameter(String paramName, String paramValue) throws IllegalArgumentException { @@ -409,7 +469,7 @@ throw new IllegalArgumentException("Parameter value may not be null"); } - Iterator iter = deprecated_parameters.iterator(); + Iterator iter = this.params.iterator(); while (iter.hasNext()) { NameValuePair pair = (NameValuePair) iter.next(); @@ -425,99 +485,6 @@ } /** - * Encode the list of parameters into a query string. - * - * @param parameters the list of query name and value - * @param charset the charset to use for encoding the parameters - * - * @return url encoded form of the parameters - * - * @throws IllegalArgumentException if parameters is null - */ - protected static String generateRequestBody(NameValuePair[] parameters, final String charset) - throws IllegalArgumentException { - LOG.trace("enter PostMethod.generateRequestBody(NameValuePair[])"); - - if (parameters == null) { - throw new IllegalArgumentException("Array of parameters may not be null"); - } - StringBuffer buff = new StringBuffer(); - - for (int i = 0; i < parameters.length; i++) { - if (i > 0) { - buff.append("&"); - } - - NameValuePair parameter = parameters[i]; - - String queryName = null; - try { - queryName = URIUtil.encodeWithinQuery(parameter.getName(), charset); - } catch (URIException e) { - if (LOG.isWarnEnabled()) { - LOG.warn("Encosing error: " + e.toString()); - } - queryName = parameter.getName(); - } - - buff.append(queryName).append("="); - String queryValue = null; - - try { - queryValue = URIUtil.encodeWithinQuery(parameter.getValue(), charset); - } catch (URIException e) { - if (LOG.isWarnEnabled()) { - LOG.warn("Encosing error: " + e.toString()); - } - queryValue = parameter.getValue(); - } - buff.append(queryValue); - } - - return buff.toString(); - } - - /** - * Sets the request body to be the specified string. - * Once this method has been invoked, the request parameters cannot be - * altered until I am {@link #recycle recycled}. - * - * @param stringBody Request body content as a string - * - * @throws IllegalArgumentException if stringBody is null - */ - public void setRequestBody(String stringBody) - throws IllegalArgumentException { - LOG.trace("enter PostMethod.setRequestBody(String)"); - - if (stringBody == null) { - throw new IllegalArgumentException("String body not be null"); - } - super.setRequestBody(stringBody); - this.contentEncoding = CUSTOM_CONTENT; - } - - /** - * Sets the request body to be the specified inputstream. - * Once this method has been invoked, the request parameters cannot be - * altered until I am {@link #recycle recycled}. - * - * @param streamBody Request body content as {@link java.io.InputStream} - * - * @throws IllegalArgumentException if streamBody is null - */ - public void setRequestBody(InputStream streamBody) - throws IllegalArgumentException { - LOG.trace("enter PostMethod.setRequestBody(InputStream)"); - - if (streamBody == null) { - throw new IllegalArgumentException("Stream body may not be null"); - } - super.setRequestBody(streamBody); - this.contentEncoding = CUSTOM_CONTENT; - } - - /** * Set an Array of parameters to be used in the POST request body * * @param parametersBody The array of parameters to add. @@ -533,8 +500,8 @@ if (parametersBody == null) { throw new IllegalArgumentException("Array of parameters may not be null"); } - super.setRequestBody(generateRequestBody(parametersBody, getRequestCharSet())); - this.contentEncoding = URL_ENCODED_CONTENT; + clearRequestBody(); + addParameters(parametersBody); } /** @@ -553,24 +520,12 @@ throws IOException, HttpException { super.addRequestHeaders(state, conn); - if (this.contentEncoding == URL_ENCODED_CONTENT) { + if (!this.params.isEmpty()) { //there are some parameters, so set the contentType header if (getRequestHeader("Content-Type") == null) { setRequestHeader("Content-Type", FORM_URL_ENCODED_CONTENT_TYPE); } } - } - - /** - * Prepare the method for reuse. - * - * @since 1.0 - */ - public void recycle() { - LOG.trace("enter PostMethod.recycle()"); - this.contentEncoding = CUSTOM_CONTENT; - this.deprecated_parameters.clear(); - super.recycle(); } } Index: test/org/apache/commons/httpclient/TestChallengeParser.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestChallengeParser.java,v retrieving revision 1.1 diff -u -r1.1 TestChallengeParser.java --- test/org/apache/commons/httpclient/TestChallengeParser.java 27 Mar 2003 21:09:57 -0000 1.1 +++ test/org/apache/commons/httpclient/TestChallengeParser.java 16 Apr 2003 18:25:48 -0000 @@ -62,11 +62,7 @@ import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; - -import java.util.Hashtable; import java.util.Map; -import java.util.StringTokenizer; - import org.apache.commons.httpclient.auth.AuthChallengeParser; import org.apache.commons.httpclient.auth.MalformedChallengeException; Index: test/org/apache/commons/httpclient/TestMethodCharEncoding.java =================================================================== RCS file: test/org/apache/commons/httpclient/TestMethodCharEncoding.java diff -N test/org/apache/commons/httpclient/TestMethodCharEncoding.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ test/org/apache/commons/httpclient/TestMethodCharEncoding.java 16 Apr 2003 18:25:50 -0000 @@ -0,0 +1,274 @@ +/* + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999-2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + *