MockResponse.java :  » Web-Framework » rife-1.6.1 » com » uwyn » rife » test » Java Open Source

Java Open Source » Web Framework » rife 1.6.1 
rife 1.6.1 » com » uwyn » rife » test » MockResponse.java
/*
 * Copyright 2001-2007 Geert Bevin <gbevin[remove] at uwyn dot com>
 * Distributed under the terms of either:
 * - the common development and distribution license (CDDL), v1.0; or
 * - the GNU Lesser General Public License, v2.1 or later
 *
 * Parts are Copyright 1999-2004 Mort Bay Consulting Pty. Ltd.
 * ------------------------------------------------------------------------
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http:*www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * $Id: MockResponse.java 3669 2007-02-26 13:51:23Z gbevin $
 */
package com.uwyn.rife.test;

import com.uwyn.rife.engine.*;
import java.io.*;
import java.util.*;

import com.uwyn.rife.cmf.loader.xhtml.Jdk14Loader;
import com.uwyn.rife.engine.exceptions.EngineException;
import com.uwyn.rife.template.Template;
import com.uwyn.rife.test.MockHeaders;
import com.uwyn.rife.test.exceptions.InvalidXmlException;
import com.uwyn.rife.tools.ExceptionUtils;
import com.uwyn.rife.tools.StringUtils;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.xml.namespace.QName;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
 * Provides a {@link Response} implementation that is suitable for testing a
 * web application outside of a servlet container.
 *
 * @author Geert Bevin (gbevin[remove] at uwyn dot com)
 * @version $Revision: 3669 $
 * @since 1.1
 */
public class MockResponse extends AbstractResponse
{
  private final static String HEADER_CONTENT_TYPE = "Content-Type";
  private final static String HEADER_CONTENT_LANGUAGE = "Content-Language";
  private final static String HEADER_CONTENT_LENGTH = "Content-Length";
  private final static String HEADER_LOCATION = "Location";
  
  private final static int SC_200_OK = 200;
  private final static int SC_302_MOVED_TEMPORARILY = 302;

  private final static Pattern STRIP_XHTML_XMLNS = Pattern.compile("html\\s+xmlns=\"[^\"]*\"");
  
  private MockConversation          mMockConversation;
  private MockHeaders               mHeaders = new MockHeaders();
  private HashMap<String, Cookie>    mNewCookies = new HashMap<String, Cookie>();
  private String                    mContentType;
  private String                    mCharacterEncoding;
  private int                       mStatus = SC_200_OK;
  private String                    mReason;
  private Locale                    mLocale;
  private ByteArrayOutputStream     mMockOutputStream = new ByteArrayOutputStream();
  private PrintWriter               mMockWriter;
  private Template                  mTemplate;
  private Map<String, MockResponse>  mEmbeddedResponses = new LinkedHashMap<String, MockResponse>();
  
  MockResponse(MockConversation conversation, Request request)
  {
    this(conversation, request, false);
  }
  
  private MockResponse(MockConversation conversation, Request request, boolean embedded)
  {
    super(request, embedded);
    
    mMockConversation = conversation;
  }
  
  MockConversation getMockConversation()
  {
    return mMockConversation;
  }
  
  /**
   * Retrieves the {@link ElementInfo} of the element that was last
   * processed with this response.
   *
   * @return the <code>ElementInfo</code> of the last element
   * @see #getLastElement
   * @see #getLastElementId
   * @since 1.1
   */
  public ElementInfo getLastElementInfo()
  {
    ElementSupport element = getLastElement();
    if (null == element)
    {
      return null;
    }
    
    return element.getElementInfo();
  }
  
  /**
   * Retrieves the identifier of the element that was last processed with
   * this response.
   *
   * @return the identifier of the last element
   * @see #getLastElement
   * @see #getLastElementInfo
   * @since 1.1
   */
  public String getLastElementId()
  {
    ElementInfo element_info = getLastElementInfo();
    if (null == element_info)
    {
      return null;
    }
    
    return element_info.getId();
  }
  
