| /* |
| * Copyright 2010 Google Inc. |
| * |
| * 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 com.google.gwt.validation.client; |
| |
| import com.google.gwt.core.client.GWT; |
| import com.google.gwt.i18n.shared.GwtLocale; |
| import com.google.gwt.regexp.shared.MatchResult; |
| import com.google.gwt.regexp.shared.RegExp; |
| |
| import java.util.Map; |
| |
| import javax.validation.MessageInterpolator; |
| |
| /** |
| * Base GWT {@link MessageInterpolator}. |
| */ |
| abstract class BaseMessageInterpolator implements MessageInterpolator { |
| |
| // local version because guava is not included. |
| private static interface Function<F, T> { |
| T apply(F from); |
| } |
| |
| /** |
| * Regular expression used to do message interpolation. |
| */ |
| private static final RegExp MESSAGE_PARAMETER_PATTERN = RegExp.compile( |
| "(\\{[^\\}]+?\\})", "g"); |
| |
| // Visible for testing |
| static Function<String, String> createAnnotationReplacer( |
| final Map<String, Object> map) { |
| return new Function<String, String>() { |
| |
| @Override |
| public String apply(String from) { |
| Object object = map.get(from); |
| return object == null ? null : object.toString(); |
| } |
| }; |
| } |
| |
| private static Function<String, String> createReplacer( |
| final ValidationMessageResolver messageResolver) { |
| return new Function<String, String>() { |
| @Override |
| public String apply(String from) { |
| Object object = messageResolver.get(from); |
| return object == null ? null : object.toString(); |
| } |
| }; |
| } |
| |
| /** |
| * Replaces keys using the Default Validation Provider properties. |
| */ |
| private final Function<String, String> providerReplacer = |
| createReplacer((ValidationMessageResolver) |
| GWT.create(ProviderValidationMessageResolver.class)); |
| |
| /** |
| * Replaces keys using the Validation User custom properties. |
| */ |
| private final Function<String, String> userReplacer; |
| |
| protected BaseMessageInterpolator( |
| UserValidationMessagesResolver userValidationMessagesResolver) { |
| userReplacer = createReplacer(userValidationMessagesResolver); |
| } |
| |
| @Override |
| public final String interpolate(String messageTemplate, Context context) { |
| return gwtInterpolate(messageTemplate, context, null); |
| } |
| |
| protected final String gwtInterpolate(String message, Context context, |
| GwtLocale locale) { |
| // see Section 4.3.1.1 |
| String resolvedMessage = message; |
| String step1message; |
| |
| // TODO(nchalko) Add a safety to make sure this does not loop forever. |
| do { |
| do { |
| step1message = resolvedMessage; |
| |
| // Step 1 Replace message parameters using custom user messages |
| // repeat |
| resolvedMessage = replaceParameters(resolvedMessage, userReplacer); |
| } while (!step1message.equals(resolvedMessage)); |
| |
| // Step2 Replace message parameter using the default provider messages. |
| resolvedMessage = replaceParameters(resolvedMessage, providerReplacer); |
| |
| // Step 3 repeat from step 1 if step 2 made changes. |
| } while (!step1message.equals(resolvedMessage)); |
| |
| // step 4 resolve annotation attributes |
| resolvedMessage = replaceParameters( |
| resolvedMessage, |
| createAnnotationReplacer(context.getConstraintDescriptor().getAttributes())); |
| |
| // Remove escapes (4.3.1) |
| resolvedMessage = resolvedMessage.replace("\\{", "{"); |
| resolvedMessage = resolvedMessage.replace("\\}", "}"); |
| resolvedMessage = resolvedMessage.replace("\\\\", "\\"); |
| return resolvedMessage; |
| } |
| |
| protected final String replaceParameters(String message, |
| Function<String, String> replacer) { |
| StringBuilder sb = new StringBuilder(); |
| int index = 0; |
| |
| MatchResult matcher; |
| while ((matcher = MESSAGE_PARAMETER_PATTERN.exec(message)) != null) { |
| String matched = matcher.getGroup(0); |
| sb.append(message.substring(index, matcher.getIndex())); |
| Object value = replacer.apply(removeCurlyBrace(matched)); |
| sb.append(value == null ? matched : value); |
| index = MESSAGE_PARAMETER_PATTERN.getLastIndex(); |
| } |
| if (index < message.length()) { |
| sb.append(message.substring(index)); |
| } |
| return sb.toString(); |
| } |
| |
| private String removeCurlyBrace(String parameter) { |
| return parameter.substring(1, parameter.length() - 1); |
| } |
| } |