You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@struts.apache.org by dg...@apache.org on 2005/06/14 23:59:17 UTC

svn commit: r190662 [5/6] - in /struts/sandbox/trunk/tiles: ./ core-library/ core-library/src/ core-library/src/conf/ core-library/src/java/ core-library/src/java/org/ core-library/src/java/org/apache/ core-library/src/java/org/apache/taglib/ core-library/src/java/org/apache/taglib/tiles/ core-library/src/java/org/apache/taglib/tiles/doc-files/ core-library/src/java/org/apache/taglib/tiles/util/ core-library/src/java/org/apache/tiles/ core-library/src/java/org/apache/tiles/beans/ core-library/src/java/org/apache/tiles/definition/ core-library/src/java/org/apache/tiles/doc-files/ core-library/src/java/org/apache/tiles/servlets/ core-library/src/java/org/apache/tiles/xmlDefinition/ core-library/src/java/org/apache/util/ core-library/src/test/ examples/ examples/simple/ examples/simple/WEB-INF/ examples/simple/WEB-INF/lib/ examples/simple/graphics/ examples/simple/graphics/flags/

Added: struts/sandbox/trunk/tiles/core-library/src/java/org/apache/tiles/xmlDefinition/I18nFactorySet.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/tiles/core-library/src/java/org/apache/tiles/xmlDefinition/I18nFactorySet.java?rev=190662&view=auto
==============================================================================
--- struts/sandbox/trunk/tiles/core-library/src/java/org/apache/tiles/xmlDefinition/I18nFactorySet.java (added)
+++ struts/sandbox/trunk/tiles/core-library/src/java/org/apache/tiles/xmlDefinition/I18nFactorySet.java Tue Jun 14 14:59:13 2005
@@ -0,0 +1,587 @@
+/*
+ * Copyright 2004-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.tiles.xmlDefinition;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.tiles.DefinitionsFactoryException;
+import org.apache.tiles.DefinitionsUtil;
+import org.apache.tiles.FactoryNotFoundException;
+import org.apache.taglib.tiles.ComponentConstants;
+import org.xml.sax.SAXException;
+
+/**
+ * Definitions factory.
+ * This implementation allows to have a set of definition factories.
+ * There is a main factory and one factory for each file associated to a Locale.
+ *
+ * To retrieve a definition, we first search for the appropriate factory using
+ * the Locale found in session context. If no factory is found, use the
+ * default one. Then we ask the factory for the definition.
+ *
+ * A definition factory file is loaded using main filename extended with locale code
+ * (ex : <code>templateDefinitions_fr.xml</code>). If no file is found under this name, use default file.
+ */
+public class I18nFactorySet extends FactorySet {
+
+    /** 
+     * Commons Logging instance. 
+     */
+    protected static Log log = LogFactory.getLog(I18nFactorySet.class);
+
+    /** 
+     * Config file parameter name. 
+     */
+    public static final String DEFINITIONS_CONFIG_PARAMETER_NAME =
+        "definitions-config";
+
+    /** 
+     * Config file parameter name. 
+     */
+    public static final String PARSER_DETAILS_PARAMETER_NAME =
+        "definitions-parser-details";
+
+    /** 
+     * Config file parameter name. 
+     */
+    public static final String PARSER_VALIDATE_PARAMETER_NAME =
+        "definitions-parser-validate";
+
+    /** 
+     * Possible definition filenames. 
+     */
+    public static final String DEFAULT_DEFINITION_FILENAMES[] =
+        {
+            "/WEB-INF/tileDefinitions.xml",
+            "/WEB-INF/componentDefinitions.xml",
+            "/WEB-INF/instanceDefinitions.xml" };
+
+    /**
+     * Maximum length of one branch of the resource search path tree.
+     * Used in getBundle().
+     */
+    private static final int MAX_BUNDLES_SEARCHED = 2;
+
+    /** 
+     * Default filenames extension. 
+     */
+    public static final String FILENAME_EXTENSION = ".xml";
+
+    /** 
+     * Default factory. 
+     */
+    protected DefinitionsFactory defaultFactory = null;
+
+    /** 
+     * XML parser used.
+     * Attribute is transient to allow serialization. In this implementaiton,
+     * xmlParser is created each time we need it ;-(.
+     */
+    protected transient XmlParser xmlParser;
+
+    /** 
+     * Do we want validating parser. Default is <code>false</code>.
+     * Can be set from servlet config file.
+     */
+    protected boolean isValidatingParser = false;
+
+    /** 
+     * Parser detail level. Default is 0.
+     * Can be set from servlet config file.
+     */
+    protected int parserDetailLevel = 0;
+
+    /** 
+     * Names of files containing instances descriptions. 
+     */
+    private List filenames = null;
+
+    /** 
+     * Collection of already loaded definitions set, referenced by their suffix. 
+     */
+    private Map loaded = null;
+
+    /**
+     * Parameterless Constructor.
+     * Method {@link #initFactory} must be called prior to any use of created factory.
+     */
+    public I18nFactorySet() {
+        super();
+		  log.info("CONSTRUCTING I18NFactorySet");
+    }
+
+    /**
+     * Constructor.
+     * Init the factory by reading appropriate configuration file.
+     * @param servletContext Servlet context.
+     * @param properties Map containing all properties.
+     * @throws FactoryNotFoundException Can't find factory configuration file.
+     */
+    public I18nFactorySet(ServletContext servletContext, Map properties)
+        throws DefinitionsFactoryException {
+
+        initFactory(servletContext, properties);
+    }
+
+    /**
+     * Initialization method.
+     * Init the factory by reading appropriate configuration file.
+     * This method is called exactly once immediately after factory creation in
+     * case of internal creation (by DefinitionUtil).
+     * @param servletContext Servlet Context passed to newly created factory.
+     * @param properties Map of name/property passed to newly created factory. Map can contains
+     * more properties than requested.
+     * @throws DefinitionsFactoryException An error occur during initialization.
+     */
+    public void initFactory(ServletContext servletContext, Map properties)
+        throws DefinitionsFactoryException {
+
+        // Set some property values
+        String value = (String) properties.get(PARSER_VALIDATE_PARAMETER_NAME);
+        if (value != null) {
+            isValidatingParser = Boolean.valueOf(value).booleanValue();
+        }
+
+        value = (String) properties.get(PARSER_DETAILS_PARAMETER_NAME);
+        if (value != null) {
+            try {
+                parserDetailLevel = Integer.valueOf(value).intValue();
+
+            } catch (NumberFormatException ex) {
+                log.error(
+                    "Bad format for parameter '"
+                        + PARSER_DETAILS_PARAMETER_NAME
+                        + "'. Integer expected.");
+            }
+        }
+
+        // init factory withappropriate configuration file
+        // Try to use provided filename, if any.
+        // If no filename are provided, try to use default ones.
+        String filename = (String) properties.get(DEFINITIONS_CONFIG_PARAMETER_NAME);
+        if (filename != null) { // Use provided filename
+            try {
+                initFactory(servletContext, filename);
+                if (log.isDebugEnabled()) {
+                    log.debug("Factory initialized from file '" + filename + "'.");
+                }
+
+            } catch (FileNotFoundException ex) { // A filename is specified, throw appropriate error.
+                log.error(ex.getMessage() + " : Can't find file '" + filename + "'");
+                throw new FactoryNotFoundException(
+                    ex.getMessage() + " : Can't find file '" + filename + "'");
+            }
+
+        } else { // try each default file names
+            for (int i = 0; i < DEFAULT_DEFINITION_FILENAMES.length; i++) {
+                filename = DEFAULT_DEFINITION_FILENAMES[i];
+                try {
+                    initFactory(servletContext, filename);
+                    if (log.isInfoEnabled()) {
+                        log.info(
+                            "Factory initialized from file '" + filename + "'.");
+                    }
+                } catch (FileNotFoundException ex) {
+                    // Do nothing
+                }
+            }
+        }
+
+    }
+
+    /**
+     * Initialization method.
+     * Init the factory by reading appropriate configuration file.
+     * This method is called exactly once immediately after factory creation in
+     * case of internal creation (by DefinitionUtil).
+     * @param servletContext Servlet Context passed to newly created factory.
+     * @param proposedFilename File names, comma separated, to use as  base file names.
+     * @throws DefinitionsFactoryException An error occur during initialization.
+     */
+    protected void initFactory(
+        ServletContext servletContext,
+        String proposedFilename)
+        throws DefinitionsFactoryException, FileNotFoundException {
+
+        // Init list of filenames
+        StringTokenizer tokenizer = new StringTokenizer(proposedFilename, ",");
+        this.filenames = new ArrayList(tokenizer.countTokens());
+        while (tokenizer.hasMoreTokens()) {
+            this.filenames.add(tokenizer.nextToken().trim());
+        }
+
+        loaded = new HashMap();
+        defaultFactory = createDefaultFactory(servletContext);
+        if (log.isDebugEnabled())
+            log.debug("default factory:" + defaultFactory);
+    }
+
+    /**
+     * Get default factory.
+     * @return Default factory
+     */
+    protected DefinitionsFactory getDefaultFactory() {
+        return defaultFactory;
+    }
+
+    /**
+     * Create default factory .
+     * Create InstancesMapper for specified Locale.
+     * If creation failes, use default mapper and log error message.
+     * @param servletContext Current servlet context. Used to open file.
+     * @return Created default definition factory.
+     * @throws DefinitionsFactoryException If an error occur while creating factory.
+     * @throws FileNotFoundException if factory can't be loaded from filenames.
+     */
+    protected DefinitionsFactory createDefaultFactory(ServletContext servletContext)
+        throws DefinitionsFactoryException, FileNotFoundException {
+
+        XmlDefinitionsSet rootXmlConfig = parseXmlFiles(servletContext, "", null);
+        if (rootXmlConfig == null) {
+				log.info("COULDN'T FIND THE FILE");
+            throw new FileNotFoundException();
+        }
+
+        rootXmlConfig.resolveInheritances();
+
+        if (log.isDebugEnabled()) {
+            log.debug(rootXmlConfig);
+        }
+
+        DefinitionsFactory factory = new DefinitionsFactory(rootXmlConfig);
+        if (log.isDebugEnabled()) {
+            log.debug("factory loaded : " + factory);
+        }
+
+        return factory;
+    }
+
+    /**
+     * Extract key that will be used to get the sub factory.
+     * @param name Name of requested definition
+     * @param request Current servlet request.
+     * @param servletContext Current servlet context.
+     * @return the key or <code>null</code> if not found.
+     */
+    protected Object getDefinitionsFactoryKey(
+        String name,
+        ServletRequest request,
+        ServletContext servletContext) {
+
+        Locale locale = null;
+        try {
+            HttpSession session = ((HttpServletRequest) request).getSession(false);
+            if (session != null) {
+                locale = (Locale) session.getAttribute(ComponentConstants.LOCALE_KEY);
+            }
+
+        } catch (ClassCastException ex) {
+            log.error("I18nFactorySet.getDefinitionsFactoryKey");
+            ex.printStackTrace();
+        }
+
+        return locale;
+    }
+
+    /**
+     * Create a factory for specified key.
+    * If creation failes, return default factory and log an error message.
+    * @param key The key.
+    * @param request Servlet request.
+    * @param servletContext Servlet context.
+    * @return Definition factory for specified key.
+    * @throws DefinitionsFactoryException If an error occur while creating factory.
+     */
+    protected DefinitionsFactory createFactory(
+        Object key,
+        ServletRequest request,
+        ServletContext servletContext)
+        throws DefinitionsFactoryException {
+
+        if (key == null) {
+            return getDefaultFactory();
+        }
+
+        // Build possible postfixes
+        List possiblePostfixes = calculatePostixes("", (Locale) key);
+
+        // Search last postix corresponding to a config file to load.
+        // First check if something is loaded for this postfix.
+        // If not, try to load its config.
+        XmlDefinitionsSet lastXmlFile = null;
+        DefinitionsFactory factory = null;
+        String curPostfix = null;
+        int i = 0;
+
+        for (i = possiblePostfixes.size() - 1; i >= 0; i--) {
+            curPostfix = (String) possiblePostfixes.get(i);
+
+            // Already loaded ?
+            factory = (DefinitionsFactory) loaded.get(curPostfix);
+            if (factory != null) { // yes, stop search
+                return factory;
+            }
+
+            // Try to load it. If success, stop search
+            lastXmlFile = parseXmlFiles(servletContext, curPostfix, null);
+            if (lastXmlFile != null) {
+                break;
+            }
+        }
+
+        // Have we found a description file ?
+        // If no, return default one
+        if (lastXmlFile == null) {
+            return getDefaultFactory();
+        }
+
+        // We found something. Need to load base and intermediate files
+        String lastPostfix = curPostfix;
+        XmlDefinitionsSet rootXmlConfig = parseXmlFiles(servletContext, "", null);
+        for (int j = 0; j < i; j++) {
+            curPostfix = (String) possiblePostfixes.get(j);
+            parseXmlFiles(servletContext, curPostfix, rootXmlConfig);
+        }
+
+        rootXmlConfig.extend(lastXmlFile);
+        rootXmlConfig.resolveInheritances();
+
+        factory = new DefinitionsFactory(rootXmlConfig);
+        loaded.put(lastPostfix, factory);
+
+        if (log.isDebugEnabled()) {
+            log.debug("factory loaded : " + factory);
+        }
+
+        // return last available found !
+        return factory;
+    }
+
+    /**
+     * Calculate the postixes along the search path from the base bundle to the
+     * bundle specified by baseName and locale.
+     * Method copied from java.util.ResourceBundle
+     * @param baseName the base bundle name
+     * @param locale the locale
+     */
+    private static List calculatePostixes(String baseName, Locale locale) {
+        final List result = new ArrayList(MAX_BUNDLES_SEARCHED);
+        final String language = locale.getLanguage();
+        final int languageLength = language.length();
+        final String country = locale.getCountry();
+        final int countryLength = country.length();
+        final String variant = locale.getVariant();
+        final int variantLength = variant.length();
+
+        if (languageLength + countryLength + variantLength == 0) {
+            //The locale is "", "", "".
+            return result;
+        }
+
+        final StringBuffer temp = new StringBuffer(baseName);
+        temp.append('_');
+        temp.append(language);
+
+        if (languageLength > 0)
+            result.add(temp.toString());
+
+        if (countryLength + variantLength == 0)
+            return result;
+
+        temp.append('_');
+        temp.append(country);
+
+        if (countryLength > 0)
+            result.add(temp.toString());
+
+        if (variantLength == 0) {
+            return result;
+        } else {
+            temp.append('_');
+            temp.append(variant);
+            result.add(temp.toString());
+            return result;
+        }
+    }
+
+    /**
+     * Parse files associated to postix if they exist.
+     * For each name in filenames, append postfix before file extension,
+     * then try to load the corresponding file.
+     * If file doesn't exist, try next one. Each file description is added to
+     * the XmlDefinitionsSet description.
+     * The XmlDefinitionsSet description is created only if there is a definition file.
+     * Inheritance is not resolved in the returned XmlDefinitionsSet.
+     * If no description file can be opened and no definiion set is provided, return <code>null</code>.
+     * @param postfix Postfix to add to each description file.
+     * @param xmlDefinitions Definitions set to which definitions will be added. If <code>null</code>, a definitions
+     * set is created on request.
+     * @return XmlDefinitionsSet The definitions set created or passed as parameter.
+     * @throws DefinitionsFactoryException On errors parsing file.
+     */
+    private XmlDefinitionsSet parseXmlFiles(
+        ServletContext servletContext,
+        String postfix,
+        XmlDefinitionsSet xmlDefinitions)
+        throws DefinitionsFactoryException {
+
+        if (postfix != null && postfix.length() == 0) {
+            postfix = null;
+        }
+
+        // Iterate throw each file name in list
+        Iterator i = filenames.iterator();
+        while (i.hasNext()) {
+            String filename = concatPostfix((String) i.next(), postfix);
+            xmlDefinitions = parseXmlFile(servletContext, filename, xmlDefinitions);
+        }
+
+        return xmlDefinitions;
+    }
+
+    /**
+     * Parse specified xml file and add definition to specified definitions set.
+     * This method is used to load several description files in one instances list.
+     * If filename exists and definition set is <code>null</code>, create a new set. Otherwise, return
+     * passed definition set (can be <code>null</code>).
+     * @param servletContext Current servlet context. Used to open file.
+     * @param filename Name of file to parse.
+     * @param xmlDefinitions Definitions set to which definitions will be added. If null, a definitions
+     * set is created on request.
+     * @return XmlDefinitionsSet The definitions set created or passed as parameter.
+     * @throws DefinitionsFactoryException On errors parsing file.
+     */
+    private XmlDefinitionsSet parseXmlFile(
+        ServletContext servletContext,
+        String filename,
+        XmlDefinitionsSet xmlDefinitions)
+        throws DefinitionsFactoryException {
+
+        try {
+            InputStream input = servletContext.getResourceAsStream(filename);
+            // Try to load using real path.
+            // This allow to load config file under websphere 3.5.x
+            // Patch proposed Houston, Stephen (LIT) on 5 Apr 2002
+            if (null == input) {
+                try {
+                    input =
+                        new java.io.FileInputStream(
+                            servletContext.getRealPath(filename));
+                } catch (Exception e) {
+                }
+            }
+
+            // If still nothing found, this mean no config file is associated
+            if (input == null) {
+                if (log.isDebugEnabled()) {
+                    log.debug("Can't open file '" + filename + "'");
+                }
+                return xmlDefinitions;
+            }
+
+            // Check if parser already exist.
+            // Doesn't seem to work yet.
+            //if( xmlParser == null )
+            if (true) {
+                xmlParser = new XmlParser();
+                xmlParser.setValidating(isValidatingParser);
+            }
+
+            // Check if definition set already exist.
+            if (xmlDefinitions == null) {
+                xmlDefinitions = new XmlDefinitionsSet();
+            }
+
+            xmlParser.parse(input, xmlDefinitions);
+
+        } catch (SAXException ex) {
+            if (log.isDebugEnabled()) {
+                log.debug("Error while parsing file '" + filename + "'.");
+                ex.printStackTrace();
+            }
+            throw new DefinitionsFactoryException(
+                "Error while parsing file '" + filename + "'. " + ex.getMessage(),
+                ex);
+
+        } catch (IOException ex) {
+            throw new DefinitionsFactoryException(
+                "IO Error while parsing file '" + filename + "'. " + ex.getMessage(),
+                ex);
+        }
+
+        return xmlDefinitions;
+    }
+
+    /**
+     * Concat postfix to the name. Take care of existing filename extension.
+     * Transform the given name "name.ext" to have "name" + "postfix" + "ext".
+     * If there is no ext, return "name" + "postfix".
+     * @param name Filename.
+     * @param postfix Postfix to add.
+     * @return Concatenated filename.
+     */
+    private String concatPostfix(String name, String postfix) {
+        if (postfix == null) {
+            return name;
+        }
+
+        // Search file name extension.
+        // take care of Unix files starting with .
+        int dotIndex = name.lastIndexOf(".");
+        int lastNameStart = name.lastIndexOf(java.io.File.pathSeparator);
+        if (dotIndex < 1 || dotIndex < lastNameStart) {
+            return name + postfix;
+        }
+
+        String ext = name.substring(dotIndex);
+        name = name.substring(0, dotIndex);
+        return name + postfix + ext;
+    }
+
+    /**
+     * Return String representation.
+     * @return String representation.
+     */
+    public String toString() {
+        StringBuffer buff = new StringBuffer("I18nFactorySet : \n");
+        buff.append("--- default factory ---\n");
+        buff.append(defaultFactory.toString());
+        buff.append("\n--- other factories ---\n");
+        Iterator i = factories.values().iterator();
+        while (i.hasNext()) {
+            buff.append(i.next().toString()).append("---------- \n");
+        }
+        return buff.toString();
+    }
+
+}

