This project has retired. For details please refer to its Attic page.
SharedVariableLoaderFreemarkerServlet xref
View Javadoc

1   /*
2    * $Id: SharedVariableLoaderFreemarkerServlet.java 1306435 2012-03-28 15:39:11Z nlebas $
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.tiles.request.freemarker.servlet;
23  
24  import java.util.Enumeration;
25  import java.util.LinkedHashMap;
26  import java.util.Map;
27  
28  import javax.servlet.ServletConfig;
29  import javax.servlet.ServletContext;
30  import javax.servlet.ServletException;
31  
32  import org.apache.tiles.request.reflect.ClassUtil;
33  
34  import freemarker.cache.TemplateLoader;
35  import freemarker.ext.servlet.FreemarkerServlet;
36  import freemarker.template.Configuration;
37  
38  /**
39   * Extends FreemarkerServlet to load Tiles directives as a shared variable.
40   *
41   * @version $Rev: 1306435 $ $Date: 2012-03-29 02:39:11 +1100 (Thu, 29 Mar 2012) $
42   */
43  public class SharedVariableLoaderFreemarkerServlet extends FreemarkerServlet {
44  
45      /**
46       * The serial UID.
47       */
48      private static final long serialVersionUID = 4301098067909854507L;
49  
50      /**
51       * The init parameter under which the factories will be put. The value of the parameter
52       * must be a semicolon (;) separated list of couples, each member of the couple must
53       * be separated by commas (,).
54       */
55      public static final String CUSTOM_SHARED_VARIABLE_FACTORIES_INIT_PARAM =
56          "org.apache.tiles.request.freemarker.CUSTOM_SHARED_VARIABLE_FACTORIES";
57  
58      /**
59       * Maps a name of a shared variable to its factory.
60       */
61      private Map<String, SharedVariableFactory> name2variableFactory =
62          new LinkedHashMap<String, SharedVariableFactory>();
63  
64      @Override
65      public void init(ServletConfig config) throws ServletException {
66          String param = config.getInitParameter(CUSTOM_SHARED_VARIABLE_FACTORIES_INIT_PARAM);
67          if (param != null) {
68              String[] couples = param.split("\\s*;\\s*");
69              for (int i = 0; i < couples.length; i++) {
70                  String[] couple = couples[i].split("\\s*,\\s*");
71                  if (couple == null || couple.length != 2) {
72                      throw new ServletException(
73                              "Cannot parse custom shared variable partial init param: '"
74                                      + couples[i] + "'");
75                  }
76                  name2variableFactory.put(couple[0],
77                          (SharedVariableFactory) ClassUtil.instantiate(couple[1]));
78              }
79          }
80          super.init(new ExcludingParameterServletConfig(config));
81      }
82  
83      /**
84       * Adds anew shared variable factory in a manual way.
85       *
86       * @param variableName The name of the shared variable.
87       * @param factory The shared variable factory.
88       */
89      public void addSharedVariableFactory(String variableName, SharedVariableFactory factory) {
90          name2variableFactory.put(variableName, factory);
91      }
92  
93      /** {@inheritDoc} */
94      @Override
95      protected Configuration createConfiguration() {
96          Configuration configuration = super.createConfiguration();
97  
98          for (Map.Entry<String, SharedVariableFactory> entry : name2variableFactory.entrySet()) {
99              configuration.setSharedVariable(entry.getKey(), entry.getValue().create());
100         }
101         return configuration;
102     }
103 
104     /** {@inheritDoc} */
105 
106     @Override
107     protected TemplateLoader createTemplateLoader(String templatePath) {
108         return new WebappClassTemplateLoader(getServletContext());
109     }
110 
111     /**
112      * Servlet configuration that excludes some parameters. It is useful to adapt to
113      * FreemarkerServlet behaviour, because it gets angry if it sees some extra
114      * parameters that it does not recognize.
115      */
116     private class ExcludingParameterServletConfig implements ServletConfig {
117 
118         /**
119          * The servlet configuration.
120          */
121         private ServletConfig config;
122 
123         /**
124          * Constructor.
125          *
126          * @param config The servlet configuration.
127          */
128         public ExcludingParameterServletConfig(ServletConfig config) {
129             this.config = config;
130         }
131 
132         @Override
133         public String getServletName() {
134             return config.getServletName();
135         }
136 
137         @Override
138         public ServletContext getServletContext() {
139             return config.getServletContext();
140         }
141 
142         @Override
143         public String getInitParameter(String name) {
144             if (CUSTOM_SHARED_VARIABLE_FACTORIES_INIT_PARAM.equals(name)) {
145                 return null;
146             }
147             return config.getInitParameter(name);
148         }
149 
150         @SuppressWarnings({ "rawtypes", "unchecked" })
151         @Override
152         public Enumeration getInitParameterNames() {
153             return new SkippingEnumeration(config.getInitParameterNames());
154         }
155 
156     }
157 
158     /**
159      * An enumeration that skip just
160      * {@link SharedVariableLoaderFreemarkerServlet#CUSTOM_SHARED_VARIABLE_FACTORIES_INIT_PARAM},
161      * again not to let the FreemarkerServlet be angry about it.
162      */
163     private static class SkippingEnumeration implements Enumeration<String> {
164 
165         /**
166          * The original enumeration.
167          */
168         private Enumeration<String> enumeration;
169 
170         /**
171          * The next element.
172          */
173         private String next = null;
174 
175         /**
176          * Constructor.
177          *
178          * @param enumeration The original enumeration.
179          */
180         public SkippingEnumeration(Enumeration<String> enumeration) {
181             this.enumeration = enumeration;
182             updateNextElement();
183         }
184 
185         @Override
186         public boolean hasMoreElements() {
187             return next != null;
188         }
189 
190         @Override
191         public String nextElement() {
192             String retValue = next;
193             updateNextElement();
194             return retValue;
195         }
196 
197         /**
198          * Updates the next element that will be passed.
199          */
200         private void updateNextElement() {
201             String value = null;
202             boolean done = false;
203             while (this.enumeration.hasMoreElements() && !done) {
204                 value = this.enumeration.nextElement();
205                 if (value.equals(CUSTOM_SHARED_VARIABLE_FACTORIES_INIT_PARAM)) {
206                     value = null;
207                 } else {
208                     done = true;
209                 }
210             }
211             next = value;
212         }
213 
214     }
215 }