/*
* Copyright 2012 Jason Miller
*
* 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 jj.i18n;
import static jj.server.ServerLocation.Virtual;
import java.util.Locale;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.Undefined;
import jj.execution.TaskRunner;
import jj.resource.ResourceFinder;
import jj.resource.ResourceTask;
import jj.script.Continuation;
import jj.script.PendingKey;
import jj.script.ContinuationProcessor;
import jj.script.ContinuationState;
import jj.script.CurrentScriptEnvironment;
import jj.util.StringUtils;
/**
* Looks up a {@link MessagesResource} for a calling script, possibly
* causing a continuation if it needs one
* @author jason
*
*/
@Singleton
public class ScriptMessages implements ContinuationProcessor {
static class ScriptMessagesLoaderBundle implements Continuation {
private PendingKey pendingKey;
private final String name;
private final Locale locale;
private final Scriptable scope;
ScriptMessagesLoaderBundle(final String name, final Locale locale, final Scriptable scope) {
this.name = name;
this.locale = locale;
this.scope = scope;
}
@Override
public String toString() {
return "name: " + name + ", locale: " + locale;
}
@Override
public void pendingKey(PendingKey pendingKey) {
this.pendingKey = pendingKey;
}
@Override
public PendingKey pendingKey() {
return pendingKey;
}
}
private final ResourceFinder resourceFinder;
private final TaskRunner taskRunner;
private final CurrentScriptEnvironment env;
private final I18NConfiguration configuration;
@Inject
ScriptMessages(
final ResourceFinder resourceFinder,
final TaskRunner taskRunner,
final CurrentScriptEnvironment env,
final I18NConfiguration configuration
) {
this.resourceFinder = resourceFinder;
this.taskRunner = taskRunner;
this.env = env;
this.configuration = configuration;
}
private Locale figureLocale(final String languageTag) {
Locale locale;
if (StringUtils.isEmpty(languageTag)) {
locale = configuration.defaultLocale();
} else {
locale = Locale.forLanguageTag(languageTag.replace('_', '-')); // being nice - we accept _ and - in the API
}
if (locale == null || "und".equals(locale.toLanguageTag())) {
locale = Locale.getDefault();
}
return locale;
}
private String figureName(final String name) {
if (StringUtils.isEmpty(name)) {
return env.current().name();
}
return name;
}
public Scriptable getMessagesResource(final String inputName, final String languageTag) {
// first, we had better be in a script
assert env.current() != null : "don't use this outside a script!";
// if no name, the current script environment name
// if no language tag, the current user's locale. if no current user, the default locale
// how to distinguish names and locales? argh. if only one is given, see if it looks like a locale?
// I DON'T KNOW - i guess it's whichever makes the most sense from an API perspective. OR if i can make it somehow
Locale locale = figureLocale(languageTag);
String name = figureName(inputName);
MessagesResource resource = resourceFinder.findResource(MessagesResource.class, Virtual, name, locale);
Scriptable scope = env.current().scope();
// if we can't find it, look it up
if (resource == null) {
throw env.preparedContinuation(new ScriptMessagesLoaderBundle(name, locale, scope));
}
return new MessagesScriptable(resource, scope);
}
@Override
public void process(final ContinuationState continuationState) {
final ScriptMessagesLoaderBundle bundle = continuationState.continuationAs(ScriptMessagesLoaderBundle.class);
taskRunner.execute(new ResourceTask("loading messages " + bundle.name + "_" + bundle.locale) {
@Override
protected void run() throws Exception {
MessagesResource resource = resourceFinder.loadResource(MessagesResource.class, Virtual, bundle.name, bundle.locale);
bundle.pendingKey.resume(resource == null ? Undefined.instance : new MessagesScriptable(resource, bundle.scope));
}
});
}
}