Added: struts/sandbox/trunk/tiles/core-library/src/java/org/apache/tiles/xmlDefinition/XmlAttribute.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/tiles/core-library/src/java/org/apache/tiles/xmlDefinition/XmlAttribute.java?rev=190662&view=auto
==============================================================================
--- struts/sandbox/trunk/tiles/core-library/src/java/org/apache/tiles/xmlDefinition/XmlAttribute.java (added)
+++ struts/sandbox/trunk/tiles/core-library/src/java/org/apache/tiles/xmlDefinition/XmlAttribute.java Tue Jun 14 14:59:13 2005
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2004-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.tiles.xmlDefinition;
+
+import org.apache.tiles.DefinitionNameAttribute;
+import org.apache.tiles.DirectStringAttribute;
+import org.apache.tiles.PathAttribute;
+import org.apache.tiles.UntypedAttribute;
+
+/**
+ * A property key-value pair.  This class is used to read configuration files.
+ */
+public class XmlAttribute {
+
+    /**
+     * Attribute name or key.
+     */
+    private String name = null;
+
+    /**
+     * Attribute value.
+     * Value read from description file.
+     */
+    private Object value = null;
+
+    /**
+     * Attribute value.
+     */
+    private String direct = null;
+
+    /**
+     * Attribute value.
+     */
+    private String valueType = null;
+
+    /**
+     * Attribute value.
+     */
+    private String role = null;
+
+    /**
+     * Real attribute value.
+     * Real value is the value after processing of valueType.
+     * I.e. if a type is defined, realValue contains wrapper for this type.
+     */
+    private Object realValue = null;
+
+    /**
+     * Constructor.
+     */
+    public XmlAttribute() {
+        super();
+    }
+
+    /**
+     * Constructor.
+     */
+    public XmlAttribute(String name, Object value) {
+        this.name = name;
+        this.value = value;
+    }
+
+    /**
+     * Access method for the name property.
+     *
+     * @return The current value of the name property.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Sets the value of the name property.
+     *
+     * @param aName the new value of the name property
+     */
+    public void setRole(String role) {
+        this.role = role;
+    }
+
+    /**
+     * Access method for the name property.
+     *
+     * @return The current value of the name property.
+     */
+    public String getRole() {
+        return role;
+    }
+
+    /**
+     * Sets the value of the name property.
+     *
+     * @param aName the new value of the name property.
+     */
+    public void setName(String aName) {
+        name = aName;
+    }
+
+    /**
+     * Another access method for the name property.
+     *
+     * @return   the current value of the name property
+     */
+    public String getAttribute() {
+        return name;
+    }
+
+    /**
+     * Sets the value of the name property.
+     *
+     * @param aName the new value of the name property
+     */
+    public void setAttribute(String aName) {
+        name = aName;
+    }
+
+    /**
+     * Access method for the value property. Return the value or a 
+     * QualifiedAttribute containing the value if 'direct' is set.
+     *
+     * @return The current value of the value property.
+     */
+    public Object getValue() {
+        // Compatibility with JSP Template
+        if (this.realValue == null) {
+            this.realValue = this.computeRealValue();
+        }
+
+        return this.realValue;
+    }
+
+    /**
+     * Sets the value of the value property.
+     *
+     * @param aValue the new value of the value property
+     */
+    public void setValue(Object aValue) {
+        realValue = null;
+        value = aValue;
+    }
+
+    /**
+     * Sets the value of the value property.
+     *
+     * @param aValue the new value of the value property
+     */
+    public void setContent(Object aValue) {
+        setValue(aValue);
+    }
+
+    /**
+     * Sets the value of the value property.
+     *
+     * @param aValue the new value of the value property
+     */
+    public void setBody(String body) {
+        if (body.length() == 0) {
+            return;
+        }
+        
+        setValue(body);
+    }
+
+    /**
+     * Sets the value of the value property.
+     *
+     * @param aValue the new value of the value property
+     */
+    public void setDirect(String value) {
+        this.direct = value;
+    }
+
+    /**
+     * Sets the value of the value property.
+     *
+     * @param aValue the new value of the value property
+     */
+    public void setType(String value) {
+        this.valueType = value;
+    }
+
+    /**
+     * Compute  real value from attributes setting.
+     */
+    protected Object computeRealValue() {
+        Object realValue = value;
+        // Is there a type set ?
+        // First check direct attribute, and translate it to a valueType.
+        // Then, evaluate valueType, and create requested typed attribute.
+        if (direct != null) {
+            this.valueType =
+                Boolean.valueOf(direct).booleanValue() ? "string" : "path";
+        }
+
+        if (value != null && valueType != null) {
+            String strValue = value.toString();
+
+            if (valueType.equalsIgnoreCase("string")) {
+                realValue = new DirectStringAttribute(strValue);
+
+            } else if (valueType.equalsIgnoreCase("page")) {
+                realValue = new PathAttribute(strValue);
+
+            } else if (valueType.equalsIgnoreCase("template")) {
+                realValue = new PathAttribute(strValue);
+
+            } else if (valueType.equalsIgnoreCase("instance")) {
+                realValue = new DefinitionNameAttribute(strValue);
+            }
+
+            // Set realValue's role value if needed
+            if (role != null) {
+                ((UntypedAttribute) realValue).setRole(role);
+            }
+        }
+
+        // Create attribute wrapper to hold role if role is set and no type specified
+        if (role != null && value != null && valueType == null) {
+            realValue = new UntypedAttribute(value.toString(), role);
+        }
+
+        return realValue;
+    }
+}

