From 10d8abea3ba2f58c4171c0944614cff08189ce5e Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Mon, 20 Apr 2009 12:07:00 +0000 Subject: [PATCH] EntityResolvers and DefaultNamespaceHandlerResolver support concurrent access now (SPR-5679) --- .../beans/factory/xml/BeansDtdResolver.java | 15 ++++-- .../xml/DefaultNamespaceHandlerResolver.java | 45 ++++++++++------ .../factory/xml/DelegatingEntityResolver.java | 9 +++- .../factory/xml/PluggableSchemaResolver.java | 54 ++++++++++++------- 4 files changed, 83 insertions(+), 40 deletions(-) diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/BeansDtdResolver.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/BeansDtdResolver.java index 86766d90c6..fcf9af9001 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/BeansDtdResolver.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/BeansDtdResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 the original author or authors. + * Copyright 2002-2009 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package org.springframework.beans.factory.xml; import java.io.IOException; +import java.util.Arrays; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -56,8 +57,8 @@ public class BeansDtdResolver implements EntityResolver { } if (systemId != null && systemId.endsWith(DTD_EXTENSION)) { int lastPathSeparator = systemId.lastIndexOf("/"); - for (int i = 0; i < DTD_NAMES.length; ++i) { - int dtdNameStart = systemId.indexOf(DTD_NAMES[i]); + for (String DTD_NAME : DTD_NAMES) { + int dtdNameStart = systemId.indexOf(DTD_NAME); if (dtdNameStart > lastPathSeparator) { String dtdFile = systemId.substring(dtdNameStart); if (logger.isTraceEnabled()) { @@ -78,7 +79,7 @@ public class BeansDtdResolver implements EntityResolver { logger.debug("Could not resolve beans DTD [" + systemId + "]: not found in class path", ex); } } - + } } } @@ -87,4 +88,10 @@ public class BeansDtdResolver implements EntityResolver { return null; } + + @Override + public String toString() { + return "EntityResolver for DTDs " + Arrays.toString(DTD_NAMES); + } + } diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/DefaultNamespaceHandlerResolver.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/DefaultNamespaceHandlerResolver.java index cfc014c29e..dd9b791898 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/DefaultNamespaceHandlerResolver.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/DefaultNamespaceHandlerResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 the original author or authors. + * Copyright 2002-2009 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,9 +17,9 @@ package org.springframework.beans.factory.xml; import java.io.IOException; -import java.util.HashMap; import java.util.Map; import java.util.Properties; +import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -64,7 +64,7 @@ public class DefaultNamespaceHandlerResolver implements NamespaceHandlerResolver private final String handlerMappingsLocation; /** Stores the mappings from namespace URI to NamespaceHandler class name / instance */ - private Map handlerMappings; + private volatile Map handlerMappings; /** @@ -110,7 +110,7 @@ public class DefaultNamespaceHandlerResolver implements NamespaceHandlerResolver * @return the located {@link NamespaceHandler}, or null if none found */ public NamespaceHandler resolve(String namespaceUri) { - Map handlerMappings = getHandlerMappings(); + Map handlerMappings = getHandlerMappings(); Object handlerOrClassName = handlerMappings.get(namespaceUri); if (handlerOrClassName == null) { return null; @@ -121,7 +121,7 @@ public class DefaultNamespaceHandlerResolver implements NamespaceHandlerResolver else { String className = (String) handlerOrClassName; try { - Class handlerClass = ClassUtils.forName(className, this.classLoader); + Class handlerClass = ClassUtils.forName(className, this.classLoader); if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) { throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri + "] does not implement the [" + NamespaceHandler.class.getName() + "] interface"); @@ -145,23 +145,34 @@ public class DefaultNamespaceHandlerResolver implements NamespaceHandlerResolver /** * Load the specified NamespaceHandler mappings lazily. */ - private Map getHandlerMappings() { + private Map getHandlerMappings() { if (this.handlerMappings == null) { - try { - Properties mappings = - PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader); - if (logger.isDebugEnabled()) { - logger.debug("Loaded mappings [" + mappings + "]"); + synchronized (this) { + if (this.handlerMappings == null) { + try { + Properties mappings = + PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader); + if (logger.isDebugEnabled()) { + logger.debug("Loaded NamespaceHandler mappings: " + mappings); + } + Map handlerMappings = new ConcurrentHashMap(); + CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings); + this.handlerMappings = handlerMappings; + } + catch (IOException ex) { + throw new IllegalStateException( + "Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex); + } } - this.handlerMappings = new HashMap(); - CollectionUtils.mergePropertiesIntoMap(mappings, this.handlerMappings); - } - catch (IOException ex) { - throw new IllegalStateException( - "Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex); } } return this.handlerMappings; } + + @Override + public String toString() { + return "NamespaceHandlerResolver using mappings " + getHandlerMappings(); + } + } diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/DelegatingEntityResolver.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/DelegatingEntityResolver.java index d39b0b060c..cd33ef1476 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/DelegatingEntityResolver.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/DelegatingEntityResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 the original author or authors. + * Copyright 2002-2009 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -88,4 +88,11 @@ public class DelegatingEntityResolver implements EntityResolver { return null; } + + @Override + public String toString() { + return "EntityResolver delegating " + XSD_SUFFIX + " to " + this.schemaResolver + + " and " + DTD_SUFFIX + " to " + this.dtdResolver; + } + } diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/PluggableSchemaResolver.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/PluggableSchemaResolver.java index 72468e85e9..3d27aa1143 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/PluggableSchemaResolver.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/PluggableSchemaResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 the original author or authors. + * Copyright 2002-2009 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,18 +17,20 @@ package org.springframework.beans.factory.xml; import java.io.IOException; +import java.util.Map; import java.util.Properties; +import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; -import org.springframework.beans.FatalBeanException; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PropertiesLoaderUtils; import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; /** * {@link EntityResolver} implementation that attempts to resolve schema URLs into @@ -67,7 +69,7 @@ public class PluggableSchemaResolver implements EntityResolver { private final String schemaMappingsLocation; /** Stores the mapping of schema URL -> local schema path */ - private Properties schemaMappings; + private volatile Map schemaMappings; /** @@ -104,7 +106,7 @@ public class PluggableSchemaResolver implements EntityResolver { "] and system id [" + systemId + "]"); } if (systemId != null) { - String resourceLocation = getSchemaMapping(systemId); + String resourceLocation = getSchemaMappings().get(systemId); if (resourceLocation != null) { Resource resource = new ClassPathResource(resourceLocation, this.classLoader); InputSource source = new InputSource(resource.getInputStream()); @@ -119,24 +121,40 @@ public class PluggableSchemaResolver implements EntityResolver { return null; } - protected String getSchemaMapping(String systemId) { + /** + * Load the specified schema mappings lazily. + */ + private Map getSchemaMappings() { if (this.schemaMappings == null) { - if (logger.isDebugEnabled()) { - logger.debug("Loading schema mappings from [" + this.schemaMappingsLocation + "]"); - } - try { - this.schemaMappings = - PropertiesLoaderUtils.loadAllProperties(this.schemaMappingsLocation, this.classLoader); - if (logger.isDebugEnabled()) { - logger.debug("Loaded schema mappings: " + this.schemaMappings); + synchronized (this) { + if (this.schemaMappings == null) { + if (logger.isDebugEnabled()) { + logger.debug("Loading schema mappings from [" + this.schemaMappingsLocation + "]"); + } + try { + Properties mappings = + PropertiesLoaderUtils.loadAllProperties(this.schemaMappingsLocation, this.classLoader); + if (logger.isDebugEnabled()) { + logger.debug("Loaded schema mappings: " + mappings); + } + Map schemaMappings = new ConcurrentHashMap(); + CollectionUtils.mergePropertiesIntoMap(mappings, schemaMappings); + this.schemaMappings = schemaMappings; + } + catch (IOException ex) { + throw new IllegalStateException( + "Unable to load schema mappings from location [" + this.schemaMappingsLocation + "]", ex); + } } } - catch (IOException ex) { - throw new FatalBeanException( - "Unable to load schema mappings from location [" + this.schemaMappingsLocation + "]", ex); - } } - return this.schemaMappings.getProperty(systemId); + return this.schemaMappings; + } + + + @Override + public String toString() { + return "EntityResolver using mappings " + getSchemaMappings(); } }