[hibernate-commits] Hibernate SVN: r19314 - in validator/trunk/hibernate-validator: src/main/java/org/hibernate/validator and 8 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Wed Apr 28 10:33:16 EDT 2010


Author: hardy.ferentschik
Date: 2010-04-28 10:33:12 -0400 (Wed, 28 Apr 2010)
New Revision: 19314

Added:
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/messageinterpolation/
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/messageinterpolation/ResourceBundleMessageInterpolator.java
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/messageinterpolation/package.html
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading/
   validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/resourceloading/
Removed:
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/Constants.java
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ResourceBundleMessageInterpolator.java
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/resourceloading/
   validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/resourceloading/
Modified:
   validator/trunk/hibernate-validator/pom.xml
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/HibernateValidatorConfiguration.java
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ConfigurationImpl.java
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ConstraintTree.java
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading/AggregateResourceBundleLocator.java
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading/CachingResourceBundleLocator.java
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading/DelegatingResourceBundleLocator.java
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading/PlatformResourceBundleLocator.java
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading/ResourceBundleLocator.java
   validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/HibernateValidatorConfigurationTest.java
   validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/messageinterpolation/MessageInterpolationTest.java
   validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/messageinterpolation/MessageInterpolationWithDefaultBundleTest.java
   validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/messageinterpolation/ResourceBundleMessageInterpolatorTest.java
   validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/resourceloading/AggregateBundleTest.java
   validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/resourceloading/AggregateResourceBundleLocatorTest.java
   validator/trunk/hibernate-validator/src/test/resources/log4j.properties
Log:
HV-310

Modified: validator/trunk/hibernate-validator/pom.xml
===================================================================
--- validator/trunk/hibernate-validator/pom.xml	2010-04-28 11:05:26 UTC (rev 19313)
+++ validator/trunk/hibernate-validator/pom.xml	2010-04-28 14:33:12 UTC (rev 19314)
@@ -135,7 +135,12 @@
                             org.xml.sax.*;version="0",
                             org.slf4j.*;version="[1.5.6,2.0.0)"
                         </Import-Package>
-                        <Export-Package>org.hibernate.validator.*;version="${pom.version}"</Export-Package>
+                        <Export-Package>
+                            org.hibernate.validator;version="${pom.version}",
+                            org.hibernate.validator.constraints;version="${pom.version}",
+                            org.hibernate.validator.messageinterpolation;version="${pom.version}",
+                            org.hibernate.validator.resourceloading;version="${pom.version}",
+                        </Export-Package>
                     </instructions>
                 </configuration>
                 <executions>

Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/HibernateValidatorConfiguration.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/HibernateValidatorConfiguration.java	2010-04-28 11:05:26 UTC (rev 19313)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/HibernateValidatorConfiguration.java	2010-04-28 14:33:12 UTC (rev 19314)
@@ -19,8 +19,7 @@
 
 import javax.validation.Configuration;
 
