001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036: package com.sun.tools.xjc.reader.xmlschema.parser;
037:
038: import java.util.HashSet;
039: import java.util.Set;
040: import java.util.Stack;
041:
042: import javax.xml.namespace.QName;
043:
044: import com.sun.tools.xjc.reader.Const;
045: import com.sun.xml.bind.v2.WellKnownNamespace;
046:
047: import org.xml.sax.Attributes;
048: import org.xml.sax.ErrorHandler;
049: import org.xml.sax.Locator;
050: import org.xml.sax.SAXException;
051: import org.xml.sax.SAXParseException;
052: import org.xml.sax.helpers.XMLFilterImpl;
053:
054: /**
055: * Checks if binding declarations are placed where they are allowed.
056: *
057: * <p>
058: * For example, if a <jaxb:property> customization is given under
059: * the <xs:simpleContent> element, this class raises an error.
060: *
061: * <p>
062: * our main checkpoint of misplaced customizations are in BGMBuilder.
063: * There, we mark a customization whenever we use it. At the end of the
064: * day, we look for unmarked customizations and raise errors for them.
065: *
066: * <p>
067: * Between this approach and the JAXB spec 1.0 is a problem that
068: * the spec allows/prohibits customizations at schema element level,
069: * while BGMBuilder and XSOM works on schema component levels.
070: *
071: * <p>
072: * For example, a property customization is allowed on a complex type
073: * schema component, but it's only allowed on the <complexType>
074: * element. The spec team informed us that they would consider resolving
075: * this discrepancy in favor of RI, but meanwhile we need to detect
076: * errors correctly.
077: *
078: * <p>
079: * This filter is implemented for this purpose.
080: *
081: *
082: * <h2>Customization and allowed locations</h2>
083: *
084: * - globalBinding/schemaBinding
085: * schema
086: *
087: * - class
088: * complexType(*), modelGroupDecl, modelGroup, element
089: *
090: * - property
091: * attribute, element, any, modelGroup, modelGroupRef, complexType(*)
092: *
093: * - javaType
094: * simpleType(*)
095: *
096: * - typesafeEnumClass
097: * simpleType(*)
098: *
099: * - typesafeEnumMember
100: * simpleType(*), enumeration
101: *
102: * Components marked with '*' needs a check by this component
103: * since more than one schema element corresponds to one schema component
104: * of that type.
105: *
106: * <p>
107: * For simple types, customizations are allowed only under the <xs:simpleType>
108: * element, and for complex types they are allowed only under the
109: * <xs:cimplexType> element.
110: *
111: * <p>
112: * So the bottom line is that it would be suffice if we just make sure
113: * that no customization will be attached under other elements of
114: * simple types and complex types. Those are:
115: *
116: * - simpleType/restriction
117: * - list
118: * - union
119: * - complexType/(simple or complex)Content
120: * - complexType/(simple or complex)Content/(restriction of extension)
121: *
122: * @author
123: * Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
124: */
125: public class CustomizationContextChecker extends XMLFilterImpl {
126:
127: /** Keep names of all the ancestor elements. */
128: private final Stack<QName> elementNames = new Stack<QName>();
129:
130: private final ErrorHandler errorHandler;
131:
132: private Locator locator;
133:
134: /** Set of element names that cannot have JAXB customizations. */
135: private static final Set<String> prohibitedSchemaElementNames = new HashSet<String>();
136:
137: /**
138: * @param _errorHandler
139: * Detected errors will be sent to this object.
140: */
141: public CustomizationContextChecker(ErrorHandler _errorHandler) {
142: this .errorHandler = _errorHandler;
143: }
144:
145: static {
146: prohibitedSchemaElementNames.add("restriction");
147: prohibitedSchemaElementNames.add("extension");
148: prohibitedSchemaElementNames.add("simpleContent");
149: prohibitedSchemaElementNames.add("complexContent");
150: prohibitedSchemaElementNames.add("list");
151: prohibitedSchemaElementNames.add("union");
152: }
153:
154: /** Gets the stack top. */
155: private QName top() {
156: return elementNames.peek();
157: }
158:
159: public void startElement(String namespaceURI, String localName,
160: String qName, Attributes atts) throws SAXException {
161: QName newElement = new QName(namespaceURI, localName);
162:
163: if (newElement.getNamespaceURI().equals(Const.JAXB_NSURI)
164: && top().getNamespaceURI().equals(
165: WellKnownNamespace.XML_SCHEMA)) {
166: // we hit a JAXB customization. the stack top should be
167: // <xs:appinfo>
168: if (elementNames.size() >= 3) {
169: // the above statement checks if the following statement doesn't
170: // cause an exception.
171: QName schemaElement = elementNames.get(elementNames
172: .size() - 3);
173: if (prohibitedSchemaElementNames.contains(schemaElement
174: .getLocalPart())) {
175: // the owner schema element is in the wanted list.
176: errorHandler
177: .error(new SAXParseException(
178: Messages
179: .format(
180: Messages.ERR_UNACKNOWLEDGED_CUSTOMIZATION,
181: localName), locator));
182: }
183: }
184:
185: }
186:
187: elementNames.push(newElement);
188:
189: super .startElement(namespaceURI, localName, qName, atts);
190: }
191:
192: public void endElement(String namespaceURI, String localName,
193: String qName) throws SAXException {
194:
195: super .endElement(namespaceURI, localName, qName);
196:
197: elementNames.pop();
198: }
199:
200: public void setDocumentLocator(Locator locator) {
201: super.setDocumentLocator(locator);
202: this.locator = locator;
203: }
204:
205: }
|