View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   /*
6    * Copyright 2001-2004 The Apache Software Foundation.
7    *
8    * Licensed under the Apache License, Version 2.0 (the "License");
9    * you may not use this file except in compliance with the License.
10   * 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, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  /*
21   * $Id: Template.java,v 1.2.4.1 2005/09/12 11:30:11 pvedula Exp $
22   */
23  
24  package com.sun.org.apache.xalan.internal.xsltc.compiler;
25  
26  import java.util.Vector;
27  
28  import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
29  import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
30  import com.sun.org.apache.bcel.internal.generic.InstructionHandle;
31  import com.sun.org.apache.bcel.internal.generic.InstructionList;
32  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
33  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
34  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
35  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NamedMethodGenerator;
36  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
37  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
38  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
39  import com.sun.org.apache.xml.internal.utils.XML11Char;
40  
41  
42  /**
43   * @author Jacek Ambroziak
44   * @author Santiago Pericas-Geertsen
45   * @author Morten Jorgensen
46   * @author Erwin Bolwidt <ejb@klomp.org>
47   */
48  public final class Template extends TopLevelElement {
49  
50      private QName   _name;     // The name of the template (if any)
51      private QName   _mode;     // Mode in which this template is instantiated.
52      private Pattern _pattern;  // Matching pattern defined for this template.
53      private double  _priority; // Matching priority of this template.
54      private int     _position; // Position within stylesheet (prio. resolution)
55      private boolean _disabled = false;
56      private boolean _compiled = false;//make sure it is compiled only once
57      private boolean _simplified = false;
58  
59      // True if this is a simple named template. A simple named
60      // template is a template which only has a name but no match pattern.
61      private boolean _isSimpleNamedTemplate = false;
62  
63      // The list of parameters in this template. This is only used
64      // for simple named templates.
65      private Vector  _parameters = new Vector();
66  
67      public boolean hasParams() {
68          return _parameters.size() > 0;
69      }
70  
71      public boolean isSimplified() {
72          return(_simplified);
73      }
74  
75      public void setSimplified() {
76          _simplified = true;
77      }
78  
79      public boolean isSimpleNamedTemplate() {
80          return _isSimpleNamedTemplate;
81      }
82  
83      public void addParameter(Param param) {
84          _parameters.addElement(param);
85      }
86  
87      public Vector getParameters() {
88          return _parameters;
89      }
90  
91      public void disable() {
92          _disabled = true;
93      }
94  
95      public boolean disabled() {
96          return(_disabled);
97      }
98  
99      public double getPriority() {
100         return _priority;
101     }
102 
103     public int getPosition() {
104         return(_position);
105     }
106 
107     public boolean isNamed() {
108         return _name != null;
109     }
110 
111     public Pattern getPattern() {
112         return _pattern;
113     }
114 
115     public QName getName() {
116         return _name;
117     }
118 
119     public void setName(QName qname) {
120         if (_name == null) _name = qname;
121     }
122 
123     public QName getModeName() {
124         return _mode;
125     }
126 
127     /**
128      * Compare this template to another. First checks priority, then position.
129      */
130     public int compareTo(Object template) {
131         Template other = (Template)template;
132         if (_priority > other._priority)
133             return 1;
134         else if (_priority < other._priority)
135             return -1;
136         else if (_position > other._position)
137             return 1;
138         else if (_position < other._position)
139             return -1;
140         else
141             return 0;
142     }
143 
144     public void display(int indent) {
145         Util.println('\n');
146         indent(indent);
147         if (_name != null) {
148             indent(indent);
149             Util.println("name = " + _name);
150         }
151         else if (_pattern != null) {
152             indent(indent);
153             Util.println("match = " + _pattern.toString());
154         }
155         if (_mode != null) {
156             indent(indent);
157             Util.println("mode = " + _mode);
158         }
159         displayContents(indent + IndentIncrement);
160     }
161 
162     private boolean resolveNamedTemplates(Template other, Parser parser) {
163 
164         if (other == null) return true;
165 
166         SymbolTable stable = parser.getSymbolTable();
167 
168         final int us = this.getImportPrecedence();
169         final int them = other.getImportPrecedence();
170 
171         if (us > them) {
172             other.disable();
173             return true;
174         }
175         else if (us < them) {
176             stable.addTemplate(other);
177             this.disable();
178             return true;
179         }
180         else {
181             return false;
182         }
183     }
184 
185     private Stylesheet _stylesheet = null;
186 
187     public Stylesheet getStylesheet() {
188         return _stylesheet;
189     }
190 
191     public void parseContents(Parser parser) {
192 
193         final String name     = getAttribute("name");
194         final String mode     = getAttribute("mode");
195         final String match    = getAttribute("match");
196         final String priority = getAttribute("priority");
197 
198         _stylesheet = super.getStylesheet();
199 
200         if (name.length() > 0) {
201             if (!XML11Char.isXML11ValidQName(name)) {
202                 ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, name, this);
203                 parser.reportError(Constants.ERROR, err);
204             }
205             _name = parser.getQNameIgnoreDefaultNs(name);
206         }
207 
208         if (mode.length() > 0) {
209             if (!XML11Char.isXML11ValidQName(mode)) {
210                 ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, mode, this);
211                 parser.reportError(Constants.ERROR, err);
212             }
213             _mode = parser.getQNameIgnoreDefaultNs(mode);
214         }
215 
216         if (match.length() > 0) {
217             _pattern = parser.parsePattern(this, "match", null);
218         }
219 
220         if (priority.length() > 0) {
221             _priority = Double.parseDouble(priority);
222         }
223         else {
224             if (_pattern != null)
225                 _priority = _pattern.getPriority();
226             else
227                 _priority = Double.NaN;
228         }
229 
230         _position = parser.getTemplateIndex();
231 
232         // Add the (named) template to the symbol table
233         if (_name != null) {
234             Template other = parser.getSymbolTable().addTemplate(this);
235             if (!resolveNamedTemplates(other, parser)) {
236                 ErrorMsg err =
237                     new ErrorMsg(ErrorMsg.TEMPLATE_REDEF_ERR, _name, this);
238                 parser.reportError(Constants.ERROR, err);
239             }
240             // Is this a simple named template?
241             if (_pattern == null && _mode == null) {
242                 _isSimpleNamedTemplate = true;
243             }
244         }
245 
246         if (_parent instanceof Stylesheet) {
247             ((Stylesheet)_parent).addTemplate(this);
248         }
249 
250         parser.setTemplate(this);       // set current template
251         parseChildren(parser);
252         parser.setTemplate(null);       // clear template
253     }
254 
255     /**
256      * When the parser realises that it is dealign with a simplified stylesheet
257      * it will create an empty Stylesheet object with the root element of the
258      * stylesheet (a LiteralElement object) as its only child. The Stylesheet
259      * object will then create this Template object and invoke this method to
260      * force some specific behaviour. What we need to do is:
261      *  o) create a pattern matching on the root node
262      *  o) add the LRE root node (the only child of the Stylesheet) as our
263      *     only child node
264      *  o) set the empty Stylesheet as our parent
265      *  o) set this template as the Stylesheet's only child
266      */
267     public void parseSimplified(Stylesheet stylesheet, Parser parser) {
268 
269         _stylesheet = stylesheet;
270         setParent(stylesheet);
271 
272         _name = null;
273         _mode = null;
274         _priority = Double.NaN;
275         _pattern = parser.parsePattern(this, "/");
276 
277         final Vector contents = _stylesheet.getContents();
278         final SyntaxTreeNode root = (SyntaxTreeNode)contents.elementAt(0);
279 
280         if (root instanceof LiteralElement) {
281             addElement(root);
282             root.setParent(this);
283             contents.set(0, this);
284             parser.setTemplate(this);
285             root.parseContents(parser);
286             parser.setTemplate(null);
287         }
288     }
289 
290     public Type typeCheck(SymbolTable stable) throws TypeCheckError {
291         if (_pattern != null) {
292             _pattern.typeCheck(stable);
293         }
294 
295         return typeCheckContents(stable);
296     }
297 
298     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
299         final ConstantPoolGen cpg = classGen.getConstantPool();
300         final InstructionList il = methodGen.getInstructionList();
301 
302         if (_disabled) return;
303         // bug fix #4433133, add a call to named template from applyTemplates
304         String className = classGen.getClassName();
305 
306         if (_compiled && isNamed()){
307             String methodName = Util.escape(_name.toString());
308             il.append(classGen.loadTranslet());
309             il.append(methodGen.loadDOM());
310             il.append(methodGen.loadIterator());
311             il.append(methodGen.loadHandler());
312             il.append(methodGen.loadCurrentNode());
313             il.append(new INVOKEVIRTUAL(cpg.addMethodref(className,
314                                                          methodName,
315                                                          "("
316                                                          + DOM_INTF_SIG
317                                                          + NODE_ITERATOR_SIG
318                                                          + TRANSLET_OUTPUT_SIG
319                                                          + "I)V")));
320             return;
321         }
322 
323         if (_compiled) return;
324         _compiled = true;
325 
326         // %OPT% Special handling for simple named templates.
327         if (_isSimpleNamedTemplate && methodGen instanceof NamedMethodGenerator) {
328             int numParams = _parameters.size();
329             NamedMethodGenerator namedMethodGen = (NamedMethodGenerator)methodGen;
330 
331             // Update load/store instructions to access Params from the stack
332             for (int i = 0; i < numParams; i++) {
333                 Param param = (Param)_parameters.elementAt(i);
334                 param.setLoadInstruction(namedMethodGen.loadParameter(i));
335                 param.setStoreInstruction(namedMethodGen.storeParameter(i));
336             }
337         }
338 
339         translateContents(classGen, methodGen);
340         il.setPositions(true);
341     }
342 
343 }