-import org.hibernate.validator.engine.ResourceBundleMessageInterpolator;
-import org.hibernate.validator.engine.resourceloading.ResourceBundleLocator;
+import org.hibernate.validator.resourceloading.ResourceBundleLocator;
 
 /**
  * Uniquely identifies Hibernate Validator in the Bean Validation bootstrap
@@ -41,7 +40,7 @@
 	 * </p>
 	 * <p>
 	 * This locator can be used as delegate for custom locators when setting a
-	 * customized {@link ResourceBundleMessageInterpolator}:
+	 * customized {@link org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator}:
 	 * </p>
 	 * <p/>
 	 * <pre>

Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ConfigurationImpl.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ConfigurationImpl.java	2010-04-28 11:05:26 UTC (rev 19313)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ConfigurationImpl.java	2010-04-28 14:33:12 UTC (rev 19314)
@@ -37,8 +37,9 @@
 
 import org.hibernate.validator.HibernateValidatorConfiguration;
 import org.hibernate.validator.engine.resolver.DefaultTraversableResolver;
-import org.hibernate.validator.engine.resourceloading.PlatformResourceBundleLocator;
-import org.hibernate.validator.engine.resourceloading.ResourceBundleLocator;
+import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;
+import org.hibernate.validator.resourceloading.PlatformResourceBundleLocator;
+import org.hibernate.validator.resourceloading.ResourceBundleLocator;
 import org.hibernate.validator.util.LoggerFactory;
 import org.hibernate.validator.util.Version;
 import org.hibernate.validator.xml.ValidationBootstrapParameters;
@@ -59,7 +60,9 @@
 
 	private static final Logger log = LoggerFactory.make();
 
-	private final ResourceBundleLocator defaultResourceBundleLocator = new PlatformResourceBundleLocator( Constants.USER_VALIDATION_MESSAGES );
+	private final ResourceBundleLocator defaultResourceBundleLocator = new PlatformResourceBundleLocator(
+			ResourceBundleMessageInterpolator.USER_VALIDATION_MESSAGES
+	);
 	private final MessageInterpolator defaultMessageInterpolator = new ResourceBundleMessageInterpolator(
 			defaultResourceBundleLocator
 	);

Deleted: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/Constants.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/Constants.java	2010-04-28 11:05:26 UTC (rev 19313)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/Constants.java	2010-04-28 14:33:12 UTC (rev 19314)
@@ -1,40 +0,0 @@
-/*
- * $Id:$
- *
- * JBoss, Home of Professional Open Source
- * Copyright 2010, Red Hat, Inc. and/or its affiliates, and individual contributors
- * by the @authors tag. See the copyright.txt in the distribution for a
- * full listing of individual contributors.
- *
- * 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.hibernate.validator.engine;
-
-/**
- * Constants used throughout the Hibernate Validator project.
- *
- * @author Gunnar Morling
- */
-public final class Constants {
-
-	private Constants() {
-	}
-
-	/**
-	 * The name of the default message bundle.
-	 */
-	public static final String DEFAULT_VALIDATION_MESSAGES = "org.hibernate.validator.ValidationMessages";
-
-	/**
-	 * The name of the user-provided message bundle as defined in the specification.
-	 */
-	public static final String USER_VALIDATION_MESSAGES = "ValidationMessages";
-}

Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ConstraintTree.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ConstraintTree.java	2010-04-28 11:05:26 UTC (rev 19313)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ConstraintTree.java	2010-04-28 14:33:12 UTC (rev 19314)
@@ -1,20 +1,24 @@
+/*
+ * $Id:$
+ *
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and/or its affiliates, and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * 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.
+ */
+
 // $Id$
