Home » freemarker-2.3.13 » freemarker.ext.jsp » [javadoc | source]

    1   /*
    2    * Copyright (c) 2003 The Visigoth Software Society. All rights
    3    * reserved.
    4    *
    5    * Redistribution and use in source and binary forms, with or without
    6    * modification, are permitted provided that the following conditions
    7    * are met:
    8    *
    9    * 1. Redistributions of source code must retain the above copyright
   10    *    notice, this list of conditions and the following disclaimer.
   11    *
   12    * 2. Redistributions in binary form must reproduce the above copyright
   13    *    notice, this list of conditions and the following disclaimer in
   14    *    the documentation and/or other materials provided with the
   15    *    distribution.
   16    *
   17    * 3. The end-user documentation included with the redistribution, if
   18    *    any, must include the following acknowledgement:
   19    *       "This product includes software developed by the
   20    *        Visigoth Software Society (http://www.visigoths.org/)."
   21    *    Alternately, this acknowledgement may appear in the software itself,
   22    *    if and wherever such third-party acknowledgements normally appear.
   23    *
   24    * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the 
   25    *    project contributors may be used to endorse or promote products derived
   26    *    from this software without prior written permission. For written
   27    *    permission, please contact visigoths@visigoths.org.
   28    *
   29    * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth"
   30    *    nor may "FreeMarker" or "Visigoth" appear in their names
   31    *    without prior written permission of the Visigoth Software Society.
   32    *
   33    * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   34    * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   35    * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   36    * DISCLAIMED.  IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR
   37    * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   38    * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   39    * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   40    * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   41    * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   42    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   43    * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   44    * SUCH DAMAGE.
   45    * ====================================================================
   46    *
   47    * This software consists of voluntary contributions made by many
   48    * individuals on behalf of the Visigoth Software Society. For more
   49    * information on the Visigoth Software Society, please see
   50    * http://www.visigoths.org/
   51    */
   52   
   53   package freemarker.ext.jsp;
   54   
   55   import java.beans.IntrospectionException;
   56   import java.io.CharArrayReader;
   57   import java.io.CharArrayWriter;
   58   import java.io.IOException;
   59   import java.io.Reader;
   60   import java.io.Writer;
   61   import java.util.Map;
   62   
   63   import javax.servlet.jsp.JspException;
   64   import javax.servlet.jsp.JspWriter;
   65   import javax.servlet.jsp.tagext.BodyContent;
   66   import javax.servlet.jsp.tagext.BodyTag;
   67   import javax.servlet.jsp.tagext.IterationTag;
   68   import javax.servlet.jsp.tagext.Tag;
   69   import javax.servlet.jsp.tagext.TryCatchFinally;
   70   
   71   import freemarker.log.Logger;
   72   import freemarker.template.TemplateModelException;
   73   import freemarker.template.TemplateTransformModel;
   74   import freemarker.template.TransformControl;
   75   import freemarker.template.utility.SecurityUtilities;
   76   
   77   /**
   78    * @version $Id: TagTransformModel.java,v 1.17.2.2 2006/07/08 14:45:34 ddekany Exp $
   79    * @author Attila Szegedi
   80    */
   81   class TagTransformModel extends JspTagModelBase implements TemplateTransformModel
   82   {
   83       private static final Logger logger = Logger.getLogger("freemarker.servlet");
   84       
   85       private final boolean isBodyTag;
   86       private final boolean isIterationTag;
   87       private final boolean isTryCatchFinally;
   88               
   89       public TagTransformModel(Class tagClass) throws IntrospectionException {
   90           super(tagClass);
   91           isIterationTag = IterationTag.class.isAssignableFrom(tagClass);
   92           isBodyTag = isIterationTag && BodyTag.class.isAssignableFrom(tagClass);
   93           isTryCatchFinally = TryCatchFinally.class.isAssignableFrom(tagClass);
   94       }
   95       
   96       public Writer getWriter(Writer out, Map args) throws TemplateModelException
   97       {
   98           try {
   99               Tag tag = (Tag)getTagInstance();
  100               FreeMarkerPageContext pageContext = PageContextFactory.getCurrentPageContext();
  101               Tag parentTag = (Tag)pageContext.peekTopTag(Tag.class);
  102               tag.setParent(parentTag);
  103               tag.setPageContext(pageContext);
  104               setupTag(tag, args, pageContext.getObjectWrapper());
  105               // If the parent of this writer is not a JspWriter itself, use
  106               // a little Writer-to-JspWriter adapter...
  107               boolean usesAdapter;
  108               if(out instanceof JspWriter) {
  109                   // This is just a sanity check. If it were JDK 1.4-only,
  110                   // we'd use an assert.
  111                   if(out != pageContext.getOut()) {
  112                       throw new TemplateModelException(
  113                           "out != pageContext.getOut(). Out is " + 
  114                           out + " pageContext.getOut() is " +
  115                           pageContext.getOut());
  116                   }
  117                   usesAdapter = false;
  118               }
  119               else {                
  120                   out = new JspWriterAdapter(out);
  121                   pageContext.pushWriter((JspWriter)out);
  122                   usesAdapter = true;
  123               }
  124               JspWriter w = new TagWriter(out, tag, pageContext, usesAdapter);
  125               pageContext.pushTopTag(tag);
  126               pageContext.pushWriter(w);
  127               return w;
  128           }
  129           catch(TemplateModelException e) {
  130               throw e;
  131           }
  132           catch(RuntimeException e) {
  133               throw e;
  134           }
  135           catch(Exception e) {
  136               throw new TemplateModelException(e);
  137           }
  138       }
  139   
  140       /**
  141        * An implementation of BodyContent that buffers it's input to a char[].
  142        */
  143       static class BodyContentImpl extends BodyContent {
  144           private CharArrayWriter buf;
  145   
  146           BodyContentImpl(JspWriter out, boolean buffer) {
  147               super(out);
  148               if (buffer) initBuffer();
  149           }
  150   
  151           void initBuffer() {
  152               buf = new CharArrayWriter();
  153           }
  154   
  155           public void flush() throws IOException {
  156               if(buf == null) {
  157                   getEnclosingWriter().flush();
  158               }
  159           }
  160   
  161           public void clear() throws IOException {
  162               if(buf != null) {
  163                   buf = new CharArrayWriter();
  164               }
  165               else {
  166                   throw new IOException("Can't clear");
  167               }
  168           }
  169   
  170           public void clearBuffer() throws IOException {
  171               if(buf != null) {
  172                   buf = new CharArrayWriter();
  173               }
  174               else {
  175                   throw new IOException("Can't clear");
  176               }
  177           }
  178   
  179           public int getRemaining() {
  180               return Integer.MAX_VALUE;
  181           }
  182   
  183           public void newLine() throws IOException {
  184               write(JspWriterAdapter.NEWLINE);
  185           }
  186   
  187           public void close() throws IOException {
  188           }
  189   
  190           public void print(boolean arg0) throws IOException {
  191               write(arg0 ? Boolean.TRUE.toString() : Boolean.FALSE.toString());
  192           }
  193   
  194           public void print(char arg0) throws IOException
  195           {
  196               write(arg0);
  197           }
  198   
  199           public void print(char[] arg0) throws IOException
  200           {
  201               write(arg0);
  202           }
  203   
  204           public void print(double arg0) throws IOException
  205           {
  206               write(Double.toString(arg0));
  207           }
  208   
  209           public void print(float arg0) throws IOException
  210           {
  211               write(Float.toString(arg0));
  212           }
  213   
  214           public void print(int arg0) throws IOException
  215           {
  216               write(Integer.toString(arg0));
  217           }
  218   
  219           public void print(long arg0) throws IOException
  220           {
  221               write(Long.toString(arg0));
  222           }
  223   
  224           public void print(Object arg0) throws IOException
  225           {
  226               write(arg0 == null ? "null" : arg0.toString());
  227           }
  228   
  229           public void print(String arg0) throws IOException
  230           {
  231               write(arg0);
  232           }
  233   
  234           public void println() throws IOException
  235           {
  236               newLine();
  237           }
  238   
  239           public void println(boolean arg0) throws IOException
  240           {
  241               print(arg0);
  242               newLine();
  243           }
  244   
  245           public void println(char arg0) throws IOException
  246           {
  247               print(arg0);
  248               newLine();
  249           }
  250   
  251           public void println(char[] arg0) throws IOException
  252           {
  253               print(arg0);
  254               newLine();
  255           }
  256   
  257           public void println(double arg0) throws IOException
  258           {
  259               print(arg0);
  260               newLine();
  261           }
  262   
  263           public void println(float arg0) throws IOException
  264           {
  265               print(arg0);
  266               newLine();
  267           }
  268   
  269           public void println(int arg0) throws IOException
  270           {
  271               print(arg0);
  272               newLine();
  273           }
  274   
  275           public void println(long arg0) throws IOException
  276           {
  277               print(arg0);
  278               newLine();
  279           }
  280   
  281           public void println(Object arg0) throws IOException
  282           {
  283               print(arg0);
  284               newLine();
  285           }
  286   
  287           public void println(String arg0) throws IOException
  288           {
  289               print(arg0);
  290               newLine();
  291           }
  292   
  293           public void write(int c) throws IOException
  294           {
  295               if(buf != null) {
  296                   buf.write(c);
  297               }
  298               else {
  299                   getEnclosingWriter().write(c);
  300               }
  301           }
  302   
  303           public void write(char[] cbuf, int off, int len) throws IOException
  304           {
  305               if(buf != null) {
  306                   buf.write(cbuf, off, len);
  307               }
  308               else {
  309                   getEnclosingWriter().write(cbuf, off, len);
  310               }
  311           }
  312   
  313           public String getString() {
  314               return buf.toString();
  315           }
  316   
  317           public Reader getReader() {
  318               return new CharArrayReader(buf.toCharArray());
  319           }
  320   
  321           public void writeOut(Writer out) throws IOException {
  322               buf.writeTo(out);
  323           }
  324   
  325       }
  326   
  327       class TagWriter extends BodyContentImpl implements TransformControl
  328       {
  329           private final Tag tag;
  330           private final FreeMarkerPageContext pageContext;
  331           private boolean needPop = true;
  332           private final boolean needDoublePop;
  333           
  334           TagWriter(Writer out, Tag tag, FreeMarkerPageContext pageContext, boolean needDoublePop)
  335           {
  336               super((JspWriter)out, false);
  337               this.needDoublePop = needDoublePop;
  338               this.tag = tag;
  339               this.pageContext = pageContext;
  340           }
  341           
  342           public String toString() {
  343               return "TagWriter for " + tag.getClass().getName() + " wrapping a " + getEnclosingWriter().toString();
  344           }
  345   
  346           Tag getTag()
  347           {
  348               return tag;
  349           }
  350           
  351           FreeMarkerPageContext getPageContext()
  352           {
  353               return pageContext;
  354           }
  355           
  356           public int onStart()
  357           throws
  358               TemplateModelException
  359           {
  360               try {
  361                   int dst = tag.doStartTag();
  362                   switch(dst) {
  363                       case Tag.SKIP_BODY:
  364                       // EVAL_PAGE is illegal actually, but some taglibs out there
  365                       // use it, and it seems most JSP compilers allow them to and
  366                       // treat it identically to SKIP_BODY, so we're going with 
  367                       // the flow and we allow it too, altough strictly speaking
  368                       // it is in violation of the spec.
  369                       case Tag.EVAL_PAGE: {
  370                           endEvaluation();
  371                           return TransformControl.SKIP_BODY;
  372                       }
  373                       case BodyTag.EVAL_BODY_BUFFERED: {
  374                           if(isBodyTag) {
  375                               initBuffer();
  376                               BodyTag btag = (BodyTag)tag;
  377                               btag.setBodyContent(this);
  378                               btag.doInitBody();
  379                           }
  380                           else {
  381                               throw new TemplateModelException("Can't buffer body since " + tag.getClass().getName() + " does not implement BodyTag.");
  382                           }
  383                           // Intentional fall-through
  384                       }
  385                       case Tag.EVAL_BODY_INCLUDE: {
  386                           return TransformControl.EVALUATE_BODY;
  387                       }
  388                       default: {
  389                           throw new RuntimeException("Illegal return value " + dst + " from " + tag.getClass().getName() + ".doStartTag()");
  390                       }
  391                   }
  392               }
  393               catch(JspException e) {
  394                   throw new TemplateModelException(e.getMessage(), e);
  395               }
  396           }
  397           
  398           public int afterBody()
  399           throws
  400               TemplateModelException
  401           {
  402               try {
  403                   if(isIterationTag) {
  404                       int dab = ((IterationTag)tag).doAfterBody();
  405                       switch(dab) {
  406                           case Tag.SKIP_BODY: {
  407                               endEvaluation();
  408                               return END_EVALUATION;
  409                           }
  410                           case IterationTag.EVAL_BODY_AGAIN: {
  411                               return REPEAT_EVALUATION;
  412                           }
  413                           default: {
  414                               throw new TemplateModelException("Unexpected return value " + dab + "from " + tag.getClass().getName() + ".doAfterBody()");
  415                           }
  416                       }
  417                   }
  418                   endEvaluation();
  419                   return END_EVALUATION;
  420               }
  421               catch(JspException e) {
  422                   throw new TemplateModelException(e);
  423               }
  424           }
  425           
  426           private void endEvaluation() throws JspException {
  427               if(needPop) {
  428                   pageContext.popWriter();
  429                   needPop = false;
  430               }
  431               if(tag.doEndTag() == Tag.SKIP_PAGE) {
  432                   logger.warn("Tag.SKIP_PAGE was ignored from a " + tag.getClass().getName() + " tag.");
  433               }
  434           }
  435           
  436           public void onError(Throwable t) throws Throwable {
  437               if(isTryCatchFinally) {
  438                   ((TryCatchFinally)tag).doCatch(t);
  439               }
  440               else {
  441                   throw t;
  442               }
  443           }
  444           
  445           public void close() {
  446               if(needPop) {
  447                   pageContext.popWriter();
  448               }
  449               pageContext.popTopTag();
  450               try {
  451                   if(isTryCatchFinally) {
  452                       ((TryCatchFinally)tag).doFinally();
  453                   }
  454                   // No pooling yet
  455                   tag.release();
  456               }
  457               finally {
  458                   if(needDoublePop) {
  459                       pageContext.popWriter();
  460                   }
  461               }
  462           }
  463           
  464       }
  465   }

Home » freemarker-2.3.13 » freemarker.ext.jsp » [javadoc | source]