package org.apache.slide.projector.i18n;
import java.io.InputStream;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.slide.projector.Projector;
import org.apache.slide.projector.URI;
import org.apache.slide.projector.application.Application;
import org.apache.slide.projector.application.ApplicationListener;
import org.apache.slide.projector.value.StreamableValue;
import org.apache.slide.projector.value.URIValue;
import org.apache.webdav.lib.Subscriber;
import org.xml.sax.InputSource;
import org.xml.sax.helpers.AttributesImpl;
import de.zeigermann.xml.simpleImporter.DefaultSimpleImportHandler;
import de.zeigermann.xml.simpleImporter.SimpleImporter;
import de.zeigermann.xml.simpleImporter.SimplePath;
public class MessageManager implements ApplicationListener, Subscriber {
private static Logger logger = Logger.getLogger(MessageManager.class.getName());
private final static String MESSAGES_CONFIG = "messages.xml";
private final static String MESSAGES_NOT_FOUND_ID = "messageNotFound";
private Map installedMessages = new HashMap();
private Map messages = new HashMap();
private static MessageManager messageManager = new MessageManager();
private MessageManager() {
}
public static MessageManager getInstance() {
return messageManager;
}
public static String getText(String id, String entry, Object[] arguments, Locale locale, String defaultText) {
Message message = messageManager.findMessage(id, locale);
if (message != null) return messageManager.format(message.getEntry(entry), arguments);
return defaultText;
}
public static String getText(String id, String entry, Object[] arguments, Locale locale) throws MessageNotFoundException {
Message message = messageManager.findMessage(id, locale);
if (message != null) return messageManager.format(message.getEntry(entry), arguments);
throw new MessageNotFoundException(new ErrorMessage(MESSAGES_NOT_FOUND_ID, new String[] { id }));
}
public static Map getEntries(String id, Locale locale) throws MessageNotFoundException {
Message message = messageManager.findMessage(id, locale);
if ( message == null ) throw new MessageNotFoundException(new ErrorMessage(MESSAGES_NOT_FOUND_ID, new String[] { id }));
return message.getEntries();
}
public void install(String type, URI applicationUri, URI configurationUri) {
if ( type == Application.MESSAGES ) {
install(configurationUri);
}
}
public void uninstall(String type, URI applicationUri, URI configurationUri) {
if ( type == Application.MESSAGES ) {
uninstall(configurationUri);
}
}
public void update(String type, URI applicationUri, URI configurationUri) {
if ( type == Application.MESSAGES ) {
update(configurationUri);
}
}
public void install(URI messagesUri) {
logger.log(Level.FINE, "Installing messages '"+messagesUri+"'");
try {
Map applicationMessages = new HashMap();
StreamableValue messagesResource = (StreamableValue)Projector.getRepository().getResource(messagesUri, Projector.getCredentials());
if ( messagesResource != null ) {
InputStream inputStream = messagesResource.getInputStream();
SimpleImporter importer = new SimpleImporter();
importer.setIncludeLeadingCDataIntoStartElementCallback(true);
ConfigurationHandler handler = new ConfigurationHandler();
importer.addSimpleImportHandler(handler);
importer.parse(new InputSource(inputStream));
Map parsedMessages = handler.getMessages();
applicationMessages.putAll(parsedMessages);
Projector.getRepository().subscribe("Update", messagesUri, 0, this, Projector.getCredentials());
} else {
logger.log(Level.FINE, "Configured messages resource '"+messagesUri+"' not found!");
}
messages.putAll(applicationMessages);
installedMessages.put(messagesUri, applicationMessages.keySet());
} catch (Exception exception) {
logger.log(Level.SEVERE, "Error while parsing messages", exception);
}
}
public void uninstall(URI messageUri) {
logger.log(Level.FINE, "Uninstalling messages '"+messageUri+"'");
Collection messageKeys = (Collection)installedMessages.get(messageUri);
for ( Iterator i = messageKeys.iterator(); i.hasNext(); ) {
String messageKey = (String)i.next();
messages.remove(messageKey);
logger.log(Level.FINE, "Removing message with key '"+messageKey+"'");
}
installedMessages.remove(messageUri);
Projector.getRepository().unsubscribe(messageUri, this, Projector.getCredentials());
}
public void update(URI messagesUri) {
uninstall(messagesUri);
install(messagesUri);
}
public void notify(String uri, Map information) {
URI messageUri = new URIValue(uri);
uninstall(messageUri);
install(messageUri);
}
private String format(String formatString, Object[] arguments) {
if (formatString == null) return null;
return MessageFormat.format(formatString, arguments);
}
private Message findMessage(String id, Locale locale) {
Message message = lookupMessage(id, locale);
if (message == null) {
message = lookupMessage(id, Locale.getDefault());
}
if (message == null) {
logger.severe("No message found for id=" + id + " locale=" + locale);
}
return message;
}
private Message lookupMessage(String id, Locale locale) {
StringBuffer keyBuffer = new StringBuffer(64);
keyBuffer.append(id);
if (locale.getLanguage() != null) keyBuffer.append("_" + locale.getLanguage());
if (locale.getCountry() != null) keyBuffer.append("_" + locale.getCountry());
if (locale.getVariant() != null) keyBuffer.append("_" + locale.getVariant());
String key = keyBuffer.toString();
if (messages.containsKey(key)) return (Message)messages.get(key);
while (key.lastIndexOf('_') > 0) {
key = key.substring(0, key.lastIndexOf('_'));
if (messages.containsKey(key)) return (Message)messages.get(key);
}
return null;
}
class ConfigurationHandler extends DefaultSimpleImportHandler {
private Map messages = new HashMap();
private String id;
private Message message;
public void startElement(SimplePath path, String name, AttributesImpl attributes, String leadingCDdata) {
if (path.matches("message")) {
id = attributes.getValue("id");
} else if (path.matches("message/locale")) {
message = new Message(id);
message.setLanguage(attributes.getValue("language"));
message.setCountry(attributes.getValue("country"));
message.setVariant(attributes.getValue("variant"));
} else if (path.matches("message/locale/entry")) {
String key = attributes.getValue("key");
message.addEntry(key, leadingCDdata);
}
}
public void endElement(SimplePath path, String name) {
if (path.matches("message/locale")) {
messages.put(message.getKey(), message);
}
}
Map getMessages() {
return messages;
}
}
static class Message {
private String id, language, country, variant;
private Map entries = new HashMap();
public Message(String id) {
this.id = id;
}
public void addEntry(String key, String value) {
entries.put(key, value);
}
public String getEntry(String key) {
return (String)entries.get(key);
}
public Map getEntries() {
return entries;
}
public void setLanguage(String language) {
this.language = language;
}
public void setCountry(String country) {
this.country = country;
}
public void setVariant(String variant) {
this.variant = variant;
}
public String getKey() {
StringBuffer key = new StringBuffer(64);
key.append(id);
if (language != null) key.append("_" + language);
if (country != null) key.append("_" + country);
if (variant != null) key.append("_" + variant);
return key.toString();
}
}
}