-/*
-* JBoss, Home of Professional Open Source
-* Copyright 2009, Red Hat, Inc. and/or its affiliates, and individual contributors
-* by the @authors tag. See the copyright.txt in the distribution for a
-* full listing of individual contributors.
-*
-* 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.hibernate.validator.engine;
 
 import java.lang.annotation.Annotation;

Deleted: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ResourceBundleMessageInterpolator.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ResourceBundleMessageInterpolator.java	2010-04-28 11:05:26 UTC (rev 19313)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ResourceBundleMessageInterpolator.java	2010-04-28 14:33:12 UTC (rev 19314)
@@ -1,281 +0,0 @@
-// $Id$
-/*
-* JBoss, Home of Professional Open Source
-* Copyright 2009, Red Hat, Inc. and/or its affiliates, and individual contributors
-* by the @authors tag. See the copyright.txt in the distribution for a
-* full listing of individual contributors.
-*
-* 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.hibernate.validator.engine;
-
-import java.util.Locale;
-import java.util.Map;
-import java.util.MissingResourceException;
-import java.util.ResourceBundle;
-import java.util.WeakHashMap;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import javax.validation.MessageInterpolator;
-
-import org.hibernate.validator.engine.resourceloading.CachingResourceBundleLocator;
-import org.hibernate.validator.engine.resourceloading.PlatformResourceBundleLocator;
-import org.hibernate.validator.engine.resourceloading.ResourceBundleLocator;
-
-/**
- * Resource bundle backed message interpolator.
- *
- * @author Emmanuel Bernard
- * @author Hardy Ferentschik
- * @author Gunnar Morling
- */
-public class ResourceBundleMessageInterpolator implements MessageInterpolator {
-
-	/**
-	 * Regular expression used to do message interpolation.
-	 */
-	private static final Pattern messageParameterPattern = Pattern.compile( "(\\{[^\\}]+?\\})" );
-
-	/**
-	 * The default locale for the current user.
-	 */
-	private final Locale defaultLocale;
-
-	/**
-	 * Loads user-specified resource bundles.
-	 */
-	private final ResourceBundleLocator userResourceBundleLocator;
-
-	/**
-	 * Loads built-in resource bundles.
-	 */
-	private final ResourceBundleLocator defaultResourceBundleLocator;
-
-	/**
-	 * Step 1-3 of message interpolation can be cached. We do this in this map.
-	 */
-	private final Map<LocalisedMessage, String> resolvedMessages = new WeakHashMap<LocalisedMessage, String>();
-
-	public ResourceBundleMessageInterpolator() {
-		this( ( ResourceBundleLocator ) null );
-	}
-
-	/**
-	 * @param resourceBundle the resource bundle to use
-	 *
-	 * @deprecated Use {@link ResourceBundleMessageInterpolator#ResourceBundleMessageInterpolator(ResourceBundleLocator)} instead.
-	 */
-	@Deprecated
-	public ResourceBundleMessageInterpolator(final ResourceBundle resourceBundle) {
-		this(
-				new PlatformResourceBundleLocator( Constants.USER_VALIDATION_MESSAGES ) {
-					public ResourceBundle getResourceBundle(Locale locale) {
-						return locale == Locale.getDefault() ? resourceBundle : super.getResourceBundle( locale );
-					}
-				}
-		);
-	}
-
-	public ResourceBundleMessageInterpolator(ResourceBundleLocator userResourceBundleLocator) {
-
-		defaultLocale = Locale.getDefault();
-
-		if ( userResourceBundleLocator == null ) {
-			userResourceBundleLocator = new PlatformResourceBundleLocator( Constants.USER_VALIDATION_MESSAGES );
-		}
-
-		this.userResourceBundleLocator = new CachingResourceBundleLocator( userResourceBundleLocator );
-
-		this.defaultResourceBundleLocator =
-				new CachingResourceBundleLocator(
-						new PlatformResourceBundleLocator( Constants.DEFAULT_VALIDATION_MESSAGES )
-				);
-	}
-
-	public String interpolate(String message, Context context) {
-		// probably no need for caching, but it could be done by parameters since the map
-		// is immutable and uniquely built per Validation definition, the comparison has to be based on == and not equals though
-		return interpolateMessage( message, context.getConstraintDescriptor().getAttributes(), defaultLocale );
-	}
-
-	public String interpolate(String message, Context context, Locale locale) {
-		return interpolateMessage( message, context.getConstraintDescriptor().getAttributes(), locale );
-	}
-
-	/**
-	 * Runs the message interpolation according to algorithm specified in JSR 303.
-	 * <br/>
-	 * Note:
-	 * <br/>
-	 * Look-ups in user bundles is recursive whereas look-ups in default bundle are not!
-	 *
-	 * @param message the message to interpolate
-	 * @param annotationParameters the parameters of the annotation for which to interpolate this message
-	 * @param locale the <code>Locale</code> to use for the resource bundle.
-	 *
-	 * @return the interpolated message.
-	 */
-	private String interpolateMessage(String message, Map<String, Object> annotationParameters, Locale locale) {
-		LocalisedMessage localisedMessage = new LocalisedMessage( message, locale );
-		String resolvedMessage = resolvedMessages.get( localisedMessage );
-
-		// if the message is not already in the cache we have to run step 1-3 of the message resolution 
-		if ( resolvedMessage == null ) {
-			ResourceBundle userResourceBundle = userResourceBundleLocator
-					.getResourceBundle( locale );
-			ResourceBundle defaultResourceBundle = defaultResourceBundleLocator
-					.getResourceBundle( locale );
-
-			String userBundleResolvedMessage;
-			resolvedMessage = message;
-			boolean evaluatedDefaultBundleOnce = false;
-			do {
-				// search the user bundle recursive (step1)
-				userBundleResolvedMessage = replaceVariables(
-						resolvedMessage, userResourceBundle, locale, true
-				);
-
-				// exit condition - we have at least tried to validate against the default bundle and there was no
-				// further replacements
-				if ( evaluatedDefaultBundleOnce
-						&& !hasReplacementTakenPlace( userBundleResolvedMessage, resolvedMessage ) ) {
-					break;
-				}
-
-				// search the default bundle non recursive (step2)
-				resolvedMessage = replaceVariables( userBundleResolvedMessage, defaultResourceBundle, locale, false );
-				evaluatedDefaultBundleOnce = true;
-				resolvedMessages.put( localisedMessage, resolvedMessage );
-			} while ( true );
-		}
-
-		// resolve annotation attributes (step 4)
-		resolvedMessage = replaceAnnotationAttributes( resolvedMessage, annotationParameters );
-
-		// last but not least we have to take care of escaped literals
-		resolvedMessage = resolvedMessage.replace( "\\{", "{" );
-		resolvedMessage = resolvedMessage.replace( "\\}", "}" );
-		resolvedMessage = resolvedMessage.replace( "\\\\", "\\" );
-		return resolvedMessage;
-	}
-
-	private boolean hasReplacementTakenPlace(String origMessage, String newMessage) {
-		return !origMessage.equals( newMessage );
-	}
-
-	private String replaceVariables(String message, ResourceBundle bundle, Locale locale, boolean recurse) {
-		Matcher matcher = messageParameterPattern.matcher( message );
-		StringBuffer sb = new StringBuffer();
-		String resolvedParameterValue;
-		while ( matcher.find() ) {
-			String parameter = matcher.group( 1 );
-			resolvedParameterValue = resolveParameter(
-					parameter, bundle, locale, recurse
-			);
-
-			matcher.appendReplacement( sb, escapeMetaCharacters( resolvedParameterValue ) );
-		}
-		matcher.appendTail( sb );
-		return sb.toString();
-	}
-
-	private String replaceAnnotationAttributes(String message, Map<String, Object> annotationParameters) {
-		Matcher matcher = messageParameterPattern.matcher( message );
-		StringBuffer sb = new StringBuffer();
-		while ( matcher.find() ) {
-			String resolvedParameterValue;
-			String parameter = matcher.group( 1 );
-			Object variable = annotationParameters.get( removeCurlyBrace( parameter ) );
-			if ( variable != null ) {
-				resolvedParameterValue = escapeMetaCharacters( variable.toString() );
-			}
-			else {
-				resolvedParameterValue = parameter;
-			}
-			matcher.appendReplacement( sb, resolvedParameterValue );
-		}
-		matcher.appendTail( sb );
-		return sb.toString();
-	}
-
-	private String resolveParameter(String parameterName, ResourceBundle bundle, Locale locale, boolean recurse) {
-		String parameterValue;
-		try {
-			if ( bundle != null ) {
-				parameterValue = bundle.getString( removeCurlyBrace( parameterName ) );
-				if ( recurse ) {
-					parameterValue = replaceVariables( parameterValue, bundle, locale, recurse );
-				}
-			}
-			else {
-				parameterValue = parameterName;
-			}
-		}
-		catch ( MissingResourceException e ) {
-			// return parameter itself
-			parameterValue = parameterName;
-		}
-		return parameterValue;
-	}
-
-	private String removeCurlyBrace(String parameter) {
-		return parameter.substring( 1, parameter.length() - 1 );
-	}
-
-	/**
-	 * @param s The string in which to replace the meta characters '$' and '\'.
-	 *
-	 * @return A string where meta characters relevant for {@link Matcher#appendReplacement} are escaped.
-	 */
-	private String escapeMetaCharacters(String s) {
-		String escapedString = s.replace( "\\", "\\\\" );
-		escapedString = escapedString.replace( "$", "\\$" );
-		return escapedString;
-	}
-
-	private static class LocalisedMessage {
-		private final String message;
-		private final Locale locale;
-
-		LocalisedMessage(String message, Locale locale) {
-			this.message = message;
-			this.locale = locale;
-		}
-
-		@Override
-		public boolean equals(Object o) {
-			if ( this == o ) {
-				return true;
-			}
-			if ( o == null || getClass() != o.getClass() ) {
-				return false;
-			}
-
-			LocalisedMessage that = ( LocalisedMessage ) o;
-
-			if ( locale != null ? !locale.equals( that.locale ) : that.locale != null ) {
-				return false;
-			}
-			if ( message != null ? !message.equals( that.message ) : that.message != null ) {
-				return false;
-			}
-
-			return true;
-		}
-
-		@Override
-		public int hashCode() {
-			int result = message != null ? message.hashCode() : 0;
-			result = 31 * result + ( locale != null ? locale.hashCode() : 0 );
-			return result;
-		}
-	}
-}

