| /* |
| * The Apache Software License, Version 1.1 |
| * |
| * |
| * Copyright (c) 2003 The Apache Software Foundation. All rights |
| * reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. The end-user documentation included with the redistribution, |
| * if any, must include the following acknowledgment: |
| * "This product includes software developed by the |
| * Apache Software Foundation (http://www.apache.org/)." |
| * Alternately, this acknowledgment may appear in the software itself, |
| * if and wherever such third-party acknowledgments normally appear. |
| * |
| * 4. The names "Apache" and "Apache Software Foundation" must |
| * not be used to endorse or promote products derived from this |
| * software without prior written permission. For written |
| * permission, please contact apache@apache.org. |
| * |
| * 5. Products derived from this software may not be called "Apache |
| * XMLBeans", nor may "Apache" appear in their name, without prior |
| * written permission of the Apache Software Foundation. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation and was |
| * originally based on software copyright (c) 2000-2003 BEA Systems |
| * Inc., <http://www.bea.com/>. For more information on the Apache Software |
| * Foundation, please see <http://www.apache.org/>. |
| */ |
| |
| package org.apache.xmlbeans.impl.schema; |
| |
| import org.apache.xmlbeans.impl.common.XmlErrorContext; |
| import org.apache.xmlbeans.impl.common.QNameHelper; |
| import org.apache.xmlbeans.impl.config.SchemaConfig; |
| import org.apache.xmlbeans.XmlObject; |
| import org.apache.xmlbeans.SchemaGlobalElement; |
| import org.apache.xmlbeans.SchemaComponent; |
| import org.apache.xmlbeans.SchemaType; |
| import org.apache.xmlbeans.SchemaGlobalAttribute; |
| import org.apache.xmlbeans.SchemaAttributeGroup; |
| import org.apache.xmlbeans.SchemaModelGroup; |
| import org.apache.xmlbeans.SchemaTypeLoader; |
| import org.apache.xmlbeans.XmlError; |
| import org.apache.xmlbeans.XmlBeans; |
| import org.apache.xmlbeans.XmlOptions; |
| import org.apache.xmlbeans.impl.values.XmlStringImpl; |
| import org.apache.xmlbeans.impl.values.XmlValueOutOfRangeException; |
| import org.apache.xmlbeans.impl.util.HexBin; |
| |
| import java.util.*; |
| import java.net.URISyntaxException; |
| import java.net.URI; |
| import java.io.File; |
| |
| |
| import javax.xml.namespace.QName; |
| |
| import org.w3.x2001.xmlSchema.SchemaDocument; |
| import org.xml.sax.EntityResolver; |
| |
| /** |
| * This class represents the state of the SchemaTypeSystemCompiler as it's |
| * going. |
| */ |
| public class StscState |
| { |
| private String _givenStsName; |
| private Collection _errorListener; |
| private SchemaTypeSystemImpl _target; |
| private SchemaConfig _config; |
| private Map _compatMap; |
| private boolean _doingDownloads; |
| private byte[] _digest = null; |
| private boolean _noDigest = false; |
| |
| private SchemaTypeLoader _importingLoader; |
| |
| private Map _redefinedGlobalTypes = new LinkedHashMap(); |
| private Map _redefinedModelGroups = new LinkedHashMap(); |
| private Map _redefinedAttributeGroups = new LinkedHashMap(); |
| |
| private Map _globalTypes = new LinkedHashMap(); |
| private Map _globalElements = new LinkedHashMap(); |
| private Map _globalAttributes = new LinkedHashMap(); |
| private Map _modelGroups = new LinkedHashMap(); |
| private Map _attributeGroups = new LinkedHashMap(); |
| private Map _documentTypes = new LinkedHashMap(); |
| private Map _attributeTypes = new LinkedHashMap(); |
| private Map _typesByClassname = new LinkedHashMap(); |
| private Map _misspelledNames = new HashMap(); |
| private Set _processingGroups = new HashSet(); |
| private Map _idConstraints = new LinkedHashMap(); |
| private Set _namespaces = new HashSet(); |
| private boolean _noUpa; |
| private boolean _noPvr; |
| private Set _mdefNamespaces = buildDefaultMdefNamespaces(); |
| private EntityResolver _entityResolver; |
| |
| private static Set buildDefaultMdefNamespaces() |
| { |
| // namespaces which are known to appear in WSDLs redundantly |
| return new HashSet( |
| Arrays.asList( new String[] { |
| "http://www.openuri.org/2002/04/soap/conversation/", |
| })); |
| } |
| |
| /** |
| * Used to store the new target namespace for a chameleon |
| * included schema. |
| */ |
| public static final Object CHAMELEON_INCLUDE_URI = new Object(); |
| |
| /** |
| * Only constructed via StscState.start(). |
| */ |
| private StscState() |
| { |
| } |
| |
| /** |
| * Initializer for schematypepath |
| */ |
| public void setImportingTypeLoader(SchemaTypeLoader loader) |
| { |
| _importingLoader = loader; |
| } |
| |
| /** |
| * Initializer for error handling. |
| */ |
| public void setErrorListener(Collection errorListener) |
| { _errorListener = errorListener; } |
| |
| /** |
| * Passes an error on to the current XmlErrorContext. |
| */ |
| public void error(String message, int code, XmlObject loc) |
| { addError(_errorListener, message, code, loc); } |
| |
| /** |
| * Passes a warning on to the current XmlErrorContext. |
| */ |
| public void warning(String message, int code, XmlObject loc) |
| { |
| // it's OK for XMLSchema.xsd itself to have reserved type names |
| if (code == XmlErrorContext.RESERVED_TYPE_NAME && |
| loc.documentProperties().getSourceName() != null && |
| loc.documentProperties().getSourceName().indexOf("XMLSchema.xsd") > 0) |
| return; |
| |
| addWarning(_errorListener, message, code, loc); |
| } |
| |
| /** |
| * Passes a warning on to the current XmlErrorContext. |
| */ |
| public void info(String message) |
| { addInfo(_errorListener, message); } |
| |
| public static void addError(Collection errorListener, String message, int code, XmlObject location) |
| { |
| XmlError err = |
| XmlError.forObject( |
| message, |
| XmlError.SEVERITY_ERROR, |
| location); |
| errorListener.add(err); |
| } |
| |
| public static void addError(Collection errorListener, String message, int code, File location) |
| { |
| XmlError err = |
| XmlError.forLocation( |
| message, |
| XmlError.SEVERITY_ERROR, |
| location.toURI().toString(), 0, 0, 0); |
| errorListener.add(err); |
| } |
| |
| public static void addWarning(Collection errorListener, String message, int code, XmlObject location) |
| { |
| XmlError err = |
| XmlError.forObject( |
| message, |
| XmlError.SEVERITY_WARNING, |
| location); |
| errorListener.add(err); |
| } |
| |
| public static void addInfo(Collection errorListener, String message) |
| { |
| XmlError err = XmlError.forMessage(message, XmlError.SEVERITY_INFO); |
| errorListener.add(err); |
| } |
| |
| public void setGivenTypeSystemName(String name) |
| { _givenStsName = name; } |
| |
| /** |
| * Initializer for references to the SchemaTypeLoader |
| */ |
| public void setTargetSchemaTypeSystem(SchemaTypeSystemImpl target) |
| { _target = target; } |
| |
| /** |
| * Accumulates a schema digest... |
| */ |
| public void addSchemaDigest(byte[] digest) |
| { |
| if (_noDigest) |
| return; |
| |
| if (digest == null) |
| { |
| _noDigest = true; |
| _digest = null; |
| return; |
| } |
| |
| if (_digest == null) |
| _digest = new byte[128/8]; // 128 bits. |
| int len = _digest.length; |
| if (digest.length < len) |
| len = digest.length; |
| for (int i = 0; i < len; i++) |
| _digest[i] ^= digest[i]; |
| } |
| |
| /** |
| * The SchemaTypeSystem which we're building types on behalf of. |
| */ |
| public SchemaTypeSystemImpl sts() |
| { |
| if (_target != null) |
| return _target; |
| |
| String name = _givenStsName; |
| if (name == null && _digest != null) |
| name = "s" + new String(HexBin.encode(_digest)); |
| |
| _target = new SchemaTypeSystemImpl(name); |
| return _target; |
| } |
| |
| /** |
| * True if the given URI is a local file |
| */ |
| public boolean shouldDownloadURI(String uriString) |
| { |
| if (_doingDownloads) |
| return true; |
| |
| if (uriString == null) |
| return false; |
| |
| try |
| { |
| URI uri = new URI(uriString); |
| return uri.getScheme().equalsIgnoreCase("file"); |
| } |
| catch (Exception e) |
| { |
| return false; |
| } |
| } |
| |
| /** |
| * Initializer for compatMap. |
| */ |
| public void setOptions(XmlOptions options) |
| { |
| if (options == null) |
| { |
| return; // defaults are all false. |
| } |
| |
| _compatMap = (Map)options.get(XmlOptions.COMPILE_SUBSTITUTE_NAMES); |
| _noUpa = options.hasOption(XmlOptions.COMPILE_NO_UPA_RULE) ? true : |
| !"true".equals(System.getProperty("xmlbean.uniqueparticleattribution", "true")); |
| _noPvr = options.hasOption(XmlOptions.COMPILE_NO_PVR_RULE) ? true : |
| !"true".equals(System.getProperty("xmlbean.particlerestriction", "true")); |
| _doingDownloads = options.hasOption(XmlOptions.COMPILE_DOWNLOAD_URLS) ? true : |
| "true".equals(System.getProperty("xmlbean.downloadurls", "false")); |
| _entityResolver = (EntityResolver)options.get(XmlOptions.ENTITY_RESOLVER); |
| if (_entityResolver != null) |
| _doingDownloads = true; |
| |
| if (options.hasOption(XmlOptions.COMPILE_MDEF_NAMESPACES)) |
| _mdefNamespaces.addAll((Collection)options.get(XmlOptions.COMPILE_MDEF_NAMESPACES)); |
| } |
| |
| /** |
| * May return null if there is no custom entity resolver. |
| */ |
| public EntityResolver getEntityResolver() |
| { |
| return _entityResolver; |
| } |
| |
| /** |
| * True if no unique particle attribution option is set |
| */ |
| public boolean noUpa() |
| { |
| return _noUpa; |
| } |
| |
| /** |
| * True if no particle valid (restriciton) option is set |
| */ |
| public boolean noPvr() |
| { |
| return _noPvr; |
| } |
| |
| |
| /** |
| * Intercepts XML names and translates them |
| * through the compat map, if any. |
| * |
| * Also looks for a default namespace for global definitions. |
| */ |
| private QName compatName(QName name, String chameleonNamespace) |
| { |
| // first check for a chameleonNamespace namespace |
| if (name.getNamespaceURI().length() == 0 && chameleonNamespace != null && chameleonNamespace.length() > 0) |
| name = new QName(chameleonNamespace, name.getLocalPart()); |
| |
| if (_compatMap == null) |
| return name; |
| |
| QName subst = (QName)_compatMap.get(name); |
| if (subst == null) |
| return name; |
| return subst; |
| } |
| |
| /** |
| * Initializer for the schema config object. |
| */ |
| public void setSchemaConfig(SchemaConfig config) |
| throws IllegalArgumentException |
| { |
| _config = config; |
| } |
| |
| /** |
| * Looks up package override for a namespace URI |
| */ |
| public String getPackageOverride(String namespace) |
| { |
| return _config.lookupPackageForNamespace(namespace); |
| } |
| |
| /** |
| * Looks up package override for a namespace URI |
| */ |
| public String getJavaPrefix(String namespace) |
| { |
| return _config.lookupPrefixForNamespace(namespace); |
| } |
| |
| /** |
| * Looks up package override for a namespace URI |
| */ |
| public String getJavaSuffix(String namespace) |
| { |
| return _config.lookupSuffixForNamespace(namespace); |
| } |
| |
| /** |
| * Looks up configured java name for the given qname. |
| */ |
| public String getJavaname(QName qname) |
| { |
| return _config.lookupJavanameForQName(qname); |
| } |
| |
| /* SPELLINGS ======================================================*/ |
| |
| private static String crunchName(QName name) |
| { |
| // lowercase, and drop namespace. |
| return name.getLocalPart().toLowerCase(); |
| } |
| |
| void addSpelling(QName name, SchemaComponent comp) |
| { |
| _misspelledNames.put(crunchName(name), comp); |
| } |
| |
| SchemaComponent findSpelling(QName name) |
| { |
| return (SchemaComponent)_misspelledNames.get(crunchName(name)); |
| } |
| |
| /* NAMESPACES ======================================================*/ |
| |
| void addNamespace(String targetNamespace) |
| { |
| _namespaces.add(targetNamespace); |
| } |
| |
| String[] getNamespaces() |
| { |
| return (String[])_namespaces.toArray(new String[_namespaces.size()]); |
| } |
| |
| boolean linkerDefinesNamespace(String namespace) |
| { |
| return _importingLoader.isNamespaceDefined(namespace); |
| } |
| |
| /* TYPES ==========================================================*/ |
| |
| SchemaTypeImpl findGlobalType(QName name, String chameleonNamespace) |
| { |
| name = compatName(name, chameleonNamespace); |
| SchemaTypeImpl result = (SchemaTypeImpl)_globalTypes.get(name); |
| if (result == null) |
| result = (SchemaTypeImpl)_importingLoader.findType(name); |
| return result; |
| } |
| |
| SchemaTypeImpl findRedefinedGlobalType(QName name, String chameleonNamespace, QName redefinedName) |
| { |
| name = compatName(name, chameleonNamespace); |
| if (name.equals(redefinedName)) |
| { |
| return (SchemaTypeImpl)_redefinedGlobalTypes.get(name); |
| // BUGBUG: should also link against _importingLoader.findRedefinedType |
| } |
| SchemaTypeImpl result = (SchemaTypeImpl)_globalTypes.get(name); |
| if (result == null) |
| result = (SchemaTypeImpl)_importingLoader.findType(name); |
| return result; |
| } |
| |
| void addGlobalType(SchemaTypeImpl type, boolean redefined) |
| { |
| if (type != null) |
| { |
| QName name = type.getName(); |
| |
| if (redefined) |
| { |
| if (_redefinedGlobalTypes.containsKey(name)) |
| { |
| if (!ignoreMdef(name)) |
| error("Duplicate global type: " + QNameHelper.pretty(name), XmlErrorContext.DUPLICATE_GLOBAL_TYPE, null); |
| } |
| else |
| _redefinedGlobalTypes.put(name, type); |
| } |
| else |
| { |
| if (_globalTypes.containsKey(name)) |
| { |
| if (!ignoreMdef(name)) |
| error("Duplicate global type: " + QNameHelper.pretty(name), XmlErrorContext.DUPLICATE_GLOBAL_TYPE, null); |
| } |
| else |
| { |
| _globalTypes.put(name, type); |
| addSpelling(name, type); |
| } |
| } |
| } |
| } |
| |
| private boolean ignoreMdef(QName name) |
| { |
| return _mdefNamespaces.contains(name.getNamespaceURI()); |
| } |
| |
| SchemaType[] globalTypes() |
| { return (SchemaType[])_globalTypes.values().toArray(new SchemaType[_globalTypes.size()]); } |
| |
| SchemaType[] redefinedGlobalTypes() |
| { return (SchemaType[])_redefinedGlobalTypes.values().toArray(new SchemaType[_redefinedGlobalTypes.size()]); } |
| |
| /* DOCUMENT TYPES =================================================*/ |
| |
| SchemaTypeImpl findDocumentType(QName name, String chameleonNamespace) |
| { |
| name = compatName(name, chameleonNamespace); |
| SchemaTypeImpl result = (SchemaTypeImpl)_documentTypes.get(name); |
| if (result == null) |
| result = (SchemaTypeImpl)_importingLoader.findDocumentType(name); |
| return result; |
| } |
| |
| void addDocumentType(SchemaTypeImpl type, QName name) |
| { |
| if (_documentTypes.containsKey(name)) |
| { |
| if (!ignoreMdef(name)) |
| error("Duplicate global element: " + QNameHelper.pretty(name), XmlErrorContext.DUPLICATE_GLOBAL_ELEMENT, null); |
| } |
| else |
| _documentTypes.put(name, type); |
| } |
| |
| SchemaType[] documentTypes() |
| { return (SchemaType[])_documentTypes.values().toArray(new SchemaType[_documentTypes.size()]); } |
| |
| /* ATTRIBUTE TYPES =================================================*/ |
| |
| SchemaTypeImpl findAttributeType(QName name, String chameleonNamespace) |
| { |
| name = compatName(name, chameleonNamespace); |
| SchemaTypeImpl result = (SchemaTypeImpl)_attributeTypes.get(name); |
| if (result == null) |
| result = (SchemaTypeImpl)_importingLoader.findAttributeType(name); |
| return result; |
| } |
| |
| void addAttributeType(SchemaTypeImpl type, QName name) |
| { |
| if (_attributeTypes.containsKey(name)) |
| { |
| if (!ignoreMdef(name)) |
| error("Duplicate global attribute: " + QNameHelper.pretty(name), XmlErrorContext.DUPLICATE_GLOBAL_ATTRIBUTE, null); |
| } |
| else |
| _attributeTypes.put(name, type); |
| } |
| |
| SchemaType[] attributeTypes() |
| { return (SchemaType[])_attributeTypes.values().toArray(new SchemaType[_attributeTypes.size()]); } |
| |
| /* ATTRIBUTES =====================================================*/ |
| |
| SchemaGlobalAttributeImpl findGlobalAttribute(QName name, String chameleonNamespace) |
| { |
| name = compatName(name, chameleonNamespace); |
| SchemaGlobalAttributeImpl result = (SchemaGlobalAttributeImpl)_globalAttributes.get(name); |
| if (result == null) |
| result = (SchemaGlobalAttributeImpl)_importingLoader.findAttribute(name); |
| return result; |
| } |
| |
| void addGlobalAttribute(SchemaGlobalAttributeImpl attribute) |
| { |
| if (attribute != null) |
| { |
| QName name = attribute.getName(); |
| _globalAttributes.put(name, attribute); |
| addSpelling(name, attribute); |
| } |
| } |
| |
| SchemaGlobalAttribute[] globalAttributes() |
| { return (SchemaGlobalAttribute[])_globalAttributes.values().toArray(new SchemaGlobalAttribute[_globalAttributes.size()]); } |
| |
| /* ELEMENTS =======================================================*/ |
| |
| SchemaGlobalElementImpl findGlobalElement(QName name, String chameleonNamespace) |
| { |
| name = compatName(name, chameleonNamespace); |
| SchemaGlobalElementImpl result = (SchemaGlobalElementImpl)_globalElements.get(name); |
| if (result == null) |
| result = (SchemaGlobalElementImpl)_importingLoader.findElement(name); |
| return result; |
| } |
| |
| void addGlobalElement(SchemaGlobalElementImpl element) |
| { |
| if (element != null) |
| { |
| QName name = element.getName(); |
| _globalElements.put(name, element); |
| addSpelling(name, element); |
| } |
| } |
| |
| SchemaGlobalElement[] globalElements() |
| { return (SchemaGlobalElement[])_globalElements.values().toArray(new SchemaGlobalElement[_globalElements.size()]); } |
| |
| /* ATTRIBUTE GROUPS ===============================================*/ |
| |
| SchemaAttributeGroupImpl findAttributeGroup(QName name, String chameleonNamespace) |
| { |
| name = compatName(name, chameleonNamespace); |
| SchemaAttributeGroupImpl result = (SchemaAttributeGroupImpl)_attributeGroups.get(name); |
| if (result == null) |
| result = (SchemaAttributeGroupImpl)_importingLoader.findAttributeGroup(name); |
| return result; |
| } |
| |
| SchemaAttributeGroupImpl findRedefinedAttributeGroup(QName name, String chameleonNamespace, QName redefinitionFor) |
| { |
| name = compatName(name, chameleonNamespace); |
| if (name.equals(redefinitionFor)) |
| { |
| return (SchemaAttributeGroupImpl)_redefinedAttributeGroups.get(name); |
| // BUGBUG: should also link against _importingLoader.findRedefinedAttributeGroup |
| } |
| SchemaAttributeGroupImpl result = (SchemaAttributeGroupImpl)_attributeGroups.get(name); |
| if (result == null) |
| result = (SchemaAttributeGroupImpl)_importingLoader.findAttributeGroup(name); |
| return result; |
| } |
| |
| void addAttributeGroup(SchemaAttributeGroupImpl attributeGroup, boolean redefined) |
| { |
| if (attributeGroup != null) |
| { |
| QName name = attributeGroup.getName(); |
| if (redefined) |
| { |
| if (_redefinedAttributeGroups.containsKey(name)) |
| { |
| if (!ignoreMdef(name)) |
| error("Duplicate attribute group: " + QNameHelper.pretty(name), XmlErrorContext.DUPLICATE_GLOBAL_TYPE, null); |
| } |
| else |
| _redefinedAttributeGroups.put(name, attributeGroup); |
| |
| } |
| else |
| { |
| if (_attributeGroups.containsKey( name )) |
| { |
| if (!ignoreMdef(name)) |
| error("Duplicate attribute group: " + QNameHelper.pretty(name), XmlErrorContext.DUPLICATE_GLOBAL_TYPE, null); |
| } |
| else |
| { |
| _attributeGroups.put(attributeGroup.getName(), attributeGroup); |
| addSpelling(attributeGroup.getName(), attributeGroup); |
| } |
| } |
| } |
| } |
| |
| SchemaAttributeGroup[] attributeGroups() |
| { return (SchemaAttributeGroup[])_attributeGroups.values().toArray(new SchemaAttributeGroup[_attributeGroups.size()]); } |
| |
| SchemaAttributeGroup[] redefinedAttributeGroups() |
| { return (SchemaAttributeGroup[])_redefinedAttributeGroups.values().toArray(new SchemaAttributeGroup[_redefinedAttributeGroups.size()]); } |
| |
| /* MODEL GROUPS ===================================================*/ |
| |
| SchemaModelGroupImpl findModelGroup(QName name, String chameleonNamespace) |
| { |
| name = compatName(name, chameleonNamespace); |
| SchemaModelGroupImpl result = (SchemaModelGroupImpl)_modelGroups.get(name); |
| if (result == null) |
| result = (SchemaModelGroupImpl)_importingLoader.findModelGroup(name); |
| return result; |
| } |
| |
| SchemaModelGroupImpl findRedefinedModelGroup(QName name, String chameleonNamespace, QName redefinitionFor) |
| { |
| name = compatName(name, chameleonNamespace); |
| if (name.equals(redefinitionFor)) |
| { |
| return (SchemaModelGroupImpl)_redefinedModelGroups.get(name); |
| // BUGBUG: should also link against _importingLoader.findRedefinedModelGroup |
| } |
| SchemaModelGroupImpl result = (SchemaModelGroupImpl)_modelGroups.get(name); |
| if (result == null) |
| result = (SchemaModelGroupImpl)_importingLoader.findModelGroup(name); |
| return result; |
| } |
| |
| void addModelGroup(SchemaModelGroupImpl modelGroup, boolean redefined) |
| { |
| if (modelGroup != null) |
| { |
| QName name = modelGroup.getName(); |
| if (redefined) |
| { |
| if (_redefinedModelGroups.containsKey(name)) |
| { |
| if (!ignoreMdef(name)) |
| error("Duplicate model group: " + QNameHelper.pretty(name), XmlErrorContext.DUPLICATE_GLOBAL_TYPE, null); |
| } |
| else |
| _redefinedModelGroups.put(name, modelGroup); |
| } |
| else |
| { |
| if (_modelGroups.containsKey(name)) |
| { |
| if (!ignoreMdef(name)) |
| error("Duplicate model group: " + QNameHelper.pretty(name), XmlErrorContext.DUPLICATE_GLOBAL_TYPE, null); |
| } |
| else |
| { |
| _modelGroups.put(modelGroup.getName(), modelGroup); |
| addSpelling(modelGroup.getName(), modelGroup); |
| } |
| } |
| } |
| } |
| |
| SchemaModelGroup[] modelGroups() |
| { return (SchemaModelGroup[])_modelGroups.values().toArray(new SchemaModelGroup[_modelGroups.size()]); } |
| |
| SchemaModelGroup[] redefinedModelGroups() |
| { return (SchemaModelGroup[])_redefinedModelGroups.values().toArray(new SchemaModelGroup[_redefinedModelGroups.size()]); } |
| |
| /* IDENTITY CONSTRAINTS ===========================================*/ |
| |
| SchemaIdentityConstraintImpl findIdConstraint(QName name, String chameleonNamespace) |
| { |
| name = compatName(name, chameleonNamespace); |
| return (SchemaIdentityConstraintImpl)_idConstraints.get(name); |
| } |
| |
| void addIdConstraint(SchemaIdentityConstraintImpl idc) |
| { |
| if (idc != null) |
| { |
| _idConstraints.put(idc.getName(), idc); |
| addSpelling(idc.getName(), idc); |
| } |
| } |
| |
| SchemaIdentityConstraintImpl[] idConstraints() |
| { return (SchemaIdentityConstraintImpl[])_idConstraints.values().toArray(new SchemaIdentityConstraintImpl[_idConstraints.size()]); } |
| |
| /* RECURSION AVOIDANCE ============================================*/ |
| boolean isProcessing(Object obj) |
| { |
| return _processingGroups.contains(obj); |
| } |
| |
| void startProcessing(Object obj) |
| { |
| assert(!_processingGroups.contains(obj)); |
| _processingGroups.add(obj); |
| } |
| |
| void finishProcessing(Object obj) |
| { |
| assert(_processingGroups.contains(obj)); |
| _processingGroups.remove(obj); |
| } |
| |
| /* JAVAIZATION ====================================================*/ |
| |
| Map typesByClassname() |
| { return Collections.unmodifiableMap(_typesByClassname); } |
| |
| void addClassname(String classname, SchemaType type) |
| { _typesByClassname.put(classname, type); } |
| |
| |
| |
| /** |
| * Stack management if (heaven help us) we ever need to do |
| * nested compilation of schema type system. |
| */ |
| private static final class StscStack |
| { |
| StscState current; |
| ArrayList stack = new ArrayList(); |
| final StscState push() |
| { |
| stack.add(current); |
| current = new StscState(); |
| return current; |
| } |
| final void pop() |
| { |
| current = (StscState)stack.get(stack.size() - 1); |
| stack.remove(stack.size() - 1); |
| } |
| } |
| |
| private static ThreadLocal stscStack = new ThreadLocal() |
| { |
| protected Object initialValue() { return new StscStack(); } |
| }; |
| |
| public static StscState start() |
| { |
| return ((StscStack)stscStack.get()).push(); |
| } |
| |
| public static StscState get() |
| { |
| return ((StscStack)stscStack.get()).current; |
| } |
| |
| public static void end() |
| { |
| ((StscStack)stscStack.get()).pop(); |
| } |
| |
| private final static XmlValueRef XMLSTR_PRESERVE = buildString("preserve"); |
| private final static XmlValueRef XMLSTR_REPLACE = buildString("preserve"); |
| private final static XmlValueRef XMLSTR_COLLAPSE = buildString("preserve"); |
| |
| static final SchemaType[] EMPTY_ST_ARRAY = new SchemaType[0]; |
| static final SchemaType.Ref[] EMPTY_STREF_ARRAY = new SchemaType.Ref[0]; |
| |
| private final static XmlValueRef[] FACETS_NONE = new XmlValueRef[] |
| { null, null, null, null, null, null, null, null, null, |
| null, null, null }; |
| |
| private final static boolean[] FIXED_FACETS_NONE = new boolean[] |
| { false, false, false, false, false, false, false, false, false, |
| false, false, false }; |
| |
| private final static XmlValueRef[] FACETS_WS_COLLAPSE = new XmlValueRef[] |
| { null, null, null, null, null, null, null, null, null, |
| build_wsstring(SchemaType.WS_COLLAPSE), null, null }; |
| |
| private final static boolean[] FIXED_FACETS_WS = new boolean[] |
| { false, false, false, false, false, false, false, false, false, |
| true, false, false }; |
| |
| final static XmlValueRef[] FACETS_UNION = FACETS_NONE; |
| final static boolean[] FIXED_FACETS_UNION = FIXED_FACETS_NONE; |
| final static XmlValueRef[] FACETS_LIST = FACETS_WS_COLLAPSE; |
| final static boolean[] FIXED_FACETS_LIST = FIXED_FACETS_WS; |
| |
| static XmlValueRef build_wsstring(int wsr) |
| { |
| switch (wsr) |
| { |
| case SchemaType.WS_PRESERVE: |
| return XMLSTR_PRESERVE; |
| case SchemaType.WS_REPLACE: |
| return XMLSTR_REPLACE; |
| case SchemaType.WS_COLLAPSE: |
| return XMLSTR_COLLAPSE; |
| } |
| return null; |
| } |
| |
| static XmlValueRef buildString(String str) |
| { |
| if (str == null) |
| return null; |
| |
| try |
| { |
| XmlStringImpl i = new XmlStringImpl(); |
| i.set(str); |
| i.setImmutable(); |
| return new XmlValueRef(i); |
| } |
| catch (XmlValueOutOfRangeException e) |
| { |
| return null; |
| } |
| } |
| |
| public void notFoundError(QName itemName, int code, XmlObject loc) |
| { |
| String basicMessage; |
| |
| switch (code) |
| { |
| case XmlErrorContext.TYPE_NOT_FOUND: |
| basicMessage = "Type " + QNameHelper.pretty(itemName) + " not found."; |
| break; |
| case XmlErrorContext.ELEMENT_REF_NOT_FOUND: |
| basicMessage = "Element " + QNameHelper.pretty(itemName) + " not found."; |
| break; |
| case XmlErrorContext.ATTRIBUTE_REF_NOT_FOUND: |
| basicMessage = "Attribute " + QNameHelper.pretty(itemName) + " not found."; |
| break; |
| case XmlErrorContext.MODEL_GROUP_NOT_FOUND: |
| basicMessage = "Model group " + QNameHelper.pretty(itemName) + " not found."; |
| break; |
| case XmlErrorContext.ATTRIBUTE_GROUP_NOT_FOUND: |
| basicMessage = "Attribute group " + QNameHelper.pretty(itemName) + " not found."; |
| break; |
| case XmlErrorContext.IDC_NOT_FOUND: |
| basicMessage = "Identity constraint '" + QNameHelper.pretty(itemName) + "' not found."; |
| break; |
| default: |
| assert(false); |
| basicMessage = "Definition " + QNameHelper.pretty(itemName) + " not found."; |
| break; |
| } |
| |
| String helpfulMessage = ""; |
| SchemaComponent foundComponent = findSpelling(itemName); |
| QName name; |
| if (foundComponent != null) |
| { |
| name = foundComponent.getName(); |
| if (name != null) |
| { |
| String sourceName = null; |
| switch (foundComponent.getComponentType()) |
| { |
| case SchemaComponent.TYPE: |
| sourceName = ((SchemaType)foundComponent).getSourceName(); |
| break; |
| case SchemaComponent.ELEMENT: |
| sourceName = ((SchemaGlobalElement)foundComponent).getSourceName(); |
| break; |
| case SchemaComponent.ATTRIBUTE: |
| sourceName = ((SchemaGlobalAttribute)foundComponent).getSourceName(); |
| break; |
| } |
| String source = ""; |
| if (sourceName != null) |
| { |
| source = " (in " + sourceName.substring(sourceName.lastIndexOf('/') + 1) + ")"; |
| } |
| |
| if (name.equals(itemName)) |
| { |
| switch (foundComponent.getComponentType()) |
| { |
| case SchemaComponent.TYPE: |
| helpfulMessage = " Do you mean to refer to the type with that name" + source + "?"; |
| break; |
| case SchemaComponent.ELEMENT: |
| helpfulMessage = " Do you mean to refer to the element with that name" + source + "?"; |
| break; |
| case SchemaComponent.ATTRIBUTE: |
| helpfulMessage = " Do you mean to refer to the attribute with that name" + source + "?"; |
| break; |
| case SchemaComponent.ATTRIBUTE_GROUP: |
| helpfulMessage = " Do you mean to refer to the attribute group with that name" + source + "?"; |
| break; |
| case SchemaComponent.MODEL_GROUP: |
| helpfulMessage = " Do you mean to refer to the model group with that name" + source + "?"; |
| break; |
| } |
| } |
| else |
| { |
| switch (foundComponent.getComponentType()) |
| { |
| case SchemaComponent.TYPE: |
| helpfulMessage = " Do you mean to refer to the type named " + QNameHelper.pretty(name) + source + "?"; |
| break; |
| case SchemaComponent.ELEMENT: |
| helpfulMessage = " Do you mean to refer to the element named " + QNameHelper.pretty(name) + source + "?"; |
| break; |
| case SchemaComponent.ATTRIBUTE: |
| helpfulMessage = " Do you mean to refer to the attribute named " + QNameHelper.pretty(name) + source + "?"; |
| break; |
| case SchemaComponent.ATTRIBUTE_GROUP: |
| helpfulMessage = " Do you mean to refer to the attribute group named " + QNameHelper.pretty(name) + source + "?"; |
| break; |
| case SchemaComponent.MODEL_GROUP: |
| helpfulMessage = " Do you mean to refer to the model group named " + QNameHelper.pretty(name) + source + "?"; |
| break; |
| } |
| } |
| } |
| } |
| |
| error(basicMessage + helpfulMessage, code, loc); |
| } |
| |
| /** |
| * Produces the "sourceName" (to be used within the schema project |
| * source file copies) from the URI of the original source. |
| * |
| * Returns null if none. |
| */ |
| public String sourceNameForUri(String uri) |
| { |
| return (String)_sourceForUri.get(uri); |
| } |
| |
| /** |
| * Returns the whole sourceCopyMap, mapping URI's that have |
| * been read to "sourceName" local names that have been used |
| * to tag the types. |
| */ |
| public Map sourceCopyMap() |
| { |
| return Collections.unmodifiableMap(_sourceForUri); |
| } |
| |
| /** |
| * The base URI to use for nice filenames when saving sources. |
| */ |
| public void setBaseUri(URI uri) |
| { |
| _baseURI = uri; |
| } |
| |
| private final static String PROJECT_URL_PREFIX = "project://local"; |
| |
| public String relativize(String uri) |
| { |
| return relativize(uri, false); |
| } |
| |
| public String computeSavedFilename(String uri) |
| { |
| return relativize(uri, true); |
| } |
| |
| private String relativize(String uri, boolean forSavedFilename) |
| { |
| if (uri == null) |
| return null; |
| |
| // deal with things that do not look like absolute uris |
| if (uri.startsWith("/")) |
| { |
| uri = PROJECT_URL_PREFIX + uri.replace('\\', '/'); |
| } |
| else |
| { |
| // looks like a URL? |
| int colon = uri.indexOf(':'); |
| if (colon <= 1 || !uri.substring(0, colon).matches("^\\w+$")) |
| uri = PROJECT_URL_PREFIX + "/" + uri.replace('\\', '/'); |
| } |
| |
| // now relativize against that... |
| if (_baseURI != null) |
| { |
| try |
| { |
| URI relative = _baseURI.relativize(new URI(uri)); |
| if (!relative.isAbsolute()) |
| return relative.toString(); |
| else |
| uri = relative.toString(); |
| } |
| catch (URISyntaxException e) |
| { |
| } |
| } |
| |
| if (!forSavedFilename) |
| return uri; |
| |
| int lastslash = uri.lastIndexOf('/'); |
| String dir = QNameHelper.hexsafe(lastslash == -1 ? "" : uri.substring(0, lastslash)); |
| return dir + "/" + uri.substring(lastslash + 1); |
| } |
| |
| /** |
| * Notes another URI that has been consumed during compilation |
| * (this is the URI that is in the document .NAME property) |
| */ |
| public void addSourceUri(String uri, String nameToUse) |
| { |
| if (uri == null) |
| return; |
| |
| if (nameToUse == null) |
| nameToUse = computeSavedFilename(uri); |
| |
| _sourceForUri.put(uri, nameToUse); |
| } |
| |
| /** |
| * Returns the error listener being filled in during this compilation |
| */ |
| public Collection getErrorListener() |
| { |
| return _errorListener; |
| } |
| |
| /** |
| * Returns the schema type loader to use for processing s4s |
| */ |
| public SchemaTypeLoader getS4SLoader() |
| { |
| return _s4sloader; |
| } |
| |
| Map _sourceForUri = new HashMap(); |
| URI _baseURI = URI.create(PROJECT_URL_PREFIX + "/"); |
| SchemaTypeLoader _s4sloader = XmlBeans.typeLoaderForClassLoader(SchemaDocument.class.getClassLoader()); |
| } |