Package org.apache.taglibs.standard.tag.common.core

Source Code of org.apache.taglibs.standard.tag.common.core.ImportSupport$PrintWriterWrapper

/*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the "License").  You may not use this file except
* in compliance with the License.
*
* You can obtain a copy of the license at
* glassfish/bootstrap/legal/CDDLv1.0.txt or
* https://glassfish.dev.java.net/public/CDDLv1.0.html.
* See the License for the specific language governing
* permissions and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* HEADER in each file and include the License file at
* glassfish/bootstrap/legal/CDDLv1.0.txt.  If applicable,
* add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your
* own identifying information: Portions Copyright [yyyy]
* [name of copyright owner]
*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
*
* Portions Copyright Apache Software Foundation.
*/

package org.apache.taglibs.standard.tag.common.core;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Writer;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.Locale;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspTagException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.BodyTagSupport;
import javax.servlet.jsp.tagext.TryCatchFinally;

import org.apache.taglibs.standard.resources.Resources;

/**
* <p>Support for tag handlers for &lt;import&gt;, the general-purpose
* text-importing mechanism for JSTL 1.0.  The rtexprvalue and expression-
* evaluating libraries each have handlers that extend this class.</p>
*
* @author Shawn Bayern
*/

public abstract class ImportSupport extends BodyTagSupport
        implements TryCatchFinally, ParamParent {

    //*********************************************************************
    // Public constants
   
    /** <p>Valid characters in a scheme.</p>
     <p>RFC 1738 says the following:</p>
     <blockquote>
     *   Scheme names consist of a sequence of characters. The lower
     *   case letters "a"--"z", digits, and the characters plus ("+"),
     *   period ("."), and hyphen ("-") are allowed. For resiliency,
     *   programs interpreting URLs should treat upper case letters as
     *   equivalent to lower case in scheme names (e.g., allow "HTTP" as
     *   well as "http").
     *  </blockquote>
     * <p>We treat as absolute any URL that begins with such a scheme name,
     * followed by a colon.</p>
     */
    public static final String VALID_SCHEME_CHARS =
  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+.-";

    /** Default character encoding for response. */
    public static final String DEFAULT_ENCODING = "ISO-8859-1";

    //*********************************************************************
    // Protected state

    protected String url;                         // 'url' attribute
    protected String context;        // 'context' attribute
    protected String charEncoding;                // 'charEncoding' attrib.

    //*********************************************************************
    // Private state (implementation details)

    private String var;                 // 'var' attribute
    private int scope;      // processed 'scope' attribute
    private String varReader;           // 'varReader' attribute
    private Reader r;       // exposed reader, if relevant
    private boolean isAbsoluteUrl;  // is our URL absolute?
    private ParamSupport.ParamManager params;    // parameters
    private String urlWithParams;  // URL with parameters, if applicable

    //*********************************************************************
    // Constructor and initialization

    public ImportSupport() {
  super();
  init();
    }

    private void init() {
  url = var = varReader = context = charEncoding = urlWithParams = null;
  params = null;
        scope = PageContext.PAGE_SCOPE;
    }


    //*********************************************************************
    // Tag logic

    // determines what kind of import and variable exposure to perform
    public int doStartTag() throws JspException {
  // Sanity check
  if (context != null
          && (!context.startsWith("/") || !url.startsWith("/"))) {
      throw new JspTagException(
    Resources.getMessage("IMPORT_BAD_RELATIVE"));
  }

  // reset parameter-related state
  urlWithParams = null;
  params = new ParamSupport.ParamManager();

  // check the URL
  if (url == null || url.equals(""))
      throw new NullAttributeException("import", "url");

  // Record whether our URL is absolute or relative
  isAbsoluteUrl = isAbsoluteUrl();

  try {
      // If we need to expose a Reader, we've got to do it right away
      if  (varReader != null) {
          r = acquireReader();
          pageContext.setAttribute(varReader, r);
      }
  } catch (IOException ex) {
      throw new JspTagException(ex.toString(), ex);
  }

  return EVAL_BODY_INCLUDE;
    }

    // manages connections as necessary (creating or destroying)
    public int doEndTag() throws JspException {
        try {
      // If we didn't expose a Reader earlier...
      if (varReader == null) {
          // ... store it in 'var', if available ...
          if (var != null)
              pageContext.setAttribute(var, acquireString(), scope);
                // ... or simply output it, if we have nowhere to expose it
          else
              pageContext.getOut().print(acquireString());
      }
      return EVAL_PAGE;
        } catch (IOException ex) {
      throw new JspTagException(ex.toString(), ex);
        }
    }

    // simply rethrows its exception
    public void doCatch(Throwable t) throws Throwable {
  throw t;
    }

    // cleans up if appropriate
    public void doFinally() {
        try {
      // If we exposed a Reader in doStartTag(), close it.
      if (varReader != null) {
    // 'r' can be null if an exception was thrown...
          if (r != null)
        r.close();
    pageContext.removeAttribute(varReader, PageContext.PAGE_SCOPE);
      }
        } catch (IOException ex) {
      // ignore it; close() failed, but there's nothing more we can do
        }
    }

    // Releases any resources we may have (or inherit)
    public void release() {
  init();
        super.release();
    }

    //*********************************************************************
    // Tag attributes known at translation time

    public void setVar(String var) {
  this.var = var;
    }

    public void setVarReader(String varReader) {
  this.varReader = varReader;
    }

    public void setScope(String scope) {
  this.scope = Util.getScope(scope);
    }


    //*********************************************************************
    // Collaboration with subtags

    // inherit Javadoc
    public void addParameter(String name, String value) {
  params.addParameter(name, value);
    }

    //*********************************************************************
    // Actual URL importation logic

    /*
     * Overall strategy:  we have two entry points, acquireString() and
     * acquireReader().  The latter passes data through unbuffered if
     * possible (but note that it is not always possible -- specifically
     * for cases where we must use the RequestDispatcher.  The remaining
     * methods handle the common.core logic of loading either a URL or a local
     * resource.
     *
     * We consider the 'natural' form of absolute URLs to be Readers and
     * relative URLs to be Strings.  Thus, to avoid doing extra work,
     * acquireString() and acquireReader() delegate to one another as
     * appropriate.  (Perhaps I could have spelled things out more clearly,
     * but I thought this implementation was instructive, not to mention
     * somewhat cute...)
     */

    private String acquireString() throws IOException, JspException {
        if (isAbsoluteUrl) {
            // for absolute URLs, delegate to our peer
            BufferedReader r = new BufferedReader(acquireReader());
            StringBuffer sb = new StringBuffer();
            int i;
           
            // under JIT, testing seems to show this simple loop is as fast
            // as any of the alternatives
            //
            // gmurray71 : putting in try/catch/finally block to make sure the
            // reader is closed to fix a bug with file descriptors being left open
            try {
                while ((i = r.read()) != -1)
                    sb.append((char)i);
            } catch (IOException iox) {
              throw iox;
            } finally {
                r.close();
            }
           
            return sb.toString();
        } else {
            // handle relative URLs ourselves
           
            // URL is relative, so we must be an HTTP request
            if (!(pageContext.getRequest() instanceof HttpServletRequest
                  && pageContext.getResponse() instanceof HttpServletResponse))
                throw new JspTagException(
                                          Resources.getMessage("IMPORT_REL_WITHOUT_HTTP"));
           
            // retrieve an appropriate ServletContext
            ServletContext c = null;
            String targetUrl = targetUrl();
            if (context != null)
                c = pageContext.getServletContext().getContext(context);
            else {
                c = pageContext.getServletContext();
               
                // normalize the URL if we have an HttpServletRequest
                if (!targetUrl.startsWith("/")) {
                    String sp = ((HttpServletRequest)
                                 pageContext.getRequest()).getServletPath();
                    targetUrl = sp.substring(0, sp.lastIndexOf('/'))
                        + '/' + targetUrl;
                }
            }
           
            if (c == null) {
                throw new JspTagException(
                                          Resources.getMessage(
                                                               "IMPORT_REL_WITHOUT_DISPATCHER", context, targetUrl));
            }
           
            // from this context, get a dispatcher
            RequestDispatcher rd =
                c.getRequestDispatcher(stripSession(targetUrl));
            if (rd == null)
                throw new JspTagException(stripSession(targetUrl));
           
            // include the resource, using our custom wrapper
            ImportResponseWrapper irw =
                new ImportResponseWrapper(pageContext);
           
            // spec mandates specific error handling form include()
            try {
                rd.include(pageContext.getRequest(), irw);
            } catch (IOException ex) {
                throw new JspException(ex);
            } catch (RuntimeException ex) {
                throw new JspException(ex);
            } catch (ServletException ex) {
                Throwable rc = ex.getRootCause();
                if (rc == null)
                    throw new JspException(ex);
                else
                    throw new JspException(rc);
            }
           
            // disallow inappropriate response codes per JSTL spec
            if (irw.getStatus() < 200 || irw.getStatus() > 299) {
                throw new JspTagException(irw.getStatus() + " " +
                                          stripSession(targetUrl));
            }
           
            // recover the response String from our wrapper
            return irw.getString();
        }
    }

    private Reader acquireReader() throws IOException, JspException {
        if (!isAbsoluteUrl) {
            // for relative URLs, delegate to our peer
            return new StringReader(acquireString());
        } else {
            // absolute URL
            String target = targetUrl();
            try {
                // handle absolute URLs ourselves, using java.net.URL
                URL u = new URL(target);
                URLConnection uc = u.openConnection();
                InputStream i = uc.getInputStream();
               
                // okay, we've got a stream; encode it appropriately
                Reader r = null;
                String charSet;
                if (charEncoding != null && !charEncoding.equals("")) {
                    charSet = charEncoding;
                } else {
                    // charSet extracted according to RFC 2045, section 5.1
                    String contentType = uc.getContentType();
                    if (contentType != null) {
                        charSet = Util.getContentTypeAttribute(contentType, "charset");
                        if (charSet == null) charSet = DEFAULT_ENCODING;
                    } else {
                        charSet = DEFAULT_ENCODING;
                    }
                }
                try {
                    r = new InputStreamReader(i, charSet);
                } catch (Exception ex) {
                    r = new InputStreamReader(i, DEFAULT_ENCODING);
                }
               
                // check response code for HTTP URLs before returning, per spec,
                // before returning
                if (uc instanceof HttpURLConnection) {
                    int status = ((HttpURLConnection) uc).getResponseCode();
                    if (status < 200 || status > 299)
                        throw new JspTagException(status + " " + target);
                }
                return r;
            } catch (IOException ex) {
                throw new JspException(
                                       Resources.getMessage("IMPORT_ABS_ERROR", target, ex), ex);
            } catch (RuntimeException ex) {  // because the spec makes us
                throw new JspException(
                                       Resources.getMessage("IMPORT_ABS_ERROR", target, ex), ex);
            }
        }
    }

    /** Wraps responses to allow us to retrieve results as Strings. */
    private class ImportResponseWrapper extends HttpServletResponseWrapper {

  //************************************************************
  // Overview

  /*
   * We provide either a Writer or an OutputStream as requested.
   * We actually have a true Writer and an OutputStream backing
   * both, since we don't want to use a character encoding both
   * ways (Writer -> OutputStream -> Writer).  So we use no
   * encoding at all (as none is relevant) when the target resource
   * uses a Writer.  And we decode the OutputStream's bytes
   * using OUR tag's 'charEncoding' attribute, or ISO-8859-1
   * as the default.  We thus ignore setLocale() and setContentType()
   * in this wrapper.
   *
   * In other words, the target's asserted encoding is used
   * to convert from a Writer to an OutputStream, which is typically
   * the medium through with the target will communicate its
   * ultimate response.  Since we short-circuit that mechanism
   * and read the target's characters directly if they're offered
   * as such, we simply ignore the target's encoding assertion.
   */

  //************************************************************
  // Data

  /** The Writer we convey. */
  private StringWriter sw = new StringWriter();

  /** A buffer, alternatively, to accumulate bytes. */
  private ByteArrayOutputStream bos = new ByteArrayOutputStream();

  /** A ServletOutputStream we convey, tied to this Writer. */
  private ServletOutputStream sos = new ServletOutputStream() {
      public void write(int b) throws IOException {
    bos.write(b);
      }
  };

  /** 'True' if getWriter() was called; false otherwise. */
  private boolean isWriterUsed;

  /** 'True if getOutputStream() was called; false otherwise. */
  private boolean isStreamUsed;

  /** The HTTP status set by the target. */
  private int status = 200;

        private PageContext pageContext;
 
  //************************************************************
  // Constructor and methods

  /** Constructs a new ImportResponseWrapper. */
  public ImportResponseWrapper(PageContext pageContext) {
            super((HttpServletResponse)pageContext.getResponse());
            this.pageContext = pageContext;
  }
 
  /** Returns a Writer designed to buffer the output. */
       public PrintWriter getWriter() throws IOException {
      if (isStreamUsed)
    throw new IllegalStateException(
        Resources.getMessage("IMPORT_ILLEGAL_STREAM"));
      isWriterUsed = true;
      return new PrintWriterWrapper(sw, pageContext.getOut());
  }
 
  /** Returns a ServletOutputStream designed to buffer the output. */
  public ServletOutputStream getOutputStream() {
      if (isWriterUsed)
    throw new IllegalStateException(
        Resources.getMessage("IMPORT_ILLEGAL_WRITER"));
      isStreamUsed = true;
      return sos;
  }

  /** Has no effect. */
  public void setContentType(String x) {
      // ignore
  }

  /** Has no effect. */
  public void setLocale(Locale x) {
      // ignore
  }

  public void setStatus(int status) {
      this.status = status;
  }

  public int getStatus() {
      return status;
  }

  /**
   * Retrieves the buffered output, using the containing tag's
   * 'charEncoding' attribute, or the tag's default encoding,
   * <b>if necessary</b>.
         */
  // not simply toString() because we need to throw
  // UnsupportedEncodingException
  public String getString() throws UnsupportedEncodingException {
      if (isWriterUsed)
    return sw.toString();
      else if (isStreamUsed) {
    if (charEncoding != null && !charEncoding.equals(""))
        return bos.toString(charEncoding);
    else
        return bos.toString(DEFAULT_ENCODING);
      } else
    return "";    // target didn't write anything
  }
    }

    private static class PrintWriterWrapper extends PrintWriter {

        private StringWriter out;
        private Writer parentWriter;

        public PrintWriterWrapper(StringWriter out, Writer parentWriter) {
            super(out);
            this.out = out;
            this.parentWriter = parentWriter;
        }

        public void flush() {
            try {
                parentWriter.write(out.toString());
                StringBuffer sb = out.getBuffer();
                sb.delete(0, sb.length());
            } catch (IOException ex) {
            }
        }
     }

    //*********************************************************************
    // Some private utility methods

    /** Returns our URL (potentially with parameters) */
    private String targetUrl() {
  if (urlWithParams == null)
      urlWithParams = params.aggregateParams(url);
  return urlWithParams;
    }

    /**
     * Returns <tt>true</tt> if our current URL is absolute,
     * <tt>false</tt> otherwise.
     */
    private boolean isAbsoluteUrl() throws JspTagException {
        return isAbsoluteUrl(url);
    }


    //*********************************************************************
    // Public utility methods

    /**
     * Returns <tt>true</tt> if our current URL is absolute,
     * <tt>false</tt> otherwise.
     */
    public static boolean isAbsoluteUrl(String url) {
  // a null URL is not absolute, by our definition
  if (url == null)
      return false;

  // do a fast, simple check first
  int colonPos;
  if ((colonPos = url.indexOf(":")) == -1)
      return false;

  // if we DO have a colon, make sure that every character
  // leading up to it is a valid scheme character
  for (int i = 0; i < colonPos; i++)
      if (VALID_SCHEME_CHARS.indexOf(url.charAt(i)) == -1)
    return false;

  // if so, we've got an absolute url
  return true;
    }

    /**
     * Strips a servlet session ID from <tt>url</tt>.  The session ID
     * is encoded as a URL "path parameter" beginning with "jsessionid=".
     * We thus remove anything we find between ";jsessionid=" (inclusive)
     * and either EOS or a subsequent ';' (exclusive).
     */
    public static String stripSession(String url) {
  StringBuffer u = new StringBuffer(url);
        int sessionStart;
        while ((sessionStart = u.toString().indexOf(";jsessionid=")) != -1) {
            int sessionEnd = u.toString().indexOf(";", sessionStart + 1);
            if (sessionEnd == -1)
    sessionEnd = u.toString().indexOf("?", sessionStart + 1);
      if (sessionEnd == -1)         // still
                sessionEnd = u.length();
            u.delete(sessionStart, sessionEnd);
        }
        return u.toString();
    }
}
TOP

Related Classes of org.apache.taglibs.standard.tag.common.core.ImportSupport$PrintWriterWrapper

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.