blob: f4642003a80dafa52691b3d918e7fbf274cf022e [file] [log] [blame]
/* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.xmlbeans.impl.schema;
import org.apache.xmlbeans.XmlErrorCodes;
import org.apache.xmlbeans.impl.common.QNameHelper;
import org.apache.xmlbeans.impl.common.ResolverUtil;
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.SchemaIdentityConstraint;
import org.apache.xmlbeans.SchemaAttributeGroup;
import org.apache.xmlbeans.SchemaModelGroup;
import org.apache.xmlbeans.SchemaTypeLoader;
import org.apache.xmlbeans.SystemProperties;
import org.apache.xmlbeans.XmlError;
import org.apache.xmlbeans.XmlBeans;
import org.apache.xmlbeans.XmlOptions;
import org.apache.xmlbeans.BindingConfig;
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.net.URL;
import java.io.File;
import javax.xml.namespace.QName;
import org.apache.xmlbeans.impl.xb.xsdschema.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 BindingConfig _config;
private Map _compatMap;
private boolean _doingDownloads;
private byte[] _digest = null;
private boolean _noDigest = false;
// EXPERIMENTAL: recovery from compilation errors and partial type systems
private boolean _allowPartial = false;
private int _recoveredErrors = 0;
private SchemaTypeLoader _importingLoader;
private Map _containers = new LinkedHashMap();
private SchemaDependencies _dependencies;
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 LinkedHashSet();
private Map _idConstraints = new LinkedHashMap();
private Set _namespaces = new HashSet();
private List _annotations = new ArrayList();
private boolean _noUpa;
private boolean _noPvr;
private boolean _noAnn;
private boolean _mdefAll;
private Set _mdefNamespaces = buildDefaultMdefNamespaces();
private EntityResolver _entityResolver;
private File _schemasDir;
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 incremental compilation
*/
public void initFromTypeSystem(SchemaTypeSystemImpl system, Set newNamespaces)
{
// setGivenTypeSystemName(system.getName().substring(14));
SchemaContainer[] containers = system.containers();
for (int i = 0; i < containers.length; i++)
{
if (!newNamespaces.contains(containers[i].getNamespace()))
{
// Copy data from the given container
addContainer(containers[i]);
}
}
}
/* CONTAINERS ================================================================*/
void addNewContainer(String namespace)
{
if (_containers.containsKey(namespace))
return;
SchemaContainer container = new SchemaContainer(namespace);
container.setTypeSystem(sts());
addNamespace(namespace);
_containers.put(namespace, container);
}
private void addContainer(SchemaContainer container)
{
_containers.put(container.getNamespace(), container);
List redefModelGroups = container.redefinedModelGroups();
for (int i = 0; i < redefModelGroups.size(); i++)
{
QName name = ((SchemaModelGroup) redefModelGroups.get(i)).getName();
_redefinedModelGroups.put(name, redefModelGroups.get(i));
}
List redefAttrGroups = container.redefinedAttributeGroups();
for (int i = 0; i < redefAttrGroups.size(); i++)
{
QName name = ((SchemaAttributeGroup) redefAttrGroups.get(i)).getName();
_redefinedAttributeGroups.put(name, redefAttrGroups.get(i));
}
List redefTypes = container.redefinedGlobalTypes();
for (int i = 0; i < redefTypes.size(); i++)
{
QName name = ((SchemaType) redefTypes.get(i)).getName();
_redefinedGlobalTypes.put(name, redefTypes.get(i));
}
List globalElems = container.globalElements();
for (int i = 0; i < globalElems.size(); i++)
{
QName name = ((SchemaGlobalElement) globalElems.get(i)).getName();
_globalElements.put(name, globalElems.get(i));
}
List globalAtts = container.globalAttributes();
for (int i = 0; i < globalAtts.size(); i++)
{
QName name = ((SchemaGlobalAttribute) globalAtts.get(i)).getName();
_globalAttributes.put(name, globalAtts.get(i));
}
List modelGroups = container.modelGroups();
for (int i = 0; i < modelGroups.size(); i++)
{
QName name = ((SchemaModelGroup) modelGroups.get(i)).getName();
_modelGroups.put(name, modelGroups.get(i));
}
List attrGroups = container.attributeGroups();
for (int i = 0; i < attrGroups.size(); i++)
{
QName name = ((SchemaAttributeGroup) attrGroups.get(i)).getName();
_attributeGroups.put(name, attrGroups.get(i));
}
List globalTypes = container.globalTypes();
for (int i = 0; i < globalTypes.size(); i++)
{
SchemaType t = (SchemaType) globalTypes.get(i);
QName name = t.getName();
_globalTypes.put(name, t);
if (t.getFullJavaName() != null)
addClassname(t.getFullJavaName(), t);
}
List documentTypes = container.documentTypes();
for (int i = 0; i < documentTypes.size(); i++)
{
SchemaType t = (SchemaType) documentTypes.get(i);
QName name = t.getProperties()[0].getName();
_documentTypes.put(name, t);
if (t.getFullJavaName() != null)
addClassname(t.getFullJavaName(), t);
}
List attributeTypes = container.attributeTypes();
for (int i = 0; i < attributeTypes.size(); i++)
{
SchemaType t = (SchemaType) attributeTypes.get(i);
QName name = t.getProperties()[0].getName();
_attributeTypes.put(name, t);
if (t.getFullJavaName() != null)
addClassname(t.getFullJavaName(), t);
}
List identityConstraints = container.identityConstraints();
for (int i = 0; i < identityConstraints.size(); i++)
{
QName name = ((SchemaIdentityConstraint) identityConstraints.get(i)).getName();
_idConstraints.put(name, identityConstraints.get(i));
}
_annotations.addAll(container.annotations());
_namespaces.add(container.getNamespace());
container.unsetImmutable();
}
SchemaContainer getContainer(String namespace)
{
return (SchemaContainer) _containers.get(namespace);
}
Map getContainerMap()
{
return Collections.unmodifiableMap(_containers);
}
/* DEPENDENCIES ================================================================*/
void registerDependency(String sourceNs, String targetNs)
{
_dependencies.registerDependency(sourceNs, targetNs);
}
void registerContribution(String ns, String fileUrl)
{
_dependencies.registerContribution(ns, fileUrl);
}
SchemaDependencies getDependencies()
{
return _dependencies;
}
void setDependencies(SchemaDependencies deps)
{
_dependencies = deps;
}
boolean isFileProcessed(String url)
{
return _dependencies.isFileRepresented(url);
}
/**
* 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 error listener.
* KHK: remove this
*/
public void error(String message, int code, XmlObject loc)
{ addError(_errorListener, message, code, loc); }
/**
* Passes an error on to the current error listener.
*/
public void error(String code, Object[] args, XmlObject loc)
{ addError(_errorListener, code, args, loc); }
/**
* Passes a recovered error on to the current error listener.
*/
public void recover(String code, Object[] args, XmlObject loc)
{ addError(_errorListener, code, args, loc); _recoveredErrors++; }
/**
* Passes an error on to the current error listener.
*/
public void warning(String message, int code, XmlObject loc)
{
addWarning(_errorListener, message, code, loc);
}
/**
* Passes an error on to the current error listener.
*/
public void warning(String code, Object[] args, XmlObject loc)
{
// it's OK for XMLSchema.xsd itself to have reserved type names
if (code == XmlErrorCodes.RESERVED_TYPE_NAME &&
loc.documentProperties().getSourceName() != null &&
loc.documentProperties().getSourceName().indexOf("XMLSchema.xsd") > 0)
return;
addWarning(_errorListener, code, args, loc);
}
/**
* Passes a warning on to the current error listener.
*/
public void info(String message)
{ addInfo(_errorListener, message); }
/**
* Passes a warning on to the current error listener.
*/
public void info(String code, Object[] args)
{ addInfo(_errorListener, code, args); }
// KHK: remove this
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 code, Object[] args, XmlObject location)
{
XmlError err =
XmlError.forObject(
code,
args,
XmlError.SEVERITY_ERROR,
location);
errorListener.add(err);
}
public static void addError(Collection errorListener, String code, Object[] args, File location)
{
XmlError err =
XmlError.forLocation(
code,
args,
XmlError.SEVERITY_ERROR,
location.toURI().toString(), 0, 0, 0);
errorListener.add(err);
}
public static void addError(Collection errorListener, String code, Object[] args, URL location)
{
XmlError err =
XmlError.forLocation(
code,
args,
XmlError.SEVERITY_ERROR,
location.toString(), 0, 0, 0);
errorListener.add(err);
}
// KHK: remove this
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 addWarning(Collection errorListener, String code, Object[] args, XmlObject location)
{
XmlError err =
XmlError.forObject(
code,
args,
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 static void addInfo(Collection errorListener, String code, Object[] args)
{
XmlError err = XmlError.forMessage(code, args, 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);
if (uri.getScheme().equalsIgnoreCase("jar") ||
uri.getScheme().equalsIgnoreCase("zip"))
{
// It may be local or not, depending on the embedded URI
String s = uri.getSchemeSpecificPart();
int i = s.lastIndexOf('!');
return shouldDownloadURI(i > 0 ? s.substring(0, i) : s);
}
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.
}
_allowPartial = options.hasOption("COMPILE_PARTIAL_TYPESYSTEM");
_compatMap = (Map)options.get(XmlOptions.COMPILE_SUBSTITUTE_NAMES);
_noUpa = options.hasOption(XmlOptions.COMPILE_NO_UPA_RULE) ? true :
!"true".equals(SystemProperties.getProperty("xmlbean.uniqueparticleattribution", "true"));
_noPvr = options.hasOption(XmlOptions.COMPILE_NO_PVR_RULE) ? true :
!"true".equals(SystemProperties.getProperty("xmlbean.particlerestriction", "true"));
_noAnn = options.hasOption(XmlOptions.COMPILE_NO_ANNOTATIONS) ? true :
!"true".equals(SystemProperties.getProperty("xmlbean.schemaannotations", "true"));
_doingDownloads = options.hasOption(XmlOptions.COMPILE_DOWNLOAD_URLS) ? true :
"true".equals(SystemProperties.getProperty("xmlbean.downloadurls", "false"));
_entityResolver = (EntityResolver)options.get(XmlOptions.ENTITY_RESOLVER);
if (_entityResolver == null)
_entityResolver = ResolverUtil.getGlobalEntityResolver();
if (_entityResolver != null)
_doingDownloads = true;
if (options.hasOption(XmlOptions.COMPILE_MDEF_NAMESPACES))
{
_mdefNamespaces.addAll((Collection)options.get(XmlOptions.COMPILE_MDEF_NAMESPACES));
String local = "##local";
String any = "##any";
if (_mdefNamespaces.contains(local))
{
_mdefNamespaces.remove(local);
_mdefNamespaces.add("");
}
if (_mdefNamespaces.contains(any))
{
_mdefNamespaces.remove(any);
_mdefAll = true;
}
}
}
/**
* 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;
}
/**
* True if annotations should be skipped
*/
public boolean noAnn()
{
return _noAnn;
}
/**
* True if a partial SchemaTypeSystem should be produced
*/
// EXPERIMENTAL
public boolean allowPartial()
{
return _allowPartial;
}
/**
* Get count of recovered errors. Not for public.
*/
// EXPERIMENTAL
public int getRecovered()
{
return _recoveredErrors;
}
/**
* 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 setBindingConfig(BindingConfig config)
throws IllegalArgumentException
{
_config = config;
}
public BindingConfig getBindingConfig()
throws IllegalArgumentException
{
return _config;
}
/**
* Looks up package override for a namespace URI
*/
public String getPackageOverride(String namespace)
{
if (_config == null)
return null;
return _config.lookupPackageForNamespace(namespace);
}
/**
* Looks up package override for a namespace URI
*/
public String getJavaPrefix(String namespace)
{
if (_config == null)
return null;
return _config.lookupPrefixForNamespace(namespace);
}
/**
* Looks up package override for a namespace URI
*/
public String getJavaSuffix(String namespace)
{
if (_config == null)
return null;
return _config.lookupSuffixForNamespace(namespace);
}
/**
* Looks up configured java name for the given qname.
*/
public String getJavaname(QName qname, int kind)
{
if (_config == null)
return null;
return _config.lookupJavanameForQName(qname, kind);
}
/* 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, String sourceNamespace)
{
name = compatName(name, chameleonNamespace);
SchemaTypeImpl result = (SchemaTypeImpl)_globalTypes.get(name);
boolean foundOnLoader = false;
if (result == null)
{
result = (SchemaTypeImpl)_importingLoader.findType(name);
foundOnLoader = result != null;
}
if (!foundOnLoader && sourceNamespace != null)
registerDependency(sourceNamespace, name.getNamespaceURI());
return result;
}
SchemaTypeImpl findRedefinedGlobalType(QName name, String chameleonNamespace, SchemaTypeImpl redefinedBy)
{
QName redefinedName = redefinedBy.getName();
name = compatName(name, chameleonNamespace);
if (name.equals(redefinedName))
{
return (SchemaTypeImpl)_redefinedGlobalTypes.get(redefinedBy);
// BUGBUG: should also link against _importingLoader.findRedefinedType
}
SchemaTypeImpl result = (SchemaTypeImpl)_globalTypes.get(name);
if (result == null)
result = (SchemaTypeImpl)_importingLoader.findType(name);
// no dependency is needed here, necause it's intra-namespace
return result;
}
void addGlobalType(SchemaTypeImpl type, SchemaTypeImpl redefined)
{
if (type != null)
{
QName name = type.getName();
SchemaContainer container = getContainer(name.getNamespaceURI());
assert container != null && container == type.getContainer();
if (redefined != null)
{
if (_redefinedGlobalTypes.containsKey(redefined))
{
if (!ignoreMdef(name)) {
if (_mdefAll) {
warning(XmlErrorCodes.SCHEMA_PROPERTIES$DUPLICATE,
new Object[] { "global type", QNameHelper.pretty(name), ((SchemaType) _redefinedGlobalTypes.get(redefined)).getSourceName() } ,
type.getParseObject());
} else {
error(XmlErrorCodes.SCHEMA_PROPERTIES$DUPLICATE,
new Object[] { "global type", QNameHelper.pretty(name), ((SchemaType) _redefinedGlobalTypes.get(redefined)).getSourceName() } ,
type.getParseObject());
}
}
}
else
{
_redefinedGlobalTypes.put(redefined, type);
container.addRedefinedType(type.getRef());
}
}
else
{
if (_globalTypes.containsKey(name))
{
if (!ignoreMdef(name)) {
if (_mdefAll) {
warning(XmlErrorCodes.SCHEMA_PROPERTIES$DUPLICATE,
new Object[] { "global type", QNameHelper.pretty(name), ((SchemaType) _globalTypes.get(name)).getSourceName() },
type.getParseObject());
} else {
error(XmlErrorCodes.SCHEMA_PROPERTIES$DUPLICATE,
new Object[] { "global type", QNameHelper.pretty(name), ((SchemaType) _globalTypes.get(name)).getSourceName() },
type.getParseObject());
}
}
}
else
{
_globalTypes.put(name, type);
container.addGlobalType(type.getRef());
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, String sourceNamespace)
{
name = compatName(name, chameleonNamespace);
SchemaTypeImpl result = (SchemaTypeImpl)_documentTypes.get(name);
boolean foundOnLoader = false;
if (result == null)
{
result = (SchemaTypeImpl)_importingLoader.findDocumentType(name);
foundOnLoader = result != null;
}
if (!foundOnLoader && sourceNamespace != null)
registerDependency(sourceNamespace, name.getNamespaceURI());
return result;
}
void addDocumentType(SchemaTypeImpl type, QName name)
{
if (_documentTypes.containsKey(name))
{
if (!ignoreMdef(name)) {
if (_mdefAll) {
warning(XmlErrorCodes.SCHEMA_PROPERTIES$DUPLICATE,
new Object[] { "global element", QNameHelper.pretty(name), ((SchemaComponent) _documentTypes.get(name)).getSourceName() },
type.getParseObject());
} else {
error(XmlErrorCodes.SCHEMA_PROPERTIES$DUPLICATE,
new Object[] { "global element", QNameHelper.pretty(name), ((SchemaComponent) _documentTypes.get(name)).getSourceName() },
type.getParseObject());
}
}
}
else
{
_documentTypes.put(name, type);
SchemaContainer container = getContainer(name.getNamespaceURI());
assert container != null && container == type.getContainer();
container.addDocumentType(type.getRef());
}
}
SchemaType[] documentTypes()
{ return (SchemaType[])_documentTypes.values().toArray(new SchemaType[_documentTypes.size()]); }
/* ATTRIBUTE TYPES =================================================*/
SchemaTypeImpl findAttributeType(QName name, String chameleonNamespace, String sourceNamespace)
{
name = compatName(name, chameleonNamespace);
SchemaTypeImpl result = (SchemaTypeImpl)_attributeTypes.get(name);
boolean foundOnLoader = false;
if (result == null)
{
result = (SchemaTypeImpl)_importingLoader.findAttributeType(name);
foundOnLoader = result != null;
}
if (!foundOnLoader && sourceNamespace != null)
registerDependency(sourceNamespace, name.getNamespaceURI());
return result;
}
void addAttributeType(SchemaTypeImpl type, QName name)
{
if (_attributeTypes.containsKey(name))
{
if (!ignoreMdef(name)) {
if (_mdefAll) {
warning(XmlErrorCodes.SCHEMA_PROPERTIES$DUPLICATE,
new Object[] { "global attribute", QNameHelper.pretty(name), ((SchemaComponent) _attributeTypes.get(name)).getSourceName() },
type.getParseObject());
} else {
error(XmlErrorCodes.SCHEMA_PROPERTIES$DUPLICATE,
new Object[] { "global attribute", QNameHelper.pretty(name), ((SchemaComponent) _attributeTypes.get(name)).getSourceName() },
type.getParseObject());
}
}
}
else
{
_attributeTypes.put(name, type);
SchemaContainer container = getContainer(name.getNamespaceURI());
assert container != null && container == type.getContainer();
container.addAttributeType(type.getRef());
}
}
SchemaType[] attributeTypes()
{ return (SchemaType[])_attributeTypes.values().toArray(new SchemaType[_attributeTypes.size()]); }
/* ATTRIBUTES =====================================================*/
SchemaGlobalAttributeImpl findGlobalAttribute(QName name, String chameleonNamespace, String sourceNamespace)
{
name = compatName(name, chameleonNamespace);
SchemaGlobalAttributeImpl result = (SchemaGlobalAttributeImpl)_globalAttributes.get(name);
boolean foundOnLoader = false;
if (result == null)
{
result = (SchemaGlobalAttributeImpl)_importingLoader.findAttribute(name);
foundOnLoader = result != null;
}
if (!foundOnLoader && sourceNamespace != null)
registerDependency(sourceNamespace, name.getNamespaceURI());
return result;
}
void addGlobalAttribute(SchemaGlobalAttributeImpl attribute)
{
if (attribute != null)
{
QName name = attribute.getName();
_globalAttributes.put(name, attribute);
addSpelling(name, attribute);
SchemaContainer container = getContainer(name.getNamespaceURI());
assert container != null && container == attribute.getContainer();
container.addGlobalAttribute(attribute.getRef());
}
}
SchemaGlobalAttribute[] globalAttributes()
{ return (SchemaGlobalAttribute[])_globalAttributes.values().toArray(new SchemaGlobalAttribute[_globalAttributes.size()]); }
/* ELEMENTS =======================================================*/
SchemaGlobalElementImpl findGlobalElement(QName name, String chameleonNamespace, String sourceNamespace)
{
name = compatName(name, chameleonNamespace);
SchemaGlobalElementImpl result = (SchemaGlobalElementImpl)_globalElements.get(name);
boolean foundOnLoader = false;
if (result == null)
{
result = (SchemaGlobalElementImpl)_importingLoader.findElement(name);
foundOnLoader = result != null;
}
if (!foundOnLoader && sourceNamespace != null)
registerDependency(sourceNamespace, name.getNamespaceURI());
return result;
}
void addGlobalElement(SchemaGlobalElementImpl element)
{
if (element != null)
{
QName name = element.getName();
_globalElements.put(name, element);
SchemaContainer container = getContainer(name.getNamespaceURI());
assert container != null && container == element.getContainer();
container.addGlobalElement(element.getRef());
addSpelling(name, element);
}
}
SchemaGlobalElement[] globalElements()
{ return (SchemaGlobalElement[])_globalElements.values().toArray(new SchemaGlobalElement[_globalElements.size()]); }
/* ATTRIBUTE GROUPS ===============================================*/
SchemaAttributeGroupImpl findAttributeGroup(QName name, String chameleonNamespace, String sourceNamespace)
{
name = compatName(name, chameleonNamespace);
SchemaAttributeGroupImpl result = (SchemaAttributeGroupImpl)_attributeGroups.get(name);
boolean foundOnLoader = false;
if (result == null)
{
result = (SchemaAttributeGroupImpl)_importingLoader.findAttributeGroup(name);
foundOnLoader = result != null;
}
if (!foundOnLoader && sourceNamespace != null)
registerDependency(sourceNamespace, name.getNamespaceURI());
return result;
}
SchemaAttributeGroupImpl findRedefinedAttributeGroup(QName name, String chameleonNamespace, SchemaAttributeGroupImpl redefinedBy)
{
QName redefinitionFor = redefinedBy.getName();
name = compatName(name, chameleonNamespace);
if (name.equals(redefinitionFor))
{
return (SchemaAttributeGroupImpl)_redefinedAttributeGroups.get(redefinedBy);
// 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, SchemaAttributeGroupImpl redefined)
{
if (attributeGroup != null)
{
QName name = attributeGroup.getName();
SchemaContainer container = getContainer(name.getNamespaceURI());
assert container != null && container == attributeGroup.getContainer();
if (redefined != null)
{
if (_redefinedAttributeGroups.containsKey(redefined))
{
if (!ignoreMdef(name)) {
if (_mdefAll) {
warning(XmlErrorCodes.SCHEMA_PROPERTIES$DUPLICATE,
new Object[] { "attribute group", QNameHelper.pretty(name), ((SchemaComponent) _redefinedAttributeGroups.get(redefined)).getSourceName() },
attributeGroup.getParseObject());
} else {
error(XmlErrorCodes.SCHEMA_PROPERTIES$DUPLICATE,
new Object[] { "attribute group", QNameHelper.pretty(name), ((SchemaComponent) _redefinedAttributeGroups.get(redefined)).getSourceName() },
attributeGroup.getParseObject());
}
}
}
else
{
_redefinedAttributeGroups.put(redefined, attributeGroup);
container.addRedefinedAttributeGroup(attributeGroup.getRef());
}
}
else
{
if (_attributeGroups.containsKey( name ))
{
if (!ignoreMdef(name)) {
if (_mdefAll) {
warning(XmlErrorCodes.SCHEMA_PROPERTIES$DUPLICATE,
new Object[] { "attribute group", QNameHelper.pretty(name), ((SchemaComponent) _attributeGroups.get(name)).getSourceName() },
attributeGroup.getParseObject());
} else {
error(XmlErrorCodes.SCHEMA_PROPERTIES$DUPLICATE,
new Object[] { "attribute group", QNameHelper.pretty(name), ((SchemaComponent) _attributeGroups.get(name)).getSourceName() },
attributeGroup.getParseObject());
}
}
}
else
{
_attributeGroups.put(attributeGroup.getName(), attributeGroup);
addSpelling(attributeGroup.getName(), attributeGroup);
container.addAttributeGroup(attributeGroup.getRef());
}
}
}
}
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, String sourceNamespace)
{
name = compatName(name, chameleonNamespace);
SchemaModelGroupImpl result = (SchemaModelGroupImpl)_modelGroups.get(name);
boolean foundOnLoader = false;
if (result == null)
{
result = (SchemaModelGroupImpl)_importingLoader.findModelGroup(name);
foundOnLoader = result != null;
}
if (!foundOnLoader && sourceNamespace != null)
registerDependency(sourceNamespace, name.getNamespaceURI());
return result;
}
SchemaModelGroupImpl findRedefinedModelGroup(QName name, String chameleonNamespace, SchemaModelGroupImpl redefinedBy)
{
QName redefinitionFor = redefinedBy.getName();
name = compatName(name, chameleonNamespace);
if (name.equals(redefinitionFor))
{
return (SchemaModelGroupImpl)_redefinedModelGroups.get(redefinedBy);
// 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, SchemaModelGroupImpl redefined)
{
if (modelGroup != null)
{
QName name = modelGroup.getName();
SchemaContainer container = getContainer(name.getNamespaceURI());
assert container != null && container == modelGroup.getContainer();
if (redefined != null)
{
if (_redefinedModelGroups.containsKey(redefined))
{
if (!ignoreMdef(name)) {
if (_mdefAll) {
warning(XmlErrorCodes.SCHEMA_PROPERTIES$DUPLICATE,
new Object[] { "model group", QNameHelper.pretty(name), ((SchemaComponent) _redefinedModelGroups.get(redefined)).getSourceName() },
modelGroup.getParseObject());
} else {
error(XmlErrorCodes.SCHEMA_PROPERTIES$DUPLICATE,
new Object[] { "model group", QNameHelper.pretty(name), ((SchemaComponent) _redefinedModelGroups.get(redefined)).getSourceName() },
modelGroup.getParseObject());
}
}
}
else
{
_redefinedModelGroups.put(redefined, modelGroup);
container.addRedefinedModelGroup(modelGroup.getRef());
}
}
else
{
if (_modelGroups.containsKey(name))
{
if (!ignoreMdef(name)) {
if (_mdefAll) {
warning(XmlErrorCodes.SCHEMA_PROPERTIES$DUPLICATE,
new Object[] { "model group", QNameHelper.pretty(name), ((SchemaComponent) _modelGroups.get(name)).getSourceName() },
modelGroup.getParseObject());
} else {
error(XmlErrorCodes.SCHEMA_PROPERTIES$DUPLICATE,
new Object[] { "model group", QNameHelper.pretty(name), ((SchemaComponent) _modelGroups.get(name)).getSourceName() },
modelGroup.getParseObject());
}
}
}
else
{
_modelGroups.put(modelGroup.getName(), modelGroup);
addSpelling(modelGroup.getName(), modelGroup);
container.addModelGroup(modelGroup.getRef());
}
}
}
}
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, String sourceNamespace)
{
name = compatName(name, chameleonNamespace);
if (sourceNamespace != null)
registerDependency(sourceNamespace, name.getNamespaceURI());
return (SchemaIdentityConstraintImpl)_idConstraints.get(name);
}
void addIdConstraint(SchemaIdentityConstraintImpl idc)
{
if (idc != null)
{
QName name = idc.getName();
SchemaContainer container = getContainer(name.getNamespaceURI());
assert container != null && container == idc.getContainer();
if (_idConstraints.containsKey(name))
{
if (!ignoreMdef(name))
warning(XmlErrorCodes.SCHEMA_PROPERTIES$DUPLICATE,
new Object[] { "identity constraint", QNameHelper.pretty(name), ((SchemaComponent) _idConstraints.get(name)).getSourceName() },
idc.getParseObject());
}
else
{
_idConstraints.put(name, idc);
addSpelling(idc.getName(), idc);
container.addIdentityConstraint(idc.getRef());
}
}
}
SchemaIdentityConstraintImpl[] idConstraints()
{ return (SchemaIdentityConstraintImpl[])_idConstraints.values().toArray(new SchemaIdentityConstraintImpl[_idConstraints.size()]); }
/* ANNOTATIONS ===========================================*/
void addAnnotation(SchemaAnnotationImpl ann, String targetNamespace)
{
if (ann != null)
{
SchemaContainer container = getContainer(targetNamespace);
assert container != null && container == ann.getContainer();
_annotations.add(ann);
container.addAnnotation(ann);
}
}
List annotations()
{ return _annotations; }
/* 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);
}
Object[] getCurrentProcessing()
{
return _processingGroups.toArray();
}
/* 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 tl_stscStack = new ThreadLocal();
public static void clearThreadLocals() {
tl_stscStack.remove();
}
public static StscState start()
{
StscStack stscStack = (StscStack) tl_stscStack.get();
if (stscStack==null)
{
stscStack = new StscStack();
tl_stscStack.set(stscStack);
}
return stscStack.push();
}
public static StscState get()
{
return ((StscStack) tl_stscStack.get()).current;
}
public static void end()
{
StscStack stscStack = (StscStack) tl_stscStack.get();
stscStack.pop();
if (stscStack.stack.size()==0)
tl_stscStack.set(null); // this is required to release all the references in this classloader
// which will enable class unloading and avoid OOM in PermGen
}
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, boolean recovered)
{
String expected;
String expectedName = QNameHelper.pretty(itemName);
String found = null;
String foundName = null;
String sourceName = null;
if (recovered)
_recoveredErrors++;
switch (code)
{
case SchemaType.TYPE:
expected = "type";
break;
case SchemaType.ELEMENT:
expected = "element";
break;
case SchemaType.ATTRIBUTE:
expected = "attribute";
break;
case SchemaType.MODEL_GROUP:
expected = "model group";
break;
case SchemaType.ATTRIBUTE_GROUP:
expected = "attribute group";
break;
case SchemaType.IDENTITY_CONSTRAINT:
expected = "identity constraint";
break;
default:
assert(false);
expected = "definition";
break;
}
SchemaComponent foundComponent = findSpelling(itemName);
QName name;
if (foundComponent != null)
{
name = foundComponent.getName();
if (name != null)
{
switch (foundComponent.getComponentType())
{
case SchemaComponent.TYPE:
found = "type";
sourceName = ((SchemaType)foundComponent).getSourceName();
break;
case SchemaComponent.ELEMENT:
found = "element";
sourceName = ((SchemaGlobalElement)foundComponent).getSourceName();
break;
case SchemaComponent.ATTRIBUTE:
found = "attribute";
sourceName = ((SchemaGlobalAttribute)foundComponent).getSourceName();
break;
case SchemaComponent.ATTRIBUTE_GROUP:
found = "attribute group";
break;
case SchemaComponent.MODEL_GROUP:
found = "model group";
break;
}
if (sourceName != null)
{
sourceName = sourceName.substring(sourceName.lastIndexOf('/') + 1);
}
if (!name.equals(itemName))
{
foundName = QNameHelper.pretty(name);
}
}
}
if (found == null)
{
// error with no help
error(XmlErrorCodes.SCHEMA_QNAME_RESOLVE,
new Object[] { expected, expectedName }, loc);
}
else {
// error with help
error(XmlErrorCodes.SCHEMA_QNAME_RESOLVE$HELP,
new Object[] {
expected,
expectedName,
found,
(foundName == null ? new Integer(0) : new Integer(1)),
foundName,
(sourceName == null ? new Integer(0) : new Integer(1)),
sourceName
},
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));
int question = uri.indexOf('?', lastslash + 1);
if (question == -1)
return dir + "/" + uri.substring(lastslash + 1);
String query = QNameHelper.hexsafe(question == -1 ? "" : uri.substring(question));
// if encoded query part is longer than 64 characters, just drop it
if (query.startsWith(QNameHelper.URI_SHA1_PREFIX))
return dir + "/" + uri.substring(lastslash + 1, question);
else
return dir + "/" + uri.substring(lastslash + 1, question) + query;
}
/**
* 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());
public File getSchemasDir()
{
return _schemasDir;
}
public void setSchemasDir(File _schemasDir)
{
this._schemasDir = _schemasDir;
}
}