View Javadoc

1   //========================================================================
2   //Copyright 2004-2008 Mort Bay Consulting Pty. Ltd.
3   //------------------------------------------------------------------------
4   //Licensed under the Apache License, Version 2.0 (the "License");
5   //you may not use this file except in compliance with the License.
6   //You may obtain a copy of the License at 
7   //http://www.apache.org/licenses/LICENSE-2.0
8   //Unless required by applicable law or agreed to in writing, software
9   //distributed under the License is distributed on an "AS IS" BASIS,
10  //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  //See the License for the specific language governing permissions and
12  //limitations under the License.
13  //========================================================================
14  
15  package org.mortbay.servlet;
16  
17  import java.io.IOException;
18  
19  import javax.servlet.RequestDispatcher;
20  import javax.servlet.ServletContext;
21  import javax.servlet.ServletException;
22  import javax.servlet.http.HttpServlet;
23  import javax.servlet.http.HttpServletRequest;
24  import javax.servlet.http.HttpServletResponse;
25  
26  /* ------------------------------------------------------------ */
27  /** Concatenation Servlet
28   * This servlet may be used to concatenate multiple resources into
29   * a single response.  It is intended to be used to load multiple
30   * javascript or css files, but may be used for any content of the 
31   * same mime type that can be meaningfully concatenated.
32   * <p>
33   * The servlet uses {@link RequestDispatcher#include(javax.servlet.ServletRequest, javax.servlet.ServletResponse)}
34   * to combine the requested content, so dynamically generated content
35   * may be combined (Eg engine.js for DWR).
36   * <p>
37   * The servlet uses parameter names of the query string as resource names
38   * relative to the context root.  So these script tags:
39   * <pre>
40   *  &lt;script type="text/javascript" src="../js/behaviour.js"&gt;&lt;/script&gt;
41   *  &lt;script type="text/javascript" src="../js/ajax.js&/chat/chat.js"&gt;&lt;/script&gt;
42   *  &lt;script type="text/javascript" src="../chat/chat.js"&gt;&lt;/script&gt;
43   * </pre> can be replaced with the single tag (with the ConcatServlet mapped to /concat):
44   * <pre>
45   *  &lt;script type="text/javascript" src="../concat?/js/behaviour.js&/js/ajax.js&/chat/chat.js"&gt;&lt;/script&gt;
46   * </pre>
47   * The {@link ServletContext#getMimeType(String)} method is used to determine the 
48   * mime type of each resource.  If the types of all resources do not match, then a 415 
49   * UNSUPPORTED_MEDIA_TYPE error is returned.
50   * <p>
51   * If the init parameter "development" is set to "true" then the servlet will run in
52   * development mode and the content will be concatenated on every request. Otherwise
53   * the init time of the servlet is used as the lastModifiedTime of the combined content
54   * and If-Modified-Since requests are handled with 206 NOT Modified responses if 
55   * appropriate. This means that when not in development mode, the servlet must be 
56   * restarted before changed content will be served.
57   * 
58   * @author gregw
59   *
60   */
61  public class ConcatServlet extends HttpServlet
62  {
63      boolean _development;
64      long _lastModified;
65      ServletContext _context;
66  
67      /* ------------------------------------------------------------ */
68      public void init() throws ServletException
69      {
70          _lastModified=System.currentTimeMillis();
71          _context=getServletContext();   
72          _development="true".equals(getInitParameter("development"));
73      }
74  
75      /* ------------------------------------------------------------ */
76      /* 
77       * @return The start time of the servlet unless in development mode, in which case -1 is returned.
78       */
79      protected long getLastModified(HttpServletRequest req)
80      {
81          return _development?-1:_lastModified;
82      }
83      
84      /* ------------------------------------------------------------ */
85      protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
86      {
87          String q=req.getQueryString();
88          if (q==null)
89          {
90              resp.sendError(HttpServletResponse.SC_NO_CONTENT);
91              return;
92          }
93          
94          String[] parts = q.split("\\&");
95          String type=null;
96          for (int i=0;i<parts.length;i++)
97          {
98              String t = _context.getMimeType(parts[i]);
99              if (t!=null)
100             {
101                 if (type==null)
102                     type=t;
103                 else if (!type.equals(t))
104                 {
105                     resp.sendError(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);
106                     return;
107                 }
108             }   
109         }
110 
111         if (type!=null)
112             resp.setContentType(type);
113 
114         for (int i=0;i<parts.length;i++)
115         {
116             RequestDispatcher dispatcher=_context.getRequestDispatcher(parts[i]);
117             if (dispatcher!=null)
118                 dispatcher.include(req,resp);
119         }
120     }
121 }