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 * <script type="text/javascript" src="../js/behaviour.js"></script> 41 * <script type="text/javascript" src="../js/ajax.js&/chat/chat.js"></script> 42 * <script type="text/javascript" src="../chat/chat.js"></script> 43 * </pre> can be replaced with the single tag (with the ConcatServlet mapped to /concat): 44 * <pre> 45 * <script type="text/javascript" src="../concat?/js/behaviour.js&/js/ajax.js&/chat/chat.js"></script> 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 }