  /**
   * Retrieves the an array of all the bytes that have been written to this
   * reponse.
   *
   * @return an array of bytes with the response content
   * @see #getText
   * @see #getTemplate
   * @see #getParsedHtml
   * @since 1.1
   */
  public byte[] getBytes()
  {
    return mMockOutputStream.toByteArray();
  }
  
  /**
   * Retrieves the content of this reponse as text.
   *
   * @return the response content as text
   * @see #getBytes
   * @see #getTemplate
   * @see #getParsedHtml
   * @since 1.1
   */
  public String getText()
  {
    String  charset = mCharacterEncoding;
    if (null == charset)
    {
      charset = StringUtils.ENCODING_ISO_8859_1;
    }
    try
    {
      return new String(getBytes(), charset);
    }
    catch (UnsupportedEncodingException e)
    {
      return ExceptionUtils.getExceptionStackTrace(e);
    }
  }
  
  /**
   * Retrieves the template instance that was printed to the response.
   *
   * @return the template instance that was printed to the response; or
   * <p><code>null</code> of no template was printed to the response
   * @see #getBytes
   * @see #getText
   * @see #getParsedHtml
   * @since 1.1
   */
  public Template getTemplate()
  {
    return mTemplate;
  }

  /**
   * Retrieves the content of this reponse as parsed HTML.
   *
   * @exception IOException when exception occured during the retrieval on
   * the response content
   * @exception SAXException when exception occured during the parsing of
   * the content as HTML
   * @return the response content as parsed HTML
   * @see #getBytes
   * @see #getText
   * @see #getTemplate
   * @since 1.1
   */
  public ParsedHtml getParsedHtml()
  throws IOException, SAXException
  {
    return ParsedHtml.parse(this);
  }
  
  public String getContentType()
  {
    return getHeader(HEADER_CONTENT_TYPE);
  }
  
  /**
   * Evaluate an XPath expression in the context of the response text and
   * return the result as a list of DOM nodes.
   * <p>More information about XPath can be found in the <a
   * href="http://www.w3.org/TR/xpath">original specification</a> or in this
   * <a href="http://zvon.org/xxl/XMLTutorial/General/book.html">tutorial</a>.
   *
   * @exception XPathExpressionException if expression cannot be evaluated.
   * @return the result as a <code>NodeList</code>
   * @see #xpathNode(String)
   * @see #xpathString(String)
   * @see #xpathBoolean(String)
   * @see #xpathNumber(String)
   * @since 1.1
   */
  public NodeList xpathNodeSet(String expression)
  throws XPathExpressionException
  {
    return (NodeList)xpath(expression, XPathConstants.NODESET);
  }
  
  /**
   * Evaluate an XPath expression in the context of the response text and
   * return the result as a DOM node.
   *
   * @exception XPathExpressionException if expression cannot be evaluated.
   * @return the result as a <code>Node</code>
   * @see #xpathNodeSet(String)
   * @see #xpathString(String)
   * @see #xpathBoolean(String)
   * @see #xpathNumber(String)
   * @since 1.1
   */
  public Node xpathNode(String expression)
  throws XPathExpressionException
  {
    return (Node)xpath(expression, XPathConstants.NODE);
  }
  
  /**
   * Evaluate an XPath expression in the context of the response text and
   * return the result as a string.
   *
   * @exception XPathExpressionException if expression cannot be evaluated.
   * @return the result as a <code>Node</code>
   * @see #xpathNodeSet(String)
   * @see #xpathNode(String)
   * @see #xpathBoolean(String)
   * @see #xpathNumber(String)
   * @since 1.1
   */
  public String xpathString(String expression)
  throws XPathExpressionException
  {
    return (String)xpath(expression, XPathConstants.STRING);
  }
  
  /**
   * Evaluate an XPath expression in the context of the response text and
   * return the result as a boolean.
   *
   * @exception XPathExpressionException if expression cannot be evaluated.
   * @return the result as a <code>Node</code>
   * @see #xpathNodeSet(String)
   * @see #xpathNode(String)
   * @see #xpathString(String)
   * @see #xpathNumber(String)
   * @since 1.1
   */
  public Boolean xpathBoolean(String expression)
  throws XPathExpressionException
  {
    return (Boolean)xpath(expression, XPathConstants.BOOLEAN);
  }
  