Added: struts/sandbox/trunk/tiles/core-library/src/java/org/apache/tiles/xmlDefinition/XmlDefinition.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/tiles/core-library/src/java/org/apache/tiles/xmlDefinition/XmlDefinition.java?rev=190662&view=auto
==============================================================================
--- struts/sandbox/trunk/tiles/core-library/src/java/org/apache/tiles/xmlDefinition/XmlDefinition.java (added)
+++ struts/sandbox/trunk/tiles/core-library/src/java/org/apache/tiles/xmlDefinition/XmlDefinition.java Tue Jun 14 14:59:13 2005
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2004-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.tiles.xmlDefinition;
+
+import org.apache.tiles.ComponentDefinition;
+import org.apache.tiles.NoSuchDefinitionException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.util.Iterator;
+
+/**
+  *A definition read from an XML definitions file.
+  */
+public class XmlDefinition extends ComponentDefinition
+{
+  /**
+   * Extends attribute value.
+   */
+  private String inherit;
+
+    /** Commons Logging instance. */
+   protected static Log log = LogFactory.getLog(XmlDefinition.class);
+
+  /**
+   * Used for resolving inheritance.
+   */
+  private boolean isVisited=false;
+
+
+     /**
+      * Constructor.
+      */
+   public XmlDefinition()
+   {
+   super();
+   //if(debug)
+     //System.out.println( "create definition" );
+   }
+
+  /**
+   * Add an attribute to this component.
+   *
+   * @param attribute Attribute to add.
+   */
+  public void addAttribute( XmlAttribute attribute)
+    {
+    putAttribute( attribute.getName(), attribute.getValue() );
+    }
+
+  /**
+   * Set extends.
+   *
+   * @param name Name of the extended definition.
+   */
+  public void setExtends(String name)
+    {
+    inherit = name;
+    }
+
+  /**
+   * Get extends.
+   *
+   * @return Name of the extended definition.
+   */
+  public String getExtends()
+    {
+    return inherit;
+    }
+
+  /**
+   * Get extends flag.
+   *
+   */
+  public boolean isExtending( )
+    {
+    return inherit!=null;
+    }
+
+  /**
+   * Set isVisited.
+   *
+   */
+  public void setIsVisited( boolean isVisited )
+    {
+    this.isVisited = isVisited;
+    }
+
+    /**
+     * Resolve inheritance.
+     * First, resolve parent's inheritance, then set path to the parent's path.
+     * Also copy attributes setted in parent, and not set in child
+     * If instance doesn't extend anything, do nothing.
+     * @throws NoSuchDefinitionException If an inheritance can not be solved.
+     */
+  public void resolveInheritance( XmlDefinitionsSet definitionsSet )
+    throws NoSuchDefinitionException
+    {
+      // Already done, or not needed ?
+    if( isVisited || !isExtending() )
+      return;
+
+    if(log.isDebugEnabled())
+      log.debug( "Resolve definition for child name='" + getName()
+              + "' extends='" + getExtends() + "'.");
+
+      // Set as visited to avoid endless recurisvity.
+    setIsVisited( true );
+
+      // Resolve parent before itself.
+    XmlDefinition parent = definitionsSet.getDefinition( getExtends() );
+    if( parent == null )
+      { // error
+      String msg = "Error while resolving definition inheritance: child '"
+                           + getName() +    "' can't find its ancestor '"
+                           + getExtends() + "'. Please check your description file.";
+      log.error( msg );
+        // to do : find better exception
+      throw new NoSuchDefinitionException( msg );
+      }
+
+    parent.resolveInheritance( definitionsSet );
+
+      // Iterate on each parent's attribute and add it if not defined in child.
+    Iterator parentAttributes = parent.getAttributes().keySet().iterator();
+    while( parentAttributes.hasNext() )
+      {
+      String name = (String)parentAttributes.next();
+      if( !getAttributes().containsKey(name) )
+        putAttribute( name, parent.getAttribute(name) );
+      }
+      // Set path and role if not setted
+    if( path == null )
+      setPath( parent.getPath() );
+    if( role == null )
+      setRole( parent.getRole() );
+    if( controller==null )
+      {
+      setController( parent.getController());
+      setControllerType( parent.getControllerType());
+      }
+    }
+
+  /**
+   * Overload this definition with passed child.
+   * All attributes from child are copied to this definition. Previous attributes with
+   * same name are disguarded.
+   * Special attribute 'path','role' and 'extends' are overloaded if defined in child.
+   * @param child Child used to overload this definition.
+   */
+  public void overload( XmlDefinition child )
+    {
+    if( child.getPath() != null )
+      {
+      path = child.getPath();
+      }
+    if( child.getExtends() != null )
+      {
+      inherit = child.getExtends();
+      }
+    if( child.getRole() != null )
+      {
+      role = child.getRole();
+      }
+    if( child.getController()!=null )
+      {
+      controller = child.getController();
+      controllerType =  child.getControllerType();
+      }
+      // put all child attributes in parent.
+    attributes.putAll( child.getAttributes());
+    }
+}

