Package org.apache.wicket.protocol.http.portlet

Source Code of org.apache.wicket.protocol.http.portlet.WicketResponseState

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
package org.apache.wicket.protocol.http.portlet;

import java.io.ByteArrayOutputStream;
import java.io.CharArrayWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import javax.portlet.MimeResponse;
import javax.portlet.PortletRequest;
import javax.portlet.PortletResponse;
import javax.portlet.ResourceResponse;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.Cookie;

import org.apache.wicket.RequestContext;
import org.apache.wicket.settings.IRequestCycleSettings;

/**
* Temporarily holds the current state of a Wicket response when invoked from WicketPortlet: buffer,
* headers, state and the redirect location to be processed afterwards within WicketPortlet
*
* @author Ate Douma
*/
public class WicketResponseState
{
  private static class CharArrayWriterBuffer extends CharArrayWriter
  {
    public char[] getBuffer()
    {
      return buf;
    }

    public int getCount()
    {
      return count;
    }
  }

  private final boolean isActionResponse;
  private final boolean isEventResponse;
  private final boolean isRenderResponse;
  private final boolean isResourceResponse;
  private final boolean isMimeResponse;
  private final boolean isStateAwareResponse;
  private final Locale defaultLocale;
  private final PortletResponse response;
  private boolean flushed;

  private ByteArrayOutputStream byteOutputBuffer;
  private CharArrayWriterBuffer charOutputBuffer;
  private ServletOutputStream outputStream;
  private PrintWriter printWriter;
  private HashMap<String, ArrayList<String>> headers;
  private ArrayList<Cookie> cookies;
  private boolean committed;
  private boolean hasStatus;
  private boolean hasError;
  private Locale locale;
  private boolean setContentTypeAfterEncoding;
  private boolean closed;
  private String characterEncoding;
  private int contentLength = -1;
  private String contentType;
  private int statusCode;

  /**
   * FIXME javadoc
   *
   * Stores the effective wicket url which is used by {@link WicketPortlet} in the view phase to
   * request a render from wicket core.
   *
   * @see IRequestCycleSettings#REDIRECT_TO_RENDER
   * @see WicketFilterPortletHelper#initFilter
   */
  private String redirectLocation;


  public WicketResponseState(PortletRequest request, PortletResponse response)
  {
    String lifecyclePhase = (String)request.getAttribute(PortletRequest.LIFECYCLE_PHASE);
    isActionResponse = PortletRequest.ACTION_PHASE.equals(lifecyclePhase);
    isEventResponse = PortletRequest.EVENT_PHASE.equals(lifecyclePhase);
    isRenderResponse = PortletRequest.RENDER_PHASE.equals(lifecyclePhase);
    isResourceResponse = PortletRequest.RESOURCE_PHASE.equals(lifecyclePhase);
    isStateAwareResponse = isActionResponse || isEventResponse;
    isMimeResponse = isRenderResponse || isResourceResponse;
    this.response = response;
    defaultLocale = isMimeResponse ? ((MimeResponse)response).getLocale() : null;
  }

  private ArrayList<String> getHeaderList(String name, boolean create)
  {
    if (headers == null)
    {
      headers = new HashMap<String, ArrayList<String>>();
    }
    ArrayList<String> headerList = headers.get(name);
    if (headerList == null && create)
    {
      headerList = new ArrayList<String>();
      headers.put(name, headerList);
    }
    return headerList;
  }

  private void failIfCommitted()
  {
    if (committed)
    {
      throw new IllegalStateException("Response is already committed");
    }
  }

  public boolean isActionResponse()
  {
    return isActionResponse;
  }

  public boolean isEventResponse()
  {
    return isEventResponse;
  }

  public boolean isRenderResponse()
  {
    return isRenderResponse;
  }

  public boolean isResourceResponse()
  {
    return isResourceResponse;
  }

  public boolean isMimeResponse()
  {
    return isMimeResponse;
  }

