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:
037: package com.sun.tools.xjc.reader;
038:
039: import java.util.Set;
040: import java.util.HashSet;
041:
042: import com.sun.tools.xjc.util.SubtreeCutter;
043: import com.sun.tools.xjc.Options;
044: import com.sun.tools.xjc.Plugin;
045: import com.sun.xml.bind.v2.util.EditDistance;
046:
047: import org.xml.sax.helpers.NamespaceSupport;
048: import org.xml.sax.Locator;
049: import org.xml.sax.ErrorHandler;
050: import org.xml.sax.SAXParseException;
051: import org.xml.sax.SAXException;
052:
053: /**
054: * Common code between {@code DTDExtensionBindingChecker} and {@link ExtensionBindingChecker}.
055: *
056: * @author Kohsuke Kawaguchi
057: */
058: public abstract class AbstractExtensionBindingChecker extends
059: SubtreeCutter {
060: /** Remembers in-scope namespace bindings. */
061: protected final NamespaceSupport nsSupport = new NamespaceSupport();
062:
063: /**
064: * Set of namespace URIs that designates enabled extensions.
065: */
066: protected final Set<String> enabledExtensions = new HashSet<String>();
067:
068: private final Set<String> recognizableExtensions = new HashSet<String>();
069:
070: private Locator locator;
071:
072: /**
073: * Namespace URI of the target schema language. Elements in this
074: * namespace are always allowed.
075: */
076: protected final String schemaLanguage;
077:
078: /**
079: * If false, any use of extensions is reported as an error.
080: */
081: protected final boolean allowExtensions;
082:
083: private final Options options;
084:
085: /**
086: * @param handler
087: * This error handler will receive detected errors.
088: */
089: public AbstractExtensionBindingChecker(String schemaLanguage,
090: Options options, ErrorHandler handler) {
091: this .schemaLanguage = schemaLanguage;
092: this .allowExtensions = options.compatibilityMode != Options.STRICT;
093: this .options = options;
094: setErrorHandler(handler);
095:
096: for (Plugin plugin : options.getAllPlugins())
097: recognizableExtensions
098: .addAll(plugin.getCustomizationURIs());
099: recognizableExtensions.add(Const.XJC_EXTENSION_URI);
100: }
101:
102: /**
103: * Verify that the given URI is indeed a valid extension namespace URI,
104: * and if so enable it.
105: * <p>
106: * This method does all the error handling.
107: */
108: protected final void checkAndEnable(String uri) throws SAXException {
109: if (!isRecognizableExtension(uri)) {
110: String nearest = EditDistance.findNearest(uri,
111: recognizableExtensions);
112: // not the namespace URI we know of
113: error(Messages.ERR_UNSUPPORTED_EXTENSION.format(uri,
114: nearest));
115: } else if (!isSupportedExtension(uri)) {
116: // recognizable but not not supported, meaning
117: // the plug-in isn't enabled
118:
119: // look for plug-in that handles this URI
120: Plugin owner = null;
121: for (Plugin p : options.getAllPlugins()) {
122: if (p.getCustomizationURIs().contains(uri)) {
123: owner = p;
124: break;
125: }
126: }
127: if (owner != null)
128: // we know the plug-in that supports this namespace, but it's not enabled
129: error(Messages.ERR_PLUGIN_NOT_ENABLED.format(owner
130: .getOptionName(), uri));
131: else {
132: // this shouldn't happen, but be defensive...
133: error(Messages.ERR_UNSUPPORTED_EXTENSION.format(uri));
134: }
135: }
136:
137: // as an error recovery enable this namespace URI anyway.
138: enabledExtensions.add(uri);
139: }
140:
141: /**
142: * If the tag name belongs to a plugin namespace-wise, check its local name
143: * to make sure it's correct.
144: */
145: protected final void verifyTagName(String namespaceURI,
146: String localName, String qName) throws SAXException {
147: if (options.pluginURIs.contains(namespaceURI)) {
148: // make sure that this is a valid tag name
149: boolean correct = false;
150: for (Plugin p : options.activePlugins) {
151: if (p.isCustomizationTagName(namespaceURI, localName)) {
152: correct = true;
153: break;
154: }
155: }
156: if (!correct) {
157: error(Messages.ERR_ILLEGAL_CUSTOMIZATION_TAGNAME
158: .format(qName));
159: startCutting();
160: }
161: }
162: }
163:
164: /**
165: * Checks if the given namespace URI is supported as the extension
166: * bindings.
167: */
168: protected final boolean isSupportedExtension(String namespaceUri) {
169: return namespaceUri.equals(Const.XJC_EXTENSION_URI)
170: || options.pluginURIs.contains(namespaceUri);
171: }
172:
173: /**
174: * Checks if the given namespace URI can be potentially recognized
175: * by this XJC.
176: */
177: protected final boolean isRecognizableExtension(String namespaceUri) {
178: return recognizableExtensions.contains(namespaceUri);
179: }
180:
181: public void setDocumentLocator(Locator locator) {
182: super .setDocumentLocator(locator);
183: this .locator = locator;
184: }
185:
186: public void startDocument() throws SAXException {
187: super .startDocument();
188:
189: nsSupport.reset();
190: enabledExtensions.clear();
191: }
192:
193: public void startPrefixMapping(String prefix, String uri)
194: throws SAXException {
195: super .startPrefixMapping(prefix, uri);
196: nsSupport.pushContext();
197: nsSupport.declarePrefix(prefix, uri);
198: }
199:
200: public void endPrefixMapping(String prefix) throws SAXException {
201: super .endPrefixMapping(prefix);
202: nsSupport.popContext();
203: }
204:
205: /**
206: * Reports an error and returns the created SAXParseException
207: */
208: protected final SAXParseException error(String msg)
209: throws SAXException {
210: SAXParseException spe = new SAXParseException(msg, locator);
211: getErrorHandler().error(spe);
212: return spe;
213: }
214:
215: /**
216: * Reports a warning.
217: */
218: protected final void warning(String msg) throws SAXException {
219: SAXParseException spe = new SAXParseException(msg, locator);
220: getErrorHandler().warning(spe);
221: }
222: }
|