Added: struts/sandbox/trunk/tiles/core-library/src/java/org/apache/tiles/xmlDefinition/XmlDefinitionsSet.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/tiles/core-library/src/java/org/apache/tiles/xmlDefinition/XmlDefinitionsSet.java?rev=190662&view=auto
==============================================================================
--- struts/sandbox/trunk/tiles/core-library/src/java/org/apache/tiles/xmlDefinition/XmlDefinitionsSet.java (added)
+++ struts/sandbox/trunk/tiles/core-library/src/java/org/apache/tiles/xmlDefinition/XmlDefinitionsSet.java Tue Jun 14 14:59:13 2005
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2004-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.tiles.xmlDefinition;
+
+import org.apache.tiles.NoSuchDefinitionException;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * A set of definitions read from XML definitions file.
+*/
+public class XmlDefinitionsSet
+{
+    /** Defined definitions. */
+  protected Map definitions;
+
+     /**
+      * Constructor.
+      */
+  public XmlDefinitionsSet()
+   {
+   definitions = new HashMap();
+   }
+
+  /**
+   * Put definition in set.
+   * @param definition Definition to add.
+   */
+  public void putDefinition(XmlDefinition definition)
+  {
+  definitions.put( definition.getName(), definition );
+  }
+
+  /**
+   * Get requested definition.
+   * @param name Definition name.
+   */
+  public XmlDefinition getDefinition(String name)
+  {
+  return (XmlDefinition)definitions.get( name );
+  }
+
+  /**
+   * Get definitions map.
+   */
+  public Map getDefinitions()
+  {
+  return definitions;
+  }
+
+  /**
+   * Resolve extended instances.
+   */
+  public void resolveInheritances() throws NoSuchDefinitionException
+    {
+      // Walk through all definitions and resolve individual inheritance
+    Iterator i = definitions.values().iterator();
+    while( i.hasNext() )
+      {
+      XmlDefinition definition = (XmlDefinition)i.next();
+      definition.resolveInheritance( this );
+      }  // end loop
+    }
+
+  /**
+   * Add definitions from specified child definitions set.
+   * For each definition in child, look if it already exists in this set.
+   * If not, add it, if yes, overload parent's definition with child definition.
+   * @param child Definition used to overload this object.
+   */
+  public void extend( XmlDefinitionsSet child )
+    {
+    if(child==null)
+      return;
+    Iterator i = child.getDefinitions().values().iterator();
+    while( i.hasNext() )
+      {
+      XmlDefinition childInstance = (XmlDefinition)i.next();
+      XmlDefinition parentInstance = getDefinition(childInstance.getName() );
+      if( parentInstance != null )
+        {
+        parentInstance.overload( childInstance );
+        }
+       else
+        putDefinition( childInstance );
+      } // end loop
+    }
+    /**
+     * Get String representation.
+     */
+  public String toString()
+    {
+    return "definitions=" + definitions.toString() ;
+    }
+
+}

Added: struts/sandbox/trunk/tiles/core-library/src/java/org/apache/tiles/xmlDefinition/XmlListAttribute.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/tiles/core-library/src/java/org/apache/tiles/xmlDefinition/XmlListAttribute.java?rev=190662&view=auto
==============================================================================
--- struts/sandbox/trunk/tiles/core-library/src/java/org/apache/tiles/xmlDefinition/XmlListAttribute.java (added)
+++ struts/sandbox/trunk/tiles/core-library/src/java/org/apache/tiles/xmlDefinition/XmlListAttribute.java Tue Jun 14 14:59:13 2005
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2004-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.tiles.xmlDefinition;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.servlet.RequestDispatcher;
+
+public class XmlListAttribute extends XmlAttribute {
+    /** List.
+     * We declare a List to avoid cast.
+     * Parent "value" property points to the same list.
+     */
+  private List list;
+
+    /**
+     * Constructor.
+     */
+  public XmlListAttribute()
+    {
+    list = new ArrayList();
+    setValue(list);
+    }
+
+    /**
+     * Constructor.
+     * @param name Name.
+     * @param value List.
+     */
+  public XmlListAttribute( String name, List value)
+    {
+    super( name, value );
+    list = value;
+    }
+
+    /**
+     * Add an element in list.
+     * We use a property to avoid rewriting a new class.
+     * @param element XmlAttribute to add.
+     */
+  public void add( XmlAttribute element )
+    {
+    list.add( element.getValue() );
+    }
+
+    /**
+     * Add an element in list.
+     * @param value Object to add.
+     */
+  public void add( Object value )
+    {
+    //list.add( value );
+      // To correct a bug in digester, we need to check the object type
+      // Digester doesn't call correct method according to object type ;-(
+    if(value instanceof XmlAttribute)
+      {
+      add((XmlAttribute)value);
+      return;
+      }
+     else
+      list.add( value );
+    }
+
+    /**
+     * Add an element in list.
+     * @param value Object to add.
+     */
+  public void addObject( Object value )
+    {
+    list.add( value );
+    }
+
+
+
+}