  /**
   * Evaluate an XPath expression in the context of the response text and
   * return the result as a number.
   *
   * @exception XPathExpressionException if expression cannot be evaluated.
   * @return the result as a <code>Node</code>
   * @see #xpathNodeSet(String)
   * @see #xpathNode(String)
   * @see #xpathString(String)
   * @see #xpathBoolean(String)
   * @since 1.1
   */
  public Double xpathNumber(String expression)
  throws XPathExpressionException
  {
    return (Double)xpath(expression, XPathConstants.NUMBER);
  }
  
  private Object xpath(String expression, QName returnType)
  throws XPathExpressionException
  {
    Matcher matcher = STRIP_XHTML_XMLNS.matcher(getText());
    String text = matcher.replaceAll("html xmlns=\"\"");
    Reader reader = new StringReader(text);
    
    InputSource inputsource = new InputSource(reader);
    XPath xpath = XPathFactory.newInstance().newXPath();
    return xpath.evaluate(expression, inputsource, returnType);
  }
  
  
  /**
   * Evaluate an XPath expression in the provided context object and
   * return the result as a list of DOM nodes.
   * <p>More information about XPath can be found in the <a
   * href="http://www.w3.org/TR/xpath">original specification</a> or in this
   * <a href="http://zvon.org/xxl/XMLTutorial/General/book.html">tutorial</a>.
   *
   * @exception XPathExpressionException if expression cannot be evaluated.
   * @return the result as a <code>NodeList</code>
   * @see #xpathNode(String, Object)
   * @see #xpathString(String, Object)
   * @see #xpathBoolean(String, Object)
   * @see #xpathNumber(String, Object)
   * @since 1.2
   */
  public NodeList xpathNodeSet(String expression, Object context)
  throws XPathExpressionException
  {
    return (NodeList)xpath(expression, context, XPathConstants.NODESET);
  }
  
  /**
   * Evaluate an XPath expression in the provided context object and
   * return the result as a DOM node.
   *
   * @exception XPathExpressionException if expression cannot be evaluated.
   * @return the result as a <code>Node</code>
   * @see #xpathNodeSet(String, Object)
   * @see #xpathString(String, Object)
   * @see #xpathBoolean(String, Object)
   * @see #xpathNumber(String, Object)
   * @since 1.2
   */
  public Node xpathNode(String expression, Object context)
  throws XPathExpressionException
  {
    return (Node)xpath(expression, context, XPathConstants.NODE);
  }
  
  /**
   * Evaluate an XPath expression in the provided context object and
   * return the result as a string.
   *
   * @exception XPathExpressionException if expression cannot be evaluated.
   * @return the result as a <code>Node</code>
   * @see #xpathNodeSet(String, Object)
   * @see #xpathNode(String, Object)
   * @see #xpathBoolean(String, Object)
   * @see #xpathNumber(String, Object)
   * @since 1.2
   */
  public String xpathString(String expression, Object context)
  throws XPathExpressionException
  {
    return (String)xpath(expression, context, XPathConstants.STRING);
  }
  
  /**
   * Evaluate an XPath expression in the provided context object and
   * return the result as a boolean.
   *
   * @exception XPathExpressionException if expression cannot be evaluated.
   * @return the result as a <code>Node</code>
   * @see #xpathNodeSet(String, Object)
   * @see #xpathNode(String, Object)
   * @see #xpathString(String, Object)
   * @see #xpathNumber(String, Object)
   * @since 1.2
   */
  public Boolean xpathBoolean(String expression, Object context)
  throws XPathExpressionException
  {
    return (Boolean)xpath(expression, context, XPathConstants.BOOLEAN);
  }
  
  /**
   * Evaluate an XPath expression in the provided context object and
   * return the result as a number.
   *
   * @exception XPathExpressionException if expression cannot be evaluated.
   * @return the result as a <code>Node</code>
   * @see #xpathNodeSet(String, Object)
   * @see #xpathNode(String, Object)
   * @see #xpathString(String, Object)
   * @see #xpathBoolean(String, Object)
   * @since 1.2
   */
  public Double xpathNumber(String expression, Object context)
  throws XPathExpressionException
  {
    return (Double)xpath(expression, context, XPathConstants.NUMBER);
  }

