Package com.liferay.faces.util.application

Source Code of com.liferay.faces.util.application.ResourceHandlerWrapperBase

/**
* Copyright (c) 2000-2014 Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.faces.util.application;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.util.Iterator;
import java.util.Map;

import javax.faces.application.Resource;
import javax.faces.application.ResourceHandler;
import javax.faces.application.ResourceHandlerWrapper;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletResponse;

import com.liferay.faces.util.io.Filterable;
import com.liferay.faces.util.io.ResourceOutputStream;
import com.liferay.faces.util.logging.Logger;
import com.liferay.faces.util.logging.LoggerFactory;


/**
* This is an abstract class provides base functionality for a {@link ResourceHandler} that can write the contents of a
* {@link Resource} to the underlying response.
*
* @author  Neil Griffin
*/
public class ResourceHandlerWrapperBase extends ResourceHandlerWrapper {

  // Public Constants
  public static final int DEFAULT_BUFFER_SIZE = 1024;

  // Logger
  private static final Logger logger = LoggerFactory.getLogger(ResourceHandlerWrapperBase.class);

  // Private Data Members
  private ResourceHandler wrappedResourceHandler;

  public ResourceHandlerWrapperBase(ResourceHandler resourceHandler) {
    this.wrappedResourceHandler = resourceHandler;
  }