Added: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/messageinterpolation/ResourceBundleMessageInterpolator.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/messageinterpolation/ResourceBundleMessageInterpolator.java	                        (rev 0)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/messageinterpolation/ResourceBundleMessageInterpolator.java	2010-04-28 14:33:12 UTC (rev 19314)
@@ -0,0 +1,291 @@
+// $Id: ResourceBundleMessageInterpolator.java 19081 2010-03-22 20:19:52Z hardy.ferentschik $
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2009, Red Hat, Inc. and/or its affiliates, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* 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.hibernate.validator.messageinterpolation;
+
+import java.util.Locale;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.WeakHashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.validation.MessageInterpolator;
+
+import org.hibernate.validator.resourceloading.CachingResourceBundleLocator;
+import org.hibernate.validator.resourceloading.PlatformResourceBundleLocator;
+import org.hibernate.validator.resourceloading.ResourceBundleLocator;
+
+/**
+ * Resource bundle backed message interpolator.
+ *
+ * @author Emmanuel Bernard
+ * @author Hardy Ferentschik
+ * @author Gunnar Morling
+ */
+public class ResourceBundleMessageInterpolator implements MessageInterpolator {
+
+	/**
+	 * The name of the default message bundle.
+	 */
+	public static final String DEFAULT_VALIDATION_MESSAGES = "org.hibernate.validator.ValidationMessages";
+
+	/**
+	 * The name of the user-provided message bundle as defined in the specification.
+	 */
+	public static final String USER_VALIDATION_MESSAGES = "ValidationMessages";
+
+	/**
+	 * Regular expression used to do message interpolation.
+	 */
+	private static final Pattern messageParameterPattern = Pattern.compile( "(\\{[^\\}]+?\\})" );
+
+	/**
+	 * The default locale for the current user.
+	 */
+	private final Locale defaultLocale;
+
+	/**
+	 * Loads user-specified resource bundles.
+	 */
+	private final ResourceBundleLocator userResourceBundleLocator;
+
+	/**
+	 * Loads built-in resource bundles.
+	 */
+	private final ResourceBundleLocator defaultResourceBundleLocator;
+
+	/**
+	 * Step 1-3 of message interpolation can be cached. We do this in this map.
+	 */
+	private final Map<LocalisedMessage, String> resolvedMessages = new WeakHashMap<LocalisedMessage, String>();
+
+	public ResourceBundleMessageInterpolator() {
+		this( ( ResourceBundleLocator ) null );
+	}
+
+	/**
+	 * @param resourceBundle the resource bundle to use
+	 *
+	 * @deprecated Use {@link ResourceBundleMessageInterpolator#ResourceBundleMessageInterpolator(ResourceBundleLocator)} instead.
+	 */
+	@Deprecated
+	public ResourceBundleMessageInterpolator(final ResourceBundle resourceBundle) {
+		this(
+				new PlatformResourceBundleLocator( USER_VALIDATION_MESSAGES ) {
+					public ResourceBundle getResourceBundle(Locale locale) {
+						return locale == Locale.getDefault() ? resourceBundle : super.getResourceBundle( locale );
+					}
+				}
+		);
+	}
+
+	public ResourceBundleMessageInterpolator(ResourceBundleLocator userResourceBundleLocator) {
+
+		defaultLocale = Locale.getDefault();
+
+		if ( userResourceBundleLocator == null ) {
+			userResourceBundleLocator = new PlatformResourceBundleLocator( USER_VALIDATION_MESSAGES );
+		}
+
+		this.userResourceBundleLocator = new CachingResourceBundleLocator( userResourceBundleLocator );
+
+		this.defaultResourceBundleLocator =
+				new CachingResourceBundleLocator(
+						new PlatformResourceBundleLocator( DEFAULT_VALIDATION_MESSAGES )
+				);
+	}
+
+	public String interpolate(String message, Context context) {
+		// probably no need for caching, but it could be done by parameters since the map
+		// is immutable and uniquely built per Validation definition, the comparison has to be based on == and not equals though
+		return interpolateMessage( message, context.getConstraintDescriptor().getAttributes(), defaultLocale );
+	}
+
+	public String interpolate(String message, Context context, Locale locale) {
+		return interpolateMessage( message, context.getConstraintDescriptor().getAttributes(), locale );
+	}
+
+	/**
+	 * Runs the message interpolation according to algorithm specified in JSR 303.
+	 * <br/>
+	 * Note:
+	 * <br/>
+	 * Look-ups in user bundles is recursive whereas look-ups in default bundle are not!
+	 *
+	 * @param message the message to interpolate
+	 * @param annotationParameters the parameters of the annotation for which to interpolate this message
+	 * @param locale the <code>Locale</code> to use for the resource bundle.
+	 *
+	 * @return the interpolated message.
+	 */
+	private String interpolateMessage(String message, Map<String, Object> annotationParameters, Locale locale) {
+		LocalisedMessage localisedMessage = new LocalisedMessage( message, locale );
+		String resolvedMessage = resolvedMessages.get( localisedMessage );
+
+		// if the message is not already in the cache we have to run step 1-3 of the message resolution 
+		if ( resolvedMessage == null ) {
+			ResourceBundle userResourceBundle = userResourceBundleLocator
+					.getResourceBundle( locale );
+			ResourceBundle defaultResourceBundle = defaultResourceBundleLocator
+					.getResourceBundle( locale );
+
+			String userBundleResolvedMessage;
+			resolvedMessage = message;
+			boolean evaluatedDefaultBundleOnce = false;
+			do {
+				// search the user bundle recursive (step1)
+				userBundleResolvedMessage = replaceVariables(
+						resolvedMessage, userResourceBundle, locale, true
+				);
+
+				// exit condition - we have at least tried to validate against the default bundle and there was no
+				// further replacements
+				if ( evaluatedDefaultBundleOnce
+						&& !hasReplacementTakenPlace( userBundleResolvedMessage, resolvedMessage ) ) {
+					break;
+				}
+
+				// search the default bundle non recursive (step2)
+				resolvedMessage = replaceVariables( userBundleResolvedMessage, defaultResourceBundle, locale, false );
+				evaluatedDefaultBundleOnce = true;
+				resolvedMessages.put( localisedMessage, resolvedMessage );
+			} while ( true );
+		}
+
+		// resolve annotation attributes (step 4)
+		resolvedMessage = replaceAnnotationAttributes( resolvedMessage, annotationParameters );
+
+		// last but not least we have to take care of escaped literals
+		resolvedMessage = resolvedMessage.replace( "\\{", "{" );
+		resolvedMessage = resolvedMessage.replace( "\\}", "}" );
+		resolvedMessage = resolvedMessage.replace( "\\\\", "\\" );
+		return resolvedMessage;
+	}
+
+	private boolean hasReplacementTakenPlace(String origMessage, String newMessage) {
+		return !origMessage.equals( newMessage );
+	}
+
+	private String replaceVariables(String message, ResourceBundle bundle, Locale locale, boolean recurse) {
+		Matcher matcher = messageParameterPattern.matcher( message );
+		StringBuffer sb = new StringBuffer();
+		String resolvedParameterValue;
+		while ( matcher.find() ) {
+			String parameter = matcher.group( 1 );
+			resolvedParameterValue = resolveParameter(
+					parameter, bundle, locale, recurse
+			);
+
+			matcher.appendReplacement( sb, escapeMetaCharacters( resolvedParameterValue ) );
+		}
+		matcher.appendTail( sb );
+		return sb.toString();
+	}
+
+	private String replaceAnnotationAttributes(String message, Map<String, Object> annotationParameters) {
+		Matcher matcher = messageParameterPattern.matcher( message );
+		StringBuffer sb = new StringBuffer();
+		while ( matcher.find() ) {
+			String resolvedParameterValue;
+			String parameter = matcher.group( 1 );
+			Object variable = annotationParameters.get( removeCurlyBrace( parameter ) );
+			if ( variable != null ) {
+				resolvedParameterValue = escapeMetaCharacters( variable.toString() );
+			}
+			else {
+				resolvedParameterValue = parameter;
+			}
+			matcher.appendReplacement( sb, resolvedParameterValue );
+		}
+		matcher.appendTail( sb );
+		return sb.toString();
+	}
+
+	private String resolveParameter(String parameterName, ResourceBundle bundle, Locale locale, boolean recurse) {
+		String parameterValue;
+		try {
+			if ( bundle != null ) {
+				parameterValue = bundle.getString( removeCurlyBrace( parameterName ) );
+				if ( recurse ) {
+					parameterValue = replaceVariables( parameterValue, bundle, locale, recurse );
+				}
+			}
+			else {
+				parameterValue = parameterName;
+			}
+		}
+		catch ( MissingResourceException e ) {
+			// return parameter itself
+			parameterValue = parameterName;
+		}
+		return parameterValue;
+	}
+
+	private String removeCurlyBrace(String parameter) {
+		return parameter.substring( 1, parameter.length() - 1 );
+	}
+
+	/**
+	 * @param s The string in which to replace the meta characters '$' and '\'.
+	 *
+	 * @return A string where meta characters relevant for {@link Matcher#appendReplacement} are escaped.
+	 */
+	private String escapeMetaCharacters(String s) {
+		String escapedString = s.replace( "\\", "\\\\" );
+		escapedString = escapedString.replace( "$", "\\$" );
+		return escapedString;
+	}
+
+	private static class LocalisedMessage {
+		private final String message;
+		private final Locale locale;
+
+		LocalisedMessage(String message, Locale locale) {
+			this.message = message;
+			this.locale = locale;
+		}
+
+		@Override
+		public boolean equals(Object o) {
+			if ( this == o ) {
+				return true;
+			}
+			if ( o == null || getClass() != o.getClass() ) {
+				return false;
+			}
+
+			LocalisedMessage that = ( LocalisedMessage ) o;
+
+			if ( locale != null ? !locale.equals( that.locale ) : that.locale != null ) {
+				return false;
+			}
+			if ( message != null ? !message.equals( that.message ) : that.message != null ) {
+				return false;
+			}
+
+			return true;
+		}
+
+		@Override
+		public int hashCode() {
+			int result = message != null ? message.hashCode() : 0;
+			result = 31 * result + ( locale != null ? locale.hashCode() : 0 );
+			return result;
+		}
+	}
+}