  private Object xpath(String expression, Object context, QName returnType)
  throws XPathExpressionException
  {
    XPath xpath = XPathFactory.newInstance().newXPath();
    return xpath.evaluate(expression, context, returnType);
  }
  
  /**
   * Validates the response as an XML document.
   *
   * @exception InvalidXmlException when the XML document isn't valid
   * @since 1.2
   */
  public void validateAsXml()
  throws InvalidXmlException
  {
    Set<String> errors = new LinkedHashSet<String>();
    new Jdk14Loader().loadFromString(getText(), false, errors);
    if (errors.size() > 0)
    {
      throw new InvalidXmlException(errors);
    }
  }
  
  public void print(Template template)
  throws EngineException
  {
    mTemplate = template;
    
    super.print(template);
  }
  
  protected void _setContentType(String contentType)
  {
    if (contentType == null)
    {
      mContentType = null;
      if (mHeaders != null)
      {
        mHeaders.removeHeader(HEADER_CONTENT_TYPE);
      }
    }
    else
    {
      // Look for encoding in contentType
      int i0 = contentType.indexOf(';');
      
      if (i0 > 0)
      {
        // Strip params off mimetype
        mContentType = contentType.substring(0, i0).trim();
        
        // Look for charset
        int i1 = contentType.indexOf("charset=", i0);
        if (i1 >= 0)
        {
          i1 += 8;
          int i2 = contentType.indexOf(' ', i1);
          mCharacterEncoding = (0 < i2)
            ? contentType.substring(i1, i2)
            : contentType.substring(i1);
          mCharacterEncoding = QuotedStringTokenizer.unquote(mCharacterEncoding);
        }
        else // No encoding in the params.
        {
          if (mCharacterEncoding != null)
          {
            // Add any previously set encoding.
            contentType += ";charset=" +
              QuotedStringTokenizer.quote(mCharacterEncoding, ";= ");
          }
        }
      }
      else // No encoding and no other params
      {
        mContentType = contentType;
        // Add any previously set encoding.
        if (mCharacterEncoding != null)
        {
          contentType += ";charset=" + QuotedStringTokenizer.quote(mCharacterEncoding, ";= ");
        }
      }
      
      setHeader(HEADER_CONTENT_TYPE, contentType);
    }
    
    setHeader(HEADER_CONTENT_TYPE, contentType);
  }
  
  protected String _getCharacterEncoding()
  {
    return mCharacterEncoding;
  }
  
  protected void _setContentLength(int length)
  {
    setIntHeader(HEADER_CONTENT_LENGTH, length);
  }
  
  protected void _sendRedirect(String location)
  {
    clearBuffer();
    
    // TODO : correctly handle absolute and relative locations
    setStatus(SC_302_MOVED_TEMPORARILY);
    setHeader(HEADER_LOCATION, location);
    
    // complete
  }
  
  protected OutputStream _getOutputStream() throws IOException
  {
    return mMockOutputStream;
  }
  
  public Response createEmbeddedResponse(String valueId, String differentiator)
  {
    MockResponse response = new MockResponse(mMockConversation, getRequest(), true);
    mEmbeddedResponses.put(valueId, response);
    return response;
  }
    
  public void addCookie(Cookie cookie)
  {
    mNewCookies.put(MockConversation.buildCookieId(cookie), cookie);
    mMockConversation.addCookie(cookie);
  }
  
  /**
   * Retrieves the embedded responses that were processed.
   *
   * @return the collection of embedded responses; or
   * <p>an empty collection if no embedded elements were processed
   * @since 1.4
   */
  public List<MockResponse> getEmbeddedResponses()
  {
    return new ArrayList<MockResponse>(mEmbeddedResponses.values());
  }
  