  protected void handleResource(FacesContext facesContext, Resource resource) throws IOException {

    ExternalContext externalContext = facesContext.getExternalContext();
    String resourceName = resource.getResourceName();
    String libraryName = resource.getLibraryName();
    boolean needsUpdate = resource.userAgentNeedsUpdate(facesContext);

    if (!isAbleToSetHttpStatusCode(facesContext)) {

      if (!needsUpdate) {
        needsUpdate = true;
        logger.debug(
          "Unable to set the status code to HttpServletResponse.SC_NOT_MODIFIED ({0}) for resourceName=[{1}]",
          HttpServletResponse.SC_NOT_MODIFIED, resourceName);
      }
    }

    if (needsUpdate) {
      logger.trace("Handling - Resource was either modified or has not yet been downloaded.");

      ReadableByteChannel readableByteChannel = null;
      WritableByteChannel writableByteChannel = null;
      InputStream inputStream = null;
      int bufferSize = getBufferSize(facesContext);
      ByteBuffer byteBuffer = ByteBuffer.allocate(bufferSize);

      try {

        // Open an input stream in order to read the resource's contents/data.
        inputStream = resource.getInputStream();

        if (inputStream != null) {

          // Set the response headers by copying them from the resource.
          Map<String, String> responseHeaderMap = resource.getResponseHeaders();

          if (responseHeaderMap != null) {
            Iterator<Map.Entry<String, String>> itr = responseHeaderMap.entrySet().iterator();

            while (itr.hasNext()) {
              Map.Entry<String, String> mapEntry = itr.next();
              String name = mapEntry.getKey();
              String value = mapEntry.getValue();
              externalContext.setResponseHeader(name, value);

              if (logger.isDebugEnabled()) {

                // Surround with isDebugEnabled check in order to avoid unnecessary creation
                // of object array.
                logger.debug("Handling - COPIED resource header name=[{0}] value=[{1}]",
                  new Object[] { name, value });
              }
            }
          }

          // Set the response Content-Type header.
          String responseContentType = resource.getContentType();
          logger.trace("Handling - responseContentType=[{0}]", responseContentType);

          if (responseContentType != null) {
            externalContext.setResponseContentType(responseContentType);
          }

          // Rather than write the input stream directly to the response, write it to an
          // buffered output stream so that the length can be calculated for the
          // Content-Length header. See: http://issues.liferay.com/browse/FACES-1207
          ResourceOutputStream resourceOutputStream = getResourceOutputStream(resource, bufferSize);

          int responseContentLength = 0;
          readableByteChannel = Channels.newChannel(inputStream);
          writableByteChannel = Channels.newChannel(resourceOutputStream);

          int bytesRead = readableByteChannel.read(byteBuffer);

          if (logger.isTraceEnabled()) {

            // Surround with isTraceEnabled check in order to avoid unnecessary conversion of
            // int to String.
            logger.trace("Handling - bytesRead=[{0}]", Integer.toString(bytesRead));
          }

          int bytesWritten = 0;

          while (bytesRead != -1) {
            byteBuffer.rewind();
            byteBuffer.limit(bytesRead);

            do {
              bytesWritten += writableByteChannel.write(byteBuffer);
            }
            while (bytesWritten < responseContentLength);

            byteBuffer.clear();
            responseContentLength += bytesRead;
            bytesRead = readableByteChannel.read(byteBuffer);

            if (logger.isTraceEnabled()) {

              // Surround with isTraceEnabled check in order to avoid unnecessary conversion
              // of int to String.
              logger.trace("Handling - MORE bytesRead=[{0}]", Integer.toString(bytesRead));
            }
          }

          if (resourceOutputStream instanceof Filterable) {
            Filterable filterable = (Filterable) resourceOutputStream;
            filterable.filter();
          }

          responseContentLength = resourceOutputStream.size();

          // Now that we know how big the file is, set the response Content-Length header and the status.
          externalContext.setResponseContentLength(responseContentLength);
          externalContext.setResponseStatus(HttpServletResponse.SC_OK);

          // Set the response buffer size.
          externalContext.setResponseBufferSize(responseContentLength);

          if (logger.isTraceEnabled()) {

            // Surround with isTraceEnabled check in order to avoid unnecessary conversion of
            // int to String.
            logger.trace("Handling - responseBufferSize=[{0}]", Integer.toString(responseContentLength));
          }

          // Write the data to the response.
          resourceOutputStream.writeTo(externalContext.getResponseOutputStream());
          resourceOutputStream.flush();
          resourceOutputStream.close();

          if (logger.isDebugEnabled()) {
            logger.debug(
              "HANDLED (SC_OK) resourceName=[{0}], libraryName[{1}], responseContentType=[{4}], responseContentLength=[{5}]",
              new Object[] { resourceName, libraryName, responseContentType, responseContentLength });
          }
        }
        else {
          externalContext.setResponseStatus(HttpServletResponse.SC_NOT_FOUND);
          logger.error(
            "NOT HANDLED (SC_NOT_FOUND) because InputStream was null - resourceName=[{0}], libraryName[{1}]",
            new Object[] { resourceName, libraryName });
        }
      }
      catch (IOException e) {
        externalContext.setResponseStatus(HttpServletResponse.SC_NOT_FOUND);
        logger.error("NOT HANDLED (SC_NOT_FOUND) resourceName=[{0}], libraryName[{1}], errorMessage=[{4}]",
          new Object[] { resourceName, libraryName, e.getMessage() }, e);
      }
      finally {

        if (writableByteChannel != null) {
          writableByteChannel.close();
        }

        if (readableByteChannel != null) {
          readableByteChannel.close();
        }

        if (inputStream != null) {
          inputStream.close();
        }
      }
    }
    else {

      externalContext.setResponseStatus(HttpServletResponse.SC_NOT_MODIFIED);

      if (logger.isDebugEnabled()) {

        // Surround with isDebugEnabled check in order to avoid unnecessary creation of object array.
        logger.debug("HANDLED (SC_NOT_MODIFIED) resourceName=[{0}], libraryName[{1}]",
          new Object[] { resourceName, libraryName });
      }

    }
  }

  protected int getBufferSize(FacesContext facesContext) {
    return DEFAULT_BUFFER_SIZE;
  }

  protected boolean isAbleToSetHttpStatusCode(FacesContext facesContext) {
    return true;
  }

  /**
   * This is a factory-style method that returns a {@link ResourceOutputStream} for the specified {@link Resource}.
   * The default implementation in this class simply returns an instance of {@link ResourceOutputStream}. Subclasses
   * that {@link Override} this method can return instances that implement the optional {@link Filterable} interface.
   *
   * @param   resource  The resource that is being requested.
   * @param   size      The size of the buffer.
   *
   * @return  The output stream.
   */
  protected ResourceOutputStream getResourceOutputStream(Resource resource, int size) {
    return new ResourceOutputStream(resource, size);
  }

  @Override
  public ResourceHandler getWrapped() {
    return wrappedResourceHandler;
  }
}
TOP

Related Classes of com.liferay.faces.util.application.ResourceHandlerWrapperBase

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.