123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400 |
- /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /* $Id$ */
-
- package org.apache.fop.util;
-
- import java.io.IOException;
- import java.io.InputStream;
- import java.security.AccessController;
- import java.security.PrivilegedAction;
- import java.util.Enumeration;
- import java.util.Hashtable;
- import java.util.Locale;
- import java.util.Map;
- import java.util.MissingResourceException;
- import java.util.Properties;
- import java.util.ResourceBundle;
- import java.util.Stack;
-
- import javax.xml.transform.Transformer;
- import javax.xml.transform.TransformerException;
- import javax.xml.transform.sax.SAXResult;
- import javax.xml.transform.sax.SAXTransformerFactory;
- import javax.xml.transform.stream.StreamSource;
-
- import org.xml.sax.Attributes;
- import org.xml.sax.SAXException;
- import org.xml.sax.helpers.DefaultHandler;
-
- import org.apache.xmlgraphics.util.QName;
-
- /**
- * This class is a ResourceBundle that loads its contents from XML files instead of properties
- * files (like PropertiesResourceBundle).
- * <p>
- * The XML format for this resource bundle implementation is the following
- * (the same as Apache Cocoon's XMLResourceBundle):
- * <pre>
- * <catalogue xml:lang="en">
- * <message key="key1">Message <br/> Value 1</message>
- * <message key="key2">Message <br/> Value 1</message>
- * ...
- * </catalogue>
- * </pre>
- */
- public class XMLResourceBundle extends ResourceBundle {
-
- //Note: Some code here has been copied and adapted from Apache Harmony!
-
- private Properties resources = new Properties();
-
- private Locale locale;
-
- private static SAXTransformerFactory tFactory
- = (SAXTransformerFactory)SAXTransformerFactory.newInstance();
-
- /**
- * Creates a resource bundle from an InputStream.
- * @param in the stream to read from
- * @throws IOException if an I/O error occurs
- */
- public XMLResourceBundle(InputStream in) throws IOException {
- try {
- Transformer transformer = tFactory.newTransformer();
- StreamSource src = new StreamSource(in);
- SAXResult res = new SAXResult(new CatalogueHandler());
- transformer.transform(src, res);
- } catch (TransformerException e) {
- throw new IOException("Error while parsing XML resource bundle: " + e.getMessage());
- }
- }
-
- /**
- * Gets a resource bundle using the specified base name, default locale, and class loader.
- * @param baseName the base name of the resource bundle, a fully qualified class name
- * @param loader the class loader from which to load the resource bundle
- * @return a resource bundle for the given base name and the default locale
- * @throws MissingResourceException if no resource bundle for the specified base name can be
- * found
- * @see java.util.ResourceBundle#getBundle(String)
- */
- public static ResourceBundle getXMLBundle(String baseName, ClassLoader loader)
- throws MissingResourceException {
- return getXMLBundle(baseName, Locale.getDefault(), loader);
- }
-
- /**
- * Gets a resource bundle using the specified base name, locale, and class loader.
- * @param baseName the base name of the resource bundle, a fully qualified class name
- * @param locale the locale for which a resource bundle is desired
- * @param loader the class loader from which to load the resource bundle
- * @return a resource bundle for the given base name and locale
- * @throws MissingResourceException if no resource bundle for the specified base name can be
- * found
- * @see java.util.ResourceBundle#getBundle(String, Locale, ClassLoader)
- */
- public static ResourceBundle getXMLBundle(String baseName, Locale locale, ClassLoader loader)
- throws MissingResourceException {
- if (loader == null) {
- throw new NullPointerException("loader must not be null");
- }
- if (baseName == null) {
- throw new NullPointerException("baseName must not be null");
- }
- assert locale != null;
- ResourceBundle bundle;
- if (!locale.equals(Locale.getDefault())) {
- bundle = handleGetXMLBundle(baseName, "_" + locale, false, loader);
- if (bundle != null) {
- return bundle;
- }
- }
- bundle = handleGetXMLBundle(baseName, "_" + Locale.getDefault(), true, loader);
- if (bundle != null) {
- return bundle;
- }
- throw new MissingResourceException(
- baseName + " (" + locale + ")", baseName + '_' + locale, null);
- }
-
- static class MissingBundle extends ResourceBundle {
- public Enumeration getKeys() {
- return null;
- }
-
- public Object handleGetObject(String name) {
- return null;
- }
- }
-
- private static final ResourceBundle MISSING = new MissingBundle();
- private static final ResourceBundle MISSINGBASE = new MissingBundle();
-
- private static Map cache = new java.util.WeakHashMap();
- //<Object, Hashtable<String, ResourceBundle>>
-
- private static ResourceBundle handleGetXMLBundle(String base, String locale,
- boolean loadBase, final ClassLoader loader) {
- XMLResourceBundle bundle = null;
- String bundleName = base + locale;
- Object cacheKey = loader != null ? (Object) loader : (Object) "null";
- Hashtable loaderCache; //<String, ResourceBundle>
- synchronized (cache) {
- loaderCache = (Hashtable)cache.get(cacheKey);
- if (loaderCache == null) {
- loaderCache = new Hashtable();
- cache.put(cacheKey, loaderCache);
- }
- }
- ResourceBundle result = (ResourceBundle)loaderCache.get(bundleName);
- if (result != null) {
- if (result == MISSINGBASE) {
- return null;
- }
- if (result == MISSING) {
- if (!loadBase) {
- return null;
- }
- String extension = strip(locale);
- if (extension == null) {
- return null;
- }
- return handleGetXMLBundle(base, extension, loadBase, loader);
- }
- return result;
- }
-
- final String fileName = bundleName.replace('.', '/') + ".xml";
- InputStream stream = (InputStream)AccessController
- .doPrivileged(new PrivilegedAction() {
- public Object run() {
- return loader == null
- ? ClassLoader.getSystemResourceAsStream(fileName)
- : loader.getResourceAsStream(fileName);
- }
- });
- if (stream != null) {
- try {
- try {
- bundle = new XMLResourceBundle(stream);
- } finally {
- stream.close();
- }
- bundle.setLocale(locale);
- } catch (IOException e) {
- throw new MissingResourceException(e.getMessage(), base, null);
- }
- }
-
- String extension = strip(locale);
- if (bundle != null) {
- if (extension != null) {
- ResourceBundle parent = handleGetXMLBundle(base, extension, true,
- loader);
- if (parent != null) {
- bundle.setParent(parent);
- }
- }
- loaderCache.put(bundleName, bundle);
- return bundle;
- }
-
- if (extension != null) {
- ResourceBundle fallback = handleGetXMLBundle(base, extension, loadBase, loader);
- if (fallback != null) {
- loaderCache.put(bundleName, fallback);
- return fallback;
- }
- }
- loaderCache.put(bundleName, loadBase ? MISSINGBASE : MISSING);
- return null;
- }
-
- private void setLocale(String name) {
- String language = "";
- String country = "";
- String variant = "";
- if (name.length() > 1) {
- int nextIndex = name.indexOf('_', 1);
- if (nextIndex == -1) {
- nextIndex = name.length();
- }
- language = name.substring(1, nextIndex);
- if (nextIndex + 1 < name.length()) {
- int index = nextIndex;
- nextIndex = name.indexOf('_', nextIndex + 1);
- if (nextIndex == -1) {
- nextIndex = name.length();
- }
- country = name.substring(index + 1, nextIndex);
- if (nextIndex + 1 < name.length()) {
- variant = name.substring(nextIndex + 1, name.length());
- }
- }
- }
- this.locale = new Locale(language, country, variant);
- }
-
- private static String strip(String name) {
- int index = name.lastIndexOf('_');
- if (index != -1) {
- return name.substring(0, index);
- }
- return null;
- }
-
- private Enumeration getLocalKeys() {
- return (Enumeration)resources.propertyNames();
- }
-
- /** {@inheritDoc} */
- public Locale getLocale() {
- return this.locale;
- }
-
- /** {@inheritDoc} */
- public Enumeration getKeys() {
- if (parent == null) {
- return getLocalKeys();
- }
- return new Enumeration() {
- private Enumeration local = getLocalKeys();
- private Enumeration pEnum = parent.getKeys();
-
- private Object nextElement;
-
- private boolean findNext() {
- if (nextElement != null) {
- return true;
- }
- while (pEnum.hasMoreElements()) {
- Object next = pEnum.nextElement();
- if (!resources.containsKey(next)) {
- nextElement = next;
- return true;
- }
- }
- return false;
- }
-
- public boolean hasMoreElements() {
- if (local.hasMoreElements()) {
- return true;
- }
- return findNext();
- }
-
- public Object nextElement() {
- if (local.hasMoreElements()) {
- return local.nextElement();
- }
- if (findNext()) {
- Object result = nextElement;
- nextElement = null;
- return result;
- }
- // Cause an exception
- return pEnum.nextElement();
- }
- };
- }
-
- /** {@inheritDoc} */
- protected Object handleGetObject(String key) {
- if (key == null) {
- throw new NullPointerException("key must not be null");
- }
- return resources.get(key);
- }
-
- /** {@inheritDoc} */
- public String toString() {
- return "XMLResourceBundle: " + getLocale();
- }
-
- private class CatalogueHandler extends DefaultHandler {
-
- private static final String CATALOGUE = "catalogue";
- private static final String MESSAGE = "message";
-
- private StringBuffer valueBuffer = new StringBuffer();
- private Stack elementStack = new Stack();
- private String currentKey;
-
- private boolean isOwnNamespace(String uri) {
- return ("".equals(uri));
- }
-
- private QName getParentElementName() {
- return (QName)elementStack.peek();
- }
-
- /** {@inheritDoc} */
- public void startElement(String uri, String localName, String qName,
- Attributes atts) throws SAXException {
- super.startElement(uri, localName, qName, atts);
- QName elementName = new QName(uri, qName);
- if (isOwnNamespace(uri)) {
- if (CATALOGUE.equals(localName)) {
- //nop
- } else if (MESSAGE.equals(localName)) {
- if (!CATALOGUE.equals(getParentElementName().getLocalName())) {
- throw new SAXException(MESSAGE + " must be a child of " + CATALOGUE);
- }
- this.currentKey = atts.getValue("key");
- } else {
- throw new SAXException("Invalid element name: " + elementName);
- }
- } else {
- //ignore
- }
- this.valueBuffer.setLength(0);
- elementStack.push(elementName);
- }
-
- /** {@inheritDoc} */
- public void endElement(String uri, String localName, String qName) throws SAXException {
- super.endElement(uri, localName, qName);
- elementStack.pop();
- if (isOwnNamespace(uri)) {
- if (CATALOGUE.equals(localName)) {
- //nop
- } else if (MESSAGE.equals(localName)) {
- if (this.currentKey == null) {
- throw new SAXException(
- "current key is null (attribute 'key' might be mistyped)");
- }
- resources.put(this.currentKey, this.valueBuffer.toString());
- this.currentKey = null;
- }
- } else {
- //ignore
- }
- this.valueBuffer.setLength(0);
- }
-
- /** {@inheritDoc} */
- public void characters(char[] ch, int start, int length) throws SAXException {
- super.characters(ch, start, length);
- valueBuffer.append(ch, start, length);
- }
-
- }
-
- }
|