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