View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.struts2.jasper.compiler;
19  
20  import org.apache.struts2.jasper.JasperException;
21  import org.apache.struts2.jasper.compiler.tagplugin.TagPlugin;
22  import org.apache.struts2.jasper.compiler.tagplugin.TagPluginContext;
23  import org.apache.struts2.jasper.xmlparser.ParserUtils;
24  import org.apache.struts2.jasper.xmlparser.TreeNode;
25  
26  import javax.servlet.ServletContext;
27  import java.io.InputStream;
28  import java.util.HashMap;
29  import java.util.Iterator;
30  
31  /***
32   * Manages tag plugin optimizations.
33   *
34   * @author Kin-man Chung
35   */
36  
37  public class TagPluginManager {
38  
39      private static final String TAG_PLUGINS_XML = "/WEB-INF/tagPlugins.xml";
40      private static final String TAG_PLUGINS_ROOT_ELEM = "tag-plugins";
41  
42      private boolean initialized = false;
43      private HashMap tagPlugins = null;
44      private ServletContext ctxt;
45      private PageInfo pageInfo;
46  
47      public TagPluginManager(ServletContext ctxt) {
48          this.ctxt = ctxt;
49      }
50  
51      public void apply(Node.Nodes page, ErrorDispatcher err, PageInfo pageInfo)
52              throws JasperException {
53  
54          init(err);
55          if (tagPlugins == null || tagPlugins.size() == 0) {
56              return;
57          }
58  
59          this.pageInfo = pageInfo;
60  
61          page.visit(new Node.Visitor() {
62              public void visit(Node.CustomTag n)
63                      throws JasperException {
64                  invokePlugin(n);
65                  visitBody(n);
66              }
67          });
68  
69      }
70  
71      private void init(ErrorDispatcher err) throws JasperException {
72          if (initialized)
73              return;
74  
75          InputStream is = ctxt.getResourceAsStream(TAG_PLUGINS_XML);
76          if (is == null)
77              return;
78  
79          TreeNode root = (new ParserUtils()).parseXMLDocument(TAG_PLUGINS_XML,
80                  is);
81          if (root == null) {
82              return;
83          }
84  
85          if (!TAG_PLUGINS_ROOT_ELEM.equals(root.getName())) {
86              err.jspError("jsp.error.plugin.wrongRootElement", TAG_PLUGINS_XML,
87                      TAG_PLUGINS_ROOT_ELEM);
88          }
89  
90          tagPlugins = new HashMap();
91          Iterator pluginList = root.findChildren("tag-plugin");
92          while (pluginList.hasNext()) {
93              TreeNode pluginNode = (TreeNode) pluginList.next();
94              TreeNode tagClassNode = pluginNode.findChild("tag-class");
95              if (tagClassNode == null) {
96                  // Error
97                  return;
98              }
99              String tagClass = tagClassNode.getBody().trim();
100             TreeNode pluginClassNode = pluginNode.findChild("plugin-class");
101             if (pluginClassNode == null) {
102                 // Error
103                 return;
104             }
105 
106             String pluginClassStr = pluginClassNode.getBody();
107             TagPlugin tagPlugin = null;
108             try {
109                 Class pluginClass = Class.forName(pluginClassStr);
110                 tagPlugin = (TagPlugin) pluginClass.newInstance();
111             } catch (Exception e) {
112                 throw new JasperException(e);
113             }
114             if (tagPlugin == null) {
115                 return;
116             }
117             tagPlugins.put(tagClass, tagPlugin);
118         }
119         initialized = true;
120     }
121 
122     /***
123      * Invoke tag plugin for the given custom tag, if a plugin exists for
124      * the custom tag's tag handler.
125      * <p/>
126      * The given custom tag node will be manipulated by the plugin.
127      */
128     private void invokePlugin(Node.CustomTag n) {
129         TagPlugin tagPlugin = (TagPlugin)
130                 tagPlugins.get(n.getTagHandlerClass().getName());
131         if (tagPlugin == null) {
132             return;
133         }
134 
135         TagPluginContext tagPluginContext = new TagPluginContextImpl(n, pageInfo);
136         n.setTagPluginContext(tagPluginContext);
137         tagPlugin.doTag(tagPluginContext);
138     }
139 
140     static class TagPluginContextImpl implements TagPluginContext {
141         private Node.CustomTag node;
142         private Node.Nodes curNodes;
143         private PageInfo pageInfo;
144         private HashMap pluginAttributes;
145 
146         TagPluginContextImpl(Node.CustomTag n, PageInfo pageInfo) {
147             this.node = n;
148             this.pageInfo = pageInfo;
149             curNodes = new Node.Nodes();
150             n.setAtETag(curNodes);
151             curNodes = new Node.Nodes();
152             n.setAtSTag(curNodes);
153             n.setUseTagPlugin(true);
154             pluginAttributes = new HashMap();
155         }
156 
157         public TagPluginContext getParentContext() {
158             Node parent = node.getParent();
159             if (!(parent instanceof Node.CustomTag)) {
160                 return null;
161             }
162             return ((Node.CustomTag) parent).getTagPluginContext();
163         }
164 
165         public void setPluginAttribute(String key, Object value) {
166             pluginAttributes.put(key, value);
167         }
168 
169         public Object getPluginAttribute(String key) {
170             return pluginAttributes.get(key);
171         }
172 
173         public boolean isScriptless() {
174             return node.getChildInfo().isScriptless();
175         }
176 
177         public boolean isConstantAttribute(String attribute) {
178             Node.JspAttribute attr = getNodeAttribute(attribute);
179             if (attr == null)
180                 return false;
181             return attr.isLiteral();
182         }
183 
184         public String getConstantAttribute(String attribute) {
185             Node.JspAttribute attr = getNodeAttribute(attribute);
186             if (attr == null)
187                 return null;
188             return attr.getValue();
189         }
190 
191         public boolean isAttributeSpecified(String attribute) {
192             return getNodeAttribute(attribute) != null;
193         }
194 
195         public String getTemporaryVariableName() {
196             return JspUtil.nextTemporaryVariableName();
197         }
198 
199         public void generateImport(String imp) {
200             pageInfo.addImport(imp);
201         }
202 
203         public void generateDeclaration(String id, String text) {
204             if (pageInfo.isPluginDeclared(id)) {
205                 return;
206             }
207             curNodes.add(new Node.Declaration(text, node.getStart(), null));
208         }
209 
210         public void generateJavaSource(String sourceCode) {
211             curNodes.add(new Node.Scriptlet(sourceCode, node.getStart(),
212                     null));
213         }
214 
215         public void generateAttribute(String attributeName) {
216             curNodes.add(new Node.AttributeGenerator(node.getStart(),
217                     attributeName,
218                     node));
219         }
220 
221         public void dontUseTagPlugin() {
222             node.setUseTagPlugin(false);
223         }
224 
225         public void generateBody() {
226             // Since we'll generate the body anyway, this is really a nop,
227             // except for the fact that it lets us put the Java sources the
228             // plugins produce in the correct order (w.r.t the body).
229             curNodes = node.getAtETag();
230         }
231 
232         private Node.JspAttribute getNodeAttribute(String attribute) {
233             Node.JspAttribute[] attrs = node.getJspAttributes();
234             for (int i = 0; attrs != null && i < attrs.length; i++) {
235                 if (attrs[i].getName().equals(attribute)) {
236                     return attrs[i];
237                 }
238             }
239             return null;
240         }
241     }
242 }