  /**
   * Retrieves the embedded response that corresponds to a specific
   * value in the embedding template.
   *
   * @param valueId the template value in which the embedded element has
   * been processed, the "ELEMENT:" prefix is optional and will be
   * automatically added if you leave it off
   * @return the embedded responses that corresponds to the value; or
   * <p><code>null</code> if no such value could be found
   * @since 1.4
   */
  public MockResponse getEmbeddedResponse(String valueId)
  {
    if (valueId != null &&
      !valueId.startsWith(ElementContext.PREFIX_ELEMENT))
    {
      valueId = ElementContext.PREFIX_ELEMENT+valueId;
    }
    return mEmbeddedResponses.get(valueId);
  }
  
  /**
   * Retrieves the list of cookies that have been added in this reponse.
   *
   * @return the list of added cookies; or
   * <p>an empty list if no cookies have been added
   * @since 1.1
   */
  public List<String> getNewCookieNames()
  {
    ArrayList<String> names = new ArrayList<String>();
    for (Cookie cookie : mNewCookies.values())
    {
      if (!names.contains(cookie.getName()))
      {
        names.add(cookie.getName());
      }
    }
    
    return names;
  }
  
  /**
   * Returns the value of the specified response header as a long value that
   * represents a Date object. Use this method with headers that contain
   * dates.
   * <p>The date is returned as the number of milliseconds since January 1,
   * 1970 GMT. The header name is case insensitive.
   * <p>If the response did not have a header of the specified name, this
   * method returns <code>-1</code>. If the header can't be converted to a
   * date, the method throws an <code>IllegalArgumentException</code>.
   *
   * @param name the name of the header
   * @exception java.lang.IllegalArgumentException if the header value can't
   * be converted to a date
   * @return a <code>long</code> value representing the date specified in
   * the header expressed as the number of milliseconds since January 1,
   * 1970 GMT; or
   * <p><code>-1</code> if the named header was not included with the
   * response
   * @since 1.1
   */
  public long getDateHeader(String name)
  {
    return mHeaders.getDateHeader(name);
  }
  
  /**
   * Returns the value of the specified response header as a
   * <code>String</code>. If the reponse did not include a header of the
   * specified name, this method returns <code>null</code>. The header name
   * is case insensitive. You can use this method with any response header.
   *
   * @param name the name of the header
   * @return a <code>String</code> containing the value of the response
   * header; or
   * <p><code>null</code> if the response does not have a header of that
   * name
   * @since 1.1
   */
  public String getHeader(String name)
  {
    return mHeaders.getHeader(name);
  }
  
  /**
   * Returns the value of the specified response header as a
   * <code>String</code>. If the reponse did not include a header of the
   * specified name, this method returns <code>null</code>. The header name
   * is case insensitive. You can use this method with any response header.
   *
   * @return a <code>Collection</code> of all the header names sent with
   * this response; or
   * <p>if the response has no headers, an empty <code>Collection</code>
   * @since 1.1
   */
  public Collection getHeaderNames()
  {
    return mHeaders.getHeaderNames();
  }
  
  /**
   * Returns all the values of the specified response header as an
   * <code>Collection</code> of <code>String</code> objects.
   * <p>If the response did not include any headers of the specified name,
   * this method returns an empty <code>Collection</code>. The header name
   * is case insensitive. You can use this method with any response header.
   *
   * @param name the name of the header
   * @return a <code>Collection</code> containing the values of the response
   * header; or
   * <p>if the response does not have any headers of that name return an
   * empty <code>Collection</code>
   * @since 1.1
   */
  public Collection getHeaders(String name)
  {
    return mHeaders.getHeaders(name);
  }
  
  /**
   * Returns the value of the specified response header as an
   * <code>int</code>. If the response does not have a header of the
   * specified name, this method returns <code>-1</code>. If the header
   * cannot be converted to an <code>integer</code>, this method throws a
   * <code>NumberFormatException</code>.
   * <p>The header name is case insensitive.
   *
   * @param name the name of the header
   * @return an <code>integer</code> expressing the value of the response
   * header; or
   * <p><code>-1</code> if the response doesn't have a header of this name
   * @exception java.lang.NumberFormatException if the header value can't be
   * converted to an <code>int</code>
   * @since 1.1
   */
  public int getIntHeader(String name)
  {
    return mHeaders.getIntHeader(name);
  }
  