Added: struts/sandbox/trunk/tiles/core-library/src/java/org/apache/tiles/xmlDefinition/XmlParser.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/tiles/core-library/src/java/org/apache/tiles/xmlDefinition/XmlParser.java?rev=190662&view=auto
==============================================================================
--- struts/sandbox/trunk/tiles/core-library/src/java/org/apache/tiles/xmlDefinition/XmlParser.java (added)
+++ struts/sandbox/trunk/tiles/core-library/src/java/org/apache/tiles/xmlDefinition/XmlParser.java Tue Jun 14 14:59:13 2005
@@ -0,0 +1,345 @@
+/*
+ * Copyright 2004-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.tiles.xmlDefinition;
+
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import org.apache.commons.digester.Digester;
+import org.xml.sax.SAXException;
+
+/**
+ * Parse an XML definitions file.
+ *
+ * @author Cedric Dumoulin
+ * @author David Geary
+ */
+public class XmlParser {
+    /** Associated digester. */
+  protected Digester digester;
+    /**
+     * Should we use a validating XML parser to read the configuration file.
+     * Default is <code>false</code>.
+     */
+    protected boolean validating = false;
+    /**
+     * The set of public identifiers, and corresponding resource names for
+     * the versions of the configuration file DTDs we know about.  There
+     * <strong>MUST</strong> be an even number of Strings in this list!
+     */
+    protected String registrations[] = {
+          // pre 1.1
+        "-//Apache Software Foundation//DTD Tiles Configuration//EN",
+        "/org/apache/struts/resources/tiles-config_1_1.dtd",
+        "-//Apache Software Foundation//DTD Components Configuration//EN",
+        "/org/apache/struts/resources/tiles-config.dtd",
+         // version 1.1
+        "-//Apache Software Foundation//DTD Tiles Configuration 1.1//EN",
+        "/org/apache/struts/resources/tiles-config_1_1.dtd",
+    };
+
+     /**
+      * Constructor.
+      * Creates a digester parser and initializes syntax rules.
+      */
+  public XmlParser()
+  {
+	digester = new Digester();
+	digester.setValidating(validating);
+	digester.setNamespaceAware(true);
+	digester.setUseContextClassLoader(true);
+	// Register our local copy of the DTDs that we can find
+  for (int i = 0; i < registrations.length; i += 2) {
+      URL url = this.getClass().getResource(registrations[i+1]);
+      if (url != null)
+          {
+          digester.register(registrations[i], url.toString());
+          }
+  }
+    // Init syntax rules
+  initDigester( digester );
+  }
+
+    /**
+     * Set digester validating flag.
+     */
+  public void setValidating( boolean validating )
+    {
+    digester.setValidating( validating);
+    }
+
+
+   /**
+    * Init digester for components syntax.
+    * This is an old set of rules, left for backward compatibility.
+    * @param digester Digester instance to use.
+    */
+  private void initDigesterForComponentsDefinitionsSyntax( Digester digester )
+  {
+	 // Common constants
+  String PACKAGE_NAME = "org.apache.tiles.xmlDefinition";
+  String DEFINITION_TAG = "component-definitions/definition";
+  String definitionHandlerClass = PACKAGE_NAME + ".XmlDefinition";
+
+  String PUT_TAG  = DEFINITION_TAG + "/put";
+  String putAttributeHandlerClass = PACKAGE_NAME + ".XmlAttribute";
+
+  String LIST_TAG = DEFINITION_TAG + "/putList";
+  String listHandlerClass     = PACKAGE_NAME + ".XmlListAttribute";
+
+  String ADD_LIST_ELE_TAG = LIST_TAG + "/add";
+
+    // syntax rules
+	digester.addObjectCreate(  DEFINITION_TAG, definitionHandlerClass );
+	digester.addSetProperties( DEFINITION_TAG);
+	digester.addSetNext(       DEFINITION_TAG, "putDefinition", definitionHandlerClass);
+    // put / putAttribute rules
+	digester.addObjectCreate(  PUT_TAG, putAttributeHandlerClass);
+	digester.addSetNext(       PUT_TAG, "addAttribute", putAttributeHandlerClass);
+	digester.addSetProperties( PUT_TAG);
+	digester.addCallMethod(    PUT_TAG, "setBody", 0);
+    // list rules
+	digester.addObjectCreate(  LIST_TAG, listHandlerClass);
+	digester.addSetProperties( LIST_TAG);
+	digester.addSetNext(       LIST_TAG, "addAttribute", putAttributeHandlerClass);
+    // list elements rules
+    // We use Attribute class to avoid rewriting a new class.
+    // Name part can't be used in listElement attribute.
+	digester.addObjectCreate(  ADD_LIST_ELE_TAG, putAttributeHandlerClass);
+	digester.addSetNext(       ADD_LIST_ELE_TAG, "add", putAttributeHandlerClass);
+	digester.addSetProperties( ADD_LIST_ELE_TAG);
+	digester.addCallMethod(    ADD_LIST_ELE_TAG, "setBody", 0);
+  }
+
+   /**
+    * Init digester for Tiles syntax.
+    * Same as components, but with first element = tiles-definitions
+    * @param digester Digester instance to use.
+    */
+  private void initDigesterForTilesDefinitionsSyntax( Digester digester )
+  {
+	 // Common constants
+  String PACKAGE_NAME = "org.apache.tiles.xmlDefinition";
+  String DEFINITION_TAG = "tiles-definitions/definition";
+  String definitionHandlerClass = PACKAGE_NAME + ".XmlDefinition";
+
+  String PUT_TAG  = DEFINITION_TAG + "/put";
+  String putAttributeHandlerClass = PACKAGE_NAME + ".XmlAttribute";
+
+  //String LIST_TAG = DEFINITION_TAG + "/putList";
+    // List tag value
+  String LIST_TAG = "putList";
+  String DEF_LIST_TAG = DEFINITION_TAG + "/" + LIST_TAG;
+  String listHandlerClass     = PACKAGE_NAME + ".XmlListAttribute";
+    // Tag value for adding an element in a list
+  String ADD_LIST_ELE_TAG = "*/" + LIST_TAG + "/add";
+
+    // syntax rules
+	digester.addObjectCreate(  DEFINITION_TAG, definitionHandlerClass );
+	digester.addSetProperties( DEFINITION_TAG);
+	digester.addSetNext(       DEFINITION_TAG, "putDefinition", definitionHandlerClass);
+    // put / putAttribute rules
+    // Rules for a same pattern are called in order, but rule.end() are called
+    // in reverse order.
+    // SetNext and CallMethod use rule.end() method. So, placing SetNext in
+    // first position ensure it will be called last (sic).
+	digester.addObjectCreate(  PUT_TAG, putAttributeHandlerClass);
+	digester.addSetNext(       PUT_TAG, "addAttribute", putAttributeHandlerClass);
+	digester.addSetProperties( PUT_TAG);
+	digester.addCallMethod(    PUT_TAG, "setBody", 0);
+    // Definition level list rules
+    // This is rules for lists nested in a definition
+	digester.addObjectCreate(  DEF_LIST_TAG, listHandlerClass);
+	digester.addSetProperties( DEF_LIST_TAG);
+	digester.addSetNext(       DEF_LIST_TAG, "addAttribute", putAttributeHandlerClass);
+    // list elements rules
+    // We use Attribute class to avoid rewriting a new class.
+    // Name part can't be used in listElement attribute.
+	digester.addObjectCreate(  ADD_LIST_ELE_TAG, putAttributeHandlerClass);
+	digester.addSetNext(       ADD_LIST_ELE_TAG, "add", putAttributeHandlerClass);
+	digester.addSetProperties( ADD_LIST_ELE_TAG);
+	digester.addCallMethod(    ADD_LIST_ELE_TAG, "setBody", 0);
+
+    // nested list elements rules
+    // Create a list handler, and add it to parent list
+  String NESTED_LIST = "*/" + LIST_TAG + "/" + LIST_TAG;
+	digester.addObjectCreate(  NESTED_LIST, listHandlerClass);
+	digester.addSetProperties( NESTED_LIST);
+	digester.addSetNext(       NESTED_LIST, "add", putAttributeHandlerClass);
+
+    // item elements rules
+    // We use Attribute class to avoid rewriting a new class.
+    // Name part can't be used in listElement attribute.
+  //String ADD_WILDCARD = LIST_TAG + "/addItem";
+  // non String ADD_WILDCARD = LIST_TAG + "/addx*";
+  String ADD_WILDCARD = "*/item";
+  String menuItemDefaultClass = "org.apache.tiles.beans.SimpleMenuItem";
+	digester.addObjectCreate(  ADD_WILDCARD, menuItemDefaultClass, "classtype");
+	digester.addSetNext(       ADD_WILDCARD, "add", "java.lang.Object");
+	digester.addSetProperties( ADD_WILDCARD);
+
+    // bean elements rules
+  String BEAN_TAG = "*/bean";
+  String beanDefaultClass = "org.apache.tiles.beans.SimpleMenuItem";
+	digester.addObjectCreate(  BEAN_TAG, beanDefaultClass, "classtype");
+	digester.addSetNext(       BEAN_TAG, "add", "java.lang.Object");
+	digester.addSetProperties( BEAN_TAG);
+
+    // Set properties to surrounding element
+  digester.addSetProperty(BEAN_TAG+ "/set-property", "property", "value");
+  }
+
+   /**
+    * Init digester in order to parse instances definition file syntax.
+    * Instances is an old name for "definition". This method is left for
+    * backwards compatibility.
+    * @param digester Digester instance to use.
+    */
+  private void initDigesterForInstancesSyntax( Digester digester )
+  {
+    	// Build a digester to process our configuration resource
+  String PACKAGE_NAME = "org.apache.tiles.xmlDefinition";
+  String INSTANCE_TAG = "component-instances/instance";
+  String instanceHandlerClass = PACKAGE_NAME + ".XmlDefinition";
+
+  String PUT_TAG = INSTANCE_TAG + "/put";
+  String PUTATTRIBUTE_TAG = INSTANCE_TAG + "/putAttribute";
+  String putAttributeHandlerClass = PACKAGE_NAME + ".XmlAttribute";
+
+  String LIST_TAG     = INSTANCE_TAG + "/putList";
+  String listHandlerClass     = PACKAGE_NAME + ".XmlListAttribute";
+
+  String ADD_LIST_ELE_TAG = LIST_TAG + "/add";
+
+    // component instance rules
+	digester.addObjectCreate(  INSTANCE_TAG, instanceHandlerClass );
+	digester.addSetProperties( INSTANCE_TAG);
+	digester.addSetNext(       INSTANCE_TAG, "putDefinition", instanceHandlerClass);
+    // put / putAttribute rules
+	digester.addObjectCreate(  PUTATTRIBUTE_TAG, putAttributeHandlerClass);
+	digester.addSetProperties( PUTATTRIBUTE_TAG);
+	digester.addSetNext(       PUTATTRIBUTE_TAG, "addAttribute", putAttributeHandlerClass);
+    // put / putAttribute rules
+	digester.addObjectCreate(  PUT_TAG, putAttributeHandlerClass);
+	digester.addSetProperties( PUT_TAG);
+	digester.addSetNext(       PUT_TAG, "addAttribute", putAttributeHandlerClass);
+    // list rules
+	digester.addObjectCreate(  LIST_TAG, listHandlerClass);
+	digester.addSetProperties( LIST_TAG);
+	digester.addSetNext(       LIST_TAG, "addAttribute", putAttributeHandlerClass);
+    // list elements rules
+    // We use Attribute class to avoid rewriting a new class.
+    // Name part can't be used in listElement attribute.
+	digester.addObjectCreate(  ADD_LIST_ELE_TAG, putAttributeHandlerClass);
+	digester.addSetProperties( ADD_LIST_ELE_TAG);
+	digester.addSetNext(       ADD_LIST_ELE_TAG, "add", putAttributeHandlerClass);
+  }
+
+   /**
+    * Init digester.
+    * @param digester Digester instance to use.
+    */
+  protected void initDigester( Digester digester )
+  {
+  initDigesterForTilesDefinitionsSyntax( digester );
+  initDigesterForComponentsDefinitionsSyntax( digester );
+  initDigesterForInstancesSyntax( digester );
+  }
+
+  /**
+   * Parse input reader and add encountered definitions to definitions set.
+   * @param in Input stream.
+   * @param definitions Xml Definitions set to which encountered definition are added.
+   * @throws IOException On errors during file parsing.
+   * @throws SAXException On errors parsing XML.
+   */
+  public void parse( InputStream in, XmlDefinitionsSet definitions ) throws IOException, SAXException
+  {
+	try
+    {
+      // set first object in stack
+    //digester.clear();
+    digester.push(definitions);
+      // parse
+	  digester.parse(in);
+	  in.close();
+	  }
+  catch (SAXException e)
+    {
+	  //throw new ServletException( "Error while parsing " + mappingConfig, e);
+    throw e;
+	  }
+
+  }
+
+    /**
+     * Main method to check file syntax.
+     */
+  public static void main(String[] args)
+  {
+  //String filename = "E:/programs/jakarta-tomcat/webapps/wtiles-struts/WEB-INF/tiles-examples-defs.xml";
+  String filename = "E:/programs/jakarta-tomcat-4.0.3/webapps/wtiles-struts/WEB-INF/tiles-examples-defs.xml";
+  //String filename = "E:/programs/jakarta-tomcat/webapps/wtiles-struts/WEB-INF/tilesDefinitions.xml";
+  //String filename = "E:/programs/jakarta-tomcat/webapps/wtiles-channel/WEB-INF/componentDefinitions.xml";
+  //String filename2 = "E:/programs/jakarta-tomcat/webapps/wtiles-tutorial/WEB-INF/componentDefinitions.xml";
+
+
+    if( args.length > 1 )
+      {
+      filename = args[1];
+      } // end if
+
+  System.out.println( "Read file '" + filename  +"'" );
+
+  InputStream input = null;
+  // InputStream input2 = null;
+    // Open file
+    try
+      {
+	    input = new BufferedInputStream(
+                             new FileInputStream( filename) );
+	//    input2 = new BufferedInputStream(
+          //                   new FileInputStream( filename2) );
+      }
+     catch( IOException ex )
+      {
+      System.out.println( "can't open file '" + filename + "' : " + ex.getMessage() );
+      }
+    // Check file syntax
+    try
+      {
+	    XmlParser parser = new XmlParser();
+      parser.setValidating(true);
+      XmlDefinitionsSet definitions = new XmlDefinitionsSet();
+        System.out.println( "  Parse file" );
+      parser.parse( input, definitions);
+      //  System.out.println( "  Check file 2" );
+      //parser.parse( input2, definitions);
+        System.out.println( "  done." );
+      System.out.println( "  Result : " + definitions.toString() );
+      }
+     catch( Exception ex )
+      {
+      System.out.println( "Error during parsing '" + filename + "' : " + ex.getMessage() );
+      ex.printStackTrace();
+      }
+  }
+
+}

