cocoon-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jheym...@apache.org
Subject svn commit: r330548 [48/132] - in /cocoon/whiteboard/maven2/cocoon-flat-layout: ./ cocoon-ajax-block/ cocoon-ajax-block/api/ cocoon-ajax-block/api/src/ cocoon-ajax-block/api/src/main/ cocoon-ajax-block/api/src/main/java/ cocoon-ajax-block/api/src/main/...
Date Thu, 03 Nov 2005 14:00:48 GMT
Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/generation/XPathTraversableGenerator.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/generation/XPathTraversableGenerator.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/generation/XPathTraversableGenerator.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/generation/XPathTraversableGenerator.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,291 @@
+/*
+ * Copyright 1999-2005 The Apache Software Foundation.
+ *
+ * Licensed 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.
+ */
+package org.apache.cocoon.generation;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.avalon.framework.logger.Logger;
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.cocoon.ProcessingException;
+import org.apache.cocoon.components.source.SourceUtil;
+import org.apache.cocoon.environment.Context;
+import org.apache.cocoon.environment.ObjectModelHelper;
+import org.apache.cocoon.environment.SourceResolver;
+import org.apache.cocoon.xml.dom.DOMStreamer;
+import org.apache.excalibur.source.TraversableSource;
+import org.apache.excalibur.xml.xpath.PrefixResolver;
+import org.apache.excalibur.xml.xpath.XPathProcessor;
+import org.apache.regexp.RE;
+import org.apache.regexp.RESyntaxException;
+import org.w3c.dom.Document;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+/**
+ * Generates an XML collection listing performing XPath queries on XML sources.
+ * It can be used both as a plain TraversableGenerator or, if an XPath is
+ * specified, it will perform an XPath query on every XML resource, where "xml
+ * resource" is, by default, any resource ending with ".xml", which can be
+ * overriden by setting the (regexp) pattern "xmlFiles as a sitemap parameter,
+ * or where the name of the resource has a container-wide mime-type mapping to
+ * 'text/xml' such as specified by mime-mapping elements in a web.xml
+ * descriptor file.
+ *
+ * The XPath can be specified in two ways:
+ * <ol>
+ *    <li>By using an XPointerish syntax in the URL: everything following the
+ *         pound                 sign                 (possiby preceding  query
+ * string arguments)  will be treated as the XPath;
+ *     </li>
+ *     <li>Specifying it as a sitemap parameter named "xpath"
+ *  </ol>
+ *
+ * Sample usage:
+ *
+ * Sitemap:
+ * &lt;map:match pattern="documents/**"&gt;
+ *   &lt;map:generate type="xpathdirectory"
+ *     src="    docs/{1}#/article/title|/article/abstract" &gt;
+ *     &lt;          map:parameter name="xmlFiles" value="\.xml$"/&gt;
+ * &lt;/map:generate&gt;
+ * &lt;map: serialize type="xml" /&gt; &lt;/map:match&gt;
+ *
+ * Request:
+ *   http://www.some.host/documents/test
+ * Result:
+ * &lt;collection:collection
+ *   name="test" lastModified="1010400942000"
+ *   date="1/7/02 11:55 AM" requested="true"
+ *   xmlns:collection="http://apache.org/cocoon/collection/1.0"&gt;
+ *   &lt;collection:collection name="subdirectory" lastModified="1010400942000" date="1/7/02 11:55 AM" /&gt;
+ *   &lt;collection:resource name="test.xml" lastModified="1011011579000" date="1/14/02 1:32 PM"&gt;
+ *     &lt;collection:xpath docid="test.xml" query="/article/title"&gt;
+ *       &lt;title&gt;This is a test document&lt;/title&gt;
+ *       &lt;abstract&gt;
+ *         &lt;para&gt;Abstract of my test article&lt;/para&gt;
+ *       &lt;/abstract&gt;
+ *     &lt;/collection:xpath&gt;
+ *   &lt;/collection:resource&gt;
+ *   &lt;collection:resource name="test.gif" lastModified="1011011579000" date="1/14/02 1:32 PM"&gt;
+ * &lt;/collection:collection&gt;
+ *
+ * If you need to use namespaces, you can set them as sitemap parameters in
+ * the form:
+ * lt;map:parameter name="xmlns:<i>your prefix</i>" value="nsURI"/**"&gt;
+ *
+ * @author <a href="mailto:gianugo@apache.org">Gianugo Rabellino</a>
+ * @author <a href="mailto:d.madama@pro-netics.com">Daniele Madama</a>
+ * @version CVS $Id: XPathTraversableGenerator.java 240318 2005-08-26 19:26:46Z vgritsenko $
+ */
+public class XPathTraversableGenerator extends TraversableGenerator {
+
+    /** Local name for the element that contains the included XML snippet. */
+    protected static final String XPATH_NODE_NAME = "xpath";
+    /** Attribute for the XPath query. */
+    protected static final String QUERY_ATTR_NAME = "query";
+    /** The document containing a successful XPath query */
+    protected static final String RESULT_DOCID_ATTR = "docid";
+
+    /** The regular expression for the XML files pattern. */
+    protected RE xmlRE;
+
+    /** The document that should be parsed and (partly) included. */
+    protected Document doc;
+
+    /** The XPath. */
+    protected String xpath;
+
+    /** The XPath processor. */
+    protected XPathProcessor processor;
+
+    /** The prefix resolver for namespaced queries */
+    protected XPathPrefixResolver prefixResolver;
+
+    /** The cocoon context used for mime-type mappings */
+    protected Context context;
+
+
+    public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par)
+    throws ProcessingException, SAXException, IOException {
+        super.setup(resolver, objectModel, src, par);
+
+        // See if an XPath was specified
+        int pointer;
+        if ((pointer = this.source.indexOf("#")) != -1) {
+            int endpointer = this.source.indexOf('?');
+            if (endpointer != -1) {
+                this.xpath = source.substring(pointer + 1, endpointer);
+            } else {
+                this.xpath = source.substring(pointer + 1);
+            }
+            this.source = src.substring(0, pointer);
+            if (endpointer != -1) {
+                this.source += src.substring(endpointer);
+            }
+        } else {
+            this.xpath = par.getParameter("xpath", null);
+        }
+        this.cacheKeyParList.add(this.xpath);
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug("Applying XPath: " + xpath + " to collection " + source);
+        }
+
+        String xmlFilesPattern = null;
+        try {
+            xmlFilesPattern = par.getParameter("xmlFiles", "\\.xml$");
+            this.cacheKeyParList.add(xmlFilesPattern);
+            this.xmlRE = new RE(xmlFilesPattern);
+            if (this.getLogger().isDebugEnabled()) {
+                this.getLogger().debug("pattern for XML files: " + xmlFilesPattern);
+            }
+        } catch (RESyntaxException rese) {
+            throw new ProcessingException("Syntax error in regexp pattern '"
+                    + xmlFilesPattern + "'", rese);
+        }
+
+        String[] params = par.getNames();
+        this.prefixResolver = new XPathPrefixResolver(this.getLogger());
+        for (int i = 0; i < params.length; i++) {
+            if (params[i].startsWith("xmlns:")) {
+                String paramValue = par.getParameter(params[i], "");
+                String paramName = params[i].substring(6);
+                if (getLogger().isDebugEnabled()) {
+                    getLogger().debug("add param to prefixResolver: " + paramName);
+                }
+                this.prefixResolver.addPrefix(paramName, paramValue);
+            }
+        }
+
+        this.context = ObjectModelHelper.getContext(objectModel);
+    }
+
+    public void service(ServiceManager manager) throws ServiceException {
+        super.service(manager);
+        processor = (XPathProcessor)manager.lookup(XPathProcessor.ROLE);
+    }
+
+    public void dispose() {
+        if ( this.manager != null ) {
+            this.manager.release( processor );
+            this.processor = null;
+        }
+        super.dispose();
+    }
+
+    protected void addContent(TraversableSource source)
+    throws SAXException, ProcessingException {
+        super.addContent(source);
+        if (!source.isCollection() && isXML(source) && xpath != null) {
+            performXPathQuery(source);
+        }
+    }
+
+    /**
+     * Determines if a given TraversableSource shall be handled as XML.
+     *
+     * @param path  the TraversableSource to check
+     * @return true  if the given TraversableSource shall handled as XML, false
+     * otherwise.
+     */
+    protected boolean isXML(TraversableSource path) {
+        String mimeType = this.context.getMimeType(path.getName());
+        return this.xmlRE.match(path.getName()) || "text/xml".equalsIgnoreCase(mimeType);
+    }
+
+    /**
+     * Performs an XPath query on the source.
+     * @param in  the Source the XPath is performed on.
+     * @throws SAXException  if something goes wrong while adding the XML snippet.
+     */
+    protected void performXPathQuery(TraversableSource in) throws SAXException {
+        doc = null;
+        try {
+            doc = SourceUtil.toDOM(this.manager, "text/xml", in);
+        } catch (SAXException se) {
+            getLogger().error("Warning:" + in.getName() + " is not a valid XML document. Ignoring");
+        } catch (Exception e) {
+            this.getLogger().error("Unable to resolve and parse document" + e);
+        }
+        if (doc != null) {
+            NodeList nl = processor.selectNodeList(doc.getDocumentElement(), xpath, this.prefixResolver);
+            final String id = in.getName();
+            AttributesImpl attributes = new AttributesImpl();
+            attributes.addAttribute("", RESULT_DOCID_ATTR, RESULT_DOCID_ATTR," CDATA", id);
+            attributes.addAttribute("", QUERY_ATTR_NAME, QUERY_ATTR_NAME, "CDATA",xpath);
+            super.contentHandler.startElement(URI, XPATH_NODE_NAME, PREFIX + ":" + XPATH_NODE_NAME, attributes);
+            DOMStreamer ds = new DOMStreamer(super.xmlConsumer);
+            for (int i = 0; i < nl.getLength(); i++) {
+                ds.stream(nl.item(i));
+            }
+            super.contentHandler.endElement(URI, XPATH_NODE_NAME, PREFIX + ":" + XPATH_NODE_NAME);
+        }
+    }
+
+    /**
+     * Recycle resources
+     *
+     */
+    public void recycle() {
+        this.xpath = null;
+        this.doc = null;
+        this.xmlRE = null;
+        this.prefixResolver = null;
+        this.context = null;
+        super.recycle();
+    }
+
+    /**
+     * A brain-dead PrefixResolver implementation
+     */
+    class XPathPrefixResolver implements PrefixResolver {
+
+        private Map params;
+
+        private Logger logger;
+
+        public XPathPrefixResolver(Logger logger) {
+            this.params = new HashMap();
+            this.logger = logger;
+        }
+
+        /**
+         * Get a namespace URI given a prefix.
+         *
+         * @see org.apache.excalibur.xml.xpath.PrefixResolver#prefixToNamespace(java.lang.String)
+         */
+        public String prefixToNamespace(String prefix) {
+            if (this.logger.isDebugEnabled()) {
+                this.logger.debug("prefix: " + prefix);
+            }
+            if (this.params.containsKey(prefix)) {
+                if(this.logger.isDebugEnabled()) {
+                    this.logger.debug("prefix; " + prefix + " - namespace: " + this.params.get(prefix));
+                }
+                return (String) this.params.get(prefix);
+            }
+            return null;
+        }
+
+        public void addPrefix(String prefix, String uri) {
+            this.params.put(prefix, uri);
+        }
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/generation/XPathTraversableGenerator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/i18n/Bundle.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/i18n/Bundle.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/i18n/Bundle.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/i18n/Bundle.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,49 @@
+/*
+ * Copyright 1999-2005 The Apache Software Foundation.
+ *
+ * Licensed 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.
+ */
+package org.apache.cocoon.i18n;
+
+import java.util.MissingResourceException;
+
+/**
+ * Resource bundle component interface.
+ * Provide the minimal number of methods to be used for i18n.
+ *
+ * @author <a href="mailto:kpiroumian@apache.org">Konstantin Piroumian</a>
+ * @version $Id: Bundle.java 312970 2005-10-11 22:50:06Z vgritsenko $
+ */
+public interface Bundle {
+
+    String ROLE = Bundle.class.getName();
+
+    /**
+     * Get string value by key.
+     *
+     * @param key
+     * @return Resource as string.
+     * @exception MissingResourceException if resource was not found
+     */
+    String getString(String key) throws MissingResourceException;
+
+    /**
+     * Get object value by key.
+     *
+     * @param key The resource key.
+     * @return The resource as object.
+     * @exception MissingResourceException if resource was not found
+     */
+    Object getObject(String key) throws MissingResourceException;
+
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/i18n/Bundle.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/i18n/BundleFactory.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/i18n/BundleFactory.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/i18n/BundleFactory.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/i18n/BundleFactory.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,127 @@
+/*
+ * Copyright 1999-2005 The Apache Software Foundation.
+ *
+ * Licensed 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.
+ */
+package org.apache.cocoon.i18n;
+
+import java.util.Locale;
+
+/**
+ * Bundle Factory implementations are responsible for loading and providing
+ * particular types of resource bundles, implementors of Bundle interface.
+ *
+ * @author <a href="mailto:kpiroumian@apache.org">Konstantin Piroumian</a>
+ * @author <a href="mailto:vgritsenko@apache.org">Vadim Gritsenko</a>
+ * @version $Id: BundleFactory.java 312970 2005-10-11 22:50:06Z vgritsenko $
+ */
+public interface BundleFactory {
+
+    /**
+     * Bundle factory ROLE name
+     */
+    String ROLE = BundleFactory.class.getName();
+
+    /**
+     * Constants for bundle factory configuration keys
+     */
+    static class ConfigurationKeys {
+        /**
+         * Configuration element specifying default location of the
+         * resource bundles.
+         *
+         * @see BundleFactory#select(String, String)
+         * @see BundleFactory#select(String, java.util.Locale)
+         */
+        public static final String ROOT_DIRECTORY = "catalogue-location";
+
+        /**
+         * Configuration element specifying role of the Store instance to use
+         * for storing cached bundles
+         * @since 2.1.8
+         */
+        public static final String STORE_ROLE = "store-role";
+
+        /**
+         * Configuration element specifying delay (in ms) between
+         * reload checks.
+         * @since 2.1.8
+         */
+        public static final String RELOAD_INTERVAL = "reload-interval";
+    }
+
+    /**
+     * Select a bundle based on the catalogue base location, bundle name,
+     * and the locale name.
+     *
+     * @param base    catalogue base location (URI)
+     * @param bundleName    bundle name
+     * @param locale  locale name
+     * @return        the bundle
+     * @exception     Exception if a bundle is not found
+     */
+    Bundle select(String base, String bundleName, String locale) throws Exception;
+
+    /**
+     * Select a bundle based on the catalogue base location, bundle name,
+     * and the locale.
+     *
+     * @param base    catalogue base location (URI)
+     * @param bundleName    bundle name
+     * @param locale  locale
+     * @return        the bundle
+     * @exception     Exception if a bundle is not found
+     */
+    Bundle select(String base, String bundleName, Locale locale) throws Exception;
+
+    /**
+     * Select a bundle based on the catalogue base location, bundle name,
+     * and the locale.
+     *
+     * @param directories    catalogue base location (URI)
+     * @param bundleName    bundle name
+     * @param locale  locale
+     * @return        the bundle
+     * @exception     Exception if a bundle is not found
+     */
+    Bundle select(String[] directories, String bundleName, Locale locale) throws Exception;
+
+    /**
+     * Select a bundle based on the bundle name and the locale name from
+     * the default catalogue.
+     *
+     * @param bundleName    bundle name
+     * @param locale  locale name
+     * @return        the bundle
+     * @exception     Exception if a bundle is not found
+     */
+    Bundle select(String bundleName, String locale) throws Exception;
+
+    /**
+     * Select a bundle based on the bundle name and the locale from
+     * the default catalogue.
+     *
+     * @param bundleName    bundle name
+     * @param locale  locale
+     * @return        the bundle
+     * @exception     Exception if a bundle is not found
+     */
+    Bundle select(String bundleName, Locale locale) throws Exception;
+
+    /**
+     * Releases a bundle back to the bundle factory when it's not needed
+     * anymore.
+     * @param bundle the bundle
+     */
+    void release(Bundle bundle);
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/i18n/BundleFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/i18n/I18nUtils.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/i18n/I18nUtils.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/i18n/I18nUtils.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/i18n/I18nUtils.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,245 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ *
+ * Licensed 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.
+ */
+package org.apache.cocoon.i18n;
+
+import org.apache.avalon.framework.parameters.Parameters;
+
+import org.apache.cocoon.environment.Cookie;
+import org.apache.cocoon.environment.ObjectModelHelper;
+import org.apache.cocoon.environment.Request;
+import org.apache.cocoon.environment.Session;
+import org.apache.cocoon.environment.Response;
+
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+/**
+ * A utility class for i18n formatting and parsing routing.
+ *
+ * @author <a href="mailto:kpiroumian@apache.org">Konstantin Piroumian</a>
+ * @author <a href="mailto:vgritsenko@apache.org">Vadim Gritsenko</a>
+ * @version $Id: I18nUtils.java 312970 2005-10-11 22:50:06Z vgritsenko $
+ */
+public class I18nUtils {
+
+    // Locale string delimiter
+    private static final String LOCALE_DELIMITER = "_-@.";
+
+    private I18nUtils() {
+        // Disable instantiation
+    }
+
+    /**
+     * Parses given locale string to Locale object. If the string is null
+     * then the given locale is returned.
+     *
+     * @param localeString a string containing locale in
+     * <code>language_country_variant</code> format.
+     * @param defaultLocale returned if localeString is <code>null</code>
+     */
+    public static Locale parseLocale(String localeString, Locale defaultLocale) {
+        if (localeString != null) {
+            StringTokenizer st = new StringTokenizer(localeString,
+                                                     LOCALE_DELIMITER);
+            String l = st.hasMoreElements() ? st.nextToken()
+                                            : defaultLocale.getLanguage();
+            String c = st.hasMoreElements() ? st.nextToken() : "";
+            String v = st.hasMoreElements() ? st.nextToken() : "";
+            return new Locale(l, c, v);
+        }
+
+        return defaultLocale;
+    }
+
+    /**
+     * Parses given locale string to Locale object. If the string is null
+     * then the VM default locale is returned.
+     *
+     * @param localeString a string containing locale in
+     * <code>language_country_variant</code> format.
+     *
+     * @see #parseLocale(String, Locale)
+     * @see java.util.Locale#getDefault()
+     */
+    public static Locale parseLocale(String localeString) {
+        return parseLocale(localeString, Locale.getDefault());
+    }
+
+
+    /**
+     * Callback interface for
+     * {@link I18nUtils#findLocale(Map, String, Parameters, Locale, boolean, boolean, boolean, I18nUtils.LocaleValidator)}
+     * @since 2.1.6
+     */
+    public interface LocaleValidator {
+
+        /**
+         * @param name of the locale (for debugging)
+         * @param locale to test
+         * @return true if locale satisfies validator's criteria
+         */
+        public boolean test(String name, Locale locale);
+    }
+
+    /**
+     * Find a suitable locale from an objectModel.
+     * @since 2.1.6
+     * @return locale found, or null if none found.
+     */
+    public static Locale findLocale(Map objectModel,
+                                    String attribute,
+                                    Parameters parameters,
+                                    Locale defaultLocale,
+                                    boolean useLocale,
+                                    boolean useLocales,
+                                    boolean useBlankLocale,
+                                    LocaleValidator test) {
+        String localeStr;
+        Locale locale;
+
+        Request request = ObjectModelHelper.getRequest(objectModel);
+
+        // 1. Request parameter 'locale'
+        localeStr = request.getParameter(attribute);
+        if (localeStr != null) {
+            locale = parseLocale(localeStr);
+            if (test == null || test.test("request", locale)) {
+                return locale;
+            }
+        }
+
+        // 2. Session attribute 'locale'
+        Session session = request.getSession(false);
+        if (session != null &&
+                ((localeStr = (String) session.getAttribute(attribute)) != null)) {
+            locale = parseLocale(localeStr);
+            if (test == null || test.test("session", locale)) {
+                return locale;
+            }
+        }
+
+        // 3. First matching cookie parameter 'locale' within each cookie sent
+        Cookie[] cookies = request.getCookies();
+        if (cookies != null) {
+            for (int i = 0; i < cookies.length; i++) {
+                Cookie cookie = cookies[i];
+                if (cookie.getName().equals(attribute)) {
+                    localeStr = cookie.getValue();
+                    locale = parseLocale(localeStr);
+                    if (test == null || test.test("cookie", locale)) {
+                        return locale;
+                    }
+                    break;
+                }
+            }
+        }
+
+        // 4. Sitemap parameter "locale"
+        if (parameters != null) {
+            localeStr = parameters.getParameter("locale", null);
+            if (localeStr != null) {
+                locale = parseLocale(localeStr);
+                if (test == null || test.test("sitemap", locale)) {
+                    return locale;
+                }
+            }
+        }
+
+        // 5. Locale setting of the requesting browser or server default
+        if (useLocale && !useLocales) {
+            locale = request.getLocale();
+            if (test == null || test.test("request", locale)) {
+                return locale;
+            }
+        }
+        if (useLocales) {
+            Enumeration locales = request.getLocales();
+            while (locales.hasMoreElements()) {
+                locale = (Locale)locales.nextElement();
+                if (test == null || test.test("request", locale)) {
+                    return locale;
+                }
+            }
+        }
+
+        // 6. Default
+        if (defaultLocale != null) {
+            locale = defaultLocale;
+            if (test == null || test.test("default", locale)) {
+                return locale;
+            }
+        }
+
+        // 7. Blank
+        if (useBlankLocale) {
+            locale = new Locale("", "");
+            if (test == null || test.test("blank", locale)) {
+                return locale;
+            }
+        }
+
+        // 8. Fail
+        return null;
+    }
+
+    /**
+     * Find a suitable locale from an objectModel.
+     * @since 2.1.6
+     * @return locale found, or server default (never null).
+     */
+    public static Locale findLocale(Map objectModel,
+                                    String attribute,
+                                    Parameters parameters,
+                                    Locale defaultLocale,
+                                    boolean useLocale) {
+        return findLocale(objectModel, attribute, parameters, defaultLocale, useLocale, false, false, null);
+    }
+
+    /**
+     * Store locale in request, session, or cookie.
+     * @since 2.1.6
+     */
+    public static void storeLocale(Map objectModel,
+                                   String attribute,
+                                   String locale,
+                                   boolean storeInRequest,
+                                   boolean storeInSession,
+                                   boolean storeInCookie,
+                                   boolean createSession) {
+        // store in a request if so configured
+        if (storeInRequest) {
+            Request request = ObjectModelHelper.getRequest(objectModel);
+            request.setAttribute(attribute, locale);
+        }
+
+        // store in session if so configured
+        if (storeInSession) {
+            Request request = ObjectModelHelper.getRequest(objectModel);
+            Session session = request.getSession(createSession);
+            if (session != null) {
+                session.setAttribute(attribute, locale);
+            }
+        }
+
+        // store in a cookie if so configured
+        if (storeInCookie) {
+            Response response = ObjectModelHelper.getResponse(objectModel);
+            response.addCookie(response.createCookie(attribute, locale));
+        }
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/i18n/I18nUtils.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/i18n/XMLResourceBundle.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/i18n/XMLResourceBundle.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/i18n/XMLResourceBundle.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/i18n/XMLResourceBundle.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,410 @@
+/*
+ * Copyright 1999-2005 The Apache Software Foundation.
+ *
+ * Licensed 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.
+ */
+package org.apache.cocoon.i18n;
+
+import org.apache.avalon.framework.logger.AbstractLogEnabled;
+import org.apache.excalibur.source.Source;
+import org.apache.excalibur.source.SourceNotFoundException;
+import org.apache.excalibur.source.SourceResolver;
+import org.apache.excalibur.source.SourceValidity;
+import org.apache.excalibur.source.impl.validity.ExpiresValidity;
+
+import org.apache.cocoon.ResourceNotFoundException;
+import org.apache.cocoon.components.source.SourceUtil;
+import org.apache.cocoon.components.source.impl.validity.DelayedValidity;
+import org.apache.cocoon.xml.ParamSaxBuffer;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+
+import java.net.MalformedURLException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Implementation of <code>Bundle</code> interface for XML resources. Represents a
+ * single XML message bundle.
+ *
+ * <p>
+ * XML format for this resource bundle implementation is the following:
+ * <pre>
+ * &lt;catalogue xml:lang="en"&gt;
+ *   &lt;message key="key1"&gt;Message &lt;br/&gt; Value 1&lt;/message&gt;
+ *   &lt;message key="key2"&gt;Message &lt;br/&gt; Value 1&lt;/message&gt;
+ *   ...
+ * &lt;/catalogue&gt;
+ * </pre>
+ *
+ * <p>
+ * Value can be any well formed XML snippet and it will be cached by the key specified
+ * in the attribute <code>key</code>. Objects returned by this {@link Bundle} implementation
+ * are instances of the {@link ParamSaxBuffer} class.
+ *
+ * <p>
+ * If value for a key is not present in this bundle, parent bundle will be queried.
+ *
+ * @author <a href="mailto:dev@cocoon.apache.org">Apache Cocoon Team</a>
+ * @version $Id: XMLResourceBundle.java 327205 2005-10-21 15:00:32Z sylvain $
+ */
+public class XMLResourceBundle extends AbstractLogEnabled
+                               implements Bundle {
+
+    /**
+     * Namespace for the Bundle markup
+     */
+    public static final String NS = "http://apache.org/cocoon/i18n/2.0";
+
+    /**
+     * XML bundle root element name
+     */
+    public static final String EL_CATALOGUE = "catalogue";
+
+    /**
+     * XML bundle message element name
+     */
+    public static final String EL_MESSAGE = "message";
+
+    /**
+     * XML bundle message element's key attribute name
+     */
+    public static final String AT_KEY = "key";
+
+    /**
+     * Source URI of the bundle
+     */
+    private String sourceURI;
+
+    /**
+     * Bundle validity
+     */
+    private SourceValidity validity;
+
+    /**
+     * Locale of the bundle
+     */
+    private Locale locale;
+
+    /**
+     * Parent of the current bundle
+     */
+    protected Bundle parent;
+
+    /**
+     * Objects stored in the bundle
+     */
+    protected Map values;
+
+
+    /**
+     * Processes XML bundle file and creates map of values
+     */
+    private static class SAXContentHandler implements ContentHandler {
+        private Map values;
+        private int state;
+        private String namespace;
+        private ParamSaxBuffer buffer;
+
+        public SAXContentHandler(Map values) {
+            this.values = values;
+        }
+
+        public void setDocumentLocator(Locator arg0) {
+            // Ignore
+        }
+
+        public void startDocument() throws SAXException {
+            // Ignore
+        }
+
+        public void endDocument() throws SAXException {
+            // Ignore
+        }
+
+        public void processingInstruction(String arg0, String arg1) throws SAXException {
+            // Ignore
+        }
+
+        public void skippedEntity(String arg0) throws SAXException {
+            // Ignore
+        }
+
+        public void startElement(String ns, String localName, String qName, Attributes atts) throws SAXException {
+            switch (this.state) {
+                case 0:
+                    // <i18n:catalogue>
+                    if (!"".equals(ns) && !NS.equals(ns)) {
+                        throw new SAXException("Root element <" + EL_CATALOGUE +
+                                               "> must be non-namespaced or in i18n namespace.");
+                    }
+                    if (!EL_CATALOGUE.equals(localName)) {
+                        throw new SAXException("Root element must be <" + EL_CATALOGUE + ">.");
+                    }
+                    this.namespace = ns;
+                    this.state++;
+                    break;
+
+                case 1:
+                    // <i18n:message>
+                    if (!EL_MESSAGE.equals(localName)) {
+                        throw new SAXException("<" + EL_CATALOGUE + "> must contain <" +
+                                               EL_MESSAGE + "> elements only.");
+                    }
+                    if (!this.namespace.equals(ns)) {
+                        throw new SAXException("<" + EL_MESSAGE + "> element must be in '" +
+                                               this.namespace + "' namespace.");
+                    }
+                    String key =  atts.getValue(AT_KEY);
+                    if (key == null) {
+                        throw new SAXException("<" + EL_MESSAGE + "> must have '" +
+                                               AT_KEY + "' attribute.");
+                    }
+                    this.buffer = new ParamSaxBuffer();
+                    this.values.put(key, this.buffer);
+                    this.state++;
+                    break;
+
+                case 2:
+                    this.buffer.startElement(ns, localName, qName, atts);
+                    break;
+
+                default:
+                    throw new SAXException("Internal error: Invalid state");
+            }
+        }
+
+        public void endElement(String ns, String localName, String qName) throws SAXException {
+            switch (this.state) {
+                case 0:
+                    break;
+
+                case 1:
+                    // </i18n:catalogue>
+                    this.state--;
+                    break;
+
+                case 2:
+                    if (this.namespace.equals(ns) && EL_MESSAGE.equals(localName)) {
+                        // </i18n:message>
+                        this.buffer = null;
+                        this.state--;
+                    } else {
+                        this.buffer.endElement(ns, localName, qName);
+                    }
+                    break;
+
+                default:
+                    throw new SAXException("Internal error: Invalid state");
+            }
+        }
+
+        public void startPrefixMapping(String prefix, String uri) throws SAXException {
+            if (this.buffer != null) {
+                this.buffer.startPrefixMapping(prefix, uri);
+            }
+        }
+
+        public void endPrefixMapping(String prefix) throws SAXException {
+            if (this.buffer != null) {
+                this.buffer.endPrefixMapping(prefix);
+            }
+        }
+
+        public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
+            if (this.buffer != null) {
+                this.buffer.ignorableWhitespace(ch, start, length);
+            }
+        }
+
+        public void characters(char[] ch, int start, int length) throws SAXException {
+            if (this.buffer != null) {
+                this.buffer.characters(ch, start, length);
+            }
+        }
+    }
+
+
+    /**
+     * Construct a bundle.
+     * @param sourceURI source URI of the XML bundle
+     * @param locale locale
+     * @param parent parent bundle of this bundle
+     */
+    public XMLResourceBundle(String sourceURI, Locale locale, Bundle parent) {
+        this.sourceURI = sourceURI;
+        this.locale = locale;
+        this.parent = parent;
+        this.values = Collections.EMPTY_MAP;
+    }
+
+    /**
+     * (Re)Loads the XML bundle if necessary, based on the source URI.
+     * @return true if reloaded successfully
+     */
+    protected boolean reload(SourceResolver resolver, long interval) {
+        Source newSource = null;
+        Map newValues;
+
+        try {
+            int valid = this.validity == null ? SourceValidity.INVALID : this.validity.isValid();
+            if (valid != SourceValidity.VALID) {
+                // Saved validity is not valid, get new source and validity
+                newSource = resolver.resolveURI(this.sourceURI);
+                SourceValidity newValidity = newSource.getValidity();
+
+                if (valid == SourceValidity.INVALID || this.validity.isValid(newValidity) != SourceValidity.VALID) {
+                    newValues = new HashMap();
+                    SourceUtil.toSAX(newSource, new SAXContentHandler(newValues));
+                    synchronized (this) {
+                        // Update source validity and values
+                        if (interval > 0 && newValidity != null) {
+                            this.validity = new DelayedValidity(interval, newValidity);
+                        } else {
+                            this.validity = newValidity;
+                        }
+                        this.values = newValues;
+                    }
+                }
+            }
+
+            // Success
+            return true;
+
+        } catch (MalformedURLException e) {
+            getLogger().error("Bundle <" + this.sourceURI + "> not loaded: Invalid URI", e);
+            newValues = Collections.EMPTY_MAP;
+
+        } catch (ResourceNotFoundException e) {
+            if (getLogger().isDebugEnabled()) {
+                getLogger().info("Bundle <" + sourceURI + "> not loaded: Source URI not found", e);
+            } else if (getLogger().isInfoEnabled()) {
+                getLogger().info("Bundle <" + sourceURI + "> not loaded: Source URI not found");
+            }
+            newValues = Collections.EMPTY_MAP;
+
+        } catch (SourceNotFoundException e) {
+            // Nominal case where a bundle doesn't exist
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug("Bundle <" + sourceURI + "> not loaded: Source URI not found");
+            }
+            newValues = Collections.EMPTY_MAP;
+
+        } catch (SAXException e) {
+            getLogger().error("Bundle <" + sourceURI + "> not loaded: Invalid XML", e);
+            // Keep existing loaded values
+            newValues = this.values;
+
+        } catch (Exception e) {
+            getLogger().error("Bundle <" + sourceURI + "> not loaded: Exception", e);
+            // Keep existing loaded values
+            newValues = this.values;
+
+        } finally {
+            if (newSource != null) {
+                resolver.release(newSource);
+            }
+        }
+
+        synchronized (this) {
+            // Use expires validity to delay next reloading.
+            if (interval > 0) {
+                this.validity = new ExpiresValidity(interval);
+            } else {
+                this.validity = null;
+            }
+            this.values = newValues;
+        }
+
+        // Failure
+        return false;
+    }
+
+    /**
+     * Gets the locale of the bundle.
+     *
+     * @return the locale
+     */
+    public Locale getLocale() {
+        return this.locale;
+    }
+
+    /**
+     * Gets the source URI of the bundle.
+     *
+     * @return the source URI
+     */
+    public String getSourceURI() {
+        return this.sourceURI;
+    }
+
+    /**
+     * Gets the validity of the bundle.
+     *
+     * @return the validity
+     */
+    public SourceValidity getValidity() {
+        return this.validity;
+    }
+
+    /**
+     * Get an instance of the {@link ParamSaxBuffer} associated with the key.
+     *
+     * @param key the key
+     * @return the value, or null if no value associated with the key.
+     */
+    public Object getObject(String key) {
+        if (key == null) {
+            return null;
+        }
+
+        Object value = this.values.get(key);
+        if (value != null) {
+            return value;
+        }
+
+        if (this.parent != null) {
+            return this.parent.getObject(key);
+        }
+
+        return null;
+    }
+
+    /**
+     * Get a string representation of the value object by key.
+     *
+     * @param key the key
+     * @return the string value, or null if no value associated with the key.
+     */
+    public String getString(String key) {
+        if (key == null) {
+            return null;
+        }
+
+        Object value = this.values.get(key);
+        if (value != null) {
+            return value.toString();
+        }
+
+        if (this.parent != null) {
+            return this.parent.getString(key);
+        }
+
+        return null;
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/i18n/XMLResourceBundle.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/i18n/XMLResourceBundleFactory.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/i18n/XMLResourceBundleFactory.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/i18n/XMLResourceBundleFactory.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/i18n/XMLResourceBundleFactory.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,431 @@
+/*
+ * Copyright 1999-2005 The Apache Software Foundation.
+ *
+ * Licensed 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.
+ */
+package org.apache.cocoon.i18n;
+
+import org.apache.avalon.framework.activity.Disposable;
+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.AbstractLogEnabled;
+import org.apache.avalon.framework.logger.LogEnabled;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.Serviceable;
+import org.apache.avalon.framework.thread.ThreadSafe;
+import org.apache.excalibur.source.Source;
+import org.apache.excalibur.source.SourceException;
+import org.apache.excalibur.source.SourceNotFoundException;
+import org.apache.excalibur.source.SourceResolver;
+import org.apache.excalibur.store.Store;
+
+import org.apache.cocoon.util.NetUtils;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * This is the XMLResourceBundleFactory, the method for getting and creating
+ * XMLResourceBundles.
+ *
+ * @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>
+ * @author <a href="mailto:kpiroumian@apache.org">Konstantin Piroumian</a>
+ * @author <a href="mailto:vgritsenko@apache.org">Vadim Gritsenko</a>
+ * @version $Id: XMLResourceBundleFactory.java 315012 2005-10-12 19:36:45Z vgritsenko $
+ */
+public class XMLResourceBundleFactory extends AbstractLogEnabled
+                                      implements BundleFactory, Serviceable, Configurable,
+                                                 Disposable, ThreadSafe, LogEnabled {
+
+    /**
+     * Root directory to all bundle names
+     */
+    private String directory;
+
+    /**
+     * Reload check interval in milliseconds.
+     * Defaults to 60000 (1 minute), use <code>-1</code> to
+     * disable reloads and <code>0</code> to check for modifications
+     * on each catalogue request.
+     */
+    private long interval;
+
+    /**
+     * Service Manager
+     */
+    protected ServiceManager manager;
+
+    /**
+     * Source resolver
+     */
+    protected SourceResolver resolver;
+
+    /**
+     * Store of the loaded bundles
+     */
+    protected Store cache;
+
+
+    //
+    // Lifecycle
+    //
+
+    public void service(ServiceManager manager) throws ServiceException {
+        this.manager = manager;
+        this.resolver = (SourceResolver) this.manager.lookup(SourceResolver.ROLE);
+    }
+
+    /**
+     * Configure the component.
+     *
+     * @param configuration the configuration
+     */
+    public void configure(Configuration configuration) throws ConfigurationException {
+        this.directory = configuration.getChild(ConfigurationKeys.ROOT_DIRECTORY).getValue("");
+
+        String cacheRole = configuration.getChild(ConfigurationKeys.STORE_ROLE).getValue(Store.TRANSIENT_STORE);
+        try {
+            this.cache = (Store) this.manager.lookup(cacheRole);
+        } catch (ServiceException e) {
+            throw new ConfigurationException("Unable to lookup store '" + cacheRole + "'");
+        }
+
+        this.interval = configuration.getChild(ConfigurationKeys.RELOAD_INTERVAL).getValueAsLong(60000L);
+
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug("Bundle directory '" + this.directory + "'");
+            getLogger().debug("Store role '" + cacheRole + "'");
+        }
+    }
+
+    /**
+     * Disposes this component.
+     */
+    public void dispose() {
+        this.manager.release(this.resolver);
+        this.manager.release(this.cache);
+        this.resolver = null;
+        this.cache = null;
+        this.manager = null;
+    }
+
+    //
+    // BundleFactory Interface
+    //
+
+    /**
+     * Returns the root directory to all bundles.
+     *
+     * @return the directory path
+     */
+    protected String getDirectory() {
+        return this.directory;
+    }
+
+    /**
+     * Select a bundle based on the bundle name and the locale name.
+     *
+     * @param name        bundle name
+     * @param locale      locale name
+     * @return            the bundle
+     * @exception         Exception if a bundle is not found
+     */
+    public Bundle select(String name, String locale) throws Exception {
+        return select(getDirectory(), name, locale);
+    }
+
+    /**
+     * Select a bundle based on the bundle name and the locale.
+     *
+     * @param name        bundle name
+     * @param locale      locale
+     * @return            the bundle
+     * @exception         Exception if a bundle is not found
+     */
+    public Bundle select(String name, Locale locale) throws Exception {
+        return select(getDirectory(), name, locale);
+    }
+
+    /**
+     * Select a bundle based on the catalogue base location, bundle name,
+     * and the locale name.
+     *
+     * @param directory   catalogue base location (URI)
+     * @param name        bundle name
+     * @param localeName  locale name
+     * @return            the bundle
+     * @exception         Exception if a bundle is not found
+     */
+    public Bundle select(String directory, String name, String localeName)
+    throws Exception {
+        return select(directory, name, new Locale(localeName, localeName));
+    }
+
+    /**
+     * Select a bundle based on the catalogue base location, bundle name,
+     * and the locale.
+     *
+     * @param directory   catalogue base location (URI)
+     * @param name        bundle name
+     * @param locale      locale
+     * @return            the bundle
+     * @exception         Exception if a bundle is not found
+     */
+    public Bundle select(String directory, String name, Locale locale)
+    throws Exception {
+        return select(new String[] { directory }, name, locale);
+    }
+
+    /**
+     * Select a bundle based on the catalogue base location, bundle name,
+     * and the locale.
+     *
+     * @param directories catalogue base location (URI)
+     * @param name        bundle name
+     * @param locale      locale
+     * @return            the bundle
+     * @exception         Exception if a bundle is not found
+     */
+    public Bundle select(String[] directories, String name, Locale locale)
+    throws Exception {
+        Bundle bundle = _select(directories, 0, name, locale);
+        if (bundle == null) {
+            throw new Exception("Unable to locate resource: " + name);
+        }
+        return bundle;
+    }
+
+    public void release(Bundle bundle) {
+        // Do nothing
+    }
+
+    //
+    // Implementation
+    //
+
+    /**
+     * Select a bundle based on bundle name and locale.
+     *
+     * @param directories       catalogue location(s)
+     * @param name              bundle name
+     * @param locale            locale
+     * @return                  the bundle
+     */
+    private XMLResourceBundle _select(String[] directories, int index, String name,
+                                      Locale locale)
+    throws Exception {
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug("Selecting from: " + name + ", locale: " + locale +
+                              ", directory: " + directories[index]);
+        }
+
+        final String cacheKey = getCacheKey(directories, index, name, locale);
+
+        XMLResourceBundle bundle = selectCached(cacheKey);
+        if (bundle == null) {
+            synchronized (this) {
+                bundle = selectCached(cacheKey);
+                if (bundle == null) {
+                    boolean localeAvailable = (locale != null && !locale.getLanguage().equals(""));
+                    index++;
+
+                    // Find parent bundle first
+                    XMLResourceBundle parent = null;
+                    if (localeAvailable && index == directories.length) {
+                        // all directories have been searched with this locale,
+                        // now start again with the first directory and the parent locale
+                        parent = _select(directories, 0, name, getParentLocale(locale));
+                    } else if (index < directories.length) {
+                        // there are directories left to search for with this locale
+                        parent = _select(directories, index, name, locale);
+                    }
+
+                    // Create this bundle (if source exists) and pass parent to it.
+                    final String sourceURI = getSourceURI(directories[index - 1], name, locale);
+                    bundle = _create(sourceURI, locale, parent);
+                    updateCache(cacheKey, bundle);
+                }
+            }
+        }
+        return bundle;
+    }
+
+    /**
+     * Constructs new bundle.
+     *
+     * <p>
+     * If there is a problem loading the bundle, created bundle will be empty.
+     *
+     * @param sourceURI   source URI of the XML resource bundle
+     * @param locale      locale of the bundle
+     * @param parent      parent bundle, if any
+     * @return            the bundle
+     */
+    private XMLResourceBundle _create(String sourceURI,
+                                      Locale locale,
+                                      XMLResourceBundle parent) {
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug("Creating bundle <" + sourceURI + ">");
+        }
+
+        XMLResourceBundle bundle = new XMLResourceBundle(sourceURI, locale, parent);
+        bundle.enableLogging(getLogger());
+        bundle.reload(this.resolver, this.interval);
+        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 locale) {
+        Locale newloc;
+        if (locale.getVariant().equals("")) {
+            if (locale.getCountry().equals("")) {
+                newloc = new Locale("", "", "");
+            } else {
+                newloc = new Locale(locale.getLanguage(), "", "");
+            }
+        } else {
+            newloc = new Locale(locale.getLanguage(), locale.getCountry(), "");
+        }
+        return newloc;
+    }
+
+    /**
+     * Creates a cache key for the bundle.
+     * @return the cache key
+     */
+    protected String getCacheKey(String[] directories, int index, String name, Locale locale)
+    throws SourceException {
+        StringBuffer cacheKey = new StringBuffer("XRB");
+        for (; index < directories.length; index++) {
+            cacheKey.append(":");
+            cacheKey.append(getSourceURI(directories[index], name, locale));
+        }
+        return cacheKey.toString();
+    }
+
+    /**
+     * Maps a bundle name and locale to a bundle source URI.
+     * If you need a different mapping, then just override this method.
+     *
+     * @param base    the base URI for the catalogues
+     * @param name    the name of the catalogue
+     * @param locale  the locale of the bundle
+     * @return        the source URI for the bundle
+     */
+    protected String getSourceURI(String base, String name, Locale locale)
+    throws SourceException {
+        // If base is null default to the current location
+        if (base == null) {
+            base = "";
+        }
+
+        // Resolve base URI
+        Source src = null;
+        Map parameters = Collections.EMPTY_MAP;
+        StringBuffer sb = new StringBuffer();
+        try {
+            src = this.resolver.resolveURI(base);
+
+            // Deparameterize base URL before adding catalogue name
+            String uri = NetUtils.deparameterize(src.getURI(),
+                                                 parameters = new HashMap(7));
+
+            // Append trailing slash
+            sb.append(uri);
+            if (!uri.endsWith("/")) {
+                sb.append('/');
+            }
+
+        } catch (IOException e) {
+            throw new SourceNotFoundException("Cannot resolve catalogue base URI <" + base + ">", e);
+        } finally {
+            this.resolver.release(src);
+        }
+
+        // Append catalogue name
+        sb.append(name);
+
+        // Append catalogue locale
+        if (locale != null) {
+            if (!locale.getLanguage().equals("")) {
+                sb.append("_");
+                sb.append(locale.getLanguage());
+            }
+            if (!locale.getCountry().equals("")) {
+                sb.append("_");
+                sb.append(locale.getCountry());
+            }
+            if (!locale.getVariant().equals("")) {
+                sb.append("_");
+                sb.append(locale.getVariant());
+            }
+        }
+        sb.append(".xml");
+
+        // Reconstruct complete bundle URI with parameters
+        String uri = NetUtils.parameterize(sb.toString(), parameters);
+
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug("Resolved name: " + name +
+                              ", locale: " + locale + " --> " + uri);
+        }
+        return uri;
+    }
+
+    /**
+     * Selects a bundle from the cache, and reloads it if needed.
+     *
+     * @param cacheKey    caching key of the bundle
+     * @return            the cached bundle; null, if not found
+     */
+    protected XMLResourceBundle selectCached(String cacheKey) {
+        XMLResourceBundle bundle = (XMLResourceBundle) this.cache.get(cacheKey);
+
+        if (bundle != null && this.interval != -1) {
+            // Reload this bundle and all parent bundles, as necessary
+            for (XMLResourceBundle b = bundle; b != null; b = (XMLResourceBundle) b.parent) {
+                b.reload(this.resolver, this.interval);
+            }
+        }
+
+        return bundle;
+    }
+
+    /**
+     * Stores bundle in the cache.
+     *
+     * @param cacheKey    caching key of the bundle
+     * @param bundle      bundle to be placed in the cache
+     */
+    protected void updateCache(String cacheKey, XMLResourceBundle bundle) {
+        try {
+            this.cache.store(cacheKey, bundle);
+        } catch (IOException e) {
+            getLogger().error("Bundle <" + bundle.getSourceURI() + ">: unable to store.", e);
+        }
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/i18n/XMLResourceBundleFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/i18n/package.html
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/i18n/package.html?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/i18n/package.html (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/i18n/package.html Thu Nov  3 05:41:06 2005
@@ -0,0 +1,30 @@
+<!--
+  Copyright 1999-2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<html>
+  <head>
+    <title>Internationalization</title>
+  </head>
+  <body>
+    <h1>Internationalization support.</h1>
+    <p>
+      Internationalization bundle resource handling interfaces and default
+      implementation for XML message catalogue. 
+    </p>
+    <p>
+      Other helper classes for i18n and localization.
+    </p>
+  </body>
+</html>

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/i18n/package.html
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/matching/AbstractPreparableMatcher.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/matching/AbstractPreparableMatcher.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/matching/AbstractPreparableMatcher.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/matching/AbstractPreparableMatcher.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,41 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.
+ */
+package org.apache.cocoon.matching;
+
+import org.apache.avalon.framework.logger.AbstractLogEnabled;
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.cocoon.sitemap.PatternException;
+
+import java.util.Map;
+
+/**
+ * A matcher that can prepare patterns during sitemap setup for faster match at request time.
+ * This is also a regular matcher, meaning the sitemap can decide either to prepare the pattern
+ * or to match with a request-time evaluated pattern (for {..} substitution).
+ *
+ * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
+ * @version CVS $Id: AbstractPreparableMatcher.java 30941 2004-07-29 19:56:58Z vgritsenko $
+ */
+public abstract class AbstractPreparableMatcher extends AbstractLogEnabled implements PreparableMatcher {
+
+    /**
+     * Match the pattern by preparing it and matching the prepared pattern.
+     */
+    public Map match (String pattern, Map objectModel, Parameters parameters)
+      throws PatternException {
+        return preparedMatch(preparePattern(pattern), objectModel, parameters);
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/matching/AbstractPreparableMatcher.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/matching/AbstractRegexpMatcher.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/matching/AbstractRegexpMatcher.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/matching/AbstractRegexpMatcher.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/matching/AbstractRegexpMatcher.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,108 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.
+ */
+package org.apache.cocoon.matching;
+
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.avalon.framework.thread.ThreadSafe;
+import org.apache.cocoon.sitemap.PatternException;
+import org.apache.cocoon.sitemap.SitemapParameters;
+import org.apache.regexp.RE;
+import org.apache.regexp.RECompiler;
+import org.apache.regexp.REProgram;
+import org.apache.regexp.RESyntaxException;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Base class for all matchers using a regular expression pattern.
+ *
+ * @author <a href="mailto:Giacomo.Pati@pwr.ch">Giacomo Pati</a>
+ * @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
+ * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
+ * @version CVS $Id: AbstractRegexpMatcher.java 30941 2004-07-29 19:56:58Z vgritsenko $
+ */
+
+public abstract class AbstractRegexpMatcher extends AbstractPreparableMatcher implements ThreadSafe {
+
+    /**
+     * Compile the pattern in a <code>org.apache.regexp.REProgram</code>.
+     */
+    public Object preparePattern(String pattern) throws PatternException {
+        // if pattern is null, return null to allow throwing a located exception in preparedMatch()
+        if (pattern == null) {
+            return null;
+        }
+
+        if (pattern.length() == 0) {
+            pattern = "^$";
+            if (getLogger().isWarnEnabled()) {
+                getLogger().warn("The empty pattern string was rewritten to '^$'"
+                                 + " to match for empty strings.  If you intended"
+                                 + " to match all strings, please change your"
+                                 + " pattern to '.*'");
+            }
+        }
+
+        try {
+            RECompiler compiler = new RECompiler();
+            REProgram program = compiler.compile(pattern);
+            return program;
+
+        } catch (RESyntaxException rse) {
+            getLogger().debug("Failed to compile the pattern '" + pattern + "'", rse);
+            throw new PatternException(rse.getMessage(), rse);
+        }
+    }
+
+    /**
+     * Match the prepared pattern against the value returned by {@link #getMatchString(Map, Parameters)}.
+     */
+    public Map preparedMatch(Object preparedPattern, Map objectModel, Parameters parameters) throws PatternException {
+
+        if(preparedPattern == null) {
+            throw new PatternException("A pattern is needed at " + SitemapParameters.getStatementLocation(parameters));
+        }
+
+        RE re = new RE((REProgram)preparedPattern);
+        String match = getMatchString(objectModel, parameters);
+
+        if (match == null)
+            return null;
+
+        if(re.match(match)) {
+            /* Handle parenthesised subexpressions. XXX: could be faster if we count
+             * parens *outside* the generated code.
+             * Note: *ONE* based, not zero, zero contains complete match
+             */
+            int parenCount = re.getParenCount();
+            Map map = new HashMap();
+            for (int paren = 0; paren <= parenCount; paren++) {
+                map.put(Integer.toString(paren), re.getParen(paren));
+            }
+
+            return map;
+        }
+
+        return null;
+    }
+
+    /**
+     * Get the string to test against the regular expression. To be defined
+     * by concrete subclasses.
+     */
+    protected abstract String getMatchString(Map objectModel, Parameters parameters);
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/matching/AbstractRegexpMatcher.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/matching/AbstractWildcardMatcher.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/matching/AbstractWildcardMatcher.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/matching/AbstractWildcardMatcher.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/matching/AbstractWildcardMatcher.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,74 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.
+ */
+package org.apache.cocoon.matching;
+
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.avalon.framework.thread.ThreadSafe;
+import org.apache.cocoon.matching.helpers.WildcardHelper;
+import org.apache.cocoon.sitemap.PatternException;
+import org.apache.cocoon.sitemap.SitemapParameters;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Base class for wildcard matchers
+ *
+ * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
+ * @version CVS $Id: AbstractWildcardMatcher.java 30941 2004-07-29 19:56:58Z vgritsenko $
+ */
+
+public abstract class AbstractWildcardMatcher extends AbstractPreparableMatcher implements ThreadSafe {
+
+    /**
+     * Compile the pattern in an <code>int[]</code>.
+     */
+    public Object preparePattern(String pattern) {
+        // if pattern is null, return null to allow throwing a located exception in preparedMatch()
+        return pattern == null ? null : WildcardHelper.compilePattern(pattern);
+    }
+
+    /**
+     * Match the prepared pattern against the result of {@link #getMatchString(Map, Parameters)}.
+     */
+    public Map preparedMatch(Object preparedPattern, Map objectModel, Parameters parameters) throws PatternException {
+
+        if(preparedPattern == null) {
+            throw new PatternException("A pattern is needed at " +
+                    SitemapParameters.getStatementLocation(parameters));
+        }
+
+        String match = getMatchString(objectModel, parameters);
+
+        if (match == null) {
+            return null;
+        }
+
+        HashMap map = new HashMap();
+
+        if (WildcardHelper.match(map, match, (int[])preparedPattern)) {
+            return map;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Get the string to test against the wildcard expression. To be defined
+     * by concrete subclasses.
+     */
+    protected abstract String getMatchString(Map objectModel, Parameters parameters);
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/matching/AbstractWildcardMatcher.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/matching/CookieMatcher.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/matching/CookieMatcher.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/matching/CookieMatcher.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/matching/CookieMatcher.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,62 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.
+ */
+package org.apache.cocoon.matching;
+
+import org.apache.avalon.framework.logger.AbstractLogEnabled;
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.avalon.framework.thread.ThreadSafe;
+
+import org.apache.cocoon.environment.Cookie;
+import org.apache.cocoon.environment.Request;
+import org.apache.cocoon.environment.ObjectModelHelper;
+import org.apache.cocoon.sitemap.PatternException;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Matches cookies agains given name. Returns value of the matched cookie.
+ *
+ * @author <a href="mailto:maciejka@tiger.com.pl">Maciek Kaminski</a>
+ * @version CVS $Id: CookieMatcher.java 30941 2004-07-29 19:56:58Z vgritsenko $
+ */
+public class CookieMatcher extends AbstractLogEnabled implements Matcher, ThreadSafe {
+
+    public Map match(String pattern, Map objectModel, Parameters parameters)
+            throws PatternException {
+
+        if (pattern == null) {
+            throw new PatternException("No cookie name given.");
+        }
+
+        Request request = ObjectModelHelper.getRequest(objectModel);
+        Cookie[] cookies = request.getCookies();
+        HashMap result = null;
+
+        if (cookies != null) {
+            for (int i = 0; i < cookies.length; i++) {
+                Cookie cookie = cookies[i];
+                if (cookie.getName().equals(pattern)) {
+                    result = new HashMap();
+                    result.put("1", cookie.getValue());
+                    break;
+                }
+            }
+        }
+
+        return result;
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/matching/CookieMatcher.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/matching/HeaderMatcher.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/matching/HeaderMatcher.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/matching/HeaderMatcher.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/matching/HeaderMatcher.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,64 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.
+ */
+package org.apache.cocoon.matching;
+
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.avalon.framework.thread.ThreadSafe;
+import org.apache.cocoon.environment.ObjectModelHelper;
+import org.apache.cocoon.environment.Request;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This class allows for matching based on a request header.
+ * If the specified request header parameter exists, its value is
+ * retrieved for later sitemap substitution.
+ *
+ * <p><b>Example:</b></p>
+ * <pre>
+ * &lt;map:match type="header" pattern="referer"&gt;
+ *     &lt;map:redirect-to uri="{1}"/&gt;
+ * &lt;/map:match&gt;
+ * </pre>
+ *
+ * @author <a href="mailto:vgritsenko@apache.org">Vadim Gritsenko</a>
+ * @version CVS $Id: HeaderMatcher.java 30941 2004-07-29 19:56:58Z vgritsenko $
+ */
+public class HeaderMatcher implements Matcher, ThreadSafe
+{
+    /**
+     * Match method to see if the request header exists. If it does
+     * have a value the header added to the array list for later
+     * sitemap substitution.
+     *
+     * @param pattern name of request header to find
+     * @param objectModel environment passed through via cocoon
+     * @return null or map containing value of request header 'pattern'
+     */
+    public Map match(String pattern, Map objectModel, Parameters parameters) {
+        Request request = ObjectModelHelper.getRequest(objectModel);
+
+        String value = request.getHeader(pattern);
+        if (value == null) {
+            return null; // no request header defined
+        } else {
+            Map map = new HashMap();
+            map.put("1", value);
+            return map; // request header defined, return map
+        }
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/matching/HeaderMatcher.java
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message