  public void addHeader(String name, String value)
  {
    mHeaders.addHeader(name, value);
  }
  
  public void addDateHeader(String name, long date)
  {
    mHeaders.addDateHeader(name, date);
  }
  
  public void addIntHeader(String name, int integer)
  {
    mHeaders.addIntHeader(name, integer);
  }
  
  public boolean containsHeader(String name)
  {
    return mHeaders.containsHeader(name);
  }
  
  public void setDateHeader(String name, long date)
  {
    mHeaders.setDateHeader(name, date);
  }
  
  public void setHeader(String name, String value)
  {
    mHeaders.setHeader(name, value);
  }
  
  public void setIntHeader(String name, int value)
  {
    mHeaders.setIntHeader(name, value);
  }
  
  /**
   * Removes a response header with the given name.
   *
   * @param name the name of the header to remove
   * @since 1.1
   */
  public void removeHeader(String name)
  {
    mHeaders.removeHeader(name);
  }
  
  /**
   * Returns the status code of this response.
   *
   * @return an <code>integer</code> expressing the status code of this
   * response
   * @since 1.2
   */
  public int getStatus()
  {
    return mStatus;
  }
  
  /**
   * Returns the error reason of this response.
   *
   * @return an <code>String</code> expressing the reason of this response error
   * @since 1.2
   */
  public String getReason()
  {
    return mReason;
  }
  
  public void setStatus(int statusCode)
  {
    mStatus = statusCode;
  }
  
  public void sendError(int statusCode)
  throws EngineException
  {
    sendError(statusCode, null);
  }
  
  public void sendError(int statusCode, String message)
  throws EngineException
  {
    mStatus = statusCode;
    mReason = message;
  }
  
  public String encodeURL(String url)
  {
    MockRequest request = (MockRequest)getRequest();
    
    // should not encode if cookies in evidence
    if (null == request ||
      request.isRequestedSessionIdFromCookie())
    {
      return url;
    }
    
    // get session
    HttpSession session = getRequest().getSession(false);
    
    // no session or no url
    if (null == session || null == url)
    {
      return url;
    }
    
    // invalid session
    String id = session.getId();
    if (null == id)
    {
      return url;
    }
    
    // Already encoded
    int prefix = url.indexOf(MockConversation.SESSION_URL_PREFIX);
    if (prefix != -1)
    {
      int suffix = url.indexOf("?", prefix);
      if (suffix < 0)
      {
        suffix = url.indexOf("#", prefix);
      }
      
      if (suffix <= prefix)
      {
        return url.substring(0, prefix + MockConversation.SESSION_URL_PREFIX.length()) + id;
      }
      
      return url.substring(0, prefix + MockConversation.SESSION_URL_PREFIX.length()) + id + url.substring(suffix);
    }
    
    // edit the session
    int suffix = url.indexOf('?');
    if (suffix < 0)
    {
      suffix = url.indexOf('#');
    }
    
    if (suffix < 0)
    {
      return url + MockConversation.SESSION_URL_PREFIX + id;
    }
    
    return url.substring(0, suffix) + MockConversation.SESSION_URL_PREFIX + id + url.substring(suffix);
  }
  
  public void setLocale(Locale locale)
  {
    if (null == locale)
    {
      return;
    }
    
    mLocale = locale;
    setHeader(HEADER_CONTENT_LANGUAGE, locale.toString().replace('_', '-'));
  }
  
  public Locale getLocale()
  {
    if (null == mLocale)
    {
      return Locale.getDefault();
    }
    
    return mLocale;
  }
  
  public PrintWriter getWriter()
  throws IOException
  {
    mMockOutputStream.flush();
    
    /* if there is no writer yet */
    if (mMockWriter == null)
    {
      /* get encoding from Content-Type header */
      String encoding = getCharacterEncoding();
      
      if (encoding == null)
      {
        encoding = StringUtils.ENCODING_ISO_8859_1;
      }
      
      setCharacterEncoding(encoding);
      
      /* construct Writer using correct encoding */
      mMockWriter = new PrintWriter(new OutputStreamWriter(mMockOutputStream, encoding));
    }
    
    return mMockWriter;
  }
  
