Save This Page
Home » struts-2.1.8.1-src » org.apache » struts2 » components » [javadoc | source]
    1   /*
    2    * $Id: Include.java 720222 2008-11-24 16:41:07Z musachy $
    3    *
    4    * Licensed to the Apache Software Foundation (ASF) under one
    5    * or more contributor license agreements.  See the NOTICE file
    6    * distributed with this work for additional information
    7    * regarding copyright ownership.  The ASF licenses this file
    8    * to you under the Apache License, Version 2.0 (the
    9    * "License"); you may not use this file except in compliance
   10    * with the License.  You may obtain a copy of the License at
   11    *
   12    *  http://www.apache.org/licenses/LICENSE-2.0
   13    *
   14    * Unless required by applicable law or agreed to in writing,
   15    * software distributed under the License is distributed on an
   16    * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   17    * KIND, either express or implied.  See the License for the
   18    * specific language governing permissions and limitations
   19    * under the License.
   20    */
   21   
   22   package org.apache.struts2.components;
   23   
   24   import java.io.IOException;
   25   import java.io.OutputStreamWriter;
   26   import java.io.PrintWriter;
   27   import java.io.Writer;
   28   import java.net.URLEncoder;
   29   import java.util.ArrayList;
   30   import java.util.Iterator;
   31   import java.util.List;
   32   import java.util.Map;
   33   import java.util.Stack;
   34   import java.util.StringTokenizer;
   35   
   36   import javax.servlet.RequestDispatcher;
   37   import javax.servlet.ServletException;
   38   import javax.servlet.ServletOutputStream;
   39   import javax.servlet.ServletRequest;
   40   import javax.servlet.http.HttpServletRequest;
   41   import javax.servlet.http.HttpServletResponse;
   42   import javax.servlet.http.HttpServletResponseWrapper;
   43   
   44   import org.apache.struts2.RequestUtils;
   45   import org.apache.struts2.StrutsConstants;
   46   import org.apache.struts2.util.FastByteArrayOutputStream;
   47   import org.apache.struts2.views.annotations.StrutsTag;
   48   import org.apache.struts2.views.annotations.StrutsTagAttribute;
   49   
   50   import com.opensymphony.xwork2.inject.Inject;
   51   import com.opensymphony.xwork2.util.ValueStack;
   52   import com.opensymphony.xwork2.util.logging.Logger;
   53   import com.opensymphony.xwork2.util.logging.LoggerFactory;
   54   
   55   /**
   56    * <!-- START SNIPPET: javadoc -->
   57    * <p>Include a servlet's output (result of servlet or a JSP page).</p>
   58    * <p>Note: Any additional params supplied to the included page are <b>not</b>
   59    * accessible within the rendered page through the &lt;s:property...&gt; tag
   60    * since no valuestack will be created. You can, however, access them in a 
   61    * servlet via the HttpServletRequest object or from a JSP page via
   62    * a scriptlet.</p>
   63    * <!-- END SNIPPET: javadoc -->
   64    *
   65    *
   66    * <!-- START SNIPPET: params -->
   67    * <ul>
   68    *      <li>value* (String) - jsp page to be included</li>
   69    * </ul>
   70    * <!-- END SNIPPET: params -->
   71    *
   72    *
   73    * <p/> <b>Examples</b>
   74    * <pre>
   75    * <!-- START SNIPPET: example -->
   76    * &lt;-- One: --&gt;
   77    * &lt;s:include value="myJsp.jsp" /&gt;
   78    *
   79    * &lt;-- Two: --&gt;
   80    * &lt;s:include value="myJsp.jsp"&gt;
   81    *    &lt;s:param name="param1" value="value2" /&gt;
   82    *    &lt;s:param name="param2" value="value2" /&gt;
   83    * &lt;/s:include&gt;
   84    *
   85    * &lt;-- Three: --&gt;
   86    * &lt;s:include value="myJsp.jsp"&gt;
   87    *    &lt;s:param name="param1"&gt;value1&lt;/s:param&gt;
   88    *    &lt;s:param name="param2"&gt;value2&lt;/s:param&gt;
   89    * &lt;/s:include&gt;
   90    * <!-- END SNIPPET: example -->
   91    *
   92    * <!-- START SNIPPET: exampledescription -->
   93    * Example one - do an include myJsp.jsp page
   94    * Example two - do an include to myJsp.jsp page with parameters param1=value1 and param2=value2
   95    * Example three - do an include to myJsp.jsp page with parameters param1=value1 and param2=value2
   96    * <!-- END SNIPPET: exampledescription -->
   97    * </pre>
   98    *
   99    */
  100   @StrutsTag(name="include", tldTagClass="org.apache.struts2.views.jsp.IncludeTag", description="Include a servlet's output " +
  101                   "(result of servlet or a JSP page)")
  102   public class Include extends Component {
  103   
  104       private static final Logger LOG = LoggerFactory.getLogger(Include.class);
  105   
  106       private static String encoding;
  107       private static boolean encodingDefined = true;
  108   
  109       protected String value;
  110       private HttpServletRequest req;
  111       private HttpServletResponse res;
  112       private static String defaultEncoding;
  113   
  114       public Include(ValueStack stack, HttpServletRequest req, HttpServletResponse res) {
  115           super(stack);
  116           this.req = req;
  117           this.res = res;
  118       }
  119   
  120       @Inject(StrutsConstants.STRUTS_I18N_ENCODING)
  121       public void setDefaultEncoding(String encoding) {
  122           defaultEncoding = encoding;
  123       }
  124   
  125       public boolean end(Writer writer, String body) {
  126           String page = findString(value, "value", "You must specify the URL to include. Example: /foo.jsp");
  127           StringBuilder urlBuf = new StringBuilder();
  128   
  129           // Add URL
  130           urlBuf.append(page);
  131   
  132           // Add request parameters
  133           if (parameters.size() > 0) {
  134               urlBuf.append('?');
  135   
  136               String concat = "";
  137   
  138               // Set parameters
  139               Iterator iter = parameters.entrySet().iterator();
  140   
  141               while (iter.hasNext()) {
  142                   Map.Entry entry = (Map.Entry) iter.next();
  143                   Object name = entry.getKey();
  144                   List values = (List) entry.getValue();
  145   
  146                   for (int i = 0; i < values.size(); i++) {
  147                       urlBuf.append(concat);
  148                       urlBuf.append(name);
  149                       urlBuf.append('=');
  150   
  151                       try {
  152                           urlBuf.append(URLEncoder.encode(values.get(i).toString(), "UTF-8"));
  153                       } catch (Exception e) {
  154                           LOG.warn("unable to url-encode "+values.get(i).toString()+", it will be ignored");
  155                       }
  156   
  157                       concat = "&";
  158                   }
  159               }
  160           }
  161   
  162           String result = urlBuf.toString();
  163   
  164           // Include
  165           try {
  166               include(result, writer, req, res);
  167           } catch (Exception e) {
  168               LOG.warn("Exception thrown during include of " + result, e);
  169           }
  170   
  171           return super.end(writer, body);
  172       }
  173   
  174       @StrutsTagAttribute(description="The jsp/servlet output to include", required=true)
  175       public void setValue(String value) {
  176           this.value = value;
  177       }
  178   
  179       public static String getContextRelativePath(ServletRequest request, String relativePath) {
  180           String returnValue;
  181   
  182           if (relativePath.startsWith("/")) {
  183               returnValue = relativePath;
  184           } else if (!(request instanceof HttpServletRequest)) {
  185               returnValue = relativePath;
  186           } else {
  187               HttpServletRequest hrequest = (HttpServletRequest) request;
  188               String uri = (String) request.getAttribute("javax.servlet.include.servlet_path");
  189   
  190               if (uri == null) {
  191                   uri = RequestUtils.getServletPath(hrequest);
  192               }
  193   
  194               returnValue = uri.substring(0, uri.lastIndexOf('/')) + '/' + relativePath;
  195           }
  196   
  197           // .. is illegal in an absolute path according to the Servlet Spec and will cause
  198           // known problems on Orion application servers.
  199           if (returnValue.indexOf("..") != -1) {
  200               Stack stack = new Stack();
  201               StringTokenizer pathParts = new StringTokenizer(returnValue.replace('\\', '/'), "/");
  202   
  203               while (pathParts.hasMoreTokens()) {
  204                   String part = pathParts.nextToken();
  205   
  206                   if (!part.equals(".")) {
  207                       if (part.equals("..")) {
  208                           stack.pop();
  209                       } else {
  210                           stack.push(part);
  211                       }
  212                   }
  213               }
  214   
  215               StringBuilder flatPathBuffer = new StringBuilder();
  216   
  217               for (int i = 0; i < stack.size(); i++) {
  218                   flatPathBuffer.append("/").append(stack.elementAt(i));
  219               }
  220   
  221               returnValue = flatPathBuffer.toString();
  222           }
  223   
  224           return returnValue;
  225       }
  226   
  227       public void addParameter(String key, Object value) {
  228           // don't use the default implementation of addParameter,
  229           // instead, include tag requires that each parameter be a list of objects,
  230           // just like the HTTP servlet interfaces are (String[])
  231           if (value != null) {
  232               List currentValues = (List) parameters.get(key);
  233   
  234               if (currentValues == null) {
  235                   currentValues = new ArrayList();
  236                   parameters.put(key, currentValues);
  237               }
  238   
  239               currentValues.add(value);
  240           }
  241       }
  242   
  243       public static void include(String aResult, Writer writer, ServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  244           String resourcePath = getContextRelativePath(request, aResult);
  245           RequestDispatcher rd = request.getRequestDispatcher(resourcePath);
  246   
  247           if (rd == null) {
  248               throw new ServletException("Not a valid resource path:" + resourcePath);
  249           }
  250   
  251           PageResponse pageResponse = new PageResponse(response);
  252   
  253           // Include the resource
  254           rd.include((HttpServletRequest) request, pageResponse);
  255   
  256           //write the response back to the JspWriter, using the correct encoding.
  257           String encoding = getEncoding();
  258   
  259           if (encoding != null) {
  260               //use the encoding specified in the property file
  261               pageResponse.getContent().writeTo(writer, encoding);
  262           } else {
  263               //use the platform specific encoding
  264               pageResponse.getContent().writeTo(writer, null);
  265           }
  266       }
  267   
  268       /**
  269        * Get the encoding specified by the property 'struts.i18n.encoding' in struts.properties,
  270        * or return the default platform encoding if not specified.
  271        * <p/>
  272        * Note that if the property is not initially defined, this will return the system default,
  273        * even if the property is later defined.  This is mainly for performance reasons.  Undefined
  274        * properties throw exceptions, which are a costly operation.
  275        * <p/>
  276        * If the property is initially defined, it is read every time, until is is undefined, and then
  277        * the system default is used.
  278        * <p/>
  279        * Why not cache it completely?  Some applications will wish to be able to dynamically set the
  280        * encoding at runtime.
  281        *
  282        * @return The encoding to be used.
  283        */
  284       private static String getEncoding() {
  285           if (encodingDefined) {
  286               try {
  287                   encoding = defaultEncoding;
  288               } catch (IllegalArgumentException e) {
  289                   encoding = System.getProperty("file.encoding");
  290                   encodingDefined = false;
  291               }
  292           }
  293   
  294           return encoding;
  295       }
  296   
  297   
  298       /**
  299        * Implementation of ServletOutputStream that stores all data written
  300        * to it in a temporary buffer accessible from {@link #getBuffer()} .
  301        *
  302        * @author <a href="joe@truemesh.com">Joe Walnes</a>
  303        * @author <a href="mailto:scott@atlassian.com">Scott Farquhar</a>
  304        */
  305       static final class PageOutputStream extends ServletOutputStream {
  306   
  307           private FastByteArrayOutputStream buffer;
  308   
  309   
  310           public PageOutputStream() {
  311               buffer = new FastByteArrayOutputStream();
  312           }
  313   
  314   
  315           /**
  316            * Return all data that has been written to this OutputStream.
  317            */
  318           public FastByteArrayOutputStream getBuffer() throws IOException {
  319               flush();
  320   
  321               return buffer;
  322           }
  323   
  324           public void close() throws IOException {
  325               buffer.close();
  326           }
  327   
  328           public void flush() throws IOException {
  329               buffer.flush();
  330           }
  331   
  332           public void write(byte[] b, int o, int l) throws IOException {
  333               buffer.write(b, o, l);
  334           }
  335   
  336           public void write(int i) throws IOException {
  337               buffer.write(i);
  338           }
  339   
  340           public void write(byte[] b) throws IOException {
  341               buffer.write(b);
  342           }
  343       }
  344   
  345   
  346       /**
  347        * Simple wrapper to HTTPServletResponse that will allow getWriter()
  348        * and getResponse() to be called as many times as needed without
  349        * causing conflicts.
  350        * <p/>
  351        * The underlying outputStream is a wrapper around
  352        * {@link PageOutputStream} which will store
  353        * the written content to a buffer.
  354        * <p/>
  355        * This buffer can later be retrieved by calling {@link #getContent}.
  356        *
  357        * @author <a href="mailto:joe@truemesh.com">Joe Walnes</a>
  358        * @author <a href="mailto:scott@atlassian.com">Scott Farquhar</a>
  359        */
  360       static final class PageResponse extends HttpServletResponseWrapper {
  361   
  362           protected PrintWriter pagePrintWriter;
  363           protected ServletOutputStream outputStream;
  364           private PageOutputStream pageOutputStream = null;
  365   
  366   
  367           /**
  368            * Create PageResponse wrapped around an existing HttpServletResponse.
  369            */
  370           public PageResponse(HttpServletResponse response) {
  371               super(response);
  372           }
  373   
  374   
  375           /**
  376            * Return the content buffered inside the {@link PageOutputStream}.
  377            *
  378            * @return
  379            * @throws IOException
  380            */
  381           public FastByteArrayOutputStream getContent() throws IOException {
  382               //if we are using a writer, we need to flush the
  383               //data to the underlying outputstream.
  384               //most containers do this - but it seems Jetty 4.0.5 doesn't
  385               if (pagePrintWriter != null) {
  386                   pagePrintWriter.flush();
  387               }
  388   
  389               return ((PageOutputStream) getOutputStream()).getBuffer();
  390           }
  391   
  392           /**
  393            * Return instance of {@link PageOutputStream}
  394            * allowing all data written to stream to be stored in temporary buffer.
  395            */
  396           public ServletOutputStream getOutputStream() throws IOException {
  397               if (pageOutputStream == null) {
  398                   pageOutputStream = new PageOutputStream();
  399               }
  400   
  401               return pageOutputStream;
  402           }
  403   
  404           /**
  405            * Return PrintWriter wrapper around PageOutputStream.
  406            */
  407           public PrintWriter getWriter() throws IOException {
  408               if (pagePrintWriter == null) {
  409                   pagePrintWriter = new PrintWriter(new OutputStreamWriter(getOutputStream(), getCharacterEncoding()));
  410               }
  411   
  412               return pagePrintWriter;
  413           }
  414       }
  415   }

Save This Page
Home » struts-2.1.8.1-src » org.apache » struts2 » components » [javadoc | source]