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 }