  private void setCharacterEncoding(String encoding)
  {
    if (null == encoding)
    {
      // Clear any encoding.
      if (mCharacterEncoding != null)
      {
        mCharacterEncoding = null;
        setHeader(HEADER_CONTENT_TYPE, mContentType);
      }
    }
    else
    {
      // No, so just add this one to the mimetype
      mCharacterEncoding = encoding;
      if (mContentType != null)
      {
        setHeader(HEADER_CONTENT_TYPE,
              mContentType + ";charset=" +
              QuotedStringTokenizer.quote(mCharacterEncoding, ";= "));
      }
    }
  }
  
  public HttpServletResponse getHttpServletResponse()
  {
    return null;
  }
  
// ========================================================================
// Copyright 1999-2004 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========================================================================
  
  /* ------------------------------------------------------------ */
  /**
   * StringTokenizer with Quoting support. This class is a copy of the
   * java.util.StringTokenizer API and the behaviour is the same, except
   * that single and doulbe quoted string values are recognized. Delimiters
   * within quotes are not considered delimiters. Quotes can be escaped with
   * '\'.
   *
   * @see java.util.StringTokenizer
   * @author Greg Wilkins (gregw)
   */
  static class QuotedStringTokenizer
  extends StringTokenizer
  {
    private final static String __delim="\t\n\r";
    private String _string;
    private String _delim = __delim;
    private boolean _returnQuotes=false;
    private boolean _returnTokens=false;
    private StringBuilder _token;
    private boolean _hasToken=false;
    private int _i=0;
    private int _lastStart=0;
    
    /* ------------------------------------------------------------ */
    public QuotedStringTokenizer(String str,
                   String delim,
                   boolean returnTokens,
                   boolean returnQuotes)
    {
      super("");
      _string = str;
      if (delim != null)
        _delim = delim;
      _returnTokens = returnTokens;
      _returnQuotes = returnQuotes;
      
      if (_delim.indexOf('\'') >= 0 ||
        _delim.indexOf('"') >= 0)
        throw new Error("Can't use quotes as delimiters: " + _delim);
      
      _token = new StringBuilder(_string.length() > 1024 ? 512: _string.length() / 2);
    }
    
    /* ------------------------------------------------------------ */
    public QuotedStringTokenizer(String str,
                   String delim,
                   boolean returnTokens)
    {
      this(str, delim, returnTokens, false);
    }
    
    /* ------------------------------------------------------------ */
    public QuotedStringTokenizer(String str,
                   String delim)
    {
      this(str, delim, false, false);
    }
    
    /* ------------------------------------------------------------ */
    public QuotedStringTokenizer(String str)
    {
      this(str, null, false, false);
    }
    
    /* ------------------------------------------------------------ */
    public boolean hasMoreTokens()
    {
      // Already found a token
      if (_hasToken)
        return true;
      
      _lastStart = _i;
      
      int state=0;
      boolean escape=false;
      while (_i < _string.length())
      {
        char c=_string.charAt(_i++);
        
        switch (state)
        {
          case 0: // Start
            if (_delim.indexOf(c) >= 0)
            {
              if (_returnTokens)
              {
                _token.append(c);
                return _hasToken = true;
              }
            }
            else if (c == '\'')
            {
              if (_returnQuotes)
                _token.append(c);
              state = 2;
            }
            else if (c == '\"')
            {
              if (_returnQuotes)
                _token.append(c);
              state = 3;
            }
            else
            {
              _token.append(c);
              _hasToken = true;
              state = 1;
            }
            continue;
            
          case 1: // Token
            _hasToken = true;
            if (_delim.indexOf(c) >= 0)
            {
              if (_returnTokens)
                _i--;
              return _hasToken;
            }
            else if (c == '\'')
            {
              if (_returnQuotes)
                _token.append(c);
              state = 2;
            }
            else if (c == '\"')
            {
              if (_returnQuotes)
                _token.append(c);
              state = 3;
            }
            else
              _token.append(c);
            continue;
            
            
          case 2: // Single Quote
            _hasToken = true;
            if (escape)
            {
              escape = false;
              _token.append(c);
            }
            else if (c == '\'')
            {
              if (_returnQuotes)
                _token.append(c);
              state = 1;
            }
            else if (c == '\\')
            {
              if (_returnQuotes)
                _token.append(c);
              escape = true;
            }
            else
              _token.append(c);
            continue;
            
            
          case 3: // Double Quote
            _hasToken = true;
            if (escape)
            {
              escape = false;
              _token.append(c);
            }
            else if (c == '\"')
            {
              if (_returnQuotes)
                _token.append(c);
              state = 1;
            }
            else if (c == '\\')
            {
              if (_returnQuotes)
                _token.append(c);
              escape = true;
            }
            else
              _token.append(c);
            continue;
        }
      }
      
      return _hasToken;
    }
    
    /* ------------------------------------------------------------ */
    public String nextToken()
    throws NoSuchElementException
    {
      if (!hasMoreTokens() || _token == null)
        throw new NoSuchElementException();
      String t=_token.toString();
      _token.setLength(0);
      _hasToken = false;
      return t;
    }
    
    /* ------------------------------------------------------------ */
    public String nextToken(String delim)
    throws NoSuchElementException
    {
      _delim = delim;
      _i = _lastStart;
      _token.setLength(0);
      _hasToken = false;
      return nextToken();
    }
    
    /* ------------------------------------------------------------ */
    public boolean hasMoreElements()
    {
      return hasMoreTokens();
    }
    
    /* ------------------------------------------------------------ */
    public Object nextElement()
    throws NoSuchElementException
    {
      return nextToken();
    }
    
    /* ------------------------------------------------------------ */
    /**
     * Not implemented.
     */
    public int countTokens()
    {
      return -1;
    }
    
    
    /* ------------------------------------------------------------ */
    /**
     * Quote a string. The string is quoted only if quoting is required
     * due to embeded delimiters, quote characters or the empty string.
     *
     * @param s The string to quote.
     * @return quoted string
     */
    public static String quote(String s, String delim)
    {
      if (s == null)
        return null;
      if (s.length() == 0)
        return "\"\"";
      
      
      for (int i=0;i < s.length();i++)
      {
        char c = s.charAt(i);
        if (c == '"' ||
          c == '\\' ||
          c == '\'' ||
          delim.indexOf(c) >= 0)
        {
          StringBuilder b=new StringBuilder(s.length() + 8);
          quote(b, s);
          return b.toString();
        }
      }
      
      return s;
    }
    
    /* ------------------------------------------------------------ */
    /**
     * Quote a string into a StringBuilder.
     *
     * @param buf The StringBuilder
     * @param s The String to quote.
     */
    public static void quote(StringBuilder buf, String s)
    {
      buf.append('"');
      for (int i=0;i < s.length();i++)
      {
        char c = s.charAt(i);
        if (c == '"')
        {
          buf.append("\\\"");
          continue;
        }
        if (c == '\\')
        {
          buf.append("\\\\");
          continue;
        }
        buf.append(c);
        continue;
      }
      buf.append('"');
    }
    
    /* ------------------------------------------------------------ */
    /**
     * Unquote a string.
     *
     * @param s The string to unquote.
     * @return quoted string
     */
    public static String unquote(String s)
    {
      if (s == null)
        return null;
      if (s.length() < 2)
        return s;
      
      char first=s.charAt(0);
      char last=s.charAt(s.length() - 1);
      if (first != last || (first != '"' && first != '\''))
        return s;
      
      StringBuilder b=new StringBuilder(s.length() - 2);
      boolean quote=false;
      for (int i=1;i < s.length() - 1;i++)
      {
        char c = s.charAt(i);
        
        if (c == '\\' && !quote)
        {
          quote = true;
          continue;
        }
        quote = false;
        b.append(c);
      }
      
      return b.toString();
    }
  }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.