Author: bimargulies Date: Fri Oct 15 00:00:18 2010 New Revision: 1022772 URL: http://svn.apache.org/viewvc?rev=1022772&view=rev Log: add a mechanism for catching invalid mods to some of the global collections
Modified: webservices/commons/trunk/modules/XmlSchema/pom.xml webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchema.java webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaAttribute.java webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaAttributeGroup.java webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaElement.java webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaExternal.java webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaGroup.java webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaNotation.java webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaType.java webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/utils/CollectionFactory.java Modified: webservices/commons/trunk/modules/XmlSchema/pom.xml URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/XmlSchema/pom.xml?rev=1022772&r1=1022771&r2=1022772&view=diff ============================================================================== --- webservices/commons/trunk/modules/XmlSchema/pom.xml (original) +++ webservices/commons/trunk/modules/XmlSchema/pom.xml Fri Oct 15 00:00:18 2010 @@ -214,11 +214,15 @@ </plugin> <plugin> <artifactId>maven-surefire-plugin</artifactId> + <version>2.6</version> <configuration> <forkMode>never</forkMode> <additionalClasspathElements> <additionalClasspathElement>w3c-testcases</additionalClasspathElement> </additionalClasspathElements> + <systemPropertyVariables> + <org.apache.ws.commons.schema.protectReadOnlyCollections>true</org.apache.ws.commons.schema.protectReadOnlyCollections> + </systemPropertyVariables> </configuration> </plugin> <plugin> @@ -386,7 +390,7 @@ <dependency> <groupId>xalan</groupId> <artifactId>xalan</artifactId> - <version>2.7.0</version> + <version>2.7.1</version> </dependency> </dependencies> <build> @@ -394,23 +398,15 @@ <plugin> <artifactId>maven-surefire-plugin</artifactId> <configuration> - <systemProperties> -<!-- - The default xalan TransformerFactory on the ibm jdk is - org.apache.xalan.processor.TransformerFactoryImpl which has a - known issue with implicit namespaces. Set this property to use - the xsltc TransformerFactory (which the sun jdk seems to - default to). - --> - <property> - <name> - javax.xml.transform.TransformerFactory - </name> - <value> - org.apache.xalan.xsltc.trax.TransformerFactoryImpl - </value> - </property> - </systemProperties> + <systemPropertyVariables> + <!-- + The default xalan TransformerFactory on the ibm jdk is + org.apache.xalan.processor.TransformerFactoryImpl which has a + known issue with implicit namespaces. Set this property to use + the xsltc TransformerFactory (which the sun jdk seems to + default to). --> + <javax.xml.transform.TransformerFactory>org.apache.xalan.xsltc.trax.TransformerFactoryImpl</javax.xml.transform.TransformerFactory> + </systemPropertyVariables> </configuration> </plugin> </plugins> Modified: webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchema.java URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchema.java?rev=1022772&r1=1022771&r2=1022772&view=diff ============================================================================== --- webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchema.java (original) +++ webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchema.java Fri Oct 15 00:00:18 2010 @@ -45,6 +45,7 @@ import javax.xml.transform.stream.Stream import org.w3c.dom.Document; import org.apache.ws.commons.schema.XmlSchemaSerializer.XmlSchemaSerializerException; +import org.apache.ws.commons.schema.utils.CollectionFactory; import org.apache.ws.commons.schema.utils.NamespaceContextOwner; import org.apache.ws.commons.schema.utils.NamespacePrefixList; @@ -201,22 +202,28 @@ public class XmlSchema extends XmlSchema * Return a map containing all the defined attribute groups of this schema. The keys are QNames, where the * namespace will always be the target namespace of this schema. This makes it easier to look up items for * cross-schema references. + * <br/> + * If org.apache.ws.commons.schema.protectReadOnlyCollections + * is 'true', this will return a map that checks at runtime. * * @return the map of attribute groups. */ public Map<QName, XmlSchemaAttributeGroup> getAttributeGroups() { - return attributeGroups; + return CollectionFactory.getProtectedMap(attributeGroups); } /** * Return a map containing all the defined attributes of this schema. The keys are QNames, where the * namespace will always be the target namespace of this schema. This makes it easier to look up items for * cross-schema references. + * <br/> + * If org.apache.ws.commons.schema.protectReadOnlyCollections + * is 'true', this will return a map that checks at runtime. * * @return the map of attributes. */ public Map<QName, XmlSchemaAttribute> getAttributes() { - return attributes; + return CollectionFactory.getProtectedMap(attributes); } /** @@ -260,20 +267,26 @@ public class XmlSchema extends XmlSchema * Return a map containing all the defined elements of this schema. The keys are QNames, where the * namespace will always be the target namespace of this schema. This makes it easier to look up items for * cross-schema references. + * <br/> + * If org.apache.ws.commons.schema.protectReadOnlyCollections + * is 'true', this will return a map that checks at runtime * * @return the map of elements. */ public Map<QName, XmlSchemaElement> getElements() { - return elements; + return CollectionFactory.getProtectedMap(elements); } /** * Return all of the includes, imports, and redefines for this schema. + * <br/> + * If org.apache.ws.commons.schema.protectReadOnlyCollections + * is 'true', this will return a list that checks at runtime * * @return a list of the objects representing includes, imports, and redefines. */ public List<XmlSchemaExternal> getExternals() { - return externals; + return CollectionFactory.getProtectedList(externals); } /** @@ -296,12 +309,14 @@ public class XmlSchema extends XmlSchema /** * Return a map containing all the defined groups of this schema. The keys are QNames, where the namespace * will always be the target namespace of this schema. This makes it easier to look up items for - * cross-schema references. + * cross-schema references.<br/> + * If org.apache.ws.commons.schema.protectReadOnlyCollections + * is 'true', this will return a map that checks at runtime * * @return the map of groups. */ public Map<QName, XmlSchemaGroup> getGroups() { - return groups; + return CollectionFactory.getProtectedMap(groups); } /** @@ -315,10 +330,14 @@ public class XmlSchema extends XmlSchema } /** + * Return all of the global items in this schema.<br/> + * If org.apache.ws.commons.schema.protectReadOnlyCollections + * is 'true', this will return a map that checks at runtime. * @return <strong>all</strong> of the global items from this schema. + * */ public List<XmlSchemaObject> getItems() { - return items; + return CollectionFactory.getProtectedList(items); } /** @@ -353,11 +372,14 @@ public class XmlSchema extends XmlSchema * Return a map containing all the defined notations of this schema. The keys are QNames, where the * namespace will always be the target namespace of this schema. This makes it easier to look up items for * cross-schema references. + * <br/> + * If org.apache.ws.commons.schema.protectReadOnlyCollections + * is 'true', this will return a map that checks at runtime. * * @return the map of notations. */ public Map<QName, XmlSchemaNotation> getNotations() { - return notations; + return CollectionFactory.getProtectedMap(notations); } /** Modified: webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaAttribute.java URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaAttribute.java?rev=1022772&r1=1022771&r2=1022772&view=diff ============================================================================== --- webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaAttribute.java (original) +++ webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaAttribute.java Fri Oct 15 00:00:18 2010 @@ -21,6 +21,7 @@ package org.apache.ws.commons.schema; import javax.xml.namespace.QName; +import org.apache.ws.commons.schema.utils.CollectionFactory; import org.apache.ws.commons.schema.utils.XmlSchemaNamedWithForm; import org.apache.ws.commons.schema.utils.XmlSchemaNamedWithFormImpl; import org.apache.ws.commons.schema.utils.XmlSchemaRef; @@ -53,8 +54,13 @@ public class XmlSchemaAttribute extends namedDelegate.setRefObject(ref); ref.setNamedObject(namedDelegate); use = XmlSchemaUse.NONE; + final XmlSchema fSchema = schema; if (topLevel) { - schema.getItems().add(this); + CollectionFactory.withSchemaModifiable(new Runnable() { + public void run() { + fSchema.getItems().add(XmlSchemaAttribute.this); + } + }); } } @@ -130,17 +136,23 @@ public class XmlSchemaAttribute extends } public void setName(String name) { + final String fName = name; + CollectionFactory.withSchemaModifiable(new Runnable() { - if (namedDelegate.isTopLevel() && namedDelegate.getName() != null) { - namedDelegate.getParent().getAttributes().remove(getQName()); - } - namedDelegate.setName(name); - if (namedDelegate.isTopLevel()) { - if (name == null) { - throw new XmlSchemaException("Top-level attributes may not be anonymous"); + public void run() { + if (namedDelegate.isTopLevel() && namedDelegate.getName() != null) { + namedDelegate.getParent().getAttributes().remove(getQName()); + } + namedDelegate.setName(fName); + if (namedDelegate.isTopLevel()) { + if (fName == null) { + throw new XmlSchemaException("Top-level attributes may not be anonymous"); + } + namedDelegate.getParent().getAttributes().put(getQName(), XmlSchemaAttribute.this); + } } - namedDelegate.getParent().getAttributes().put(getQName(), this); - } + + }); } public boolean isFormSpecified() { Modified: webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaAttributeGroup.java URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaAttributeGroup.java?rev=1022772&r1=1022771&r2=1022772&view=diff ============================================================================== --- webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaAttributeGroup.java (original) +++ webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaAttributeGroup.java Fri Oct 15 00:00:18 2010 @@ -19,20 +19,20 @@ package org.apache.ws.commons.schema; -import java.util.ArrayList; import java.util.List; import javax.xml.namespace.QName; +import org.apache.ws.commons.schema.utils.CollectionFactory; import org.apache.ws.commons.schema.utils.XmlSchemaNamed; import org.apache.ws.commons.schema.utils.XmlSchemaNamedImpl; /** - * Class for attribute groups. Groups a set of attribute declarations so that + * Class for attribute groups. Groups a set of attribute declarations so that * they can be incorporated as a - * group into complex type definitions. Represents the World Wide Web + * group into complex type definitions. Represents the World Wide Web * consortium (W3C) attributeGroup element when it does <i>not</i> have a 'ref=' - * attribute. + * attribute. */ public class XmlSchemaAttributeGroup extends XmlSchemaAnnotated implements XmlSchemaNamed, @@ -45,10 +45,16 @@ public class XmlSchemaAttributeGroup ext * Creates new XmlSchemaAttributeGroup */ public XmlSchemaAttributeGroup(XmlSchema parent) { + final XmlSchema fParent = parent; namedDelegate = new XmlSchemaNamedImpl(parent, true); - parent.getItems().add(this); + CollectionFactory.withSchemaModifiable(new Runnable() { + public void run() { + fParent.getItems().add(XmlSchemaAttributeGroup.this); + } + }); + // we can't be put in the map until we have a name. Perhaps we should be forced to have a name ? - attributes = new ArrayList<XmlSchemaAttributeGroupMember>(); + attributes = CollectionFactory.getList(XmlSchemaAttributeGroupMember.class); } public XmlSchemaAnyAttribute getAnyAttribute() { @@ -84,10 +90,15 @@ public class XmlSchemaAttributeGroup ext } public void setName(String name) { - if (name != null) { - namedDelegate.getParent().getAttributeGroups().remove(getQName()); - } - namedDelegate.setName(name); - namedDelegate.getParent().getAttributeGroups().put(getQName(), this); + final String fName = name; + CollectionFactory.withSchemaModifiable(new Runnable() { + public void run() { + if (fName != null) { + namedDelegate.getParent().getAttributeGroups().remove(getQName()); + } + namedDelegate.setName(fName); + namedDelegate.getParent().getAttributeGroups().put(getQName(), XmlSchemaAttributeGroup.this); + } + }); } } Modified: webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaElement.java URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaElement.java?rev=1022772&r1=1022771&r2=1022772&view=diff ============================================================================== --- webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaElement.java (original) +++ webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaElement.java Fri Oct 15 00:00:18 2010 @@ -25,6 +25,7 @@ import java.util.List; import javax.xml.namespace.QName; +import org.apache.ws.commons.schema.utils.CollectionFactory; import org.apache.ws.commons.schema.utils.XmlSchemaNamedWithForm; import org.apache.ws.commons.schema.utils.XmlSchemaNamedWithFormImpl; import org.apache.ws.commons.schema.utils.XmlSchemaRef; @@ -93,8 +94,13 @@ public class XmlSchemaElement extends Xm nillable = false; finalDerivation = XmlSchemaDerivationMethod.NONE; block = XmlSchemaDerivationMethod.NONE; + final XmlSchema fParentSchema = parentSchema; if (topLevel) { - parentSchema.getItems().add(this); + CollectionFactory.withSchemaModifiable(new Runnable() { + public void run() { + fParentSchema.getItems().add(XmlSchemaElement.this); + } + }); } } @@ -215,13 +221,18 @@ public class XmlSchemaElement extends Xm } public void setName(String name) { - if (namedDelegate.isTopLevel() && namedDelegate.getName() != null) { - namedDelegate.getParent().getElements().remove(getQName()); - } - namedDelegate.setName(name); - if (namedDelegate.isTopLevel()) { - namedDelegate.getParent().getElements().put(getQName(), this); - } + final String fName = name; + CollectionFactory.withSchemaModifiable(new Runnable() { + public void run() { + if (namedDelegate.isTopLevel() && namedDelegate.getName() != null) { + namedDelegate.getParent().getElements().remove(getQName()); + } + namedDelegate.setName(fName); + if (namedDelegate.isTopLevel()) { + namedDelegate.getParent().getElements().put(getQName(), XmlSchemaElement.this); + } + } + }); } public XmlSchemaForm getForm() { Modified: webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaExternal.java URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaExternal.java?rev=1022772&r1=1022771&r2=1022772&view=diff ============================================================================== --- webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaExternal.java (original) +++ webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaExternal.java Fri Oct 15 00:00:18 2010 @@ -19,6 +19,8 @@ package org.apache.ws.commons.schema; +import org.apache.ws.commons.schema.utils.CollectionFactory; + /** * Common class for include, import, and redefine. All have in common two items: * the location of the referenced schema (required) and an optional @@ -33,8 +35,14 @@ public abstract class XmlSchemaExternal * Creates new XmlSchemaExternal */ protected XmlSchemaExternal(XmlSchema parent) { - parent.getExternals().add(this); - parent.getItems().add(this); + final XmlSchema fParent = parent; + CollectionFactory.withSchemaModifiable(new Runnable() { + + public void run() { + fParent.getExternals().add(XmlSchemaExternal.this); + fParent.getItems().add(XmlSchemaExternal.this); + } + }); } public XmlSchema getSchema() { Modified: webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaGroup.java URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaGroup.java?rev=1022772&r1=1022771&r2=1022772&view=diff ============================================================================== --- webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaGroup.java (original) +++ webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaGroup.java Fri Oct 15 00:00:18 2010 @@ -22,6 +22,7 @@ package org.apache.ws.commons.schema; import javax.xml.namespace.QName; +import org.apache.ws.commons.schema.utils.CollectionFactory; import org.apache.ws.commons.schema.utils.XmlSchemaNamed; import org.apache.ws.commons.schema.utils.XmlSchemaNamedImpl; @@ -31,17 +32,22 @@ import org.apache.ws.commons.schema.util * the World Wide Web Consortium (W3C) group element. */ -public class XmlSchemaGroup extends XmlSchemaAnnotated implements XmlSchemaNamed, +public class XmlSchemaGroup extends XmlSchemaAnnotated implements XmlSchemaNamed, XmlSchemaChoiceMember, XmlSchemaSequenceMember { private XmlSchemaGroupParticle particle; private XmlSchemaNamedImpl namedDelegate; - + public XmlSchemaGroup(XmlSchema parent) { namedDelegate = new XmlSchemaNamedImpl(parent, true); - parent.getItems().add(this); + final XmlSchema fParent = parent; + CollectionFactory.withSchemaModifiable(new Runnable() { + public void run() { + fParent.getItems().add(XmlSchemaGroup.this); + } + }); } - + public XmlSchemaGroupParticle getParticle() { return particle; @@ -72,13 +78,17 @@ public class XmlSchemaGroup extends XmlS } public void setName(String name) { - if (namedDelegate.getQName() != null) { - namedDelegate.getParent().getGroups().remove(namedDelegate.getQName()); - } - namedDelegate.setName(name); - if (name != null) { - namedDelegate.getParent().getGroups().put(namedDelegate.getQName(), this); - } + final String fName = name; + CollectionFactory.withSchemaModifiable(new Runnable() { + public void run() { + if (namedDelegate.getQName() != null) { + namedDelegate.getParent().getGroups().remove(namedDelegate.getQName()); + } + namedDelegate.setName(fName); + if (fName != null) { + namedDelegate.getParent().getGroups().put(namedDelegate.getQName(), XmlSchemaGroup.this); + } + } + }); } - } Modified: webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaNotation.java URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaNotation.java?rev=1022772&r1=1022771&r2=1022772&view=diff ============================================================================== --- webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaNotation.java (original) +++ webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaNotation.java Fri Oct 15 00:00:18 2010 @@ -21,6 +21,7 @@ package org.apache.ws.commons.schema; import javax.xml.namespace.QName; +import org.apache.ws.commons.schema.utils.CollectionFactory; import org.apache.ws.commons.schema.utils.XmlSchemaNamed; import org.apache.ws.commons.schema.utils.XmlSchemaNamedImpl; @@ -41,7 +42,12 @@ public class XmlSchemaNotation extends X */ public XmlSchemaNotation(XmlSchema parent) { namedDelegate = new XmlSchemaNamedImpl(parent, true); - parent.getItems().add(this); + final XmlSchema fParent = parent; + CollectionFactory.withSchemaModifiable(new Runnable() { + public void run() { + fParent.getItems().add(XmlSchemaNotation.this); + } + }); } public String getPublic() { @@ -93,10 +99,15 @@ public class XmlSchemaNotation extends X } public void setName(String name) { - if (namedDelegate.getName() != null) { - namedDelegate.getParent().getNotations().remove(getQName()); - } - namedDelegate.setName(name); - namedDelegate.getParent().getNotations().put(getQName(), this); + final String fName = name; + CollectionFactory.withSchemaModifiable(new Runnable() { + public void run() { + if (namedDelegate.getName() != null) { + namedDelegate.getParent().getNotations().remove(getQName()); + } + namedDelegate.setName(fName); + namedDelegate.getParent().getNotations().put(getQName(), XmlSchemaNotation.this); + } + }); } } Modified: webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaType.java URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaType.java?rev=1022772&r1=1022771&r2=1022772&view=diff ============================================================================== --- webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaType.java (original) +++ webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/XmlSchemaType.java Fri Oct 15 00:00:18 2010 @@ -21,6 +21,7 @@ package org.apache.ws.commons.schema; import javax.xml.namespace.QName; +import org.apache.ws.commons.schema.utils.CollectionFactory; import org.apache.ws.commons.schema.utils.XmlSchemaNamed; import org.apache.ws.commons.schema.utils.XmlSchemaNamedImpl; @@ -42,10 +43,16 @@ public abstract class XmlSchemaType exte * Creates new XmlSchemaType */ protected XmlSchemaType(XmlSchema schema, boolean topLevel) { + final XmlSchema fSchema = schema; namedDelegate = new XmlSchemaNamedImpl(schema, topLevel); finalDerivation = XmlSchemaDerivationMethod.NONE; if (topLevel) { - schema.getItems().add(this); + CollectionFactory.withSchemaModifiable(new Runnable() { + + public void run() { + fSchema.getItems().add(XmlSchemaType.this); + } + }); } } Modified: webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/utils/CollectionFactory.java URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/utils/CollectionFactory.java?rev=1022772&r1=1022771&r2=1022772&view=diff ============================================================================== --- webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/utils/CollectionFactory.java (original) +++ webservices/commons/trunk/modules/XmlSchema/src/main/java/org/apache/ws/commons/schema/utils/CollectionFactory.java Fri Oct 15 00:00:18 2010 @@ -23,24 +23,79 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; /** - * There are many collections of XML Schema objects inside XmlSchema. - * This class provides consistent construction to centralize policy - * for thread synchronization and the like. + * There are many collections of XML Schema objects inside XmlSchema. This class provides consistent + * construction to centralize policy for thread synchronization and the like. */ public final class CollectionFactory { - + + private static final String PROTECT_READ_ONLY_COLLECTIONS_PROP = + "org.apache.ws.commons.schema.protectReadOnlyCollections"; + + private static final ThreadLocal<Boolean> PROTECT_READ_ONLY_COLLECTIONS = new ThreadLocal<Boolean>() { + + @Override + protected Boolean initialValue() { + return Boolean.parseBoolean(System.getProperty(PROTECT_READ_ONLY_COLLECTIONS_PROP)); + } + }; + private CollectionFactory() { } - + public static <T> List<T> getList(Class<T> type) { return Collections.synchronizedList(new ArrayList<T>()); } - + public static <T> Set<T> getSet(Class<T> type) { return Collections.synchronizedSet(new HashSet<T>()); } + /** + * Call this to obtain a list to return from a public API where the caller is not supposed to modify the + * list. If org.apache.ws.commons.schema.protectReadOnlyCollections is 'true', this will return a list + * that checks at runtime. + * + * @param <T> Generic parameter type of the list. + * @param list the list. + * @return + */ + public static <T> List<T> getProtectedList(List<T> list) { + if (PROTECT_READ_ONLY_COLLECTIONS.get().booleanValue()) { + return Collections.unmodifiableList(list); + } else { + return list; + } + } + + /** + * Call this to obtain a map to return from a public API where the caller is not supposed to modify the + * map. If org.apache.ws.commons.schema.protectReadOnlyCollections is 'true', this will return a map that + * checks at runtime. + * + * @param <K> key type + * @param <V> value type + * @param map the map. + * @return + */ + public static <K, V> Map<K, V> getProtectedMap(Map<K, V> map) { + if (PROTECT_READ_ONLY_COLLECTIONS.get().booleanValue()) { + return Collections.unmodifiableMap(map); + } else { + return map; + } + } + + public static void withSchemaModifiable(Runnable action) { + Boolean saved = PROTECT_READ_ONLY_COLLECTIONS.get(); + try { + PROTECT_READ_ONLY_COLLECTIONS.set(Boolean.FALSE); + action.run(); + } finally { + PROTECT_READ_ONLY_COLLECTIONS.set(saved); + } + } }