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