1 /*
2  * Copyright (c) 2015, 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  * $Id: AttributeSet.java,v 1.5 2005/09/28 13:48:04 pvedula Exp $
22  */
23 
24 package com.sun.org.apache.xalan.internal.xsltc.compiler;
25 
26 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
27 import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
28 import com.sun.org.apache.bcel.internal.generic.InstructionList;
29 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.AttributeSetMethodGenerator;
30 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
31 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
32 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
33 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
34 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
35 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
36 import com.sun.org.apache.xml.internal.utils.XML11Char;
37 import java.util.Iterator;
38 import java.util.List;
39 
40 /**
41  * @author Jacek Ambroziak
42  * @author Santiago Pericas-Geertsen
43  * @author Morten Jorgensen
44  */
45 final class AttributeSet extends TopLevelElement {
46 
47     // This prefix is used for the method name of attribute set methods
48     private static final String AttributeSetPrefix = "$as$";
49 
50     // Element contents
51     private QName            _name;
52     private UseAttributeSets _useSets;
53     private AttributeSet     _mergeSet;
54     private String           _method;
55     private boolean          _ignore = false;
56 
57     /**
58      * Returns the QName of this attribute set
59      */
getName()60     public QName getName() {
61         return _name;
62     }
63 
64     /**
65      * Returns the method name of this attribute set. This method name is
66      * generated by the compiler (XSLTC)
67      */
getMethodName()68     public String getMethodName() {
69         return _method;
70     }
71 
72     /**
73      * Call this method to prevent a method for being compiled for this set.
74      * This is used in case several <xsl:attribute-set...> elements constitute
75      * a single set (with one name). The last element will merge itself with
76      * any previous set(s) with the same name and disable the other set(s).
77      */
ignore()78     public void ignore() {
79         _ignore = true;
80     }
81 
82     /**
83      * Parse the contents of this attribute set. Recognised attributes are
84      * "name" (required) and "use-attribute-sets" (optional).
85      */
parseContents(Parser parser)86     public void parseContents(Parser parser) {
87 
88         // Get this attribute set's name
89         final String name = getAttribute("name");
90 
91         if (!XML11Char.isXML11ValidQName(name)) {
92             ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, name, this);
93             parser.reportError(Constants.ERROR, err);
94         }
95         _name = parser.getQNameIgnoreDefaultNs(name);
96         if ((_name == null) || (_name.equals(EMPTYSTRING))) {
97             ErrorMsg msg = new ErrorMsg(ErrorMsg.UNNAMED_ATTRIBSET_ERR, this);
98             parser.reportError(Constants.ERROR, msg);
99         }
100 
101         // Get any included attribute sets (similar to inheritance...)
102         final String useSets = getAttribute("use-attribute-sets");
103         if (useSets.length() > 0) {
104             if (!Util.isValidQNames(useSets)) {
105                 ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, useSets, this);
106                 parser.reportError(Constants.ERROR, err);
107             }
108             _useSets = new UseAttributeSets(useSets, parser);
109         }
110 
111         // Parse the contents of this node. All child elements must be
112         // <xsl:attribute> elements. Other elements cause an error.
113         final List<SyntaxTreeNode> contents = getContents();
114         final int count = contents.size();
115         for (int i=0; i<count; i++) {
116             SyntaxTreeNode child = contents.get(i);
117             if (child instanceof XslAttribute) {
118                 parser.getSymbolTable().setCurrentNode(child);
119                 child.parseContents(parser);
120             }
121             else if (child instanceof Text) {
122                 // ignore
123             }
124             else {
125                 ErrorMsg msg = new ErrorMsg(ErrorMsg.ILLEGAL_CHILD_ERR, this);
126                 parser.reportError(Constants.ERROR, msg);
127             }
128         }
129 
130         // Point the symbol table back at us...
131         parser.getSymbolTable().setCurrentNode(this);
132     }
133 
134     /**
135      * Type check the contents of this element
136      */
typeCheck(SymbolTable stable)137     public Type typeCheck(SymbolTable stable) throws TypeCheckError {
138 
139         if (_ignore) return (Type.Void);
140 
141         // _mergeSet Point to any previous definition of this attribute set
142         _mergeSet = stable.addAttributeSet(this);
143 
144         _method = AttributeSetPrefix + getXSLTC().nextAttributeSetSerial();
145 
146         if (_useSets != null) _useSets.typeCheck(stable);
147         typeCheckContents(stable);
148         return Type.Void;
149     }
150 
151     /**
152      * Compile a method that outputs the attributes in this set
153      */
translate(ClassGenerator classGen, MethodGenerator methodGen)154     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
155 
156         if (_ignore) return;
157 
158         // Create a new method generator for an attribute set method
159         methodGen = new AttributeSetMethodGenerator(_method, classGen);
160 
161         // Generate a reference to previous attribute-set definitions with the
162         // same name first.  Those later in the stylesheet take precedence.
163         if (_mergeSet != null) {
164             final ConstantPoolGen cpg = classGen.getConstantPool();
165             final InstructionList il = methodGen.getInstructionList();
166             final String methodName = _mergeSet.getMethodName();
167 
168             il.append(classGen.loadTranslet());
169             il.append(methodGen.loadDOM());
170             il.append(methodGen.loadIterator());
171             il.append(methodGen.loadHandler());
172             il.append(methodGen.loadCurrentNode());
173             final int method = cpg.addMethodref(classGen.getClassName(),
174                                                 methodName, ATTR_SET_SIG);
175             il.append(new INVOKESPECIAL(method));
176         }
177 
178         // Translate other used attribute sets first, as local attributes
179         // take precedence (last attributes overrides first)
180         if (_useSets != null) _useSets.translate(classGen, methodGen);
181 
182         // Translate all local attributes
183         final Iterator<SyntaxTreeNode> attributes = elements();
184         while (attributes.hasNext()) {
185             SyntaxTreeNode element = attributes.next();
186             if (element instanceof XslAttribute) {
187                 final XslAttribute attribute = (XslAttribute)element;
188                 attribute.translate(classGen, methodGen);
189             }
190         }
191         final InstructionList il = methodGen.getInstructionList();
192         il.append(RETURN);
193 
194         classGen.addMethod(methodGen);
195     }
196 
toString()197     public String toString() {
198         StringBuffer buf = new StringBuffer("attribute-set: ");
199         // Translate all local attributes
200         final Iterator<SyntaxTreeNode> attributes = elements();
201         while (attributes.hasNext()) {
202             final XslAttribute attribute =
203                 (XslAttribute)attributes.next();
204             buf.append(attribute);
205         }
206         return(buf.toString());
207     }
208 }
209