/* * Copyright 2000-2001,2004, 2008 The Apache Software Foundation, Nicolas Kruchten. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ca.myewb.frame.servlet; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.io.Writer; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; import org.apache.velocity.context.Context; import org.apache.velocity.exception.MethodInvocationException; import org.apache.velocity.exception.ParseErrorException; import org.apache.velocity.exception.ResourceNotFoundException; import org.apache.velocity.io.VelocityWriter; import org.apache.velocity.runtime.RuntimeSingleton; import org.apache.velocity.util.SimplePool; public abstract class CachingVelocityServlet extends HttpServlet { private static SimplePool writerPool = new SimplePool(40); public void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException { doRequest(request, response); } public void doPost( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException { doRequest(request, response); } protected void doRequest(HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); boolean isCachable = isCachable(request); if(isCachable) { String cacheIfFresh = getCachedOutputIfFresh(request); if(cacheIfFresh != null) { PrintWriter printWriter = new PrintWriter(response.getOutputStream()); printWriter.write(cacheIfFresh); printWriter.flush(); return; } } try { Context context = new VelocityContext(); context.put( "req", request ); context.put( "res", response ); ////////////////// This is the big call! Template template = handleRequest( request, response, context ); if ( template == null ) { return; } mergeTemplate( template, context, response, isCachable); } catch (Exception e) { error( request, response, e); } finally { requestCleanup( request, response); } } protected void mergeTemplate( Template template, Context context, HttpServletResponse response, boolean isCachable ) throws ResourceNotFoundException, ParseErrorException, MethodInvocationException, IOException, UnsupportedEncodingException, Exception { VelocityWriter vw = null; String encoding = response.getCharacterEncoding(); try { if(isCachable) { PrintWriter printWriter = new PrintWriter(response.getOutputStream()); StringWriter sw = new StringWriter(); template.merge(context, sw); String toCache = sw.toString(); saveOutputToCache(toCache); printWriter.write(toCache); printWriter.flush(); } else { vw = (VelocityWriter) writerPool.get(); Writer theWriter = new OutputStreamWriter(response.getOutputStream(), encoding); if (vw == null) { vw = new VelocityWriter(theWriter, 4 * 1024, true); } else { vw.recycle(theWriter); } template.merge(context, vw); } } finally { try { if (vw != null) { vw.flush(); vw.recycle(null); writerPool.put(vw); } } catch (Exception e) { // do nothing } } } public Template getTemplate( String name ) throws ResourceNotFoundException, ParseErrorException, Exception { return RuntimeSingleton.getTemplate(name); } protected abstract Template handleRequest( HttpServletRequest request, HttpServletResponse response, Context ctx ) throws Exception; protected abstract void error( HttpServletRequest request, HttpServletResponse response, Exception cause ) throws ServletException, IOException; protected abstract void requestCleanup( HttpServletRequest request, HttpServletResponse response); //is this particular request cachable? called after handleRequest, so no args needed protected abstract boolean isCachable(HttpServletRequest request); protected abstract void saveOutputToCache(String toCache); //return null if cache is stale public abstract String getCachedOutputIfFresh(HttpServletRequest request); }