001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements. See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership. The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the  "License");
007     * you may not use this file except in compliance with the License.
008     * You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    /*
019     * $Id: Template.java 1225842 2011-12-30 15:14:35Z mrglavas $
020     */
021    
022    package org.apache.xalan.xsltc.compiler;
023    
024    import java.util.Vector;
025    
026    import org.apache.bcel.generic.ConstantPoolGen;
027    import org.apache.bcel.generic.INVOKEVIRTUAL;
028    import org.apache.bcel.generic.InstructionList;
029    import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
030    import org.apache.xalan.xsltc.compiler.util.ErrorMsg;
031    import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
032    import org.apache.xalan.xsltc.compiler.util.NamedMethodGenerator;
033    import org.apache.xalan.xsltc.compiler.util.Type;
034    import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
035    import org.apache.xalan.xsltc.compiler.util.Util;
036    import org.apache.xml.utils.XML11Char;
037    
038    
039    /**
040     * @author Jacek Ambroziak
041     * @author Santiago Pericas-Geertsen
042     * @author Morten Jorgensen
043     * @author Erwin Bolwidt <ejb@klomp.org>
044     */
045    public final class Template extends TopLevelElement {
046    
047        private QName   _name;     // The name of the template (if any)
048        private QName   _mode;     // Mode in which this template is instantiated.
049        private Pattern _pattern;  // Matching pattern defined for this template.
050        private double  _priority; // Matching priority of this template.
051        private int     _position; // Position within stylesheet (prio. resolution)
052        private boolean _disabled = false;
053        private boolean _compiled = false;//make sure it is compiled only once
054        private boolean _simplified = false;
055    
056        // True if this is a simple named template. A simple named 
057        // template is a template which only has a name but no match pattern.
058        private boolean _isSimpleNamedTemplate = false;
059        
060        // The list of parameters in this template. This is only used
061        // for simple named templates.
062        private Vector  _parameters = new Vector();
063        
064        public boolean hasParams() {
065            return _parameters.size() > 0;
066        }
067    
068        public boolean isSimplified() {
069            return(_simplified);
070        }
071    
072        public void setSimplified() {
073            _simplified = true;
074        }
075    
076        public boolean isSimpleNamedTemplate() {
077            return _isSimpleNamedTemplate;
078        }
079        
080        public void addParameter(Param param) {
081            _parameters.addElement(param);
082        }
083        
084        public Vector getParameters() {
085            return _parameters;
086        }
087    
088        public void disable() {
089            _disabled = true;
090        }
091    
092        public boolean disabled() {
093            return(_disabled);
094        }
095    
096        public double getPriority() {
097            return _priority;
098        }
099    
100        public int getPosition() {
101            return(_position);
102        }
103    
104        public boolean isNamed() {
105            return _name != null;
106        }
107    
108        public Pattern getPattern() {
109            return _pattern;
110        }
111    
112        public QName getName() {
113            return _name;
114        }
115    
116        public void setName(QName qname) {
117            if (_name == null) _name = qname;
118        }
119    
120        public QName getModeName() {
121            return _mode;
122        }
123    
124        /**
125         * Compare this template to another. First checks priority, then position.
126         */
127        public int compareTo(Object template) {
128            Template other = (Template)template;
129            if (_priority > other._priority)
130                return 1;
131            else if (_priority < other._priority)
132                return -1;
133            else if (_position > other._position)
134                return 1;
135            else if (_position < other._position)
136                return -1;
137            else
138                return 0;
139        }
140    
141        public void display(int indent) {
142            Util.println('\n');
143            indent(indent);
144            if (_name != null) {
145                indent(indent);
146                Util.println("name = " + _name);
147            }
148            else if (_pattern != null) {
149                indent(indent);
150                Util.println("match = " + _pattern.toString());
151            }
152            if (_mode != null) {
153                indent(indent);
154                Util.println("mode = " + _mode);
155            }
156            displayContents(indent + IndentIncrement);
157        }
158    
159        private boolean resolveNamedTemplates(Template other, Parser parser) {
160    
161            if (other == null) return true;
162    
163            SymbolTable stable = parser.getSymbolTable();
164    
165            final int us = this.getImportPrecedence();
166            final int them = other.getImportPrecedence();
167    
168            if (us > them) {
169                other.disable();
170                return true;
171            }
172            else if (us < them) {
173                stable.addTemplate(other);
174                this.disable();
175                return true;
176            }
177            else {
178                return false;
179            }
180        }
181    
182        private Stylesheet _stylesheet = null;
183    
184        public Stylesheet getStylesheet() {
185            return _stylesheet;
186        }
187    
188        public void parseContents(Parser parser) {
189    
190            final String name     = getAttribute("name");
191            final String mode     = getAttribute("mode");
192            final String match    = getAttribute("match");
193            final String priority = getAttribute("priority");
194    
195            _stylesheet = super.getStylesheet();
196    
197            if (name.length() > 0) {
198                if (!XML11Char.isXML11ValidQName(name)) {
199                    ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, name, this);
200                    parser.reportError(Constants.ERROR, err);           
201                }                
202                _name = parser.getQNameIgnoreDefaultNs(name);
203            }
204            
205            if (mode.length() > 0) {
206                if (!XML11Char.isXML11ValidQName(mode)) {
207                    ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, mode, this);
208                    parser.reportError(Constants.ERROR, err);           
209                }           
210                _mode = parser.getQNameIgnoreDefaultNs(mode);
211            }
212            
213            if (match.length() > 0) {
214                _pattern = parser.parsePattern(this, "match", null);
215            }
216    
217            if (priority.length() > 0) {
218                _priority = Double.parseDouble(priority);
219            }
220            else {
221                if (_pattern != null)
222                    _priority = _pattern.getPriority();
223                else
224                    _priority = Double.NaN;
225            }
226    
227            _position = parser.getTemplateIndex();
228    
229            // Add the (named) template to the symbol table
230            if (_name != null) {
231                Template other = parser.getSymbolTable().addTemplate(this);
232                if (!resolveNamedTemplates(other, parser)) {
233                    ErrorMsg err =
234                        new ErrorMsg(ErrorMsg.TEMPLATE_REDEF_ERR, _name, this);
235                    parser.reportError(Constants.ERROR, err);
236                }
237                // Is this a simple named template?
238                if (_pattern == null && _mode == null) {
239                    _isSimpleNamedTemplate = true;
240                }
241            }
242    
243            if (_parent instanceof Stylesheet) {
244                ((Stylesheet)_parent).addTemplate(this);
245            }
246            
247            parser.setTemplate(this);       // set current template
248            parseChildren(parser);
249            parser.setTemplate(null);       // clear template
250        }
251    
252        /**
253         * When the parser realises that it is dealign with a simplified stylesheet
254         * it will create an empty Stylesheet object with the root element of the
255         * stylesheet (a LiteralElement object) as its only child. The Stylesheet
256         * object will then create this Template object and invoke this method to
257         * force some specific behaviour. What we need to do is:
258         *  o) create a pattern matching on the root node
259         *  o) add the LRE root node (the only child of the Stylesheet) as our
260         *     only child node
261         *  o) set the empty Stylesheet as our parent
262         *  o) set this template as the Stylesheet's only child
263         */
264        public void parseSimplified(Stylesheet stylesheet, Parser parser) {
265    
266            _stylesheet = stylesheet;
267            setParent(stylesheet);
268    
269            _name = null;
270            _mode = null;
271            _priority = Double.NaN;
272            _pattern = parser.parsePattern(this, "/");
273    
274            final Vector contents = _stylesheet.getContents();
275            final SyntaxTreeNode root = (SyntaxTreeNode)contents.elementAt(0);
276    
277            if (root instanceof LiteralElement) {
278                addElement(root);
279                root.setParent(this);
280                contents.set(0, this);
281                parser.setTemplate(this);
282                root.parseContents(parser);
283                parser.setTemplate(null);
284            }
285        }
286    
287        public Type typeCheck(SymbolTable stable) throws TypeCheckError {
288            if (_pattern != null) {
289                _pattern.typeCheck(stable);
290            }
291    
292            return typeCheckContents(stable);
293        }
294    
295        public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
296            final ConstantPoolGen cpg = classGen.getConstantPool();
297            final InstructionList il = methodGen.getInstructionList();
298    
299            if (_disabled) return;
300            // bug fix #4433133, add a call to named template from applyTemplates 
301            String className = classGen.getClassName();
302    
303            if (_compiled && isNamed()){
304                String methodName = Util.escape(_name.toString());
305                il.append(classGen.loadTranslet());
306                il.append(methodGen.loadDOM());
307                il.append(methodGen.loadIterator());
308                il.append(methodGen.loadHandler()); 
309                il.append(methodGen.loadCurrentNode()); 
310                il.append(new INVOKEVIRTUAL(cpg.addMethodref(className,
311                                                             methodName,
312                                                             "("
313                                                             + DOM_INTF_SIG
314                                                             + NODE_ITERATOR_SIG
315                                                             + TRANSLET_OUTPUT_SIG
316                                                             + "I)V")));
317                return;
318            }
319    
320            if (_compiled) return;
321            _compiled = true; 
322                    
323            // %OPT% Special handling for simple named templates.
324            if (_isSimpleNamedTemplate && methodGen instanceof NamedMethodGenerator) {
325                int numParams = _parameters.size();
326                NamedMethodGenerator namedMethodGen = (NamedMethodGenerator)methodGen;
327                
328                // Update load/store instructions to access Params from the stack
329                for (int i = 0; i < numParams; i++) {
330                    Param param = (Param)_parameters.elementAt(i);
331                    param.setLoadInstruction(namedMethodGen.loadParameter(i));
332                    param.setStoreInstruction(namedMethodGen.storeParameter(i));
333                }
334            }
335            
336            translateContents(classGen, methodGen);
337            il.setPositions(true);
338        }
339            
340    }