  public boolean isStateAwareResponse()
  {
    return isStateAwareResponse;
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.servlet.http.HttpServletResponseWrapper#addCookie(javax.servlet.http.Cookie)
   */
  public void addCookie(Cookie cookie)
  {
    if (!committed)
    {
      if (cookies == null)
      {
        cookies = new ArrayList<Cookie>();
      }
      cookies.add(cookie);
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.servlet.http.HttpServletResponseWrapper#addDateHeader(java.lang.String, long)
   */
  public void addDateHeader(String name, long date)
  {
    addHeader(name, Long.toString(date));
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.servlet.http.HttpServletResponseWrapper#addHeader(java.lang.String,
   * java.lang.String)
   */
  public void addHeader(String name, String value)
  {
    if (isMimeResponse && !committed)
    {
      getHeaderList(name, true).add(value);
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.servlet.http.HttpServletResponseWrapper#addIntHeader(java.lang.String, int)
   */
  public void addIntHeader(String name, int value)
  {
    addHeader(name, Integer.toString(value));
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.servlet.http.HttpServletResponseWrapper#containsHeader(java.lang.String)
   */
  public boolean containsHeader(String name)
  {
    // Note: Portlet Spec 2.0 demands this to always return false...
    return isMimeResponse && getHeaderList(name, false) != null;
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.servlet.http.HttpServletResponseWrapper#sendError(int, java.lang.String)
   */
  public void sendError(int errorCode, String errorMessage) throws IOException
  {
    failIfCommitted();
    committed = true;
    closed = true;
    hasError = true;
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.servlet.http.HttpServletResponseWrapper#sendError(int)
   */
  public void sendError(int errorCode) throws IOException
  {
    sendError(errorCode, null);
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.servlet.http.HttpServletResponseWrapper#sendRedirect(java.lang.String)
   */
  public void sendRedirect(String redirectLocation) throws IOException
  {
    if (isActionResponse || isMimeResponse)
    {
      failIfCommitted();
      closed = true;
      committed = true;

      if (isMimeResponse)
      {
        RequestContext rc = RequestContext.get();
        if (rc instanceof PortletRequestContext)
        {
          String wicketUrl = ((PortletRequestContext)rc).getLastEncodedPath(redirectLocation);
          if (wicketUrl != null)
          {
            redirectLocation = wicketUrl;
          }
          else
          {
            String contextPath = ((PortletRequestContext)rc).getPortletRequest()
              .getContextPath();
            if (redirectLocation.startsWith(contextPath + "/"))
            {
              redirectLocation = redirectLocation.substring(contextPath.length());
              if (redirectLocation.length() == 0)
              {
                redirectLocation = "/";
              }
            }
          }
        }
      }
      this.redirectLocation = redirectLocation;
    }
  }

  public String getRedirectLocation()
  {
    return redirectLocation;
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.servlet.http.HttpServletResponseWrapper#setDateHeader(java.lang.String, long)
   */
  public void setDateHeader(String name, long date)
  {
    setHeader(name, Long.toString(date));
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.servlet.http.HttpServletResponseWrapper#setHeader(java.lang.String,
   * java.lang.String)
   */
  public void setHeader(String name, String value)
  {
    if (isMimeResponse && !committed)
    {
      ArrayList<String> headerList = getHeaderList(name, true);
      headerList.clear();
      headerList.add(value);
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.servlet.http.HttpServletResponseWrapper#setIntHeader(java.lang.String, int)
   */
  public void setIntHeader(String name, int value)
  {
    setHeader(name, Integer.toString(value));
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.servlet.http.HttpServletResponseWrapper#setStatus(int, java.lang.String)
   */
  public void setStatus(int statusCode, String message)
  {
    throw new UnsupportedOperationException("This method is deprecated and no longer supported");
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.servlet.http.HttpServletResponseWrapper#setStatus(int)
   */
  public void setStatus(int statusCode)
  {
    if (!committed)
    {
      this.statusCode = statusCode;
      hasStatus = true;
      resetBuffer();
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.servlet.ServletResponseWrapper#flushBuffer()
   */
  public void flushBuffer() throws IOException
  {
    if (isMimeResponse && !closed)
    {
      committed = true;
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.servlet.ServletResponseWrapper#getBufferSize()
   */
  public int getBufferSize()
  {
    return isMimeResponse ? Integer.MAX_VALUE : 0;
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.servlet.ServletResponseWrapper#getCharacterEncoding()
   */
  public String getCharacterEncoding()
  {
    return isMimeResponse ? characterEncoding != null ? characterEncoding : "ISO-8859-1" : null;
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.servlet.ServletResponseWrapper#getContentType()
   */
  public String getContentType()
  {
    return isMimeResponse ? contentType : null;
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.servlet.ServletResponseWrapper#getLocale()
   */
  public Locale getLocale()
  {
    return isMimeResponse ? locale != null ? locale : defaultLocale : null;
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.servlet.ServletResponseWrapper#getOutputStream()
   */
  public ServletOutputStream getOutputStream() throws IOException
  {
    if (isStateAwareResponse)
    {
      // Portlet Spec 2.0 requires Portlet Container to supply a "no-op" OutputStream object
      // so delegate back to current PortletServletResponseWrapper to return that one
      return null;
    }
    if (outputStream == null)
    {
      if (printWriter != null)
      {
        throw new IllegalStateException(
          "getWriter() has already been called on this response");
      }
      byteOutputBuffer = new ByteArrayOutputStream();
      outputStream = new ServletOutputStream()
      {
        @Override
        public void write(int b) throws IOException
        {
          if (!closed)
          {
            byteOutputBuffer.write(b);
            if (contentLength > -1 && byteOutputBuffer.size() >= contentLength)
            {
              committed = true;
              closed = true;
            }
          }
        }
      };
    }
    return outputStream;
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.servlet.ServletResponseWrapper#getWriter()
   */
  public PrintWriter getWriter() throws IOException
  {
    if (isStateAwareResponse)
    {
      // Portlet Spec 2.0 requires Portlet Container to supply a "no-op" PrintWriter object
      // so delegate back to current PortletServletResponseWrapper to return that one
      return null;
    }
    if (printWriter == null)
    {
      if (outputStream != null)
      {
        throw new IllegalStateException(
          "getOutputStream() has already been called on this response");
      }
      charOutputBuffer = new CharArrayWriterBuffer();
      printWriter = new PrintWriter(charOutputBuffer);
    }
    return printWriter;
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.servlet.ServletResponseWrapper#isCommitted()
   */
  public boolean isCommitted()
  {
    return isMimeResponse && committed;
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.servlet.ServletResponseWrapper#reset()
   */
  public void reset()
  {
    resetBuffer(); // fails if committed
    headers = null;
    cookies = null;
    hasStatus = false;
    contentLength = -1;
    if (printWriter == null)
    {
      contentType = null;
      characterEncoding = null;
      locale = null;
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.servlet.ServletResponseWrapper#resetBuffer()
   */
  public void resetBuffer()
  {
    failIfCommitted();
    if (outputStream != null)
    {
      try
      {
        outputStream.flush();
      }
      catch (Exception e)
      {
      }
      byteOutputBuffer.reset();
    }
    else if (printWriter != null)
    {
      printWriter.flush();
      charOutputBuffer.reset();
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.servlet.ServletResponseWrapper#setBufferSize(int)
   */
  public void setBufferSize(int size)
  {
    // ignore
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.servlet.ServletResponseWrapper#setCharacterEncoding(java.lang.String)
   */
  public void setCharacterEncoding(String charset)
  {
    if (isResourceResponse && charset != null && !committed && printWriter == null)
    {
      characterEncoding = charset;
      setContentTypeAfterEncoding = false;
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.servlet.ServletResponseWrapper#setContentLength(int)
   */
  public void setContentLength(int len)
  {
    if (isResourceResponse && !committed && printWriter == null && len > 0)
    {
      contentLength = len;
      if (outputStream != null)
      {
        try
        {
          outputStream.flush();
        }
        catch (Exception e)
        {
        }
      }
      if (!closed && byteOutputBuffer != null && byteOutputBuffer.size() >= len)
      {
        committed = true;
        closed = true;
      }
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.servlet.ServletResponseWrapper#setContentType(java.lang.String)
   */
  public void setContentType(String type)
  {
    if (isMimeResponse && !committed)
    {
      contentType = type;
      setContentTypeAfterEncoding = false;
      if (printWriter == null)
      {
        // TODO: parse possible encoding for better return value from getCharacterEncoding()
      }
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.servlet.ServletResponseWrapper#setLocale(java.util.Locale)
   */
  public void setLocale(Locale locale)
  {
    if (isResourceResponse && !committed)
    {
      this.locale = locale;
    }
  }

  public void clear()
  {
    printWriter = null;
    byteOutputBuffer = null;
    charOutputBuffer = null;
    outputStream = null;
    printWriter = null;
    headers = null;
    cookies = null;
    committed = false;
    hasStatus = false;
    hasError = false;
    locale = null;
    setContentTypeAfterEncoding = false;
    closed = false;
    characterEncoding = null;
    contentLength = -1;
    contentType = null;
    statusCode = 0;
    redirectLocation = null;
  }

  public void flush() throws IOException
  {
    if (flushed)
    {
      throw new IllegalStateException("Already flushed");
    }
    flushed = true;

    if (cookies != null)
    {
      for (Cookie cookie : cookies)
      {
        response.addProperty(cookie);
      }
      cookies = null;
    }
    if (isMimeResponse)
    {
      MimeResponse mimeResponse = (MimeResponse)response;
      ResourceResponse resourceResponse = isResourceResponse ? (ResourceResponse)response
        : null;

      if (locale != null)
      {
        try
        {
          resourceResponse.setLocale(locale);
        }
        catch (UnsupportedOperationException usoe)
        {
          // TODO: temporary "fix" for JBoss Portal which doesn't yet support this
          // (although required by the Portlet API 2.0!)
        }
      }

      if (contentType != null)
      {
        if (characterEncoding != null)
        {
          if (setContentTypeAfterEncoding)
          {
            resourceResponse.setCharacterEncoding(characterEncoding);
            resourceResponse.setContentType(contentType);
          }
          else
          {
            resourceResponse.setContentType(contentType);
            resourceResponse.setCharacterEncoding(characterEncoding);
          }
        }
        else
        {
          mimeResponse.setContentType(contentType);
        }
      }
      else if (characterEncoding != null)
      {
        resourceResponse.setCharacterEncoding(characterEncoding);
      }

      if (headers != null)
      {
        for (Map.Entry<String, ArrayList<String>> entry : headers.entrySet())
        {
          for (String value : entry.getValue())
          {
            mimeResponse.addProperty(entry.getKey(), value);
          }
        }
        headers = null;
      }
      if (isResourceResponse && hasStatus)
      {
        resourceResponse.setProperty(ResourceResponse.HTTP_STATUS_CODE,
          Integer.toString(statusCode));
      }
      if (isResourceResponse && contentLength > -1)
      {
        try
        {
          resourceResponse.setContentLength(contentLength);
        }
        catch (UnsupportedOperationException usoe)
        {
          // TODO: temporary "fix" for JBoss Portal which doesn't yet support this
          // (although required by the Portlet API 2.0!)
        }
      }
      if (!hasError && redirectLocation == null)
      {
        if (outputStream != null)
        {
          if (!closed)
          {
            outputStream.flush();
          }
          OutputStream realOutputStream = mimeResponse.getPortletOutputStream();
          int len = byteOutputBuffer.size();
          if (contentLength > -1 && contentLength < len)
          {
            len = contentLength;
          }
          if (len > 0)
          {
            realOutputStream.write(byteOutputBuffer.toByteArray(), 0, len);
          }
          outputStream.close();
          outputStream = null;
          byteOutputBuffer = null;
        }
        else if (printWriter != null)
        {
          if (!closed)
          {
            printWriter.flush();
            if (charOutputBuffer.getCount() > 0)
            {
              mimeResponse.getWriter().write(charOutputBuffer.getBuffer(), 0,
                charOutputBuffer.getCount());
            }
            printWriter.close();

            printWriter = null;
            charOutputBuffer = null;
          }
        }
      }
    }
  }
}
TOP

Related Classes of org.apache.wicket.protocol.http.portlet.WicketResponseState

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.