001: /*
002: * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.tools.internal.xjc.reader.xmlschema.parser;
027:
028: import java.util.HashSet;
029: import java.util.Set;
030: import java.util.Stack;
031:
032: import javax.xml.namespace.QName;
033:
034: import com.sun.tools.internal.xjc.reader.Const;
035: import com.sun.xml.internal.bind.v2.WellKnownNamespace;
036:
037: import org.xml.sax.Attributes;
038: import org.xml.sax.ErrorHandler;
039: import org.xml.sax.Locator;
040: import org.xml.sax.SAXException;
041: import org.xml.sax.SAXParseException;
042: import org.xml.sax.helpers.XMLFilterImpl;
043:
044: /**
045: * Checks if binding declarations are placed where they are allowed.
046: *
047: * <p>
048: * For example, if a <jaxb:property> customization is given under
049: * the <xs:simpleContent> element, this class raises an error.
050: *
051: * <p>
052: * our main checkpoint of misplaced customizations are in BGMBuilder.
053: * There, we mark a customization whenever we use it. At the end of the
054: * day, we look for unmarked customizations and raise errors for them.
055: *
056: * <p>
057: * Between this approach and the JAXB spec 1.0 is a problem that
058: * the spec allows/prohibits customizations at schema element level,
059: * while BGMBuilder and XSOM works on schema component levels.
060: *
061: * <p>
062: * For example, a property customization is allowed on a complex type
063: * schema component, but it's only allowed on the <complexType>
064: * element. The spec team informed us that they would consider resolving
065: * this discrepancy in favor of RI, but meanwhile we need to detect
066: * errors correctly.
067: *
068: * <p>
069: * This filter is implemented for this purpose.
070: *
071: *
072: * <h2>Customization and allowed locations</h2>
073: *
074: * - globalBinding/schemaBinding
075: * schema
076: *
077: * - class
078: * complexType(*), modelGroupDecl, modelGroup, element
079: *
080: * - property
081: * attribute, element, any, modelGroup, modelGroupRef, complexType(*)
082: *
083: * - javaType
084: * simpleType(*)
085: *
086: * - typesafeEnumClass
087: * simpleType(*)
088: *
089: * - typesafeEnumMember
090: * simpleType(*), enumeration
091: *
092: * Components marked with '*' needs a check by this component
093: * since more than one schema element corresponds to one schema component
094: * of that type.
095: *
096: * <p>
097: * For simple types, customizations are allowed only under the <xs:simpleType>
098: * element, and for complex types they are allowed only under the
099: * <xs:cimplexType> element.
100: *
101: * <p>
102: * So the bottom line is that it would be suffice if we just make sure
103: * that no customization will be attached under other elements of
104: * simple types and complex types. Those are:
105: *
106: * - simpleType/restriction
107: * - list
108: * - union
109: * - complexType/(simple or complex)Content
110: * - complexType/(simple or complex)Content/(restriction of extension)
111: *
112: * @author
113: * Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
114: */
115: public class CustomizationContextChecker extends XMLFilterImpl {
116:
117: /** Keep names of all the ancestor elements. */
118: private final Stack<QName> elementNames = new Stack<QName>();
119:
120: private final ErrorHandler errorHandler;
121:
122: private Locator locator;
123:
124: /** Set of element names that cannot have JAXB customizations. */
125: private static final Set<String> prohibitedSchemaElementNames = new HashSet<String>();
126:
127: /**
128: * @param _errorHandler
129: * Detected errors will be sent to this object.
130: */
131: public CustomizationContextChecker(ErrorHandler _errorHandler) {
132: this .errorHandler = _errorHandler;
133: }
134:
135: static {
136: prohibitedSchemaElementNames.add("restriction");
137: prohibitedSchemaElementNames.add("extension");
138: prohibitedSchemaElementNames.add("simpleContent");
139: prohibitedSchemaElementNames.add("complexContent");
140: prohibitedSchemaElementNames.add("list");
141: prohibitedSchemaElementNames.add("union");
142: }
143:
144: /** Gets the stack top. */
145: private QName top() {
146: return elementNames.peek();
147: }
148:
149: public void startElement(String namespaceURI, String localName,
150: String qName, Attributes atts) throws SAXException {
151: QName newElement = new QName(namespaceURI, localName);
152:
153: if (newElement.getNamespaceURI().equals(Const.JAXB_NSURI)
154: && top().getNamespaceURI().equals(
155: WellKnownNamespace.XML_SCHEMA)) {
156: // we hit a JAXB customization. the stack top should be
157: // <xs:appinfo>
158: if (elementNames.size() >= 3) {
159: // the above statement checks if the following statement doesn't
160: // cause an exception.
161: QName schemaElement = elementNames.get(elementNames
162: .size() - 3);
163: if (prohibitedSchemaElementNames.contains(schemaElement
164: .getLocalPart())) {
165: // the owner schema element is in the wanted list.
166: errorHandler
167: .error(new SAXParseException(
168: Messages
169: .format(
170: Messages.ERR_UNACKNOWLEDGED_CUSTOMIZATION,
171: localName), locator));
172: }
173: }
174:
175: }
176:
177: elementNames.push(newElement);
178:
179: super .startElement(namespaceURI, localName, qName, atts);
180: }
181:
182: public void endElement(String namespaceURI, String localName,
183: String qName) throws SAXException {
184:
185: super .endElement(namespaceURI, localName, qName);
186:
187: elementNames.pop();
188: }
189:
190: public void setDocumentLocator(Locator locator) {
191: super.setDocumentLocator(locator);
192: this.locator = locator;
193: }
194:
195: }
|