Added: struts/sandbox/trunk/tiles/core-library/src/java/org/apache/tiles/xmlDefinition/sub
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/tiles/core-library/src/java/org/apache/tiles/xmlDefinition/sub?rev=190662&view=auto
==============================================================================
--- struts/sandbox/trunk/tiles/core-library/src/java/org/apache/tiles/xmlDefinition/sub (added)
+++ struts/sandbox/trunk/tiles/core-library/src/java/org/apache/tiles/xmlDefinition/sub Tue Jun 14 14:59:13 2005
@@ -0,0 +1,3 @@
+2,/^END/{
+  /org.apache.struts.tiles/s//org.apache.tiles/g
+}

Added: struts/sandbox/trunk/tiles/core-library/src/java/org/apache/util/MessageResources.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/tiles/core-library/src/java/org/apache/util/MessageResources.java?rev=190662&view=auto
==============================================================================
--- struts/sandbox/trunk/tiles/core-library/src/java/org/apache/util/MessageResources.java (added)
+++ struts/sandbox/trunk/tiles/core-library/src/java/org/apache/util/MessageResources.java Tue Jun 14 14:59:13 2005
@@ -0,0 +1,517 @@
+/*
+ * Copyright 2004-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.util;
+
+import java.io.Serializable;
+import java.text.MessageFormat;
+import java.util.HashMap;
+import java.util.Locale;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * General purpose abstract class that describes an API for retrieving
+ * Locale-sensitive messages from underlying resource locations of an
+ * unspecified design, and optionally utilizing the <code>MessageFormat</code>
+ * class to produce internationalized messages with parametric replacement.
+ * <p>
+ * Calls to <code>getMessage()</code> variants without a <code>Locale</code>
+ * argument are presumed to be requesting a message string in the default
+ * <code>Locale</code> for this JVM.
+ * <p>
+ * Calls to <code>getMessage()</code> with an unknown key, or an unknown
+ * <code>Locale</code> will return <code>null</code> if the
+ * <code>returnNull</code> property is set to <code>true</code>.  Otherwise,
+ * a suitable error message will be returned instead.
+ * <p>
+ * <strong>IMPLEMENTATION NOTE</strong> - Classes that extend this class
+ * must be Serializable so that instances may be used in distributable
+ * application server environments.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.18 $ $Date: 2003/07/02 03:42:09 $
+ */
+public abstract class MessageResources implements Serializable {
+
+    // ------------------------------------------------------------- Properties
+
+    /**
+     * Commons Logging instance.
+     */
+    protected static Log log = LogFactory.getLog(MessageResources.class);
+
+    /**
+     * The configuration parameter used to initialize this MessageResources.
+     */
+    protected String config = null;
+
+    /**
+     * The configuration parameter used to initialize this MessageResources.
+     * @return parameter used to initialize this MessageResources
+     */
+    public String getConfig() {
+        return (this.config);
+    }
+
+    /**
+     * The default Locale for our environment.
+     */
+    protected Locale defaultLocale = Locale.getDefault();
+
+    /**
+     * The <code>MessageResourcesFactory</code> that created this instance.
+     */
+    protected MessageResourcesFactory factory = null;
+
+    /**
+     * The <code>MessageResourcesFactory</code> that created this instance.
+     * @return <code>MessageResourcesFactory</code> that created instance
+     */
+    public MessageResourcesFactory getFactory() {
+        return (this.factory);
+    }
+
+    /**
+     * The set of previously created MessageFormat objects, keyed by the
+     * key computed in <code>messageKey()</code>.
+     */
+    protected HashMap formats = new HashMap();
+
+    /**
+     * Indicate is a <code>null</code> is returned instead of an error message string
+     * when an unknown Locale or key is requested.
+     */
+    protected boolean returnNull = false;
+
+    /**
+     * Indicates that a <code>null</code> is returned instead of an error message string
+     * if an unknown Locale or key is requested.
+     * @return true if null is returned if unknown key or locale is requested
+     */
+    public boolean getReturnNull() {
+        return (this.returnNull);
+    }
+
+    /**
+     * Indicates that a <code>null</code> is returned instead of an error message string
+     * if an unknown Locale or key is requested.
+     * @param returnNull true Indicates that a <code>null</code> is returned
+     * if an unknown Locale or key is requested.
+     */
+    public void setReturnNull(boolean returnNull) {
+        this.returnNull = returnNull;
+    }
+
+    // ----------------------------------------------------------- Constructors
+
+    /**
+     * Construct a new MessageResources according to the specified parameters.
+     *
+     * @param factory The MessageResourcesFactory that created us
+     * @param config The configuration parameter for this MessageResources
+     */
+    public MessageResources(MessageResourcesFactory factory, String config) {
+
+        this(factory, config, false);
+
+    }
+
+    /**
+     * Construct a new MessageResources according to the specified parameters.
+     *
+     * @param factory The MessageResourcesFactory that created us
+     * @param config The configuration parameter for this MessageResources
+     * @param returnNull The returnNull property we should initialize with
+     */
+    public MessageResources(
+        MessageResourcesFactory factory,
+        String config,
+        boolean returnNull) {
+
+        super();
+        this.factory = factory;
+        this.config = config;
+        this.returnNull = returnNull;
+
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Returns a text message for the specified key, for the default Locale.
+     *
+     * @param key The message key to look up
+     */
+    public String getMessage(String key) {
+
+        return this.getMessage((Locale) null, key);
+
+    }
+
+    /**
+     * Returns a text message after parametric replacement of the specified
+     * parameter placeholders.
+     *
+     * @param key The message key to look up
+     * @param args An array of replacement parameters for placeholders
+     */
+    public String getMessage(String key, Object args[]) {
+
+        return this.getMessage((Locale) null, key, args);
+
+    }
+
+    /**
+     * Returns a text message after parametric replacement of the specified
+     * parameter placeholders.
+     *
+     * @param key The message key to look up
+     * @param arg0 The replacement for placeholder {0} in the message
+     */
+    public String getMessage(String key, Object arg0) {
+
+        return this.getMessage((Locale) null, key, arg0);
+
+    }
+
+    /**
+     * Returns a text message after parametric replacement of the specified
+     * parameter placeholders.
+     *
+     * @param key The message key to look up
+     * @param arg0 The replacement for placeholder {0} in the message
+     * @param arg1 The replacement for placeholder {1} in the message
+     */
+    public String getMessage(String key, Object arg0, Object arg1) {
+
+        return this.getMessage((Locale) null, key, arg0, arg1);
+
+    }
+
+    /**
+     * Returns a text message after parametric replacement of the specified
+     * parameter placeholders.
+     *
+     * @param key The message key to look up
+     * @param arg0 The replacement for placeholder {0} in the message
+     * @param arg1 The replacement for placeholder {1} in the message
+     * @param arg2 The replacement for placeholder {2} in the message
+     */
+    public String getMessage(String key, Object arg0, Object arg1, Object arg2) {
+
+        return this.getMessage((Locale) null, key, arg0, arg1, arg2);
+
+    }
+
+    /**
+     * Returns a text message after parametric replacement of the specified
+     * parameter placeholders.
+     *
+     * @param key The message key to look up
+     * @param arg0 The replacement for placeholder {0} in the message
+     * @param arg1 The replacement for placeholder {1} in the message
+     * @param arg2 The replacement for placeholder {2} in the message
+     * @param arg3 The replacement for placeholder {3} in the message
+     */
+    public String getMessage(
+        String key,
+        Object arg0,
+        Object arg1,
+        Object arg2,
+        Object arg3) {
+
+        return this.getMessage((Locale) null, key, arg0, arg1, arg2, arg3);
+
+    }
+
+    /**
+     * Returns a text message for the specified key, for the default Locale.
+     * A null string result will be returned by this method if no relevant
+     * message resource is found for this key or Locale, if the
+     * <code>returnNull</code> property is set.  Otherwise, an appropriate
+     * error message will be returned.
+     * <p>
+     * This method must be implemented by a concrete subclass.
+     *
+     * @param locale The requested message Locale, or <code>null</code>
+     *  for the system default Locale
+     * @param key The message key to look up
+     */
+    public abstract String getMessage(Locale locale, String key);
+
+    /**
+     * Returns a text message after parametric replacement of the specified
+     * parameter placeholders.  A null string result will be returned by
+     * this method if no resource bundle has been configured.
+     *
+     * @param locale The requested message Locale, or <code>null</code>
+     *  for the system default Locale
+     * @param key The message key to look up
+     * @param args An array of replacement parameters for placeholders
+     */
+    public String getMessage(Locale locale, String key, Object args[]) {
+
+        // Cache MessageFormat instances as they are accessed
+        if (locale == null) {
+            locale = defaultLocale;
+        }
+
+        MessageFormat format = null;
+        String formatKey = messageKey(locale, key);
+
+        synchronized (formats) {
+            format = (MessageFormat) formats.get(formatKey);
+            if (format == null) {
+                String formatString = getMessage(locale, key);
+
+                if (formatString == null) {
+                    return returnNull ? null : ("???" + formatKey + "???");
+                }
+
+                format = new MessageFormat(escape(formatString));
+                formats.put(formatKey, format);
+            }
+
+        }
+
+        return format.format(args);
+    }
+
+    /**
+     * Returns a text message after parametric replacement of the specified
+     * parameter placeholders.  A null string result will never be returned
+     * by this method.
+     *
+     * @param locale The requested message Locale, or <code>null</code>
+     *  for the system default Locale
+     * @param key The message key to look up
+     * @param arg0 The replacement for placeholder {0} in the message
+     */
+    public String getMessage(Locale locale, String key, Object arg0) {
+        return this.getMessage(locale, key, new Object[] { arg0 });
+    }
+
+    /**
+     * Returns a text message after parametric replacement of the specified
+     * parameter placeholders.  A null string result will never be returned
+     * by this method.
+     *
+     * @param locale The requested message Locale, or <code>null</code>
+     *  for the system default Locale
+     * @param key The message key to look up
+     * @param arg0 The replacement for placeholder {0} in the message
+     * @param arg1 The replacement for placeholder {1} in the message
+     */
+    public String getMessage(Locale locale, String key, Object arg0, Object arg1) {
+        return this.getMessage(locale, key, new Object[] { arg0, arg1 });
+    }
+
+    /**
+     * Returns a text message after parametric replacement of the specified
+     * parameter placeholders.  A null string result will never be returned
+     * by this method.
+     *
+     * @param locale The requested message Locale, or <code>null</code>
+     *  for the system default Locale
+     * @param key The message key to look up
+     * @param arg0 The replacement for placeholder {0} in the message
+     * @param arg1 The replacement for placeholder {1} in the message
+     * @param arg2 The replacement for placeholder {2} in the message
+     */
+    public String getMessage(
+        Locale locale,
+        String key,
+        Object arg0,
+        Object arg1,
+        Object arg2) {
+
+        return this.getMessage(locale, key, new Object[] { arg0, arg1, arg2 });
+    }
+
+    /**
+     * Returns a text message after parametric replacement of the specified
+     * parameter placeholders.  A null string result will never be returned
+     * by this method.
+     *
+     * @param locale The requested message Locale, or <code>null</code>
+     *  for the system default Locale
+     * @param key The message key to look up
+     * @param arg0 The replacement for placeholder {0} in the message
+     * @param arg1 The replacement for placeholder {1} in the message
+     * @param arg2 The replacement for placeholder {2} in the message
+     * @param arg3 The replacement for placeholder {3} in the message
+     */
+    public String getMessage(
+        Locale locale,
+        String key,
+        Object arg0,
+        Object arg1,
+        Object arg2,
+        Object arg3) {
+
+        return this.getMessage(locale, key, new Object[] { arg0, arg1, arg2, arg3 });
+    }
+
+    /**
+     * Return <code>true</code> if there is a defined message for the specified
+     * key in the system default locale.
+     *
+     * @param key The message key to look up
+     */
+    public boolean isPresent(String key) {
+
+        return this.isPresent(null, key);
+
+    }
+
+    /**
+     * Return <code>true</code> if there is a defined message for the specified
+     * key in the specified Locale.
+     *
+     * @param locale The requested message Locale, or <code>null</code>
+     *  for the system default Locale
+     * @param key The message key to look up
+     */
+    public boolean isPresent(Locale locale, String key) {
+
+        String message = getMessage(locale, key);
+
+        if (message == null) {
+            return false;
+
+        } else if (message.startsWith("???") && message.endsWith("???")) {
+            return false; // FIXME - Only valid for default implementation
+
+        } else {
+            return true;
+        }
+
+    }
+
+    // ------------------------------------------------------ Protected Methods
+
+    /**
+     * Escape any single quote characters that are included in the specified
+     * message string.
+     *
+     * @param string The string to be escaped
+     */
+    protected String escape(String string) {
+
+        if ((string == null) || (string.indexOf('\'') < 0)) {
+            return string;
+        }
+
+        int n = string.length();
+        StringBuffer sb = new StringBuffer(n);
+
+        for (int i = 0; i < n; i++) {
+            char ch = string.charAt(i);
+
+            if (ch == '\'') {
+                sb.append('\'');
+            }
+
+            sb.append(ch);
+        }
+
+        return sb.toString();
+
+    }
+
+    /**
+     * Compute and return a key to be used in caching information by a Locale.
+     * <strong>NOTE</strong> - The locale key for the default Locale in our
+     * environment is a zero length String.
+     *
+     * @param locale The locale for which a key is desired
+     */
+    protected String localeKey(Locale locale) {
+        return (locale == null) ? "" : locale.toString();
+    }
+
+    /**
+     * Compute and return a key to be used in caching information
+     * by Locale and message key.
+     *
+     * @param locale The Locale for which this format key is calculated
+     * @param key The message key for which this format key is calculated
+     */
+    protected String messageKey(Locale locale, String key) {
+
+        return (localeKey(locale) + "." + key);
+
+    }
+
+    /**
+     * Compute and return a key to be used in caching information
+     * by locale key and message key.
+     *
+     * @param localeKey The locale key for which this cache key is calculated
+     * @param key The message key for which this cache key is calculated
+     */
+    protected String messageKey(String localeKey, String key) {
+
+        return (localeKey + "." + key);
+
+    }
+
+    // --------------------------------------------------------- Static Methods
+
+    /**
+     * The default MessageResourcesFactory used to create MessageResources
+     * instances.
+     */
+    protected static MessageResourcesFactory defaultFactory = null;
+
+    /**
+     * Create and return an instance of <code>MessageResources</code> for the
+     * created by the default <code>MessageResourcesFactory</code>.
+     *
+     * @param config Configuration parameter for this message bundle.
+     */
+    public synchronized static MessageResources getMessageResources(String config) {
+
+        if (defaultFactory == null) {
+            defaultFactory = MessageResourcesFactory.createFactory();
+        }
+
+        return defaultFactory.createResources(config);
+    }
+
+    /**
+     * Log a message to the Writer that has been configured for our use.
+     *
+     * @param message The message to be logged
+     */
+    public void log(String message) {
+        log.debug(message);
+    }
+
+    /**
+     * Log a message and exception to the Writer that has been configured
+     * for our use.
+     *
+     * @param message The message to be logged
+     * @param throwable The exception to be logged
+     */
+    public void log(String message, Throwable throwable) {
+        log.debug(message, throwable);
+    }
+
+}

Propchange: struts/sandbox/trunk/tiles/core-library/src/java/org/apache/util/MessageResources.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/sandbox/trunk/tiles/core-library/src/java/org/apache/util/MessageResourcesFactory.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/tiles/core-library/src/java/org/apache/util/MessageResourcesFactory.java?rev=190662&view=auto
==============================================================================
--- struts/sandbox/trunk/tiles/core-library/src/java/org/apache/util/MessageResourcesFactory.java (added)
+++ struts/sandbox/trunk/tiles/core-library/src/java/org/apache/util/MessageResourcesFactory.java Tue Jun 14 14:59:13 2005
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2004-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.util;
+
+import java.io.Serializable;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.tiles.TilesUtil;
+
+
+/**
+ * Factory for <code>MessageResources</code> instances.  The general usage
+ * pattern for this class is:
+ * <ul>
+ * <li>Call <code>MessageResourcesFactory().createFactory()</code> to retrieve
+ *     a <code>MessageResourcesFactory</code> instance.</li>
+ * <li>Set properties as required to configure this factory instance to create
+ *     <code>MessageResources</code> instances with desired
+ *     characteristics.</li>
+ * <li>Call the <code>createResources()</code> method of the factory to
+ *     retrieve a newly instantiated <code>MessageResources</code>
+ *     instance.</li>
+ * </ul>
+ *
+ * @author Craig R. McClanahan
+ * @author David Geary
+ * @version $Revision: 1.8 $ $Date: 2002/10/17 03:20:31 $
+ */
+
+public abstract class MessageResourcesFactory implements Serializable {
+
+
+    // ---------------------------------------------------- Instance Properties
+
+
+    /**
+     * The "return null" property value to which newly created
+     * MessageResourcess should be initialized.
+     */
+    protected boolean returnNull = true;
+
+    /**
+     * Get default value of the "returnNull" property used to initialize newly created
+     * MessageResourcess.
+     * @return default value of the "returnNull" property newly created
+     * MessageResourcess are initialized to.
+     */
+    public boolean getReturnNull() {
+        return (this.returnNull);
+    }
+
+    /**
+     * Set the default value of the "returnNull" property newly created
+     * MessageResourcess are initialized to.
+     * @param  returnNull default value of the "returnNull" MessageResourcess are initialized to.
+     */
+    public void setReturnNull(boolean returnNull) {
+        this.returnNull = returnNull;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Create and return a newly instansiated <code>MessageResources</code>.
+     * This method must be implemented by concrete subclasses.
+     *
+     * @param config Configuration parameter(s) for the requested bundle
+     */
+    public abstract MessageResources createResources(String config);
+
+
+    // ------------------------------------------------------ Static Properties
+
+
+    /**
+     * The Java class to be used for
+     * <code>MessageResourcesFactory</code> instances.
+     */
+    protected static transient Class clazz = null;
+
+
+    /**
+     * Commons Logging instance.
+     */
+    private static Log LOG = LogFactory.getLog(MessageResourcesFactory.class);
+
+
+    /**
+     * The fully qualified class name to be used for
+     * <code>MessageResourcesFactory</code> instances.
+     */
+    protected static String factoryClass =
+        "org.apache.util.PropertyMessageResourcesFactory";
+
+    /**
+     * The fully qualified class name that is used for
+     * <code>MessageResourcesFactory</code> instances.
+     * @return class name that is used for
+     *   <code>MessageResourcesFactory</code> instances
+     */
+    public static String getFactoryClass() {
+        return (MessageResourcesFactory.factoryClass);
+    }
+
+    /**
+     * Set the fully qualified class name that is used for
+     * <code>MessageResourcesFactory</code> instances.
+     * @param factoryClass name that is used for
+     *   <code>MessageResourcesFactory</code> instances
+     */
+    public static void setFactoryClass(String factoryClass) {
+        MessageResourcesFactory.factoryClass = factoryClass;
+        MessageResourcesFactory.clazz = null;
+    }
+
+
+    // --------------------------------------------------------- Static Methods
+
+
+    /**
+     * Create and return a <code>MessageResourcesFactory</code> instance of the
+     * appropriate class, which can be used to create customized
+     * <code>MessageResources</code> instances.  If no such factory can be
+     * created, return <code>null</code> instead.
+     */
+    public static MessageResourcesFactory createFactory() {
+
+        // Construct a new instance of the specified factory class
+        try {
+            if (clazz == null)
+                clazz = TilesUtil.applicationClass(factoryClass);
+            MessageResourcesFactory factory =
+                (MessageResourcesFactory) clazz.newInstance();
+            return (factory);
+        } catch (Throwable t) {
+            LOG.error("MessageResourcesFactory.createFactory", t);
+            return (null);
+        }
+
+    }
+
+
+}



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org