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 22:38:57 UTC
cvs commit: jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/i18n AbstractBundle.java Bundle.java BundleInfo.java BundleInfoMapper.java BundleLoader.java BundleMatcher.java BundleSelector.java DefaultBundleLoader.java FlatXmlBundle.java XmlBundle.java DefaultMapper.java DirectoryMapper.java AbstractResourceBundle.java FlatXMLResourceBundle.java LocaleToUriMapper.java PrefixedMapper.java ResourceBundle.java ResourceBundleSelector.java XMLResourceBundle.java
neeme 01/10/30 13:38:57
Modified: src/scratchpad/org/apache/avalon/excalibur/i18n
DefaultMapper.java DirectoryMapper.java
Added: src/scratchpad/org/apache/avalon/excalibur/i18n
AbstractBundle.java Bundle.java BundleInfo.java
BundleInfoMapper.java BundleLoader.java
BundleMatcher.java BundleSelector.java
DefaultBundleLoader.java FlatXmlBundle.java
XmlBundle.java
Removed: src/scratchpad/org/apache/avalon/excalibur/i18n
AbstractResourceBundle.java
FlatXMLResourceBundle.java LocaleToUriMapper.java
PrefixedMapper.java ResourceBundle.java
ResourceBundleSelector.java XMLResourceBundle.java
Log:
Changes:
* renamed all classes :-), to make the names shorter. Resourcebundles are from now on called simply bundles.
* added a notion of BundleLoaders that are more or less object factories for different bundles + they are responsible for extended functionality for pre-loading all bundles when Avalon/Cocoon/whatever starts up the first time
* added BundleInfo helper class, to encapsulate all possible parameters the bundle selection process could depend on
* BundleSelector now properly implements the Selector interface, as there is only one "hint" object (BundleInfo) passed to the .select() method
* the whole system is highly configurable and supports pluggable Bundle, BundleLoader and BundleInfoMapper implementations
* added the notion of bundlematchers that enable multiple bundle implementations to be used in parallel (matched against BundleInfo) in a working system... but I'm still not sure about the implementation, though...
Revision Changes Path
1.2 +6 -5 jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/i18n/DefaultMapper.java
Index: DefaultMapper.java
===================================================================
RCS file: /home/cvs/jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/i18n/DefaultMapper.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- DefaultMapper.java 2001/10/29 23:10:24 1.1
+++ DefaultMapper.java 2001/10/30 21:38:56 1.2
@@ -14,18 +14,20 @@
* 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 $
+ * @version CVS $Revision: 1.2 $ $Date: 2001/10/30 21:38:56 $ $Author: neeme $
*/
-public class DefaultMapper extends PrefixedMapper {
+public class DefaultMapper implements BundleInfoMapper {
/**
* 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());
+ public String map(BundleInfo bundleInfo) {
+ String name = bundleInfo.getName();
+ Locale loc = bundleInfo.getLocale();
+ StringBuffer sb = new StringBuffer();
sb.append('/').append(name);
if (loc != null)
{
@@ -48,7 +50,6 @@
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.2 +6 -5 jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/i18n/DirectoryMapper.java
Index: DirectoryMapper.java
===================================================================
RCS file: /home/cvs/jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/i18n/DirectoryMapper.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- DirectoryMapper.java 2001/10/29 23:10:24 1.1
+++ DirectoryMapper.java 2001/10/30 21:38:56 1.2
@@ -14,18 +14,20 @@
* 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 $
+ * @version CVS $Revision: 1.2 $ $Date: 2001/10/30 21:38:56 $ $Author: neeme $
*/
-public class DirectoryMapper extends PrefixedMapper {
+public class DirectoryMapper implements BundleInfoMapper {
/**
* 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());
+ public String map(BundleInfo bundleInfo) {
+ String name = bundleInfo.getName();
+ Locale loc = bundleInfo.getLocale();
+ StringBuffer sb = new StringBuffer();
if (loc != null) {
String lang = loc.getLanguage();
String country = loc.getCountry();
@@ -38,7 +40,6 @@
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/AbstractBundle.java
Index: AbstractBundle.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 AbstractBundle
implements Bundle, Component, Loggable {
/** Logger */
protected Logger logger;
/** bundle info */
private BundleInfo bundleInfo;
/** Parent of the current bundle */
private Bundle 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 bundle info.
*/
public BundleInfo getBundleInfo() {
return this.bundleInfo;
}
/**
* Set the bundle info.
*/
public void setBundleInfo(BundleInfo bundleInfo) {
this.bundleInfo = bundleInfo;
}
/**
* Get the parent bundle of the current bundle.
*
* @return the parent bundle
*/
public Bundle getParent() {
return this.parent;
}
/**
* Set the parent bundle of the current bundle.
*
* @param parent the parent bundle
*/
public void setParent(Bundle 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(bundleInfo + ": var not found: " + varKey);
result.append('{').append(varKey).append('}');
}
if (endPos < lastPos)
endPos++;
}
}
return result.toString();
}
}
1.1 jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/i18n/Bundle.java
Index: Bundle.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/30 21:38:56 $ $Author: neeme $
*/
public interface Bundle {
/**
* 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 bundle info.
*/
public BundleInfo getBundleInfo();
/**
* Set the bundle info.
*/
public void setBundleInfo(BundleInfo bundleInfo);
/**
* Get the parent bundle of the current bundle.
*
* @return the parent bundle
*/
public Bundle getParent();
/**
* Set the parent bundle of the current bundle.
*
* @param parent the parent bundle
*/
void setParent(Bundle 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/BundleInfo.java
Index: BundleInfo.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/30 21:38:56 $ $Author: neeme $
*/
public class BundleInfo {
private String name;
private Locale locale;
private String ext;
public BundleInfo(String name, Locale locale, String ext) {
this.name = name;
this.locale = locale;
this.ext = ext;
}
public BundleInfo(String name, Locale locale) {
this(name, locale, null);
}
public BundleInfo(Locale locale) {
this(null, locale);
}
public String getName() {
return this.name;
}
public Locale getLocale() {
return this.locale;
}
public String getExtensionParameter() {
return this.ext;
}
public String toString() {
return "BundleInfo(" + this.name + "," + this.locale + "," + this.ext + ")";
}
public BundleInfo getParent() {
if (this.locale != null && !this.locale.getLanguage().equals(""))
return new BundleInfo(this.name, this.getParentLocale(), this.ext);
else
return null;
}
/**
* 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 newloc;
if (this.locale.getVariant().equals("")) {
if (this.locale.getCountry().equals(""))
newloc = new Locale("","","");
else
newloc = new Locale(this.locale.getLanguage(), "", "");
}
else
newloc = new Locale(this.locale.getLanguage(), this.locale.getCountry(), "");
return newloc;
}
}
1.1 jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/i18n/BundleInfoMapper.java
Index: BundleInfoMapper.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;
/**
* Used to map bundle information to string representation (e.g. URI),
* to find the relevant bundle.
*
* @author <a href="mailto:neeme@apache.org">Neeme Praks</a>
* @version CVS $Revision: 1.1 $ $Date: 2001/10/30 21:38:56 $ $Author: neeme $
*/
public interface BundleInfoMapper {
/**
* Get the string form of the bundle, based on bundle info.
*
* @return the string form
*/
public String map(BundleInfo bundleInfo);
}
1.1 jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/i18n/BundleLoader.java
Index: BundleLoader.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.configuration.Configurable;
/**
* 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/30 21:38:56 $ $Author: neeme $
*/
public interface BundleLoader extends Configurable {
/**
* Load a bundle, based on bundleInfo.
*
* @return the bundle
*/
public Bundle loadBundle(BundleInfo bundleInfo);
public void setBundleSelector(BundleSelector bundleSelector);
}
1.1 jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/i18n/BundleMatcher.java
Index: BundleMatcher.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.List;
import java.util.LinkedList;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
/**
* Used to map bundle information to string representation (e.g. URI),
* to find the relevant bundle.
*
* @author <a href="mailto:neeme@apache.org">Neeme Praks</a>
* @version CVS $Revision: 1.1 $ $Date: 2001/10/30 21:38:56 $ $Author: neeme $
*/
public abstract class BundleMatcher implements Configurable {
private List matchers = new LinkedList();
private String type;
/**
* Get the string form of the bundle, based on bundle info.
*
* @return the string form
*/
public abstract boolean match(BundleInfo bundleInfo);
public String getType(BundleInfo bundleInfo) {
if (match(bundleInfo)) {
for (int i = 0; i < matchers.size(); i++) {
String type = ((BundleMatcher) matchers.get(i)).getType(bundleInfo);
if (type != null) return type;
}
return this.type;
}
return null;
}
/**
* Configure the component.
*
* @param configuration the configuration
*/
public void configure(Configuration configuration) throws ConfigurationException {
this.type = configuration.getAttribute("type");
Configuration[] matcherConfs = configuration.getChildren("matcher");
for (int i = 0; i < matcherConfs.length; i++) {
BundleMatcher matcher = getBundleMatcherInstance(configuration.getAttribute("class"));
matcher.configure(matcherConfs[i]);
this.matchers.add(matcher);
}
}
private BundleMatcher getBundleMatcherInstance(String className) throws ConfigurationException {
try {
return (BundleMatcher) Class.forName(className).newInstance();
}
catch (Exception e) {
throw new ConfigurationException("unable to load bundleMatcher", e);
}
}
}
1.1 jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/i18n/BundleSelector.java
Index: BundleSelector.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.HashMap;
import java.util.List;
import java.util.LinkedList;
import java.util.Locale;
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;
/**
* 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: BundleSelector.java,v 1.1 2001/10/30 21:38:56 neeme Exp $
*/
public class BundleSelector
extends DefaultComponentSelector
implements Configurable, Loggable, ThreadSafe, Composable
{
/**
* The role implemented by an <code>BundleSelector</code>.
*/
String ROLE = "org.apache.avalon.excalibur.i18n.BundleSelector";
/** Component Manager */
protected ComponentManager manager = null;
public void compose(ComponentManager manager) {
this.manager = manager;
}
/** Cache for the names of the bundles that were not found */
protected Map cacheNotFound = new HashMap();
/** Map of all bundle loaders */
private Map loaders = new HashMap();
/** List of matchers */
private List matchers = new LinkedList();
/** the default loader */
private BundleLoader defaultLoader;
/** 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 {
Configuration[] loaderConfs = configuration.getChild("loaders").getChildren("loader");
for (int i = 0; i < loaderConfs.length; i++) {
BundleLoader loader = (BundleLoader) getInstance(loaderConfs[i].getAttribute("class"));
loader.configure(loaderConfs[i]);
loader.setBundleSelector(this);
this.loaders.put(loaderConfs[i].getAttribute("type-name"), loader);
}
this.defaultLoader = (BundleLoader) this.loaders.get(configuration.getChild("matchers").getAttribute("default-type"));
if (defaultLoader == null) throw new ConfigurationException("default loader not specified (matchers/@default-type)");
Configuration[] matcherConfs = configuration.getChild("matchers").getChildren("matcher");
for (int i = 0; i < matcherConfs.length; i++) {
BundleMatcher matcher = (BundleMatcher) getInstance(configuration.getAttribute("class"));
matcher.configure(matcherConfs[i]);
this.matchers.add(matcher);
}
}
private Object getInstance(String className) throws ConfigurationException {
try {
return Class.forName(className).newInstance();
}
catch (Exception e) {
throw new ConfigurationException("unable to load object", e);
}
}
/**
* 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(Object hint) throws ComponentException {
Component bundle = select((BundleInfo) hint);
if (bundle == null)
throw new ComponentException("Unable to locate bundle: " + hint);
return bundle;
}
/**
* 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(new BundleInfo(name, new Locale(localeName, localeName)));
}
/**
* 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(BundleInfo bundleInfo) {
if (logger.isDebugEnabled()) logger.debug("_getBundle: " + bundleInfo);
Bundle bundle = (Bundle) selectCached(bundleInfo);
if (bundle == null && !isNotFoundBundle(bundleInfo)) {
if (logger.isDebugEnabled()) logger.debug("not found in cache, loading: " + bundleInfo);
synchronized(this) {
bundle = (Bundle) selectCached(bundleInfo);
if (bundle == null && !isNotFoundBundle(bundleInfo)) {
if (logger.isDebugEnabled()) logger.debug("synchronized: not found in cache, loading: " + bundleInfo);
bundle = loadBundle(bundleInfo);
BundleInfo parentBundleInfo = bundleInfo.getParent();
while (bundle == null && parentBundleInfo != null) {
if (logger.isDebugEnabled()) logger.debug("synchronized: still not found, trying parent: " + parentBundleInfo);
parentBundleInfo = bundleInfo.getParent();
bundle = loadBundle(parentBundleInfo);
updateCache(parentBundleInfo, bundle);
}
updateCache(bundleInfo, bundle);
}
}
}
return (Component) bundle;
}
private Bundle loadBundle(BundleInfo bundleInfo) {
String type = null;
for (int i = 0; i < matchers.size(); i++) {
type = ((BundleMatcher) matchers.get(i)).getType(bundleInfo);
if (type != null) break;
}
BundleLoader loader = null;
if (type != null)
loader = (BundleLoader) loaders.get(type);
if (loader == null)
loader = defaultLoader;
return loader.loadBundle(bundleInfo);
}
/**
* Selects a bundle from the cache.
*
* @param fileName file name of the bundle
* @return the cached bundle; null, if not found
*/
protected Component selectCached(BundleInfo bundleInfo) {
Component bundle = null;
try {
bundle = super.select(bundleInfo);
if (logger.isDebugEnabled()) logger.debug("Returning from cache: " + bundleInfo);
}
catch (ComponentException e) {
if (logger.isDebugEnabled()) logger.debug("Not found in cache: " + bundleInfo);
}
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(BundleInfo bundleInfo) {
BundleInfo result = (BundleInfo)(cacheNotFound.get(bundleInfo));
if (result != null) {
if (logger.isDebugEnabled()) logger.debug("Returning from not_found_cache: " + bundleInfo);
}
else {
if (logger.isDebugEnabled()) logger.debug("Not found in not_found_cache: " + bundleInfo);
}
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(BundleInfo bundleInfo, Bundle bundle) {
if (bundle == null) {
if (logger.isDebugEnabled()) logger.debug("Updating not_found_cache: " + bundleInfo);
cacheNotFound.put(bundleInfo, bundleInfo);
}
else {
if (logger.isDebugEnabled()) logger.debug("Updating cache: " + bundleInfo);
super.put((Object) bundleInfo, (Component) bundle);
}
}
}
1.1 jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/i18n/DefaultBundleLoader.java
Index: DefaultBundleLoader.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.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.component.Composable;
import org.apache.avalon.framework.component.ComponentManager;
/**
* 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/30 21:38:56 $ $Author: neeme $
*/
public class DefaultBundleLoader implements BundleLoader, Loggable, Composable {
/** Constants for configuration keys */
public static class ConfigurationKeys {
public static final String PREFIX = "prefix";
public static final String SUFFIX = "suffix";
public static final String BUNDLE = "bundle";
public static final String MAPPER = "mapper";
public static final String CACHE_ALL = "preload-all-values";
}
/** FQCN of the returned bundles */
private String bundleClassName;
/** FQCN of the used bundle info mapper */
private String bundleInfoMapperClassName;
/** bundle info mapper */
private BundleInfoMapper mapper;
/** cache all bundle values when bundles are created */
private boolean cacheAll;
/** bundle name prefix */
private String prefix;
/** bundle name suffix */
private String suffix;
/** bundle selector */
protected BundleSelector selector;
/** The logger */
protected Logger logger;
/** Component Manager */
protected ComponentManager manager = null;
/**
* Set the logger.
*
* @param logger the logger
*/
public void setLogger(final Logger logger) {
this.logger = logger;
}
/**
* Set the bundle selector.
*
* @param logger the selector
*/
public void setBundleSelector(BundleSelector selector) {
this.selector = selector;
}
public void compose(ComponentManager manager) {
this.manager = manager;
}
/**
* Configure the component.
*
* @param configuration the configuration
*/
public void configure(Configuration configuration) throws ConfigurationException {
this.bundleClassName = configuration.getAttribute(ConfigurationKeys.BUNDLE);
this.bundleInfoMapperClassName = configuration.getAttribute(ConfigurationKeys.MAPPER);
this.cacheAll = configuration.getAttributeAsBoolean(ConfigurationKeys.CACHE_ALL, true);
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 = "";
}
try {
this.suffix = configuration.getChild(ConfigurationKeys.SUFFIX, true).getValue();
}
catch (ConfigurationException e) {
if (logger.isWarnEnabled()) logger.warn("Suffix not provided in configuration, using none.");
this.suffix = "";
}
if (logger.isDebugEnabled()) {
logger.debug(
"BundleLoader configured with bundle=" + this.bundleClassName +
", mapper=" + this.bundleInfoMapperClassName +
", prefix='" + this.prefix +
"' and suffix='" + this.suffix + "'"
);
}
try {
this.mapper = (BundleInfoMapper) Class.forName(this.bundleInfoMapperClassName).newInstance();
}
catch (Exception e) {
throw new ConfigurationException("unable to load mapper", e);
}
}
protected Bundle getBundleInstance() {
try {
return (Bundle) Class.forName(this.bundleClassName).newInstance();
}
catch (Exception e) {
logger.error("could not create bundle instance", e);
}
return null;
}
/**
* Returns the bundle info mapper
*
* @return the mapper
*/
protected BundleInfoMapper getMapper() {
return this.mapper;
}
/**
* Should we pre-cache all the values for the bundles created by this
* loader?
*/
protected boolean cacheAllValues() {
return this.cacheAll;
}
/**
* Returns the prefix to all bundle names.
*
* @return the prefix
*/
public String getPrefix() {
return this.prefix;
}
/**
* Returns the suffix to all bundle names.
*
* @return the suffix
*/
public String getSuffix() {
return this.suffix;
}
/**
* Load a bundle, based on bundleInfo.
*
* @return the bundle
*/
public Bundle loadBundle(BundleInfo bundleInfo) {
if (logger.isDebugEnabled()) logger.debug("Mapping bundle: " + bundleInfo);
String uri = getPrefix() + getMapper().map(bundleInfo) + getSuffix();
Bundle bundle = null;
Bundle parentBundle = null;
BundleInfo parentBundleInfo = bundleInfo.getParent();
try {
if (logger.isDebugEnabled()) logger.debug("Loading bundle from URI: " + uri);
if (parentBundleInfo != null)
parentBundle = (Bundle) selector.select(parentBundleInfo);
bundle = getBundleInstance();
if (bundle instanceof Loggable) ((Loggable)bundle).setLogger(logger);
bundle.setBundleInfo(bundleInfo);
bundle.setParent(parentBundle);
if (bundle instanceof Composable) ((Composable)bundle).compose(this.manager);
bundle.init(uri, cacheAllValues());
bundle.setLastModified(System.currentTimeMillis());
}
catch (Exception e) {
logger.error("Error while loading bundle: " + bundleInfo + ", uri " + uri, e);
bundle = null;
}
return bundle;
}
}
1.1 jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/i18n/FlatXmlBundle.java
Index: FlatXmlBundle.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@apache.org">Neeme Praks</a>
* @version $Id: FlatXmlBundle.java,v 1.1 2001/10/30 21:38:56 neeme Exp $
*/
public class FlatXmlBundle extends XmlBundle {
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/XmlBundle.java
Index: XmlBundle.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;
/** JDK 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.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
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@apache.org">Neeme Praks</a>
* @author <a href="mailto:oleg@one.lv">Oleg Podolsky</a>
* @version $Id: XmlBundle.java,v 1.1 2001/10/30 21:38:56 neeme Exp $
*/
public class XmlBundle extends AbstractBundle
implements Disposable, Composable {
/** DOM factory */
private static DocumentBuilderFactory docfactory =
DocumentBuilderFactory.newInstance();
/** Cache for storing string values for existing XPaths */
private Map cache = new HashMap();
/** Cache for storing non-existing XPaths */
private Map cacheNotFound = new HashMap();
/** DOM-tree containing the bundle content */
private Document doc;
/** Component Manager */
protected ComponentManager manager = null;
/** XPath Processor */
private XPathProcessor processor = null;
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 fileName name of the XML source file
* @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: " + getBundleInfo());
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 String convertKey(String userKey) {
return '/' + userKey.replace('.', '/');
}
/**
* Load the DOM tree, based on the file name.
*
* @param fileName name of the XML source file
* @return the DOM tree
* @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
*/
protected static Document loadResourceBundle(String fileName)
throws IOException, ParserConfigurationException, SAXException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
return builder.parse(fileName);
}
/**
* Gets the source DOM tree of the bundle.
*
* @return the DOM tree
*/
public Document getDocument() {
return this.doc;
}
/**
* 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
*/
protected boolean cacheContains(String key) {
if (logger.isDebugEnabled()) logger.debug(getBundleInfo() + ": cache contains: " + key);
return cache.containsKey(key);
}
/**
* Does the "key-not-found-cache" contain such key?
*
* @param key the key to the value to be returned
* @return true if contains, false otherwise
*/
protected boolean cacheNotFoundContains(String key) {
if (logger.isDebugEnabled()) logger.debug(getBundleInfo() + ": cache_not_found contains: " + key);
return cacheNotFound.containsKey(key);
}
/**
* Cache the key and value in "key-cache".
*
* @param key the key
* @param value the value
*/
protected void cacheKey(String key, String value) {
if (logger.isDebugEnabled()) logger.debug(getBundleInfo() + ": caching: " + key + " = " + value);
cache.put(key, value);
}
/**
* Cache the key in "key-not-found-cache".
*
* @param key the key
*/
protected void cacheNotFoundKey(String key) {
if (logger.isDebugEnabled()) logger.debug(getBundleInfo() + ": caching not_found: " + key);
cacheNotFound.put(key, "");
}
/**
* Gets the value by the key from the "key-cache".
*
* @param key the key
* @return the value
*/
protected String getFromCache(String key) {
if (logger.isDebugEnabled()) logger.debug(getBundleInfo() + ": returning from cache: " + key);
return (String) cache.get(key);
}
/**
* Steps through the bundle tree and stores all text element values
* in bundle's cache. Also stores attributes for all element nodes.
*
* @param parent parent node, must be an element
* @param pathToParent XPath to the parent node
*/
protected void cacheAll(Node parent, String pathToParent) {
NodeList children = parent.getChildNodes();
int childnum = children.getLength();
for(int i = 0; i < childnum; i++) {
Node child = children.item(i);
if(child.getNodeType() == Node.ELEMENT_NODE) {
StringBuffer pathToChild = new StringBuffer(pathToParent).append('/').append(child.getNodeName());
NamedNodeMap attrs = child.getAttributes();
if(attrs != null) {
Node temp = null;
String pathToAttr = null;
int attrnum = attrs.getLength();
for(int j = 0; j < attrnum; j++) {
temp = attrs.item(j);
if (!temp.getNodeName().equalsIgnoreCase("xml:lang"))
pathToChild.append("[@").append(temp.getNodeName())
.append("='").append(temp.getNodeValue())
.append("']");
}
}
String childValue = getTextValue(child);
if(childValue != null)
cacheKey(pathToChild.toString(), childValue);
else
cacheAll(child, pathToChild.toString());
}
}
}
/**
* Get value by key.
*
* @param key 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,
XmlBundle.class.getName(),
key);
else
return value;
}
/**
* Get value by key.
*
* @param key the key
* @return the value
*/
protected String _getString(String key) {
if (key == null) return null;
String value = getFromCache(key);
if (value == null && !cacheNotFoundContains(key))
{
if (doc != null)
value = _getString(this.doc.getDocumentElement(), key);
if (value == null)
{
if (getParent() != null)
value = getParent().getString(key);
}
if (value != null)
cacheKey(key, value);
else
cacheNotFoundKey(key);
}
return value;
}
/**
* Get value by key from a concrete node.
*
* @param node the node
* @param key the key
* @return the value
*/
protected String _getString(Node node, String key) {
String value = null;
try {
value = getTextValue(_getNode(node, key));
}
catch (Exception e) {
logger.error(getBundleInfo() + ": error while locating resource: " + key, e);
}
return value;
}
/**
* Get the text value of the node.
*
* @param node the node
* @return the value
*/
protected static String getTextValue(Node element) {
if (element == null) return null;
NodeList list = element.getChildNodes();
int listsize = list.getLength();
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;
return itemValue;
}
return null;
}
/**
* Get the node with the supplied XPath key.
*
* @param key the key
* @return the node
*/
protected Node _getNode(String key) {
return _getNode(this.doc.getDocumentElement(), key);
}
/**
* Get the node with the supplied XPath key, starting from concrete
* root node.
*
* @param rootNode the root node
* @param key the key
* @return the node
*/
protected Node _getNode(Node rootNode, String key) {
Node node = null;
try {
node = this.processor.selectSingleNode(rootNode, key);
}
catch (Exception e) {
logger.error("Error while locating resource with key: " + key, e);
}
return node;
}
public void dispose() {
this.manager.release((Component)this.processor);
}
}
--
To unsubscribe, e-mail: <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>