1 8 package org.apache.avalon.excalibur.i18n; 9 10 11 import org.apache.avalon.framework.activity.Disposable; 12 import org.apache.avalon.framework.activity.Initializable; 13 import org.apache.avalon.framework.component.Composable; 14 import org.apache.avalon.framework.component.Component; 15 import org.apache.avalon.framework.component.ComponentManager; 16 import org.apache.avalon.framework.configuration.Configurable; 17 import org.apache.avalon.framework.configuration.Configuration; 18 import org.apache.avalon.framework.configuration.ConfigurationException; 19 import org.apache.avalon.excalibur.xml.xpath.XPathProcessor; 20 import org.apache.avalon.excalibur.xml.Parser; 21 import org.apache.avalon.excalibur.source.Source; 22 import org.apache.avalon.excalibur.source.SourceResolver; 23 import org.apache.avalon.excalibur.source.SourceUtil; 24 import org.w3c.dom.Document ; 25 import org.w3c.dom.Node ; 26 import org.w3c.dom.NodeList ; 27 import org.w3c.dom.NamedNodeMap ; 28 import org.xml.sax.InputSource ; 29 30 import java.util.HashMap ; 31 import java.util.Locale ; 32 import java.util.Map ; 33 import java.util.MissingResourceException ; 34 35 41 public class XmlBundle extends AbstractBundle implements Configurable, Initializable, Disposable, Composable { 42 43 44 public static class ConfigurationKeys { 45 public static final String LOAD_ON_INIT = "load-on-init"; 46 public static final String USE_ROOT = "use-root-element"; 47 } 48 49 50 private Map cache = new HashMap (); 51 52 53 private Map cacheNotFound = new HashMap (); 54 55 56 private Document doc; 57 58 59 protected ComponentManager manager = null; 60 61 62 private XPathProcessor processor = null; 63 64 65 private BundleInfoMapper mapper; 66 67 68 private String prefix; 69 70 71 private String suffix; 72 73 74 private boolean loadOnInit = true; 75 76 77 private boolean useRootElement = false; 78 79 public void compose(ComponentManager manager) { 80 this.manager = manager; 81 try { 82 this.processor = (XPathProcessor)this.manager.lookup(XPathProcessor.ROLE); 83 this.mapper = (BundleInfoMapper)this.manager.lookup(BundleInfoMapper.ROLE); 84 } catch (Exception e) { 85 getLogger().error("cannot obtain XPathProcessor", e); 86 } 87 } 88 89 public void configure(Configuration configuration) throws ConfigurationException { 90 this.loadOnInit = configuration.getAttributeAsBoolean(ConfigurationKeys.LOAD_ON_INIT, true); 91 this.useRootElement = configuration.getAttributeAsBoolean(ConfigurationKeys.USE_ROOT, false); 92 } 93 94 99 public void initialize() throws Exception { 100 initialize(getMapper().map(getBundleInfo())); 101 } 102 103 111 public void initialize(String uri) throws Exception { 112 SourceResolver resolver = (SourceResolver) this.manager.lookup(SourceResolver.ROLE); 113 initialize(resolver.resolve(uri)); 114 this.manager.release(resolver); 115 } 116 117 125 public void initialize(Source source) throws Exception { 126 initialize( SourceUtil.getInputSource( source ) ); 127 } 128 129 137 public void initialize(InputSource inSource) throws Exception { 138 Parser parser = (Parser) this.manager.lookup(Parser.ROLE); 139 this.doc = parser.parseDocument(inSource); 140 load(); 141 } 142 143 148 private void load() throws Exception { 149 if (this.loadOnInit) { 150 cacheAll(doc.getDocumentElement(), useRootElement ? '/' + doc.getDocumentElement().getTagName() : ""); 151 } 152 } 153 154 164 public String convertKey(String userKey) { 165 return '/' + userKey.replace('.', '/'); 166 } 167 168 173 public Document getDocument() { 174 return this.doc; 175 } 176 177 183 protected boolean cacheContains(String key) { 184 boolean result = cache.containsKey(key); 185 if (getLogger().isDebugEnabled()) getLogger().debug(getBundleInfo() + ": cache contains key '" + key + "': " + result); 186 return result; 187 } 188 189 195 protected boolean cacheNotFoundContains(String key) { 196 boolean result = cacheNotFound.containsKey(key); 197 if (getLogger().isDebugEnabled()) getLogger().debug(getBundleInfo() + ": cache_not_found contains key '" + key + "': " + result); 198 return result; 199 } 200 201 207 protected void cacheKey(String key, String value) { 208 if (getLogger().isDebugEnabled()) getLogger().debug(getBundleInfo() + ": caching: " + key + " = " + value); 209 cache.put(key, value); 210 } 211 212 217 protected void cacheNotFoundKey(String key) { 218 if (getLogger().isDebugEnabled()) getLogger().debug(getBundleInfo() + ": caching not_found: " + key); 219 cacheNotFound.put(key, ""); 220 } 221 222 228 protected String getFromCache(String key) { 229 if (getLogger().isDebugEnabled()) getLogger().debug(getBundleInfo() + ": returning from cache: " + key); 230 return (String ) cache.get(key); 231 } 232 233 240 protected void cacheAll(Node parent, String pathToParent) { 241 NodeList children = parent.getChildNodes(); 242 int childnum = children.getLength(); 243 244 for(int i = 0; i < childnum; i++) { 245 Node child = children.item(i); 246 247 if(child.getNodeType() == Node.ELEMENT_NODE) { 248 StringBuffer pathToChild = new StringBuffer (pathToParent).append('/').append(child.getNodeName()); 249 250 NamedNodeMap attrs = child.getAttributes(); 251 if(attrs != null) { 252 Node temp = null; 253 String pathToAttr = null; 254 int attrnum = attrs.getLength(); 255 for(int j = 0; j < attrnum; j++) { 256 temp = attrs.item(j); 257 if (!temp.getNodeName().equalsIgnoreCase("xml:lang")) 258 pathToChild.append("[@").append(temp.getNodeName()) 259 .append("='").append(temp.getNodeValue()) 260 .append("']"); 261 } 262 } 263 264 String childValue = getTextValue(child); 265 if(childValue != null) 266 cacheKey(pathToChild.toString(), childValue); 267 else 268 cacheAll(child, pathToChild.toString()); 269 } 270 } 271 } 272 273 280 public String getString(String key) throws MissingResourceException { 281 String value = _getString(convertKey(key)); 282 if (value == null) 283 throw new MissingResourceException ( 284 "Unable to locate resource: " + key, 285 XmlBundle.class.getName(), 286 key); 287 else 288 return value; 289 } 290 291 297 protected String _getString(String key) { 298 if (key == null) return null; 299 String value = getFromCache(key); 300 301 if (value == null && !cacheNotFoundContains(key)) 302 { 303 if (doc != null) 304 value = _getString(this.doc.getDocumentElement(), key); 305 306 if (value == null) 307 { 308 if (getParent() != null) 309 value = getParent().getString(key); 310 } 311 312 if (value != null) 313 cacheKey(key, value); 314 else 315 cacheNotFoundKey(key); 316 } 317 return value; 318 } 319 320 327 protected String _getString(Node node, String key) { 328 String value = null; 329 try { 330 value = getTextValue(_getNode(node, key)); 331 } 332 catch (Exception e) { 333 getLogger().error(getBundleInfo() + ": error while locating resource: " + key, e); 334 } 335 return value; 336 } 337 338 344 protected static String getTextValue(Node element) { 345 if (element == null) return null; 346 NodeList list = element.getChildNodes(); 347 int listsize = list.getLength(); 348 349 Node item = null; 350 String itemValue = null; 351 352 for(int i = 0; i < listsize; i++) { 353 item = list.item(i); 354 if(item.getNodeType() != Node.TEXT_NODE) 355 return null; 356 357 itemValue = item.getNodeValue(); 358 if(itemValue == null) 359 return null; 360 361 itemValue = itemValue.trim(); 362 if(itemValue.length() == 0) 363 return null; 364 365 return itemValue; 366 } 367 return null; 368 } 369 370 376 protected Node _getNode(String key) { 377 return _getNode(this.doc.getDocumentElement(), key); 378 } 379 380 388 protected Node _getNode(Node rootNode, String key) { 389 Node node = null; 390 try { 391 node = this.processor.selectSingleNode(rootNode, key); 392 } 393 catch (Exception e) { 394 getLogger().error("Error while locating resource with key: " + key, e); 395 } 396 return node; 397 } 398 399 public void dispose() { 400 this.manager.release((Component)this.processor); 401 } 402 } 403 | Popular Tags |