Added: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/messageinterpolation/package.html
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/messageinterpolation/package.html	                        (rev 0)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/messageinterpolation/package.html	2010-04-28 14:33:12 UTC (rev 19314)
@@ -0,0 +1,45 @@
+<!--
+  ~ $Id:$
+  ~
+  ~ JBoss, Home of Professional Open Source
+  ~ Copyright 2010, Red Hat, Inc. and/or its affiliates, and individual contributors
+  ~ by the @authors tag. See the copyright.txt in the distribution for a
+  ~ full listing of individual contributors.
+  ~
+  ~ 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.
+  -->
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+    <!--
+
+  JBoss, Home of Professional Open Source
+  Copyright 2010, Red Hat, Inc. and/or its affiliates, and individual contributors
+  by the @authors tag. See the copyright.txt in the distribution for a
+  full listing of individual contributors.
+
+  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.
+
+-->
+</head>
+<body>
+This package contains implementations of the MessageInterpolator interface.
+</body>
+</html>

Copied: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading (from rev 19292, validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/resourceloading)

Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading/AggregateResourceBundleLocator.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/resourceloading/AggregateResourceBundleLocator.java	2010-04-26 02:06:03 UTC (rev 19292)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading/AggregateResourceBundleLocator.java	2010-04-28 14:33:12 UTC (rev 19314)
@@ -15,7 +15,7 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
-package org.hibernate.validator.engine.resourceloading;
+package org.hibernate.validator.resourceloading;
 
 import java.util.ArrayList;
 import java.util.Collections;

Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading/CachingResourceBundleLocator.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/resourceloading/CachingResourceBundleLocator.java	2010-04-26 02:06:03 UTC (rev 19292)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading/CachingResourceBundleLocator.java	2010-04-28 14:33:12 UTC (rev 19314)
@@ -15,7 +15,7 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
-package org.hibernate.validator.engine.resourceloading;
+package org.hibernate.validator.resourceloading;
 
 import java.util.Locale;
 import java.util.ResourceBundle;

Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading/DelegatingResourceBundleLocator.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/resourceloading/DelegatingResourceBundleLocator.java	2010-04-26 02:06:03 UTC (rev 19292)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading/DelegatingResourceBundleLocator.java	2010-04-28 14:33:12 UTC (rev 19314)
@@ -15,7 +15,7 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
-package org.hibernate.validator.engine.resourceloading;
+package org.hibernate.validator.resourceloading;
 
 import java.util.Locale;
 import java.util.ResourceBundle;

Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading/PlatformResourceBundleLocator.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/resourceloading/PlatformResourceBundleLocator.java	2010-04-26 02:06:03 UTC (rev 19292)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading/PlatformResourceBundleLocator.java	2010-04-28 14:33:12 UTC (rev 19314)
@@ -15,7 +15,7 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
-package org.hibernate.validator.engine.resourceloading;
+package org.hibernate.validator.resourceloading;
 
 import java.security.AccessController;
 import java.util.Locale;
