You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@avalon.apache.org by ne...@apache.org on 2001/10/30 00:10:25 UTC
cvs commit: jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/i18n ResourceBundleSelector.java ResourceBundle.java PrefixedMapper.java LocaleToUriMapper.java FlatXMLResourceBundle.java DirectoryMapper.java DefaultMapper.java AbstractResourceBundle.java XMLResourceBundle.java XMLResourceBundleFactory.java
neeme 01/10/29 15:10:25
Modified: src/scratchpad/org/apache/avalon/excalibur/i18n
XMLResourceBundle.java
Added: src/scratchpad/org/apache/avalon/excalibur/i18n
ResourceBundleSelector.java ResourceBundle.java
PrefixedMapper.java LocaleToUriMapper.java
FlatXMLResourceBundle.java DirectoryMapper.java
DefaultMapper.java AbstractResourceBundle.java
Removed: src/scratchpad/org/apache/avalon/excalibur/i18n
XMLResourceBundleFactory.java
Log:
Made some major updates, short summary of the changes:
----------
* added org.apache.avalon.excalibur.i18n.ResourceBundle "behavioral" interface
* moved all non XMLResourceBundle specific code to AbstractResourceBundle
* made XMLResourceBundle methods more "extendable-friendly" (private vs. protected methods)
* added FlatXMLResourceBundle class (extends XMLResourceBundle) that provides support for bundles with the "flat" XML schema that Cocoon i18n transformer currently uses. this should also work as an example of how to extend the base implementations.
* added getLastModified() method that Torsten mentioned.
---
* added org.apache.avalon.excalibur.i18n.LocaleToUriMapper "behavioral" interface, to make it easy to implement different mappings
* added abstract base-class PrefixedMapper that provides base for different "prefixed" implementations (prefix = root directory under current implementations, but not always).
* moved the default mapping implementation code from XMLResourceFactory to DefaultMapper class (that extends PrefixedMapped)
* added one more mapping implementation that I had in one corner of by disk, DirectoryMapper
---
* renamed XMLResourceBundleFactory into ResourceBundleSelector as all the XMLResourceBundle specific code was moved out from there and it is generic enough now.
----------
Revision Changes Path
1.7 +107 -239 jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/i18n/XMLResourceBundle.java
Index: XMLResourceBundle.java
===================================================================
RCS file: /home/cvs/jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/i18n/XMLResourceBundle.java,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- XMLResourceBundle.java 2001/10/25 16:09:03 1.6
+++ XMLResourceBundle.java 2001/10/29 23:10:24 1.7
@@ -8,97 +8,91 @@
package org.apache.avalon.excalibur.i18n;
/** JDK classes **/
-import java.io.IOException;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.Locale;
-import java.util.Enumeration;
-import java.util.ResourceBundle;
-import java.util.MissingResourceException;
-
-/** W3C DOM classes **/
+import org.apache.avalon.framework.activity.Disposable;
+import org.apache.avalon.framework.component.Composable;
+import org.apache.avalon.framework.component.Component;
+import org.apache.avalon.framework.component.ComponentManager;
+import org.apache.avalon.excalibur.xml.xpath.XPathProcessor;
import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
-import org.w3c.dom.NamedNodeMap;
-
-/** SAX classes **/
import org.xml.sax.SAXException;
-/** Parser classes **/
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
-
-/** XPath classes **/
-import org.apache.xpath.XPathAPI;
-
-/** TRaX classes **/
-import javax.xml.transform.TransformerException;
-
-/** Avalon classes **/
-import org.apache.avalon.framework.component.Component;
-import org.apache.avalon.framework.logger.Loggable;
-import org.apache.log.Logger;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.MissingResourceException;
/**
* @author <a href="mailto:mengelhart@earthtrip.com">Mike Engelhart</a>
* @author <a href="mailto:neeme@one.lv">Neeme Praks</a>
* @author <a href="mailto:oleg@one.lv">Oleg Podolsky</a>
- * @version $Id: XMLResourceBundle.java,v 1.6 2001/10/25 16:09:03 bloritsch Exp $
+ * @version $Id: XMLResourceBundle.java,v 1.7 2001/10/29 23:10:24 neeme Exp $
*/
-public class XMLResourceBundle
- extends ResourceBundle
- implements Loggable, Component
-{
+public class XMLResourceBundle extends AbstractResourceBundle
+implements Disposable, Composable {
+
/** DOM factory */
- protected static DocumentBuilderFactory docfactory =
- DocumentBuilderFactory.newInstance();
+ private static DocumentBuilderFactory docfactory =
+ DocumentBuilderFactory.newInstance();
/** Cache for storing string values for existing XPaths */
- private Hashtable cache = new Hashtable();
+ private Map cache = new HashMap();
/** Cache for storing non-existing XPaths */
private Map cacheNotFound = new HashMap();
- /** Bundle name */
- private String name = "";
-
/** DOM-tree containing the bundle content */
private Document doc;
- /** Locale of the bundle */
- private Locale locale;
+ /** Component Manager */
+ protected ComponentManager manager = null;
- /** Parent of the current bundle */
- protected XMLResourceBundle parent = null;
+ /** XPath Processor */
+ private XPathProcessor processor = null;
- /** Logger */
- protected Logger logger;
+ public void compose(ComponentManager manager) {
+ this.manager = manager;
+ try {
+ this.processor = (XPathProcessor)this.manager.lookup(XPathProcessor.ROLE);
+ } catch (Exception e) {
+ logger.error("cannot obtain XPathProcessor", e);
+ }
+ }
/**
* Initalize the bundle
*
- * @param name name of the bundle
* @param fileName name of the XML source file
- * @param locale locale
- * @param parent parent bundle of this bundle
* @param cacheAtStartup cache all the keys when constructing?
* @exception IOException if an IO error occurs while reading the file
* @exception ParserConfigurationException if no parser is configured
* @exception SAXException if an error occurs while parsing the file
+ */
+ public void init(String fileName, boolean cacheAtStartup)
+ throws Exception {
+ if (logger.isInfoEnabled()) logger.info("Constructing XMLResourceBundle: " + getName() + ", locale: " + getLocale());
+ this.doc = loadResourceBundle(fileName);
+ if (cacheAtStartup) cacheAll(doc.getDocumentElement(), "");
+ }
+
+ /**
+ * Convert the "user view" of the lookup key to the
+ * "system view".
+ * Current implementation coverts dots into slashes, so common Java property
+ * names become XPath paths.
+ * E.g: this.is.java.property.key --> /this/is/java/property/key
+ *
+ * @param key user key
+ * @return system key
*/
- public void init(String name, String fileName, Locale locale, XMLResourceBundle parent, boolean cacheAtStartup)
- throws IOException, ParserConfigurationException, SAXException
- {
- if (logger.isInfoEnabled()) logger.info("Constructing XMLResourceBundle: " + name + ", locale: " + locale);
- this.name = name;
- this.doc = loadResourceBundle(fileName, logger);
- this.locale = locale;
- this.parent = parent;
- if (cacheAtStartup)
- cacheAll(doc.getDocumentElement(), "");
+ public String convertKey(String userKey) {
+ return '/' + userKey.replace('.', '/');
}
/**
@@ -110,31 +104,11 @@
* @exception ParserConfigurationException if no parser is configured
* @exception SAXException if an error occurs while parsing the file
*/
- protected static Document loadResourceBundle(String fileName, Logger logger)
- throws IOException, ParserConfigurationException, SAXException
- {
+ protected static Document loadResourceBundle(String fileName)
+ throws IOException, ParserConfigurationException, SAXException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
-
- try
- {
- return builder.parse(fileName);
- }
- catch (SAXException se)
- {
- logger.warn("Could not use the file '" + fileName + "' returning a new Document object instead.", se);
- return builder.newDocument();
- }
- }
-
- /**
- * Gets the name of the bundle.
- *
- * @return the name
- */
- public String getName()
- {
- return this.name;
+ return builder.parse(fileName);
}
/**
@@ -142,30 +116,18 @@
*
* @return the DOM tree
*/
- public Document getDocument()
- {
+ public Document getDocument() {
return this.doc;
}
/**
- * Gets the locale of the bundle.
- *
- * @return the locale
- */
- public Locale getLocale()
- {
- return locale;
- }
-
- /**
* Does the "key-cache" contain the value with such key?
*
* @param key the key to the value to be returned
* @return true if contains, false otherwise
*/
- private boolean cacheContains(String key)
- {
- if (logger.isDebugEnabled()) logger.debug(name + ": cache contains: " + key);
+ protected boolean cacheContains(String key) {
+ if (logger.isDebugEnabled()) logger.debug(getName() + ": cache contains: " + key);
return cache.containsKey(key);
}
@@ -175,9 +137,8 @@
* @param key the key to the value to be returned
* @return true if contains, false otherwise
*/
- private boolean cacheNotFoundContains(String key)
- {
- if (logger.isDebugEnabled()) logger.debug(name + ": cache_not_found contains: " + key);
+ protected boolean cacheNotFoundContains(String key) {
+ if (logger.isDebugEnabled()) logger.debug(getName() + ": cache_not_found contains: " + key);
return cacheNotFound.containsKey(key);
}
@@ -187,9 +148,8 @@
* @param key the key
* @param value the value
*/
- private void cacheKey(String key, String value)
- {
- if (logger.isDebugEnabled()) logger.debug(name + ": caching: " + key + " = " + value);
+ protected void cacheKey(String key, String value) {
+ if (logger.isDebugEnabled()) logger.debug(getName() + ": caching: " + key + " = " + value);
cache.put(key, value);
}
@@ -198,9 +158,8 @@
*
* @param key the key
*/
- private void cacheNotFoundKey(String key)
- {
- if (logger.isDebugEnabled()) logger.debug(name + ": caching not_found: " + key);
+ protected void cacheNotFoundKey(String key) {
+ if (logger.isDebugEnabled()) logger.debug(getName() + ": caching not_found: " + key);
cacheNotFound.put(key, "");
}
@@ -210,9 +169,8 @@
* @param key the key
* @return the value
*/
- private String getFromCache(String key)
- {
- if (logger.isDebugEnabled()) logger.debug(name + ": returning from cache: " + key);
+ protected String getFromCache(String key) {
+ if (logger.isDebugEnabled()) logger.debug(getName() + ": returning from cache: " + key);
return (String) cache.get(key);
}
@@ -223,27 +181,22 @@
* @param parent parent node, must be an element
* @param pathToParent XPath to the parent node
*/
- private void cacheAll(Node parent, String pathToParent)
- {
+ protected void cacheAll(Node parent, String pathToParent) {
NodeList children = parent.getChildNodes();
int childnum = children.getLength();
- for(int i = 0; i < childnum; i++)
- {
+ for(int i = 0; i < childnum; i++) {
Node child = children.item(i);
- if(child.getNodeType() == Node.ELEMENT_NODE)
- {
+ if(child.getNodeType() == Node.ELEMENT_NODE) {
StringBuffer pathToChild = new StringBuffer(pathToParent).append('/').append(child.getNodeName());
NamedNodeMap attrs = child.getAttributes();
- if(attrs != null)
- {
+ if(attrs != null) {
Node temp = null;
String pathToAttr = null;
int attrnum = attrs.getLength();
- for(int j = 0; j < attrnum; j++)
- {
+ for(int j = 0; j < attrnum; j++) {
temp = attrs.item(j);
if (!temp.getNodeName().equalsIgnoreCase("xml:lang"))
pathToChild.append("[@").append(temp.getNodeName())
@@ -262,24 +215,21 @@
}
/**
- * Get value by key and substitute variables.
+ * Get value by key.
*
* @param key key
- * @param dictionary map with variable values
- * @return value with variable values substituted
- * @exception MissingResourceException if resource was not found
- */
- public String getString(String key, Map dictionary)
- throws MissingResourceException
- {
- String value = _getString(key);
+ * @return value
+ * @exception MissingResourceException if value was not found
+ */
+ public String getString(String key) throws MissingResourceException {
+ String value = _getString(convertKey(key));
if (value == null)
throw new MissingResourceException(
"Unable to locate resource: " + key,
XMLResourceBundle.class.getName(),
key);
else
- return substitute(value, dictionary);
+ return value;
}
/**
@@ -288,19 +238,21 @@
* @param key the key
* @return the value
*/
- private String _getString(String key)
- {
+ protected String _getString(String key) {
if (key == null) return null;
String value = getFromCache(key);
if (value == null && !cacheNotFoundContains(key))
{
- value = _getString(this.doc.getDocumentElement(), key);
+ if (doc != null)
+ value = _getString(this.doc.getDocumentElement(), key);
+
if (value == null)
{
- if (this.parent != null)
- value = this.parent._getString(key);
+ if (getParent() != null)
+ value = getParent().getString(key);
}
+
if (value != null)
cacheKey(key, value);
else
@@ -316,16 +268,13 @@
* @param key the key
* @return the value
*/
- private String _getString(Node node, String key)
- {
+ protected String _getString(Node node, String key) {
String value = null;
- try
- {
+ try {
value = getTextValue(_getNode(node, key));
}
- catch (Exception e)
- {
- logger.error(name + ": error while locating resource: " + key, e);
+ catch (Exception e) {
+ logger.error(getName() + ": error while locating resource: " + key, e);
}
return value;
}
@@ -336,8 +285,7 @@
* @param node the node
* @return the value
*/
- private static String getTextValue(Node element)
- {
+ protected static String getTextValue(Node element) {
if (element == null) return null;
NodeList list = element.getChildNodes();
int listsize = list.getLength();
@@ -345,11 +293,19 @@
Node item = null;
String itemValue = null;
- for(int i = 0; i < listsize; i++)
- {
- item = list.item(i); if(item.getNodeType() != Node.TEXT_NODE) return null;
- itemValue = item.getNodeValue(); if(itemValue == null) return null;
- itemValue = itemValue.trim(); if(itemValue.length() == 0) return null;
+ for(int i = 0; i < listsize; i++) {
+ item = list.item(i);
+ if(item.getNodeType() != Node.TEXT_NODE)
+ return null;
+
+ itemValue = item.getNodeValue();
+ if(itemValue == null)
+ return null;
+
+ itemValue = itemValue.trim();
+ if(itemValue.length() == 0)
+ return null;
+
return itemValue;
}
return null;
@@ -361,8 +317,7 @@
* @param key the key
* @return the node
*/
- private Node _getNode(String key)
- {
+ protected Node _getNode(String key) {
return _getNode(this.doc.getDocumentElement(), key);
}
@@ -374,105 +329,18 @@
* @param key the key
* @return the node
*/
- private Node _getNode(Node rootNode, String key)
- {
+ protected Node _getNode(Node rootNode, String key) {
Node node = null;
- try
- {
- node = XPathAPI.selectSingleNode(rootNode, key);
+ try {
+ node = this.processor.selectSingleNode(rootNode, key);
}
- catch (Exception e)
- {
+ catch (Exception e) {
logger.error("Error while locating resource with key: " + key, e);
}
return node;
}
- /**
- * Substitute the "variables" in the string with the values
- * provided in the map.
- *
- * @param value value where to search for variables
- * @param dictionary map with variable values
- * @return value with variable values substituted
- */
- public String substitute(String value, Map dictionary)
- {
- if (value == null || dictionary == null) return value;
-
- StringBuffer result = new StringBuffer(value.length());
- int startPos = 0;
- int endPos = 0;
- int lastPos = value.length();
- Object varValue = "";
- String varKey = "", oldKey = "";
- while (endPos < lastPos)
- {
- startPos = endPos;
- endPos = value.indexOf('{', startPos);
- if (endPos == -1)
- endPos = lastPos;
- result.append(value.substring(startPos, endPos));
- if (endPos < lastPos)
- endPos++;
- if (endPos < lastPos)
- {
- startPos = endPos;
- endPos = value.indexOf('}', startPos);
- if (endPos == -1)
- endPos = lastPos;
- oldKey = varKey;
- varKey = value.substring(startPos, endPos);
- if (!oldKey.equals(varKey))
- varValue = dictionary.get(varKey);
- if (varValue != null)
- {
- if (logger.isDebugEnabled()) logger.debug("Substituting var: " + varKey + " --> " + varValue);
- result.append(varValue);
- }
- else
- {
- if (logger.isWarnEnabled()) logger.warn(name + ": var not found: " + varKey);
- result.append('{').append(varKey).append('}');
- }
- if (endPos < lastPos)
- endPos++;
- }
- }
- return result.toString();
- }
-
- /**
- * Set the logger.
- *
- * @param logger the logger
- */
- public void setLogger( final Logger logger )
- {
- this.logger = logger;
- }
-
- /**
- * Return an Object by key.
- * Implementation of the ResourceBundle abstract method.
- *
- * @param key the key
- * @return the object
- */
- protected Object handleGetObject(String key)
- throws MissingResourceException
- {
- return (Object) getString(key, null);
- }
-
- /**
- * Return an enumeration of the keys.
- * Implementation of the ResourceBundle abstract method.
- *
- * @return the enumeration of keys
- */
- public Enumeration getKeys()
- {
- return cache.keys();
+ public void dispose() {
+ this.manager.release((Component)this.processor);
}
}
1.1 jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/i18n/ResourceBundleSelector.java
Index: ResourceBundleSelector.java
===================================================================
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.avalon.excalibur.i18n;
import org.apache.avalon.framework.component.Composable;
import org.apache.avalon.framework.component.Component;
import org.apache.avalon.framework.component.ComponentManager;
import org.apache.avalon.framework.component.ComponentException;
import org.apache.avalon.framework.component.DefaultComponentSelector;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.logger.Loggable;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.log.Logger;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
/**
* This is the method for getting instances of ResourceBundles.
*
* @author <a href="mailto:neeme@one.lv">Neeme Praks</a>
* @author <a href="mailto:mengelhart@earthtrip.com">Mike Engelhart</a>
* @version $Id: ResourceBundleSelector.java,v 1.1 2001/10/29 23:10:24 neeme Exp $
*/
public class ResourceBundleSelector
extends DefaultComponentSelector
implements Configurable, Loggable, ThreadSafe, Composable
{
/**
* The role implemented by an <code>ResourceBundle</code>.
*/
String ROLE = "org.apache.avalon.excalibur.i18n.ResourceBundleSelector";
/** Component Manager */
protected ComponentManager manager = null;
public void compose(ComponentManager manager) {
this.manager = manager;
try {
this.mapper = (LocaleToUriMapper) manager.lookup(LocaleToUriMapper.ROLE);
} catch (Exception e) {
logger.error("cannot obtain LocaleToUriMapper", e);
}
}
/** Should we load bundles to cache on startup or not? */
protected boolean cacheAtStartup = false;
/** LocaleToUri mapper */
protected LocaleToUriMapper mapper;
/** Cache for the names of the bundles that were not found */
protected Map cacheNotFound = new HashMap();
/** The logger */
protected Logger logger;
/** Constants for configuration keys */
public static class ConfigurationKeys {
public static final String CACHE_AT_STARTUP = "cache-at-startup";
}
/**
* Set the logger.
*
* @param logger the logger
*/
public void setLogger(final Logger logger) {
this.logger = logger;
}
/**
* Configure the component.
*
* @param configuration the configuration
*/
public void configure(Configuration configuration) throws ConfigurationException {
this.cacheAtStartup = configuration.getChild(ConfigurationKeys.CACHE_AT_STARTUP).getValueAsBoolean(false);
}
/**
* Select a bundle based on bundle name and locale.
*
* @param name bundle name
* @param locale locale
* @return the bundle
* @exception ComponentException if a bundle is not found
*/
public Component select(String name, Locale locale) throws ComponentException {
return select(name, locale, cacheAtStartup);
}
/**
* Select a bundle based on bundle name and locale.
*
* @param name bundle name
* @param locale locale
* @param cacheAtStartup cache all the keys when constructing?
* @return the bundle
* @exception ComponentException if a bundle is not found
*/
public Component select(String name, Locale loc, boolean cacheAtStartup) throws ComponentException {
Component bundle = _select(name, loc, cacheAtStartup);
if (bundle == null)
throw new ComponentException("Unable to locate resource: " + name);
return bundle;
}
/**
* Select a bundle based on bundle name and locale.
*
* @param name bundle name
* @param locale locale
* @return the bundle
*/
private Component _select(String name, Locale loc) {
return _select(name, loc, cacheAtStartup);
}
/**
* Select the parent bundle of the current bundle, based on
* bundle name and locale.
*
* @param name bundle name
* @param locale locale
* @return the bundle
*/
protected Component selectParent(String name, Locale loc) {
return selectParent(name, loc, cacheAtStartup);
}
/**
* Select the parent bundle of the current bundle, based on
* bundle name and locale.
*
* @param name bundle name
* @param locale locale
* @param cacheAtStartup cache all the keys when constructing?
* @return the bundle
*/
protected Component selectParent(String name, Locale loc, boolean cacheAtStartup) {
return _select(name, getParentLocale(loc), cacheAtStartup);
}
/**
* Select a bundle based on bundle name and locale name.
*
* @param name bundle name
* @param localeName locale name
* @return the bundle
* @exception ComponentException if a bundle is not found
*/
public Component select(String name, String localeName)
throws ComponentException {
return select(name, new Locale(localeName, localeName) );
}
/**
* Select a bundle based on source file name.
*
* @param fileName file name
* @return the bundle
* @exception ComponentException if a bundle is not found
*/
public Component selectFromFilename(String fileName)
throws ComponentException {
return selectFromFilename(fileName, cacheAtStartup);
}
/**
* Select a bundle based on source file name.
*
* @param fileName file name
* @param cacheAtStartup cache all the keys when constructing?
* @return the bundle
* @exception ComponentException if a bundle is not found
*/
public Component selectFromFilename(String fileName, boolean cacheAtStartup)
throws ComponentException {
Component bundle = _select(fileName, null, cacheAtStartup);
if (bundle == null)
throw new ComponentException("Unable to locate resource: " + fileName);
return bundle;
}
/**
* Select a bundle based on bundle name and locale.
*
* @param name bundle name
* @param locale locale
* @param cacheAtStartup cache all the keys when constructing?
* @return the bundle
* @exception ComponentException if a bundle is not found
*/
private Component _select(String name, Locale loc, boolean cacheAtStartup) {
if (logger.isDebugEnabled()) logger.debug("_getBundle: " + name + ", locale " + loc);
String fileName = mapper.getUri(name, loc);
ResourceBundle bundle = (ResourceBundle) selectCached(fileName);
if (bundle == null && !isNotFoundBundle(fileName)) {
if (logger.isDebugEnabled()) logger.debug("not found in cache, loading: " + fileName);
synchronized(this) {
bundle = (ResourceBundle) selectCached(fileName);
if (bundle == null && !isNotFoundBundle(fileName)) {
if (logger.isDebugEnabled()) logger.debug("synchronized: not found in cache, loading: " + fileName);
bundle = _loadBundle(name, fileName, loc, cacheAtStartup);
Locale parentLoc = loc;
String parentBundleName;
while (bundle == null && parentLoc != null && !parentLoc.getLanguage().equals("")) {
if (logger.isDebugEnabled()) logger.debug("synchronized: still not found, trying parent: " + fileName);
parentLoc = getParentLocale(parentLoc);
parentBundleName = mapper.getUri(name, parentLoc);
bundle = _loadBundle(name, parentBundleName, parentLoc, cacheAtStartup);
updateCache(parentBundleName, bundle);
}
updateCache(fileName, bundle);
}
}
}
return (Component) bundle;
}
/**
* Construct a bundle based on bundle name, file name and locale.
*
* @param name bundle name
* @param fileName full path to source file
* @param locale locale
* @param cacheAtStartup cache all the keys when constructing?
* @return the bundle, null if loading failed
*/
private ResourceBundle _loadBundle(String name, String fileName, Locale loc, boolean cacheAtStartup) {
if (logger.isDebugEnabled()) logger.debug("Trying to load bundle: " + name + ", locale " + loc + ", filename " + fileName);
ResourceBundle bundle = null;
ResourceBundle parentBundle = null;
try {
if (loc != null && !loc.getLanguage().equals(""))
parentBundle = (ResourceBundle) selectParent(name, loc);
bundle = (ResourceBundle) manager.lookup(ResourceBundle.ROLE);
if (bundle instanceof Loggable) ((Loggable)bundle).setLogger(logger);
bundle.setName(name);
bundle.setLocale(loc);
bundle.setParent(parentBundle);
if (bundle instanceof Composable) ((Composable)bundle).compose(this.manager);
bundle.init(fileName, cacheAtStartup);
bundle.setLastModified(System.currentTimeMillis());
}
catch (Exception e) {
logger.error("Error while loading resource: " + name + ", locale " + loc + ", bundleName " + fileName, e);
bundle = null;
}
return bundle;
}
/**
* Returns the next locale up the parent hierarchy.
* E.g. the parent of new Locale("en","us","mac") would be
* new Locale("en", "us", "").
*
* @param locale the locale
* @return the parent locale
*/
protected Locale getParentLocale(Locale loc) {
Locale newloc;
if (loc.getVariant().equals("")) {
if (loc.getCountry().equals(""))
newloc = new Locale("","","");
else
newloc = new Locale(loc.getLanguage(), "", "");
}
else
newloc = new Locale(loc.getLanguage(), loc.getCountry(), "");
return newloc;
}
/**
* Selects a bundle from the cache.
*
* @param fileName file name of the bundle
* @return the cached bundle; null, if not found
*/
protected Component selectCached(String fileName) {
Component bundle = null;
try {
bundle = super.select(fileName);
if (logger.isDebugEnabled()) logger.debug("Returning from cache: " + fileName);
}
catch (ComponentException e) {
if (logger.isDebugEnabled()) logger.debug("Not found in cache: " + fileName);
}
return bundle;
}
/**
* Checks if the bundle is in the "not-found" cache.
*
* @param fileName file name of the bundle
* @return true, if the bundle wasn't found already before;
* otherwise, false.
*/
protected boolean isNotFoundBundle(String fileName) {
String result = (String)(cacheNotFound.get(fileName));
if (result != null) {
if (logger.isDebugEnabled()) logger.debug("Returning from not_found_cache: " + fileName);
}
else {
if (logger.isDebugEnabled()) logger.debug("Not found in not_found_cache: " + fileName);
}
return result != null;
}
/**
* Checks if the bundle is in the "not-found" cache.
*
* @param fileName file name of the bundle
* @return true, if the bundle wasn't found already before;
* otherwise, false.
*/
protected void updateCache(String fileName, ResourceBundle bundle) {
if (bundle == null) {
if (logger.isDebugEnabled()) logger.debug("Updating not_found_cache: " + fileName);
cacheNotFound.put(fileName, fileName);
}
else {
if (logger.isDebugEnabled()) logger.debug("Updating cache: " + fileName);
super.put((Object) fileName, (Component) bundle);
}
}
/**
* Should we load bundles to cache on startup or not?
*
* @return true if pre-loading all resources; false otherwise
*/
public boolean cacheAtStartup() {
return cacheAtStartup;
}
}
1.1 jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/i18n/ResourceBundle.java
Index: ResourceBundle.java
===================================================================
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.avalon.excalibur.i18n;
import java.util.Map;
import java.util.Locale;
/**
* This is the interface of the ResourceBundle, for used for i18n support.
*
* @author <a href="mailto:neeme@apache.org">Neeme Praks</a>
* @version CVS $Revision: 1.1 $ $Date: 2001/10/29 23:10:24 $ $Author: neeme $
*/
public interface ResourceBundle {
/**
* The role implemented by an <code>ResourceBundle</code>.
*/
String ROLE = "org.apache.avalon.excalibur.i18n.ResourceBundle";
/**
* Initalize the bundle
*
* @param fileName name of the XML source file
* @param cacheAtStartup cache all the keys when constructing?
*/
public void init(String fileName, boolean cacheAtStartup) throws Exception;
/**
* Get the name of the bundle.
*
* @return the name
*/
public String getName();
/**
* Set the name of the bundle.
*
* @param name the name
*/
void setName(String name);
/**
* Get the locale of the bundle.
*
* @return the locale
*/
public Locale getLocale();
/**
* Sets the locale of the bundle.
*
* @param name the locale
*/
void setLocale(Locale locale);
/**
* Get the parent bundle of the current bundle.
*
* @return the parent bundle
*/
public ResourceBundle getParent();
/**
* Set the parent bundle of the current bundle.
*
* @param parent the parent bundle
*/
void setParent(ResourceBundle parent);
/**
* Get value by key.
*
* @param key key
* @return value
* @exception MissingResourceException if value was not found
*/
public String getString(String key);
/**
* Get value by key and substitute variables.
*
* @param key key
* @param values map with variable values
* @return value with variable values substituted
* @exception MissingResourceException if value was not found
*/
public String getString(String key, Map values);
/**
* Convert the "user view" of the lookup key to the
* "system view". Used to hide the implemented storage
* mechanism and/or XML file schema.
*
* @param key user key
* @return system key
*/
public String convertKey(String userKey);
/**
* Returns the last modification time of this bundle, in milliseconds.
*
* @return last modification time, -1 if N/A
*/
public long getLastModified();
/**
* Sets the last modification time of this bundle, in milliseconds.
*
* @param lastModified last modification time
*/
void setLastModified(long lastModified);
}
1.1 jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/i18n/PrefixedMapper.java
Index: PrefixedMapper.java
===================================================================
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.avalon.excalibur.i18n;
import java.util.Locale;
import org.apache.log.Logger;
import org.apache.avalon.framework.logger.Loggable;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
/**
* Used to map locale information to URI space, to find the relevant bundle.
*
* @author <a href="mailto:neeme@apache.org">Neeme Praks</a>
* @version CVS $Revision: 1.1 $ $Date: 2001/10/29 23:10:24 $ $Author: neeme $
*/
public abstract class PrefixedMapper implements Loggable, Configurable, ThreadSafe {
/** Constants for configuration keys */
public static class ConfigurationKeys {
public static final String PREFIX = "prefix";
}
/** Root directory to all bundle names */
protected String prefix;
/** The logger */
protected Logger logger;
/**
* Set the logger.
*
* @param logger the logger
*/
public void setLogger(final Logger logger) {
this.logger = logger;
}
/**
* Configure the component.
*
* @param configuration the configuration
*/
public void configure(Configuration configuration) throws ConfigurationException {
try {
this.prefix = configuration.getChild(ConfigurationKeys.PREFIX, true).getValue();
}
catch (ConfigurationException e) {
if (logger.isWarnEnabled()) logger.warn("Prefix not provided in configuration, using none.");
this.prefix = "";
}
if (logger.isDebugEnabled()) {
logger.debug("PrefixedMapper configured with prefix = '" + this.prefix + "'");
}
}
/**
* Returns the root directory to all bundles.
*
* @return the directory path
*/
public String getPrefix() {
return prefix;
}
}
1.1 jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/i18n/LocaleToUriMapper.java
Index: LocaleToUriMapper.java
===================================================================
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.avalon.excalibur.i18n;
import java.util.Locale;
/**
* Used to map locale information to URI space, to find the relevant bundle.
*
* @author <a href="mailto:neeme@apache.org">Neeme Praks</a>
* @version CVS $Revision: 1.1 $ $Date: 2001/10/29 23:10:24 $ $Author: neeme $
*/
public interface LocaleToUriMapper {
/**
* The role implemented by a <code>LocaleToUriMapper</code>.
*/
String ROLE = "org.apache.avalon.excalibur.i18n.LocaleToUriMapper";
/**
* Get the URI for the bundle, based on locale and filename.
*
* @return the URI
*/
public String getUri(String name, Locale loc);
}
1.1 jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/i18n/FlatXMLResourceBundle.java
Index: FlatXMLResourceBundle.java
===================================================================
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.avalon.excalibur.i18n;
/**
* @author <a href="mailto:neeme@one.lv">Neeme Praks</a>
* @version $Id: FlatXMLResourceBundle.java,v 1.1 2001/10/29 23:10:24 neeme Exp $
*/
public class FlatXMLResourceBundle extends XMLResourceBundle {
public static final String PREFIX = "/catalogue/message[@key='";
public static final String SUFFIX = "']";
/**
* Convert the "user view" of the lookup key to the
* "system view". Used to hide the implemented storage
* mechanism and/or XML file schema.
*
* @param key user key
* @return system key
*/
public String convertKey(String userKey) {
return new StringBuffer(PREFIX).append(userKey).append(SUFFIX).toString();
}
}
1.1 jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/i18n/DirectoryMapper.java
Index: DirectoryMapper.java
===================================================================
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.avalon.excalibur.i18n;
import java.util.Locale;
/**
* Maps the locale using the standard Java mapping: en-US would be mapped to
* file ending with en_US.
*
* @author <a href="mailto:neeme@apache.org">Neeme Praks</a>
* @version CVS $Revision: 1.1 $ $Date: 2001/10/29 23:10:24 $ $Author: neeme $
*/
public class DirectoryMapper extends PrefixedMapper {
/**
* Get the URI for the bundle, based on locale and filename.
*
* @return the URI
*/
public String getUri(String name, Locale loc) {
StringBuffer sb = new StringBuffer(getPrefix());
if (loc != null) {
String lang = loc.getLanguage();
String country = loc.getCountry();
String variant = loc.getVariant();
if (lang.length() > 0) sb.append("/").append(lang);
if (country.length() > 0) sb.append("/").append(country);
if (variant.length() > 0) sb.append("/").append(variant);
}
sb.append("/").append(name).append(".xml");
String result = sb.toString();
if (logger.isDebugEnabled()) logger.debug("Resolving bundle name to file name: " + name + ", locale " + loc + " --> " + result);
return result;
}
}
1.1 jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/i18n/DefaultMapper.java
Index: DefaultMapper.java
===================================================================
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.avalon.excalibur.i18n;
import java.util.Locale;
/**
* Maps the locale using the standard Java mapping: en-US would be mapped to
* file ending with en_US.
*
* @author <a href="mailto:neeme@apache.org">Neeme Praks</a>
* @version CVS $Revision: 1.1 $ $Date: 2001/10/29 23:10:24 $ $Author: neeme $
*/
public class DefaultMapper extends PrefixedMapper {
/**
* Get the URI for the bundle, based on locale and filename.
*
* @return the URI
*/
public String getUri(String name, Locale loc) {
StringBuffer sb = new StringBuffer(getPrefix());
sb.append('/').append(name);
if (loc != null)
{
if (! loc.getLanguage().equals(""))
{
sb.append("_");
sb.append(loc.getLanguage());
}
if (! loc.getCountry().equals(""))
{
sb.append("_");
sb.append(loc.getCountry());
}
if (! loc.getVariant().equals(""))
{
sb.append("_");
sb.append(loc.getVariant());
}
}
sb.append(".xml");
String result = sb.toString();
if (logger.isDebugEnabled()) logger.debug("Resolving bundle name to file name: " + name + ", locale " + loc + " --> " + result);
return result;
}
}
1.1 jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/i18n/AbstractResourceBundle.java
Index: AbstractResourceBundle.java
===================================================================
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.avalon.excalibur.i18n;
import java.util.Map;
import java.util.Locale;
import org.apache.log.Logger;
import org.apache.avalon.framework.logger.Loggable;
import org.apache.avalon.framework.component.Component;
public abstract class AbstractResourceBundle
implements ResourceBundle, Component, Loggable {
/** Logger */
protected Logger logger;
/** Bundle name */
private String name = "";
/** Locale of the bundle */
private Locale locale;
/** Parent of the current bundle */
private ResourceBundle parent = null;
/** Last modification time */
private long lastModified = -1;
/**
* Set the logger.
*
* @param logger the logger
*/
public void setLogger( final Logger logger ) {
this.logger = logger;
}
/**
* Get the name of the bundle.
*
* @return the name
*/
public String getName() {
return this.name;
}
/**
* Set the name of the bundle.
*
* @param name the name
*/
public void setName(String name) {
this.name = name;
}
/**
* Gets the locale of the bundle.
*
* @return the locale
*/
public Locale getLocale() {
return this.locale;
}
/**
* Sets the locale of the bundle.
*
* @param name the locale
*/
public void setLocale(Locale locale) {
this.locale = locale;
}
/**
* Get the parent bundle of the current bundle.
*
* @return the parent bundle
*/
public ResourceBundle getParent() {
return this.parent;
}
/**
* Set the parent bundle of the current bundle.
*
* @param parent the parent bundle
*/
public void setParent(ResourceBundle parent) {
this.parent = parent;
}
/**
* Returns the last modification time of this bundle, in milliseconds.
*
* @return last modification time, -1 if N/A
*/
public long getLastModified() {
return this.lastModified;
}
/**
* Sets the last modification time of this bundle, in milliseconds.
*
* @param lastModified last modification time
*/
public void setLastModified(long lastModified) {
this.lastModified = lastModified;
}
/**
* Get value by key and substitute variables.
*
* @param key key
* @param variables map with variable values
* @return value with variable values substituted
* @exception MissingResourceException if value was not found
*/
public String getString(String key, Map variables) {
return convertKey(getString(key));
}
/**
* Convert the "user view" of the lookup key to the
* "system view". Used to hide the implemented storage
* mechanism and/or XML file schema.
*
* The default implementation just returns the key "as-is".
*
* @param key user key
* @return system key
*/
public String convertKey(String userKey) {
return userKey;
}
/**
* Substitute the "variables" in the string with the values
* provided in the map.
*
* @param value value where to search for variables
* @param dictionary map with variable values
* @return value with variable values substituted
*/
public String substitute(String value, Map values) {
if (value == null || values == null) return value;
StringBuffer result = new StringBuffer(value.length());
int startPos = 0;
int endPos = 0;
int lastPos = value.length();
Object varValue = "";
String varKey = "", oldKey = "";
while (endPos < lastPos) {
startPos = endPos;
endPos = value.indexOf('{', startPos);
if (endPos == -1)
endPos = lastPos;
result.append(value.substring(startPos, endPos));
if (endPos < lastPos)
endPos++;
if (endPos < lastPos) {
startPos = endPos;
endPos = value.indexOf('}', startPos);
if (endPos == -1)
endPos = lastPos;
oldKey = varKey;
varKey = value.substring(startPos, endPos);
if (!oldKey.equals(varKey))
varValue = values.get(varKey);
if (varValue != null) {
if (logger.isDebugEnabled()) logger.debug("Substituting var: " + varKey + " --> " + varValue);
result.append(varValue);
}
else {
if (logger.isWarnEnabled()) logger.warn(name + ": var not found: " + varKey);
result.append('{').append(varKey).append('}');
}
if (endPos < lastPos)
endPos++;
}
}
return result.toString();
}
}
--
To unsubscribe, e-mail: <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>