| /* |
| * 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.SchemaTypeLoader; |
| import org.apache.xmlbeans.SchemaType; |
| import org.apache.xmlbeans.SchemaGlobalElement; |
| import org.apache.xmlbeans.SchemaGlobalAttribute; |
| import org.apache.xmlbeans.SchemaModelGroup; |
| import org.apache.xmlbeans.SchemaAttributeGroup; |
| import org.apache.xmlbeans.SchemaTypeSystem; |
| import org.apache.xmlbeans.SchemaIdentityConstraint; |
| import org.apache.xmlbeans.impl.common.QNameHelper; |
| import org.apache.xmlbeans.impl.common.XBeanDebug; |
| import javax.xml.namespace.QName; |
| |
| import java.io.InputStream; |
| import java.util.Map; |
| import java.util.HashMap; |
| import java.util.Collections; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.IdentityHashMap; |
| |
| public class SchemaTypeLoaderImpl extends SchemaTypeLoaderBase |
| { |
| private ResourceLoader _resourceLoader; |
| private ClassLoader _classLoader; |
| private SchemaTypeLoader[] _searchPath; |
| |
| private Map _classpathTypeSystems; |
| private Map _classLoaderTypeSystems; |
| private Map _elementCache; |
| private Map _attributeCache; |
| private Map _modelGroupCache; |
| private Map _attributeGroupCache; |
| private Map _idConstraintCache; |
| private Map _typeCache; |
| private Map _documentCache; |
| private Map _classnameCache; |
| |
| private static SchemaTypeLoaderImpl buildContextTypeLoader() |
| { |
| return new SchemaTypeLoaderImpl(new SchemaTypeLoader[] { BuiltinSchemaTypeSystem.get() } , null, Thread.currentThread().getContextClassLoader()); |
| } |
| |
| private static ThreadLocal _threadTypeSystem = |
| new ThreadLocal() |
| { |
| protected Object initialValue() { return buildContextTypeLoader(); } |
| }; |
| |
| public static SchemaTypeLoaderImpl getContextTypeLoader() |
| { |
| SchemaTypeLoaderImpl candidate = (SchemaTypeLoaderImpl)_threadTypeSystem.get(); |
| if (candidate._classLoader != Thread.currentThread().getContextClassLoader()) |
| { |
| candidate = buildContextTypeLoader(); |
| _threadTypeSystem.set(candidate); |
| } |
| return candidate; |
| } |
| |
| public static SchemaTypeLoader build(SchemaTypeLoader[] searchPath, ResourceLoader resourceLoader, ClassLoader classLoader) |
| { |
| if (searchPath == null) |
| { |
| searchPath = EMPTY_SCHEMATYPELOADER_ARRAY; |
| } |
| else |
| { |
| // assemble a flattened search path with no duplicates |
| SubLoaderList list = new SubLoaderList(); |
| for (int i = 0; i < searchPath.length; i++) |
| { |
| if (searchPath[i] == null) |
| throw new IllegalArgumentException("searchPath[" + i + "] is null"); |
| if (!(searchPath[i] instanceof SchemaTypeLoaderImpl)) |
| list.add(searchPath[i]); |
| else |
| { |
| SchemaTypeLoaderImpl sub = (SchemaTypeLoaderImpl)searchPath[i]; |
| if (sub._classLoader != null || sub._resourceLoader != null) |
| list.add(sub); |
| else for (int j = 0; j < sub._searchPath.length; j++) |
| list.add(sub._searchPath[j]); |
| } |
| } |
| searchPath = list.toArray(); |
| } |
| |
| if (searchPath.length == 1 && resourceLoader == null && classLoader == null) |
| return searchPath[0]; |
| |
| return new SchemaTypeLoaderImpl(searchPath, resourceLoader, classLoader); |
| } |
| |
| /** |
| * Just used to avoid duplicate path entries |
| */ |
| private static class SubLoaderList |
| { |
| private List theList = new ArrayList(); |
| private Map seen = new IdentityHashMap(); |
| |
| private boolean add(SchemaTypeLoader loader) |
| { |
| if (seen.containsKey(loader)) |
| return false; |
| theList.add(loader); |
| seen.put(loader, null); |
| return true; |
| } |
| |
| private SchemaTypeLoader[] toArray() |
| { |
| return (SchemaTypeLoader[])theList.toArray(EMPTY_SCHEMATYPELOADER_ARRAY); |
| } |
| } |
| |
| /** |
| * Constructs a SchemaTypeLoaderImpl that searches for objects |
| * in the following order: |
| * |
| * (1) First on the searchPath of other SchemaTypeSystems supplied, |
| * in order that they are listed. |
| * (2) Next on the classpath of .jar files or directories supplied, |
| * in the order that they are listed. When types are returned in |
| * this way, they are instantiated from a private typesystem. |
| * In other words, if a type is loaded from another SchemaTypeLoaderImpl |
| * that was initialized on the same file, the instance of the type will |
| * be different. |
| * (3) Finally on the classloader supplied. |
| */ |
| private SchemaTypeLoaderImpl(SchemaTypeLoader[] searchPath, ResourceLoader resourceLoader, ClassLoader classLoader) |
| { |
| if (searchPath == null) |
| _searchPath = EMPTY_SCHEMATYPELOADER_ARRAY; |
| else |
| _searchPath = searchPath; |
| _resourceLoader = resourceLoader; |
| _classLoader = classLoader; |
| |
| initCaches(); |
| } |
| |
| /** |
| * Initializes the caches. |
| */ |
| private final void initCaches() |
| { |
| _classpathTypeSystems = Collections.synchronizedMap(new HashMap()); |
| _classLoaderTypeSystems = Collections.synchronizedMap(new HashMap()); |
| _elementCache = Collections.synchronizedMap(new HashMap()); |
| _attributeCache = Collections.synchronizedMap(new HashMap()); |
| _modelGroupCache = Collections.synchronizedMap(new HashMap()); |
| _attributeGroupCache = Collections.synchronizedMap(new HashMap()); |
| _idConstraintCache = Collections.synchronizedMap(new HashMap()); |
| _typeCache = Collections.synchronizedMap(new HashMap()); |
| _documentCache = Collections.synchronizedMap(new HashMap()); |
| _classnameCache = Collections.synchronizedMap(new HashMap()); |
| } |
| |
| SchemaTypeSystemImpl typeSystemForComponent(String searchdir, QName name) |
| { |
| String searchfor = searchdir + QNameHelper.hexsafedir(name) + ".xsb"; |
| String tsname = null; |
| |
| if (_resourceLoader != null) |
| tsname = crackEntry(_resourceLoader, searchfor); |
| |
| if (_classLoader != null) |
| tsname = crackEntry(_classLoader, searchfor); |
| |
| if (tsname != null) |
| return (SchemaTypeSystemImpl)typeSystemForName(tsname); |
| |
| return null; |
| } |
| |
| public SchemaTypeSystem typeSystemForName(String name) |
| { |
| if (_resourceLoader != null) |
| { |
| SchemaTypeSystem result = getTypeSystemOnClasspath(name); |
| if (result != null) |
| return result; |
| } |
| |
| if (_classLoader != null) |
| { |
| SchemaTypeSystem result = getTypeSystemOnClassloader(name); |
| if (result != null) |
| return result; |
| } |
| return null; |
| } |
| |
| SchemaTypeSystemImpl typeSystemForClassname(String searchdir, String name) |
| { |
| String searchfor = searchdir + name.replace('.', '/') + ".xsb"; |
| |
| if (_resourceLoader != null) |
| { |
| String tsname = crackEntry(_resourceLoader, searchfor); |
| if (tsname != null) |
| return getTypeSystemOnClasspath(tsname); |
| } |
| |
| if (_classLoader != null) |
| { |
| String tsname = crackEntry(_classLoader, searchfor); |
| if (tsname != null) |
| return getTypeSystemOnClassloader(tsname); |
| } |
| |
| return null; |
| } |
| |
| SchemaTypeSystemImpl getTypeSystemOnClasspath(String name) |
| { |
| SchemaTypeSystemImpl result = (SchemaTypeSystemImpl)_classpathTypeSystems.get(name); |
| if (result == null) |
| { |
| result = new SchemaTypeSystemImpl(_resourceLoader, name, this); |
| _classpathTypeSystems.put(name, result); |
| } |
| return result; |
| } |
| |
| SchemaTypeSystemImpl getTypeSystemOnClassloader(String name) |
| { |
| XBeanDebug.trace(XBeanDebug.TRACE_SCHEMA_LOADING, "Finding type system " + name + " on classloader", 0); |
| SchemaTypeSystemImpl result = (SchemaTypeSystemImpl)_classLoaderTypeSystems.get(name); |
| if (result == null) |
| { |
| XBeanDebug.trace(XBeanDebug.TRACE_SCHEMA_LOADING, "Type system " + name + " not cached - consulting field", 0); |
| result = SchemaTypeSystemImpl.forName(name, _classLoader); |
| _classLoaderTypeSystems.put(name, result); |
| } |
| return result; |
| } |
| |
| static String crackEntry(ResourceLoader loader, String searchfor) |
| { |
| InputStream is = loader.getResourceAsStream(searchfor); |
| if (is == null) |
| return null; |
| return crackPointer(is); |
| } |
| |
| static String crackEntry(ClassLoader loader, String searchfor) |
| { |
| InputStream stream = loader.getResourceAsStream(searchfor); |
| if (stream == null) |
| return null; |
| return crackPointer(stream); |
| } |
| |
| static String crackPointer(InputStream stream) |
| { |
| return SchemaTypeSystemImpl.crackPointer(stream); |
| } |
| |
| public boolean isNamespaceDefined(String namespace) |
| { |
| for (int i = 0; i < _searchPath.length; i++) |
| if (_searchPath[i].isNamespaceDefined(namespace)) |
| return true; |
| |
| SchemaTypeSystem sts = typeSystemForComponent("schema/namespace/", new QName(namespace, "xmlns")); |
| return (sts != null); |
| } |
| |
| public SchemaType.Ref findTypeRef(QName name) |
| { |
| SchemaType.Ref result = (SchemaType.Ref)_typeCache.get(name); |
| if (result == null && !_typeCache.containsKey(name)) |
| { |
| for (int i = 0; i < _searchPath.length; i++) |
| if (null != (result = _searchPath[i].findTypeRef(name))) |
| break; |
| if (result == null) |
| { |
| SchemaTypeSystem ts = typeSystemForComponent("schema/type/", name); |
| if (ts != null) |
| { |
| result = ts.findTypeRef(name); |
| assert(result != null) : "Type system registered type " + QNameHelper.pretty(name) + " but does not return it"; |
| } |
| } |
| _typeCache.put(name, result); |
| } |
| return result; |
| } |
| |
| public SchemaType typeForClassname(String classname) |
| { |
| classname = classname.replace('$', '.'); |
| |
| SchemaType result = (SchemaType)_classnameCache.get(classname); |
| if (result == null && !_classnameCache.containsKey(classname)) |
| { |
| for (int i = 0; i < _searchPath.length; i++) |
| if (null != (result = _searchPath[i].typeForClassname(classname))) |
| break; |
| if (result == null) |
| { |
| SchemaTypeSystem ts = typeSystemForClassname("schema/javaname/", classname); |
| if (ts != null) |
| { |
| result = ts.typeForClassname(classname); |
| assert(result != null) : "Type system registered type " + classname + " but does not return it"; |
| } |
| } |
| _classnameCache.put(classname, result); |
| } |
| return result; |
| } |
| |
| public SchemaType.Ref findDocumentTypeRef(QName name) |
| { |
| SchemaType.Ref result = (SchemaType.Ref)_documentCache.get(name); |
| if (result == null && !_documentCache.containsKey(name)) |
| { |
| for (int i = 0; i < _searchPath.length; i++) |
| if (null != (result = _searchPath[i].findDocumentTypeRef(name))) |
| break; |
| if (result == null) |
| { |
| SchemaTypeSystem ts = typeSystemForComponent("schema/element/", name); |
| if (ts != null) |
| { |
| result = ts.findDocumentTypeRef(name); |
| assert(result != null) : "Type system registered element " + QNameHelper.pretty(name) + " but does not contain document type"; |
| } |
| } |
| _documentCache.put(name, result); |
| } |
| return result; |
| } |
| |
| public SchemaType.Ref findAttributeTypeRef(QName name) |
| { |
| SchemaType.Ref result = (SchemaType.Ref)_attributeCache.get(name); |
| if (result == null && !_attributeCache.containsKey(name)) |
| { |
| for (int i = 0; i < _searchPath.length; i++) |
| if (null != (result = _searchPath[i].findAttributeTypeRef(name))) |
| break; |
| if (result == null) |
| { |
| SchemaTypeSystem ts = typeSystemForComponent("schema/attribute/", name); |
| if (ts != null) |
| { |
| result = ts.findAttributeTypeRef(name); |
| assert(result != null) : "Type system registered attribute " + QNameHelper.pretty(name) + " but does not contain attribute type"; |
| } |
| } |
| _attributeCache.put(name, result); |
| } |
| return result; |
| } |
| |
| public SchemaGlobalElement.Ref findElementRef(QName name) |
| { |
| SchemaGlobalElement.Ref result = (SchemaGlobalElement.Ref)_elementCache.get(name); |
| if (result == null && !_elementCache.containsKey(name)) |
| { |
| for (int i = 0; i < _searchPath.length; i++) |
| if (null != (result = _searchPath[i].findElementRef(name))) |
| break; |
| if (result == null) |
| { |
| SchemaTypeSystem ts = typeSystemForComponent("schema/element/", name); |
| if (ts != null) |
| { |
| result = ts.findElementRef(name); |
| assert(result != null) : "Type system registered element " + QNameHelper.pretty(name) + " but does not return it"; |
| } |
| } |
| _elementCache.put(name, result); |
| } |
| return result; |
| } |
| |
| public SchemaGlobalAttribute.Ref findAttributeRef(QName name) |
| { |
| SchemaGlobalAttribute.Ref result = (SchemaGlobalAttribute.Ref)_attributeCache.get(name); |
| if (result == null && !_attributeCache.containsKey(name)) |
| { |
| for (int i = 0; i < _searchPath.length; i++) |
| if (null != (result = _searchPath[i].findAttributeRef(name))) |
| break; |
| if (result == null) |
| { |
| SchemaTypeSystem ts = typeSystemForComponent("schema/attribute/", name); |
| if (ts != null) |
| { |
| result = ts.findAttributeRef(name); |
| assert(result != null) : "Type system registered attribute " + QNameHelper.pretty(name) + " but does not return it"; |
| } |
| } |
| _attributeCache.put(name, result); |
| } |
| return result; |
| } |
| |
| public SchemaModelGroup.Ref findModelGroupRef(QName name) |
| { |
| SchemaModelGroup.Ref result = (SchemaModelGroup.Ref)_modelGroupCache.get(name); |
| if (result == null && !_modelGroupCache.containsKey(name)) |
| { |
| for (int i = 0; i < _searchPath.length; i++) |
| if (null != (result = _searchPath[i].findModelGroupRef(name))) |
| break; |
| if (result == null) |
| { |
| SchemaTypeSystem ts = typeSystemForComponent("schema/modelgroup/", name); |
| if (ts != null) |
| { |
| result = ts.findModelGroupRef(name); |
| assert(result != null) : "Type system registered model group " + QNameHelper.pretty(name) + " but does not return it"; |
| } |
| } |
| _modelGroupCache.put(name, result); |
| } |
| return result; |
| } |
| |
| public SchemaAttributeGroup.Ref findAttributeGroupRef(QName name) |
| { |
| SchemaAttributeGroup.Ref result = (SchemaAttributeGroup.Ref)_attributeGroupCache.get(name); |
| if (result == null && !_attributeGroupCache.containsKey(name)) |
| { |
| for (int i = 0; i < _searchPath.length; i++) |
| if (null != (result = _searchPath[i].findAttributeGroupRef(name))) |
| break; |
| if (result == null) |
| { |
| SchemaTypeSystem ts = typeSystemForComponent("schema/attributegroup/", name); |
| if (ts != null) |
| { |
| result = ts.findAttributeGroupRef(name); |
| assert(result != null) : "Type system registered attribute group " + QNameHelper.pretty(name) + " but does not return it"; |
| } |
| } |
| _attributeGroupCache.put(name, result); |
| } |
| return result; |
| } |
| |
| public SchemaIdentityConstraint.Ref findIdentityConstraintRef(QName name) |
| { |
| SchemaIdentityConstraint.Ref result = (SchemaIdentityConstraint.Ref)_idConstraintCache.get(name); |
| if (result == null && !_idConstraintCache.containsKey(name)) |
| { |
| for (int i = 0; i < _searchPath.length; i++) |
| if (null != (result = _searchPath[i].findIdentityConstraintRef(name))) |
| break; |
| if (result == null) |
| { |
| SchemaTypeSystem ts = typeSystemForComponent("schema/identityconstraint/", name); |
| if (ts != null) |
| { |
| result = ts.findIdentityConstraintRef(name); |
| assert(result != null) : "Type system registered identity constraint " + QNameHelper.pretty(name) + " but does not return it"; |
| } |
| } |
| _idConstraintCache.put(name, result); |
| } |
| return result; |
| } |
| |
| public InputStream getSourceAsStream(String sourceName) |
| { |
| InputStream result = null; |
| |
| if (!sourceName.startsWith("/")) |
| sourceName = "/" + sourceName; |
| |
| if (_resourceLoader != null) |
| result = _resourceLoader.getResourceAsStream("schema/src" + sourceName); |
| |
| if (result == null && _classLoader != null) |
| return _classLoader.getResourceAsStream("schema/src" + sourceName); |
| |
| return result; |
| } |
| |
| private static final SchemaTypeLoader[] EMPTY_SCHEMATYPELOADER_ARRAY = new SchemaTypeLoader[0]; |
| } |