@@ -24,7 +24,6 @@
 
 import org.slf4j.Logger;
 
-import org.hibernate.validator.engine.ResourceBundleMessageInterpolator;
 import org.hibernate.validator.util.GetClassLoader;
 import org.hibernate.validator.util.LoggerFactory;
 
@@ -67,7 +66,7 @@
 		}
 		if ( rb == null ) {
 			action = GetClassLoader
-					.fromClass( ResourceBundleMessageInterpolator.class );
+					.fromClass( PlatformResourceBundleLocator.class );
 			classLoader = isSecured ? AccessController.doPrivileged( action )
 					: action.run();
 			rb = loadBundle(

Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading/ResourceBundleLocator.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/resourceloading/ResourceBundleLocator.java	2010-04-26 02:06:03 UTC (rev 19292)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading/ResourceBundleLocator.java	2010-04-28 14:33:12 UTC (rev 19314)
@@ -15,16 +15,14 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
-package org.hibernate.validator.engine.resourceloading;
+package org.hibernate.validator.resourceloading;
 
 import java.util.Locale;
 import java.util.ResourceBundle;
 
-import org.hibernate.validator.engine.ResourceBundleMessageInterpolator;
-
 /**
  * <p>
- * Used by {@link ResourceBundleMessageInterpolator} to load resource bundles
+ * Used by {@link org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator} to load resource bundles
  * containing message texts to be displayed in case of validation errors.
  * </p>
  * <p>

Modified: validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/HibernateValidatorConfigurationTest.java
===================================================================
--- validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/HibernateValidatorConfigurationTest.java	2010-04-28 11:05:26 UTC (rev 19313)
+++ validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/HibernateValidatorConfigurationTest.java	2010-04-28 14:33:12 UTC (rev 19314)
@@ -1,5 +1,5 @@
 /*
- * $Id:$
+ * $Id$
  *
  * JBoss, Home of Professional Open Source
  * Copyright 2010, Red Hat, Inc. and/or its affiliates, and individual contributors
@@ -22,7 +22,7 @@
 
 import org.testng.annotations.Test;
 
-import org.hibernate.validator.engine.resourceloading.ResourceBundleLocator;
+import org.hibernate.validator.resourceloading.ResourceBundleLocator;
 
 import static org.testng.Assert.assertNotNull;
 

Modified: validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/messageinterpolation/MessageInterpolationTest.java
===================================================================
--- validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/messageinterpolation/MessageInterpolationTest.java	2010-04-28 11:05:26 UTC (rev 19313)
+++ validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/messageinterpolation/MessageInterpolationTest.java	2010-04-28 14:33:12 UTC (rev 19314)
@@ -32,8 +32,8 @@
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
-import org.hibernate.validator.engine.ResourceBundleMessageInterpolator;
-import org.hibernate.validator.engine.resourceloading.ResourceBundleLocator;
+import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;
+import org.hibernate.validator.resourceloading.ResourceBundleLocator;
 
 import static org.testng.Assert.assertEquals;
 

Modified: validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/messageinterpolation/MessageInterpolationWithDefaultBundleTest.java
===================================================================
--- validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/messageinterpolation/MessageInterpolationWithDefaultBundleTest.java	2010-04-28 11:05:26 UTC (rev 19313)
+++ validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/messageinterpolation/MessageInterpolationWithDefaultBundleTest.java	2010-04-28 14:33:12 UTC (rev 19314)
@@ -27,7 +27,7 @@
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
-import org.hibernate.validator.engine.ResourceBundleMessageInterpolator;
+import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;
 import org.hibernate.validator.util.TestUtil;
 
 import static org.hibernate.validator.util.TestUtil.assertCorrectConstraintViolationMessages;

Modified: validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/messageinterpolation/ResourceBundleMessageInterpolatorTest.java
===================================================================
--- validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/messageinterpolation/ResourceBundleMessageInterpolatorTest.java	2010-04-28 11:05:26 UTC (rev 19313)
+++ validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/messageinterpolation/ResourceBundleMessageInterpolatorTest.java	2010-04-28 14:33:12 UTC (rev 19314)
@@ -33,8 +33,8 @@
 import org.testng.annotations.Test;
 
 import org.hibernate.validator.engine.MessageInterpolatorContext;
-import org.hibernate.validator.engine.ResourceBundleMessageInterpolator;
-import org.hibernate.validator.engine.resourceloading.ResourceBundleLocator;
+import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;
+import org.hibernate.validator.resourceloading.ResourceBundleLocator;
 import org.hibernate.validator.metadata.ConstraintDescriptorImpl;
 import org.hibernate.validator.metadata.ConstraintHelper;
 import org.hibernate.validator.metadata.ConstraintOrigin;

Copied: validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/resourceloading (from rev 19292, validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/resourceloading)

Modified: validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/resourceloading/AggregateBundleTest.java
===================================================================
--- validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/resourceloading/AggregateBundleTest.java	2010-04-26 02:06:03 UTC (rev 19292)
+++ validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/resourceloading/AggregateBundleTest.java	2010-04-28 14:33:12 UTC (rev 19314)
@@ -15,7 +15,7 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
-package org.hibernate.validator.engine.resourceloading;
+package org.hibernate.validator.resourceloading;
 
 import java.util.Arrays;
 import java.util.Collections;
@@ -26,7 +26,7 @@
 
 import org.testng.annotations.Test;
 
-import org.hibernate.validator.engine.resourceloading.AggregateResourceBundleLocator.AggregateBundle;
+import org.hibernate.validator.resourceloading.AggregateResourceBundleLocator.AggregateBundle;
 
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertTrue;

Modified: validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/resourceloading/AggregateResourceBundleLocatorTest.java
===================================================================
--- validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/resourceloading/AggregateResourceBundleLocatorTest.java	2010-04-26 02:06:03 UTC (rev 19292)
+++ validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/resourceloading/AggregateResourceBundleLocatorTest.java	2010-04-28 14:33:12 UTC (rev 19314)
@@ -15,7 +15,7 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
-package org.hibernate.validator.engine.resourceloading;
+package org.hibernate.validator.resourceloading;
 
 import java.util.Arrays;
 import java.util.Locale;

Modified: validator/trunk/hibernate-validator/src/test/resources/log4j.properties
===================================================================
--- validator/trunk/hibernate-validator/src/test/resources/log4j.properties	2010-04-28 11:05:26 UTC (rev 19313)
+++ validator/trunk/hibernate-validator/src/test/resources/log4j.properties	2010-04-28 14:33:12 UTC (rev 19314)
@@ -22,4 +22,4 @@
 
 log4j.logger.org.hibernate.validator.engine.ValidatorImpl=trace
 #log4j.logger.org.hibernate.validatorengine.ConstraintTree=trace
-log4j.logger.org.hibernate.validator.engine.ResourceBundleMessageInterpolator=info
+log4j.logger.org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator=info



More information about the hibernate-commits mailing list