/*
* Copyright (c) 2001-2007, Inversoft Inc., All Rights Reserved
*
* 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.primeframework.mvc.message.l10n;
import java.util.Formatter;
import java.util.LinkedList;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.Queue;
import java.util.ResourceBundle;
import java.util.ResourceBundle.Control;
import org.primeframework.mvc.action.ActionInvocation;
import org.primeframework.mvc.action.ActionInvocationStore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Inject;
/**
* This implements the MessageProvider using ResourceBundles inside the web context. It also adds the additional step
* of
* looking for multiple bundles if the message isn't initially found. The search method is:
* <p>
* <pre>
* uri = /foo/bar
* locale = en_US
*
* ${configuration.resourceDirectory}/messages/foo/bar_en_US
* ${configuration.resourceDirectory}/messages/foo/bar_en
* ${configuration.resourceDirectory}/messages/foo/bar
* ${configuration.resourceDirectory}/messages/foo/package_en_US
* ${configuration.resourceDirectory}/messages/foo/package_en
* ${configuration.resourceDirectory}/messages/foo/package
* ${configuration.resourceDirectory}/messages/package_en_US
* ${configuration.resourceDirectory}/messages/package_en
* ${configuration.resourceDirectory}/messages/package
* </pre>
* <p>
* This stops when ${configuration.resourceDirectory}/messages is hit.
* <p>
* Once the message is found, it is formatted using the {@link Formatter} class. The values are passed in order.
*
* @author Brian Pontarelli
*/
public class ResourceBundleMessageProvider implements MessageProvider {
private final static Logger logger = LoggerFactory.getLogger(ResourceBundleMessageProvider.class);
private final ResourceBundle.Control control;
private final ActionInvocationStore invocationStore;
private final Locale locale;
@Inject
public ResourceBundleMessageProvider(Locale locale, Control control, ActionInvocationStore invocationStore) {
this.locale = locale;
this.control = control;
this.invocationStore = invocationStore;
}
@Override
public String getMessage(String key, Object... values) throws MissingMessageException {
ActionInvocation actionInvocation = invocationStore.getCurrent();
String template = findMessage(actionInvocation, key);
Formatter f = new Formatter();
f.format(locale, template, values);
return f.out().toString();
}
protected Queue<String> determineBundles(String bundle) {
Queue<String> names = new LinkedList<String>();
names.offer(bundle);
int index = bundle.lastIndexOf('/');
while (index != -1) {
bundle = bundle.substring(0, index);
names.offer(bundle + "/package");
index = bundle.lastIndexOf('/');
}
return names;
}
/**
* Finds the message in a resource bundle using the search method described in the class comment.
*
* @param actionInvocation The action invocation.
* @param key The key of the message.
* @return The message or null if it doesn't exist.
*/
protected String findMessage(ActionInvocation actionInvocation, String key) {
String uri = actionInvocation.actionURI;
Queue<String> names = determineBundles(uri);
for (String name : names) {
try {
ResourceBundle rb = ResourceBundle.getBundle(name, locale, control);
return rb.getString(key);
} catch (MissingResourceException e) {
// Ignore and check the next bundle
}
}
if (!"[ValidationException]".equals(key)) {
logger.warn("Message could not be found for the URI [" + uri + "] and key [" + key + "]");
}
throw new MissingMessageException("Message could not be found for the URI [" + uri + "] and key [" + key + "]");
}
}