You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@struts.apache.org by cr...@apache.org on 2005/08/22 04:23:41 UTC
svn commit: r234416 [1/2] - in /struts/sandbox/trunk/tiles/src:
java/org/apache/tiles/ java/org/apache/tiles/definition/
java/org/apache/tiles/digester/ java/org/apache/tiles/filter/
java/org/apache/tiles/servlets/ test/org/apache/tiles/ test/org/apach...
Author: craigmcc
Date: Sun Aug 21 19:23:25 2005
New Revision: 234416
URL: http://svn.apache.org/viewcvs?rev=234416&view=rev
Log:
Integrate the "Refactor DefinitionsFactory and Create Reloadable Definitions"
patch. I had to tweak a few javadoc entries to avoid warnings.
PR: Bugzilla #36028
Submitted By: Greg Reddin <gr...@fnf.com>
Added:
struts/sandbox/trunk/tiles/src/java/org/apache/tiles/ComponentDefinitions.java
struts/sandbox/trunk/tiles/src/java/org/apache/tiles/DefinitionsReader.java
struts/sandbox/trunk/tiles/src/java/org/apache/tiles/ReloadableDefinitionsFactory.java
struts/sandbox/trunk/tiles/src/java/org/apache/tiles/definition/ComponentDefinitionsImpl.java
struts/sandbox/trunk/tiles/src/java/org/apache/tiles/definition/UrlDefinitionsFactory.java
struts/sandbox/trunk/tiles/src/java/org/apache/tiles/digester/
struts/sandbox/trunk/tiles/src/java/org/apache/tiles/digester/DigesterDefinitionsReader.java
struts/sandbox/trunk/tiles/src/java/org/apache/tiles/filter/
struts/sandbox/trunk/tiles/src/java/org/apache/tiles/filter/TilesFilter.java
struts/sandbox/trunk/tiles/src/test/org/apache/tiles/TestComponentDefinitions.java
struts/sandbox/trunk/tiles/src/test/org/apache/tiles/TestDigesterDefinitionsReader.java
struts/sandbox/trunk/tiles/src/test/org/apache/tiles/TestReloadableDefinitionsFactory.java
struts/sandbox/trunk/tiles/src/test/org/apache/tiles/TestUrlDefinitionsFactory.java
struts/sandbox/trunk/tiles/src/test/org/apache/tiles/config/defs1.xml
struts/sandbox/trunk/tiles/src/test/org/apache/tiles/config/defs1_FR.xml
struts/sandbox/trunk/tiles/src/test/org/apache/tiles/config/defs1_en_US.xml
struts/sandbox/trunk/tiles/src/test/org/apache/tiles/config/defs2.xml
struts/sandbox/trunk/tiles/src/test/org/apache/tiles/config/defs3.xml
struts/sandbox/trunk/tiles/src/test/org/apache/tiles/config/invalid-defs.xml
struts/sandbox/trunk/tiles/src/test/org/apache/tiles/config/malformed-defs.xml
struts/sandbox/trunk/tiles/src/test/org/apache/tiles/config/temp-defs.xml
struts/sandbox/trunk/tiles/src/test/org/apache/tiles/mock/
struts/sandbox/trunk/tiles/src/test/org/apache/tiles/mock/MockComponentDefinitions.java
struts/sandbox/trunk/tiles/src/test/org/apache/tiles/mock/MockDefinitionsReader.java
Modified:
struts/sandbox/trunk/tiles/src/java/org/apache/tiles/ComponentDefinition.java
struts/sandbox/trunk/tiles/src/java/org/apache/tiles/DefinitionsFactory.java
struts/sandbox/trunk/tiles/src/java/org/apache/tiles/TilesUtil.java
struts/sandbox/trunk/tiles/src/java/org/apache/tiles/TilesUtilImpl.java
struts/sandbox/trunk/tiles/src/java/org/apache/tiles/definition/ComponentDefinitionsFactoryWrapper.java
struts/sandbox/trunk/tiles/src/java/org/apache/tiles/servlets/TilesServlet.java
struts/sandbox/trunk/tiles/src/test/org/apache/tiles/config/tiles-defs.xml
Modified: struts/sandbox/trunk/tiles/src/java/org/apache/tiles/ComponentDefinition.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/tiles/src/java/org/apache/tiles/ComponentDefinition.java?rev=234416&r1=234415&r2=234416&view=diff
==============================================================================
--- struts/sandbox/trunk/tiles/src/java/org/apache/tiles/ComponentDefinition.java (original)
+++ struts/sandbox/trunk/tiles/src/java/org/apache/tiles/ComponentDefinition.java Sun Aug 21 19:23:25 2005
@@ -20,10 +20,13 @@
import java.io.Serializable;
import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Locale;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.tiles.xmlDefinition.XmlAttribute;
import org.apache.tiles.xmlDefinition.XmlDefinition;
import org.apache.tiles.util.RequestUtils;
@@ -35,6 +38,11 @@
public class ComponentDefinition implements Serializable {
/**
+ * Extends attribute value.
+ */
+ private String inherit;
+
+ /**
* Commons Logging instance.
*/
protected static Log log = LogFactory.getLog(ComponentDefinition.class);
@@ -68,6 +76,11 @@
*/
protected String controllerType = null;
+ /**
+ * Used for resolving inheritance.
+ */
+ private boolean isVisited=false;
+
/**
* Controller name type.
*/
@@ -541,4 +554,192 @@
}
}
+ /**
+ * 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( ComponentDefinitions 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.
+ ComponentDefinition 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());
+ }
+ }
+
+ /**
+ * Resolve locale-specific 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( ComponentDefinitions definitionsSet, Locale locale)
+ 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.
+ ComponentDefinition parent = definitionsSet.getDefinition( getExtends(),
+ locale );
+ 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, locale );
+
+ // 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( ComponentDefinition 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/src/java/org/apache/tiles/ComponentDefinitions.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/tiles/src/java/org/apache/tiles/ComponentDefinitions.java?rev=234416&view=auto
==============================================================================
--- struts/sandbox/trunk/tiles/src/java/org/apache/tiles/ComponentDefinitions.java (added)
+++ struts/sandbox/trunk/tiles/src/java/org/apache/tiles/ComponentDefinitions.java Sun Aug 21 19:23:25 2005
@@ -0,0 +1,95 @@
+/*
+ * $Id$
+ *
+ * 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.tiles;
+
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Interface for managing collections of {@link ComponentDefinition} objects.
+ *
+ * <p>The ComponentDefinitions interface provides a pattern for managing
+ * ComponentDefinition objects. Implementations will provide a means to append
+ * new ComponentDefinitions to the collection, add and retrieve lcale-specific
+ * ComponentDefinitions objects, and reset the collections.</p>
+ *
+ * @version $Rev$ $Date$
+ */
+public interface ComponentDefinitions {
+
+ /**
+ * Returns a ComponentDefinition object that matches the given name.
+ *
+ * @param name The name of the ComponentDefinition to return.
+ * @return the ComponentDefinition matching the given name or null if none
+ * is found.
+ */
+ public ComponentDefinition getDefinition(String name);
+
+ /**
+ * Adds new ComponentDefinition objects to the internal collection and
+ * resolves inheritance attraibutes.
+ *
+ * @param defsMap The new definitions to add.
+ * @throws NoSuchDefinitionException if a ComponentDefinition extends from
+ * one that doesn't exist.
+ */
+ public void addDefinitions(Map defsMap) throws NoSuchDefinitionException ;
+
+ /**
+ * Adds new locale-specific ComponentDefinition objects to the internal
+ * collection and resolves inheritance attraibutes.
+ *
+ * @param defsMap The new definitions to add.
+ * @param locale The locale to add the definitions to.
+ * @throws NoSuchDefinitionException if a ComponentDefinition extends from
+ * one that doesn't exist.
+ */
+ public void addDefinitions(Map defsMap, Locale locale) throws NoSuchDefinitionException ;
+
+ /**
+ * Returns a ComponentDefinition object that matches the given name and locale.
+ *
+ * @param name The name of the ComponentDefinition to return.
+ * @param locale The locale to use to resolve the definition.
+ * @return the ComponentDefinition matching the given name or null if none
+ * is found.
+ */
+ public ComponentDefinition getDefinition(String name, Locale locale);
+
+ /**
+ * Resolves configuration inheritance properties.
+ */
+ public void resolveInheritances() throws NoSuchDefinitionException;
+
+ /**
+ * Resolves locale-specific configuration inheritance properties.
+ */
+ public void resolveInheritances(Locale locale) throws NoSuchDefinitionException;
+
+ /**
+ * Clears definitions.
+ */
+ public void reset();
+
+ /**
+ * Returns base definitions collection;
+ */
+ public Map getBaseDefinitions();
+}
Modified: struts/sandbox/trunk/tiles/src/java/org/apache/tiles/DefinitionsFactory.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/tiles/src/java/org/apache/tiles/DefinitionsFactory.java?rev=234416&r1=234415&r2=234416&view=diff
==============================================================================
--- struts/sandbox/trunk/tiles/src/java/org/apache/tiles/DefinitionsFactory.java (original)
+++ struts/sandbox/trunk/tiles/src/java/org/apache/tiles/DefinitionsFactory.java Sun Aug 21 19:23:25 2005
@@ -16,81 +16,95 @@
* limitations under the License.
*/
-
package org.apache.tiles;
-import java.io.Serializable;
-
-import javax.servlet.ServletContext;
-import javax.servlet.ServletRequest;
+import java.util.Locale;
+import java.util.Map;
/**
- * Tiles Definition factory.
- * This interface replace old ComponentDefinitionsFactory.
- * Main method getDefinition() is exactly the same. Initialization method change.
- * This interface allows to retrieve a definition by its name, independently of
- * the factory implementation.
- * Object life cycle is as follow:
- * <ul>
- * <li>Constructor: create object</li>
- * <li>setConfig: set config and initialize factory. After first call to this
- * method, factory is operational.</li>
- * <li>destroy: factory is being shutdown.</li>
- * </ul>
- * Implementation must be Serializable, in order to be compliant with web Container
- * having this constraint (Weblogic 6.x).
+ * Interface for creating a {@link ComponentDefinitions} object and managing
+ * its contents.
+ *
+ * <p>DefinitionsFactory implementations are responsible for maintaining the data
+ * sources of Tiles configuration data and using the data to create
+ * ComponentDefinitions sets. Implementations also know how to append
+ * locale-specific configuration data to an existing ComponentDefinitions set.</p>
+ *
+ *
+ * @version $Rev$ $Date$
*/
-public interface DefinitionsFactory extends Serializable
-{
-
- /**
- * Get a definition by its name.
- * @param name Name of requested definition.
- * @param request Current servelet request
- * @param servletContext current servlet context
- * @throws DefinitionsFactoryException An error occur while getting definition.
- * @throws NoSuchDefinitionException No definition found for specified name
- * Implementation can throw more accurate exception as a subclass of this exception
- */
- public ComponentDefinition getDefinition(String name, ServletRequest request, ServletContext servletContext)
- throws NoSuchDefinitionException,DefinitionsFactoryException;
-
- /**
- * Init definition factory.
- * This method is called immediately after factory creation, and prior any call
- * to setConfig().
- *
- * @param config Configuration object used to set factory configuration.
- * @param servletContext Servlet Context passed to factory.
- * @throws DefinitionsFactoryException An error occur during initialization.
- */
- public void init(DefinitionsFactoryConfig config, ServletContext servletContext)
- throws DefinitionsFactoryException;
-
+public interface DefinitionsFactory {
+
/**
- * <p>Receive notification that the factory is being
- * shut down.</p>
+ * Property name that specifies the implementation of the DefinitionsReader.
*/
- public void destroy();
-
- /**
- * Set factory configuration.
- * This method is used to change factory configuration.
- * This method is optional, and can send an exception if implementation
- * doesn't allow change in configuration.
- *
- * @param config Configuration object used to set factory configuration.
- * @param servletContext Servlet Context passed to factory.
- * @throws DefinitionsFactoryException An error occur during initialization.
- */
- public void setConfig(DefinitionsFactoryConfig config, ServletContext servletContext)
- throws DefinitionsFactoryException;
-
- /**
- * Get factory configuration.
- * @return TilesConfig
- */
- public DefinitionsFactoryConfig getConfig();
-
+ public static final String READER_IMPL_PROPERTY =
+ "org.apache.tiles.DefinitionsReader";
+ /**
+ * Property name that specifies the implementation of ComponentDefinitions.
+ */
+ public static final String DEFINITIONS_IMPL_PROPERTY =
+ "org.apache.tiles.ComponentDefinitions";
+
+ /**
+ * Initializes the DefinitionsFactory and its subcomponents.
+ *
+ * Implementations may support configuration properties to be passed in via
+ * the params Map.
+ *
+ * @param params The Map of configuration properties.
+ * @throws DefinitionsFactoryException if an initialization error occurs.
+ */
+ public void init(Map params) throws DefinitionsFactoryException;
+
+ /**
+ * Adds a source where ComponentDefinition objects are stored.
+ *
+ * Implementations should publish what type of source object they expect.
+ * The source should contain enough information to resolve a configuration
+ * source containing definitions. The source should be a "base" source for
+ * configurations. Internationalization and Localization properties will be
+ * applied by implementations to discriminate the correct data sources based
+ * on locale.
+ *
+ * @param source The configuration source for definitions.
+ * @throws DefinitionsFactoryException if an invalid source is passed in or
+ * an error occurs resolving the source to an actual data store.
+ */
+ public void addSource(Object source) throws DefinitionsFactoryException;
+
+ /**
+ * Creates and returns a {@link ComponentDefinitions} set by reading
+ * configuration data from the applied sources.
+ *
+ * @throws DefinitionsFactoryException if an error occurs reading the
+ * sources.
+ */
+ public ComponentDefinitions readDefinitions()
+ throws DefinitionsFactoryException;
+ /**
+ * Appends locale-specific {@link ComponentDefinition} objects to an existing
+ * {@link ComponentDefinitions} set by reading locale-specific versions of
+ * the applied sources.
+ *
+ * @param definitions The ComponentDefinitions object to append to.
+ * @param locale The requested locale.
+ * @throws DefinitionsFactoryException if an error occurs reading definitions.
+ */
+ public void addDefinitions(ComponentDefinitions definitions, Locale locale)
+ throws DefinitionsFactoryException;
+
+ /**
+ * Indicates whether a given locale has been processed or not.
+ *
+ * This method can be used to avoid unnecessary synchronization of the
+ * DefinitionsFactory in multi-threaded situations. Check the return of
+ * isLoacaleProcessed before synchronizing the object and reading
+ * locale-specific definitions.
+ *
+ * @param locale The locale to check.
+ * @return true if the given lcoale has been processed and false otherwise.
+ */
+ public boolean isLocaleProcessed(Locale locale);
}
Added: struts/sandbox/trunk/tiles/src/java/org/apache/tiles/DefinitionsReader.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/tiles/src/java/org/apache/tiles/DefinitionsReader.java?rev=234416&view=auto
==============================================================================
--- struts/sandbox/trunk/tiles/src/java/org/apache/tiles/DefinitionsReader.java (added)
+++ struts/sandbox/trunk/tiles/src/java/org/apache/tiles/DefinitionsReader.java Sun Aug 21 19:23:25 2005
@@ -0,0 +1,63 @@
+/*
+ * $Id$
+ *
+ * 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.tiles;
+
+import java.util.Map;
+
+/**
+ * Interface for reading <code>{@link ComponentDefinition}</code> from a source.
+ *
+ * <p>This interface provides a standard way to read
+ * <code>{@link ComponentDefinition}</code> objects from a source. Implementations
+ * should define what the source is, whether it be a persistent store such as a
+ * configuration file or database, or something like a web service. The
+ * DefinitionsReader is responsible for reading from a single location. It does
+ * not perform any internationalization duties or inheritance of ComponentDefinitions.
+ * It only reads from the source and returns a Map of objects read.</p>
+ *
+ * @version $Rev$ $Date$
+ */
+public interface DefinitionsReader {
+
+ /**
+ * Initializes the <code>DefinitionsReader</code> object.
+ *
+ * This method must be called before the {@link #read(java.lang.Object)} method is called.
+ *
+ * @param params A map of properties used to set up the reader.
+ * @throws DefinitionsFactoryException if required properties are not
+ * passed in or the initialization fails.
+ *
+ */
+ public void init(Map params) throws DefinitionsFactoryException;
+
+ /**
+ * Reads <code>{@link ComponentDefinition}</code> objects from a source.
+ *
+ * Implementations should publish what type of source object is expected.
+ *
+ * @param source The source from which definitions will be read.
+ * @return a Map of <code>ComponentDefinition</code> objects read from
+ * the source.
+ * @throws DefinitionsFactoryException if the source is invalid or
+ * an error occurs when reading definitions.
+ */
+ public Map read(Object source) throws DefinitionsFactoryException;
+
+}
Added: struts/sandbox/trunk/tiles/src/java/org/apache/tiles/ReloadableDefinitionsFactory.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/tiles/src/java/org/apache/tiles/ReloadableDefinitionsFactory.java?rev=234416&view=auto
==============================================================================
--- struts/sandbox/trunk/tiles/src/java/org/apache/tiles/ReloadableDefinitionsFactory.java (added)
+++ struts/sandbox/trunk/tiles/src/java/org/apache/tiles/ReloadableDefinitionsFactory.java Sun Aug 21 19:23:25 2005
@@ -0,0 +1,34 @@
+/*
+ * $Id$
+ *
+ * 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.tiles;
+
+/**
+ * Indicates support for reloading Tiles configuration when it changes.
+ *
+ * @version $Rev$ $Date$
+ */
+public interface ReloadableDefinitionsFactory {
+
+ /**
+ * Indicates whether the DefinitionsFactory is out of date and needs to be
+ * reloaded.
+ */
+ public boolean refreshRequired();
+}
Modified: struts/sandbox/trunk/tiles/src/java/org/apache/tiles/TilesUtil.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/tiles/src/java/org/apache/tiles/TilesUtil.java?rev=234416&r1=234415&r2=234416&view=diff
==============================================================================
--- struts/sandbox/trunk/tiles/src/java/org/apache/tiles/TilesUtil.java (original)
+++ struts/sandbox/trunk/tiles/src/java/org/apache/tiles/TilesUtil.java Sun Aug 21 19:23:25 2005
@@ -196,15 +196,7 @@
ServletContext servletContext)
throws FactoryNotFoundException, DefinitionsFactoryException {
- try {
- return getDefinitionsFactory(request, servletContext).getDefinition(
- definitionName,
- (HttpServletRequest) request,
- servletContext);
-
- } catch (NullPointerException ex) { // Factory not found in context
- throw new FactoryNotFoundException("Can't get definitions factory from context.");
- }
+ return tilesUtilImpl.getDefinition(definitionName, request, servletContext);
}
/**
Modified: struts/sandbox/trunk/tiles/src/java/org/apache/tiles/TilesUtilImpl.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/tiles/src/java/org/apache/tiles/TilesUtilImpl.java?rev=234416&r1=234415&r2=234416&view=diff
==============================================================================
--- struts/sandbox/trunk/tiles/src/java/org/apache/tiles/TilesUtilImpl.java (original)
+++ struts/sandbox/trunk/tiles/src/java/org/apache/tiles/TilesUtilImpl.java Sun Aug 21 19:23:25 2005
@@ -23,6 +23,11 @@
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
@@ -49,6 +54,10 @@
/** Constant name used to store factory in servlet context */
public static final String DEFINITIONS_FACTORY =
"org.apache.tiles.DEFINITIONS_FACTORY";
+
+ /** Constant used to store ComponentDefinitions graph. */
+ public static final String DEFINITIONS_OBJECT =
+ "org.apache.tiles.ComponentDefinitions";
/**
* JSP 2.0 include method to use which supports configurable flushing.
@@ -165,17 +174,71 @@
DefinitionsFactoryConfig factoryConfig)
throws DefinitionsFactoryException {
+ // FIXME: Pull from servlet context.
+ String factoryClassName = "org.apache.tiles.definition.UrlDefinitionsFactory";
+
// Create configurable factory
DefinitionsFactory factory =
- createDefinitionFactoryInstance(factoryConfig.getFactoryClassname());
-
- factory.init(factoryConfig, servletContext);
+ createDefinitionFactoryInstance(factoryClassName);
+
+ Map params = factoryConfig.getAttributes();
+
+ factory.init(params);
+
+ String configFiles = factoryConfig.getDefinitionConfigFiles();
+ List filenames = getFilenames(configFiles);
+
+ try {
+ for (int i = 0; i < filenames.size(); i++) {
+ String filename = (String) filenames.get(i);
+ factory.addSource(servletContext.getResource(filename));
+ }
+ } catch (MalformedURLException e) {
+ throw new DefinitionsFactoryException("Problem with filename URL: ", e);
+ }
+
+ ComponentDefinitions definitions = factory.readDefinitions();
// Make factory accessible from jsp tags (push it in appropriate context)
makeDefinitionsFactoryAccessible(factory, servletContext);
+ makeDefinitionsAccessible(definitions, servletContext);
+
return factory;
}
+ public ComponentDefinition getDefinition(String definitionName,
+ ServletRequest request,
+ ServletContext servletContext)
+ throws FactoryNotFoundException, DefinitionsFactoryException {
+
+ try {
+ DefinitionsFactory factory = getDefinitionsFactory(request, servletContext);
+ ComponentDefinitions definitions = (ComponentDefinitions)
+ servletContext.getAttribute(TilesUtilImpl.DEFINITIONS_OBJECT);
+ ComponentDefinition definition = definitions.getDefinition(
+ definitionName, request.getLocale());
+
+ if (definition == null) {
+ if (!factory.isLocaleProcessed(request.getLocale())) {
+ // FIXME This will modify the factory as well as the definitions
+ // but we are only locking the definitions.
+ //
+ // We'll have to refactor again to remove this issue.
+ synchronized (definitions) {
+ factory.addDefinitions(definitions, request.getLocale());
+ }
+ }
+
+ definition = definitions.getDefinition(
+ definitionName, request.getLocale());
+ }
+
+ return definition;
+ } catch (NullPointerException ex) { // Factory not found in context
+ throw new FactoryNotFoundException("Can't get definitions factory from context.");
+ }
+ }
+
/**
* Create Definition factory of specified classname.
* Factory class must extend the {@link DefinitionsFactory} class.
@@ -205,7 +268,7 @@
throw new DefinitionsFactoryException(
"Error - createDefinitionsFactory : Factory class '"
+ classname
- + " must implement 'TilesDefinitionsFactory'.",
+ + " must implement 'DefinitionsFactory'.",
ex);
} catch (ClassNotFoundException ex) { // Bad classname
@@ -236,4 +299,30 @@
servletContext.setAttribute(DEFINITIONS_FACTORY, factory);
}
-}
\ No newline at end of file
+ /**
+ * Make definition factory accessible to Tags.
+ * Factory is stored in servlet context.
+ * @param definitions Definition factory to be made accessible
+ * @param servletContext Current servlet context.
+ */
+ protected void makeDefinitionsAccessible(
+ ComponentDefinitions definitions,
+ ServletContext servletContext) {
+
+ servletContext.setAttribute(DEFINITIONS_OBJECT, definitions);
+ }
+
+ /**
+ * Parses a comma-delimited string for a list of config filenames.
+ */
+ protected List getFilenames(String filenameString) {
+ // Init list of filenames
+ StringTokenizer tokenizer = new StringTokenizer(filenameString, ",");
+ List filenames = new ArrayList(tokenizer.countTokens());
+ while (tokenizer.hasMoreTokens()) {
+ filenames.add(tokenizer.nextToken().trim());
+ }
+
+ return filenames;
+ }
+}
Modified: struts/sandbox/trunk/tiles/src/java/org/apache/tiles/definition/ComponentDefinitionsFactoryWrapper.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/tiles/src/java/org/apache/tiles/definition/ComponentDefinitionsFactoryWrapper.java?rev=234416&r1=234415&r2=234416&view=diff
==============================================================================
--- struts/sandbox/trunk/tiles/src/java/org/apache/tiles/definition/ComponentDefinitionsFactoryWrapper.java (original)
+++ struts/sandbox/trunk/tiles/src/java/org/apache/tiles/definition/ComponentDefinitionsFactoryWrapper.java Sun Aug 21 19:23:25 2005
@@ -37,7 +37,7 @@
* This class provides mapping from the old interface's life cycle to the new life cycle.
* @since 20020708
*/
-public class ComponentDefinitionsFactoryWrapper implements DefinitionsFactory {
+public class ComponentDefinitionsFactoryWrapper /*FIXME: implements DefinitionsFactory*/ {
/**
* The underlying factory.
Added: struts/sandbox/trunk/tiles/src/java/org/apache/tiles/definition/ComponentDefinitionsImpl.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/tiles/src/java/org/apache/tiles/definition/ComponentDefinitionsImpl.java?rev=234416&view=auto
==============================================================================
--- struts/sandbox/trunk/tiles/src/java/org/apache/tiles/definition/ComponentDefinitionsImpl.java (added)
+++ struts/sandbox/trunk/tiles/src/java/org/apache/tiles/definition/ComponentDefinitionsImpl.java Sun Aug 21 19:23:25 2005
@@ -0,0 +1,146 @@
+/*
+ * $Id$
+ *
+ * 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.tiles.definition;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+import org.apache.tiles.ComponentDefinition;
+import org.apache.tiles.ComponentDefinitions;
+import org.apache.tiles.NoSuchDefinitionException;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class ComponentDefinitionsImpl implements ComponentDefinitions {
+ /**
+ * The base set of ComponentDefinition objects not discriminated by locale.
+ */
+ private Map baseDefinitions;
+ /**
+ * The locale-specific set of definitions objects.
+ */
+ private Map localeSpecificDefinitions;
+
+ /** Creates a new instance of ComponentDefinitionsImpl */
+ public ComponentDefinitionsImpl() {
+ baseDefinitions = new HashMap();
+ localeSpecificDefinitions = new HashMap();
+ }
+
+ /**
+ * Returns a ComponentDefinition object that matches the given name.
+ *
+ * @param name The name of the ComponentDefinition to return.
+ * @return the ComponentDefinition matching the given name or null if none
+ * is found.
+ */
+ public ComponentDefinition getDefinition(String name) {
+ return (ComponentDefinition) baseDefinitions.get(name);
+ }
+
+ /**
+ * Adds new ComponentDefinition objects to the internal collection and
+ * resolves inheritance attraibutes.
+ *
+ * @param defsMap The new definitions to add.
+ */
+ public void addDefinitions(Map defsMap) throws NoSuchDefinitionException {
+ this.baseDefinitions.putAll(defsMap);
+ resolveInheritances();
+ }
+
+ /**
+ * Adds new locale-specific ComponentDefinition objects to the internal
+ * collection and resolves inheritance attraibutes.
+ *
+ * @param defsMap The new definitions to add.
+ * @param locale The locale to add the definitions to.
+ */
+ public void addDefinitions(Map defsMap, Locale locale) throws NoSuchDefinitionException {
+ localeSpecificDefinitions.put(locale, defsMap);
+ resolveInheritances(locale);
+ }
+
+ /**
+ * Returns a ComponentDefinition object that matches the given name and locale.
+ *
+ * @param name The name of the ComponentDefinition to return.
+ * @param locale The locale to use to resolve the definition.
+ * @return the ComponentDefinition matching the given name or null if none
+ * is found.
+ */
+ public ComponentDefinition getDefinition(String name, Locale locale) {
+ ComponentDefinition definition = null;
+ Map localeSpecificMap = (Map) localeSpecificDefinitions.get(locale);
+ if (localeSpecificMap != null) {
+ definition = (ComponentDefinition) localeSpecificMap.get(name);
+ }
+
+ if (definition == null) {
+ definition = getDefinition(name);
+ }
+
+ return definition;
+ }
+
+ /**
+ * Resolve extended instances.
+ */
+ public void resolveInheritances() throws NoSuchDefinitionException {
+ Iterator i = baseDefinitions.values().iterator();
+ while( i.hasNext() ) {
+ ComponentDefinition definition = (ComponentDefinition)i.next();
+ definition.resolveInheritance( this );
+ } // end loop
+ }
+
+ /**
+ * Resolve locale-specific extended instances.
+ */
+ public void resolveInheritances(Locale locale) throws NoSuchDefinitionException {
+ resolveInheritances();
+
+ Map map = (Map) localeSpecificDefinitions.get(locale);
+ if (map != null) {
+ Iterator i = map.values().iterator();
+ while( i.hasNext() ) {
+ ComponentDefinition definition = (ComponentDefinition)i.next();
+ definition.resolveInheritance( this, locale );
+ } // end loop
+ }
+ }
+
+ /**
+ * Clears definitions.
+ */
+ public void reset() {
+ this.baseDefinitions = new HashMap();
+ this.localeSpecificDefinitions = new HashMap();
+ }
+
+ /**
+ * Returns base definitions collection;
+ */
+ public Map getBaseDefinitions() {
+ return this.baseDefinitions;
+ }
+}
Added: struts/sandbox/trunk/tiles/src/java/org/apache/tiles/definition/UrlDefinitionsFactory.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/tiles/src/java/org/apache/tiles/definition/UrlDefinitionsFactory.java?rev=234416&view=auto
==============================================================================
--- struts/sandbox/trunk/tiles/src/java/org/apache/tiles/definition/UrlDefinitionsFactory.java (added)
+++ struts/sandbox/trunk/tiles/src/java/org/apache/tiles/definition/UrlDefinitionsFactory.java Sun Aug 21 19:23:25 2005
@@ -0,0 +1,386 @@
+/*
+ * $Id$
+ *
+ * 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.tiles.definition;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+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.Set;
+import org.apache.tiles.util.RequestUtils;
+import org.apache.tiles.ComponentDefinition;
+import org.apache.tiles.ComponentDefinitions;
+import org.apache.tiles.DefinitionsFactory;
+import org.apache.tiles.DefinitionsFactoryException;
+import org.apache.tiles.DefinitionsReader;
+import org.apache.tiles.ReloadableDefinitionsFactory;
+import org.apache.tiles.digester.DigesterDefinitionsReader;
+
+/**
+ * {@link org.apache.tiles.DefinitionsFactory DefinitionsFactory} implementation
+ * that manages ComponentDefinitions configuration data from URLs.
+ *
+ * <p>The ComponentDefinition objects are read from the
+ * {@link org.apache.tiles.digester.DigesterDefinitionsReader DigesterDefinitionsReader}
+ * class unless another implementation is specified.</p>
+ *
+ * @version $Rev$ $Date$
+ */
+public class UrlDefinitionsFactory
+ implements DefinitionsFactory, ReloadableDefinitionsFactory {
+
+ /**
+ * Contains the URL objects identifying where configuration data is found.
+ */
+ private List sources;
+ /**
+ * Reader used to get definitions from the sources.
+ */
+ private DefinitionsReader reader;
+ /**
+ * Contains the dates that the URL sources were last modified.
+ */
+ private Map lastModifiedDates;
+ /**
+ * Contains a list of locales that have been processed.
+ */
+ private List processedLocales;
+
+ /**
+ * ComponentDefinitions class name.
+ */
+ private String definitionsClassName;
+
+ /** Creates a new instance of UrlDefinitionsFactory */
+ public UrlDefinitionsFactory() {
+ sources = new ArrayList();
+ lastModifiedDates = new HashMap();
+ processedLocales = new ArrayList();
+ }
+
+ /**
+ * Initializes the DefinitionsFactory and its subcomponents.
+ *
+ * Implementations may support configuration properties to be passed in via
+ * the params Map.
+ *
+ * @param params The Map of configuration properties.
+ * @throws DefinitionsFactoryException if an initialization error occurs.
+ */
+ public void init(Map params) throws DefinitionsFactoryException {
+ if (params != null) {
+ String readerClassName = (String) params.get(
+ DefinitionsFactory.READER_IMPL_PROPERTY);
+ if (readerClassName != null) {
+ try {
+ Class readerClass =
+ RequestUtils.applicationClass(readerClassName);
+ reader = (DefinitionsReader) readerClass.newInstance();
+ } catch (ClassNotFoundException e) {
+ throw new DefinitionsFactoryException(
+ "Cannot find reader class.", e);
+ } catch (InstantiationException e) {
+ throw new DefinitionsFactoryException(
+ "Unable to instantiate reader class.", e);
+ } catch (IllegalAccessException e) {
+ throw new DefinitionsFactoryException(
+ "Unable to access reader class.", e);
+ }
+ }
+
+ definitionsClassName = (String) params.get(
+ DefinitionsFactory.DEFINITIONS_IMPL_PROPERTY);
+ if (definitionsClassName != null) {
+ // Attempt to create it just to verify.
+ ComponentDefinitions definitions = createDefinitionsImpl(
+ definitionsClassName);
+ }
+ }
+
+ if (reader == null) {
+ reader = new DigesterDefinitionsReader();
+ }
+
+ reader.init(params);
+ }
+
+ /**
+ * Adds a source where ComponentDefinition objects are stored.
+ *
+ * Implementations should publish what type of source object they expect.
+ * The source should contain enough information to resolve a configuration
+ * source containing definitions. The source should be a "base" source for
+ * configurations. Internationalization and Localization properties will be
+ * applied by implementations to discriminate the correct data sources based
+ * on locale.
+ *
+ * @param source The configuration source for definitions.
+ * @throws DefinitionsFactoryException if an invalid source is passed in or
+ * an error occurs resolving the source to an actual data store.
+ */
+ public void addSource(Object source) throws DefinitionsFactoryException {
+ if (source == null) {
+ throw new DefinitionsFactoryException(
+ "Source object must not be null");
+ }
+
+ if (!(source instanceof URL)) {
+ throw new DefinitionsFactoryException(
+ "Source object must be an URL");
+ }
+
+ sources.add(source);
+ }
+
+ /**
+ * Appends locale-specific {@link ComponentDefinition} objects to an existing
+ * {@link ComponentDefinitions} set by reading locale-specific versions of
+ * the applied sources.
+ *
+ * @param definitions The ComponentDefinitions object to append to.
+ * @param locale The requested locale.
+ * @throws DefinitionsFactoryException if an error occurs reading definitions.
+ */
+ public void addDefinitions(ComponentDefinitions definitions, Locale locale)
+ throws DefinitionsFactoryException {
+
+ List postfixes = calculatePostixes(locale);
+
+ if (isLocaleProcessed(locale)) {
+ return;
+ } else {
+ processedLocales.add(locale);
+ }
+
+ for (int i = 0; i < sources.size(); i++) {
+ URL url = (URL) sources.get(i);
+ String path = url.toExternalForm();
+
+ for (int j = 0; j < postfixes.size(); j++) {
+ String newPath = concatPostfix(path, (String) postfixes.get(j));
+ try {
+ URL newUrl = new URL(newPath);
+ URLConnection connection = newUrl.openConnection();
+ connection.connect();
+ lastModifiedDates.put(newUrl.toExternalForm(),
+ new Long(connection.getLastModified()));
+ Map defsMap = reader.read(connection.getInputStream());
+ definitions.addDefinitions(defsMap, locale);
+ } catch (FileNotFoundException e) {
+ // File not found. continue.
+ } catch (IOException e) {
+ throw new DefinitionsFactoryException(
+ "I/O error processing configuration.");
+ }
+ }
+ }
+ }
+
+ /**
+ * Creates and returns a {@link ComponentDefinitions} set by reading
+ * configuration data from the applied sources.
+ *
+ * @throws DefinitionsFactoryException if an error occurs reading the
+ * sources.
+ */
+ public ComponentDefinitions readDefinitions()
+ throws DefinitionsFactoryException {
+
+ ComponentDefinitions definitions =
+ createDefinitionsImpl(definitionsClassName);
+ try {
+ for (int i = 0; i < sources.size(); i++) {
+ URL source = (URL) sources.get(i);
+ URLConnection connection = source.openConnection();
+ connection.connect();
+ lastModifiedDates.put(source.toExternalForm(),
+ new Long(connection.getLastModified()));
+ Map defsMap = reader.read(connection.getInputStream());
+ definitions.addDefinitions(defsMap);
+ }
+ } catch (IOException e) {
+ throw new DefinitionsFactoryException("I/O error accessing source.", e);
+ }
+ return definitions;
+ }
+
+ /**
+ * Indicates whether a given locale has been processed or not.
+ *
+ * This method can be used to avoid unnecessary synchronization of the
+ * DefinitionsFactory in multi-threaded situations. Check the return of
+ * isLoacaleProcessed before synchronizing the object and reading
+ * locale-specific definitions.
+ *
+ * @param locale The locale to check.
+ * @return true if the given lcoale has been processed and false otherwise.
+ */
+ public boolean isLocaleProcessed(Locale locale) {
+ if (processedLocales.contains(locale)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * 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 locale the locale
+ */
+ private static List calculatePostixes(Locale locale) {
+ final List result = new ArrayList();
+ 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();
+ 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;
+ }
+ }
+
+ /**
+ * Creates the ComponentDefinitions instance specified by the initialization
+ * parameter or the default if none is specified.
+ *
+ * @param classname The class of the ComponentDefinitins to create.
+ * @return the instantiated ComponentDefinitions object.
+ * @throws DefinitionsFactoryException if a problem occurs.
+ */
+ protected ComponentDefinitions createDefinitionsImpl(String classname)
+ throws DefinitionsFactoryException {
+
+ ComponentDefinitions definitions = null;
+ if (classname != null) {
+ try {
+ Class defsClass =
+ RequestUtils.applicationClass(classname);
+ definitions = (ComponentDefinitions) defsClass.newInstance();
+ } catch (ClassNotFoundException e) {
+ throw new DefinitionsFactoryException(
+ "Cannot find definitions class.", e);
+ } catch (InstantiationException e) {
+ throw new DefinitionsFactoryException(
+ "Unable to instantiate definitions class.", e);
+ } catch (IllegalAccessException e) {
+ throw new DefinitionsFactoryException(
+ "Unable to access definitions class.", e);
+ }
+ }
+
+ if (definitions == null) {
+ definitions = new ComponentDefinitionsImpl();
+ }
+
+ return definitions;
+ }
+
+ /**
+ * Indicates whether the DefinitionsFactory is out of date and needs to be
+ * reloaded.
+ */
+ public boolean refreshRequired() {
+ boolean status = false;
+
+ Set urls = lastModifiedDates.keySet();
+
+ try {
+ Iterator i = urls.iterator();
+ while (i.hasNext()) {
+ String urlPath = (String) i.next();
+ Long lastModifiedDate = (Long) lastModifiedDates.get(urlPath);
+ URL url = new URL(urlPath);
+ URLConnection connection = url.openConnection();
+ connection.connect();
+ long newModDate = connection.getLastModified();
+ if (newModDate != lastModifiedDate.longValue()) {
+ status = true;
+ break;
+ }
+ }
+ } catch (Exception e) {
+ // Should probably log here.
+ return true;
+ }
+ return status;
+ }
+
+}
Added: struts/sandbox/trunk/tiles/src/java/org/apache/tiles/digester/DigesterDefinitionsReader.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/tiles/src/java/org/apache/tiles/digester/DigesterDefinitionsReader.java?rev=234416&view=auto
==============================================================================
--- struts/sandbox/trunk/tiles/src/java/org/apache/tiles/digester/DigesterDefinitionsReader.java (added)
+++ struts/sandbox/trunk/tiles/src/java/org/apache/tiles/digester/DigesterDefinitionsReader.java Sun Aug 21 19:23:25 2005
@@ -0,0 +1,365 @@
+/*
+ * $Id$
+ *
+ * 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.tiles.digester;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.commons.digester.Digester;
+import org.apache.tiles.ComponentDefinition;
+import org.apache.tiles.DefinitionsFactoryException;
+import org.apache.tiles.DefinitionsReader;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+/**
+ * Reads {@link org.apache.tiles.ComponentDefinition ComponentDefinition} objects
+ * from an XML InputStream using Digester.
+ *
+ * <p>This <code>DefinitionsReader</code> implementation expects the source to be
+ * passed as an <code>InputStream</code>. It parses XML data from the source and
+ * builds a Map of ComponentDefinition objects.</p>
+ *
+ * <p>The Digester object can be configured by passing in initialization parameters.
+ * Currently the only parameter that is supported is the <code>validating</code>
+ * parameter. This value is set to <code>false</code> by default. To enable DTD
+ * validation for XML ComponentDefinition files, give the init method a parameter
+ * with a key of <code>definitions-parser-validate</code> and a value of
+ * <code>"true"</code>.
+ *
+ * <p>The ComponentDefinition objects are stored internally in a Map. The Map is
+ * stored as an instance variable rather than a local variable in the <code>read</code>
+ * method. This means that instances of this class are <strong>not</strong>
+ * thread-safe and access by multiple threads must be synchronized.</p>
+ *
+ * @version $Rev$ $Date$
+ */
+public class DigesterDefinitionsReader implements DefinitionsReader {
+
+ /**
+ * Digester validation parameter name.
+ */
+ public static final String PARSER_VALIDATE_PARAMETER_NAME =
+ "definitions-parser-validate";
+ /**
+ * <code>Digester</code> object used to read ComponentDefinition data
+ * from the source.
+ */
+ protected Digester digester;
+ /**
+ * Stores ComponentDefinition objects.
+ */
+ Map definitions;
+ /**
+ * 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[] = {
+ "-//Apache Software Foundation//DTD Tiles Configuration 1.1//EN",
+ "/org/apache/tiles/resources/tiles-config_1_1.dtd",
+ "-//Apache Software Foundation//DTD Tiles Configuration 1.2//EN",
+ "/org/apache/tiles/resources/tiles-config_1_2.dtd",
+ };
+
+ /**
+ * Indicates whether init method has been called.
+ */
+ private boolean inited = false;
+
+ /** Creates a new instance of DigesterDefinitionsReader */
+ public DigesterDefinitionsReader() {
+ 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().getClassLoader().getResource(
+ registrations[i+1]);
+ if (url != null) {
+ digester.register(registrations[i], url.toString());
+ }
+ }
+ }
+
+ /**
+ * Reads <code>{@link ComponentDefinition}</code> objects from a source.
+ *
+ * Implementations should publish what type of source object is expected.
+ *
+ * @param source The <code>InputStream</code> source from which definitions
+ * will be read.
+ * @return a Map of <code>ComponentDefinition</code> objects read from
+ * the source.
+ * @throws DefinitionsFactoryException if the source is invalid or
+ * an error occurs when reading definitions.
+ */
+ public Map read(Object source) throws DefinitionsFactoryException {
+
+ // Get out if we have not been initialized.
+ if (!inited) {
+ throw new DefinitionsFactoryException(
+ "Definitions reader has not been initialized.");
+ }
+
+ // This is an instance variable instead of a local variable because
+ // we want to be able to call the addDefinition method to populate it.
+ // But we reset the Map here, which, of course, has threading implications.
+ definitions = new HashMap();
+
+ if (source == null) {
+ // Perhaps we should throw an exception here.
+ return null;
+ }
+
+ InputStream input = null;
+ try {
+ input = (InputStream) source;
+ } catch (ClassCastException e) {
+ throw new DefinitionsFactoryException(
+ "Invalid source type. Requires java.io.InputStream.", e);
+ }
+
+ try {
+ // set first object in stack
+ //digester.clear();
+ digester.push(this);
+ // parse
+ digester.parse(input);
+
+ } catch (SAXException e) {
+ throw new DefinitionsFactoryException(
+ "XML error reading definitions.", e);
+ } catch (IOException e) {
+ throw new DefinitionsFactoryException(
+ "I/O Error reading definitions.", e);
+ }
+
+ return definitions;
+ }
+
+ /**
+ * Initializes the <code>DefinitionsReader</code> object.
+ *
+ * This method must be called before the {@link #read} method is called.
+ *
+ * @param params A map of properties used to set up the reader.
+ * @throws DefinitionsFactoryException if required properties are not
+ * passed in or the initialization fails.
+ */
+ public void init(Map params) throws DefinitionsFactoryException {
+
+ if (params != null) {
+ String value = (String) params.get(PARSER_VALIDATE_PARAMETER_NAME);
+ if (value != null) {
+ digester.setValidating(Boolean.valueOf(value).booleanValue());
+ }
+ }
+
+
+ initDigesterForTilesDefinitionsSyntax( digester );
+ initDigesterForComponentsDefinitionsSyntax( digester );
+ initDigesterForInstancesSyntax( digester );
+
+ inited = true;
+ }
+
+
+ /**
+ * 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, "addDefinition", 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, "addDefinition", 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, "addDefinition", 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);
+ }
+
+ /**
+ * Adds a new <code>ComponentDefinition</code> to the internal Map or replaces
+ * an existing one.
+ *
+ * @param definition The ComponentDefinition object to be added.
+ */
+ public void addDefinition(ComponentDefinition definition) {
+ definitions.put(definition.getName(), definition);
+ }
+}
Added: struts/sandbox/trunk/tiles/src/java/org/apache/tiles/filter/TilesFilter.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/tiles/src/java/org/apache/tiles/filter/TilesFilter.java?rev=234416&view=auto
==============================================================================
--- struts/sandbox/trunk/tiles/src/java/org/apache/tiles/filter/TilesFilter.java (added)
+++ struts/sandbox/trunk/tiles/src/java/org/apache/tiles/filter/TilesFilter.java Sun Aug 21 19:23:25 2005
@@ -0,0 +1,140 @@
+/*
+ * $Id$
+ *
+ * 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.tiles.filter;
+
+import java.io.IOException;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import org.apache.tiles.ComponentDefinitions;
+import org.apache.tiles.DefinitionsFactory;
+import org.apache.tiles.ReloadableDefinitionsFactory;
+import org.apache.tiles.TilesUtil;
+import org.apache.tiles.TilesUtilImpl;
+
+/**
+ * Processes Reloadable Tiles Definitions.
+ *
+ * @version $Rev$ $Date$
+ */
+
+public class TilesFilter implements Filter {
+
+ /**
+ * The filter configuration object we are associated with. If
+ * this value is null, this filter instance is not currently
+ * configured.
+ */
+ private FilterConfig filterConfig = null;
+
+ public TilesFilter() {
+ }
+
+ /**
+ * Checks whether Tiles Definitions need to be reloaded.
+ *
+ * @param request The servlet request we are processing
+ * @param response The servlet response we are creating
+ * @param chain The filter chain we are processing
+ *
+ * @exception IOException if an input/output error occurs
+ * @exception ServletException if a servlet error occurs
+ */
+ public void doFilter(ServletRequest request, ServletResponse response,
+ FilterChain chain)
+ throws IOException, ServletException {
+
+ try {
+ DefinitionsFactory factory = TilesUtil.getDefinitionsFactory(request,
+ filterConfig.getServletContext());
+
+ if (factory instanceof ReloadableDefinitionsFactory) {
+ if (((ReloadableDefinitionsFactory) factory).refreshRequired()) {
+ if (debug) {
+ log("Updating Tiles definitions.");
+ }
+
+ ComponentDefinitions newDefs = null;
+ synchronized (factory) {
+ newDefs = factory.readDefinitions();
+ }
+
+ ComponentDefinitions definitions = (ComponentDefinitions)
+ filterConfig.getServletContext().getAttribute(
+ TilesUtilImpl.DEFINITIONS_OBJECT);
+ synchronized (definitions) {
+ definitions.reset();
+ definitions.addDefinitions(newDefs.getBaseDefinitions());
+ }
+ }
+ }
+
+ chain.doFilter(request, response);
+
+ } catch(Exception e) {
+ throw new ServletException("Error processing request.", e);
+ }
+ }
+
+
+ /**
+ * Return the filter configuration object for this filter.
+ */
+ public FilterConfig getFilterConfig() {
+ return (this.filterConfig);
+ }
+
+
+ /**
+ * Set the filter configuration object for this filter.
+ *
+ * @param filterConfig The filter configuration object
+ */
+ public void setFilterConfig(FilterConfig filterConfig) {
+
+ this.filterConfig = filterConfig;
+ }
+
+ /**
+ * Destroy method for this filter
+ */
+ public void destroy() {
+ }
+
+
+ /**
+ * Init method for this filter
+ */
+ public void init(FilterConfig filterConfig) {
+ this.filterConfig = filterConfig;
+
+ if (debug) {
+ log("TilesFilter:Initializing filter");
+ }
+ }
+
+ public void log(String msg) {
+ filterConfig.getServletContext().log(msg);
+ }
+
+ private static final boolean debug = true;
+}
Modified: struts/sandbox/trunk/tiles/src/java/org/apache/tiles/servlets/TilesServlet.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/tiles/src/java/org/apache/tiles/servlets/TilesServlet.java?rev=234416&r1=234415&r2=234416&view=diff
==============================================================================
--- struts/sandbox/trunk/tiles/src/java/org/apache/tiles/servlets/TilesServlet.java (original)
+++ struts/sandbox/trunk/tiles/src/java/org/apache/tiles/servlets/TilesServlet.java Sun Aug 21 19:23:25 2005
@@ -187,8 +187,6 @@
* <i>definitions-config</i> context param was not
* specified, Tiles assumes that your Tiles definition
* file is <code>/WEB-INF/tiles.xml</code>.
- *
- * @param config The servlet config
*/
protected DefinitionsFactoryConfig readFactoryConfig()
throws ServletException {
@@ -243,7 +241,7 @@
* if an exception is thrown when the tiles:insert tag is
* activated.
*
- * @param servletContext The servlet context
+ * @param config The servlet configuration
* @param ex An exception
*/
private void saveExceptionMessage(ServletConfig config, Exception ex) {
Added: struts/sandbox/trunk/tiles/src/test/org/apache/tiles/TestComponentDefinitions.java
URL: http://svn.apache.org/viewcvs/struts/sandbox/trunk/tiles/src/test/org/apache/tiles/TestComponentDefinitions.java?rev=234416&view=auto
==============================================================================
--- struts/sandbox/trunk/tiles/src/test/org/apache/tiles/TestComponentDefinitions.java (added)
+++ struts/sandbox/trunk/tiles/src/test/org/apache/tiles/TestComponentDefinitions.java Sun Aug 21 19:23:25 2005
@@ -0,0 +1,214 @@
+/*
+ * $Id$
+ *
+ * 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.tiles;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.apache.tiles.definition.ComponentDefinitionsImpl;
+import org.apache.tiles.xmlDefinition.XmlAttribute;
+
+/**
+ * Tests the ComponentDefinitionsImpl class.
+ *
+ * @version $Rev$ $Date$
+ */
+public class TestComponentDefinitions extends TestCase {
+
+ /** Creates a new instance of TestComponentDefinitions */
+ public TestComponentDefinitions(String name) {
+ super(name);
+ }
+
+ /**
+ * Start the tests.
+ *
+ * @param theArgs the arguments. Not used
+ */
+ public static void main(String[] theArgs) {
+ junit.awtui.TestRunner.main(
+ new String[] { TestComponentDefinitions.class.getName()});
+ }
+
+ /**
+ * @return a test suite (<code>TestSuite</code>) that includes all methods
+ * starting with "test"
+ */
+ public static Test suite() {
+ return new TestSuite(TestComponentDefinitions.class);
+ }
+
+ /**
+ * Tests the inheritance properties of ComponentDefinition objects.
+ */
+ public void testResolveInheritances() {
+ Map defs = new HashMap();
+
+ ComponentDefinition def = new ComponentDefinition();
+ def.setName("parent.def1");
+ def.setPath("/test1.jsp");
+ XmlAttribute attr = new XmlAttribute();
+ attr.setName("attr1");
+ attr.setValue("value1");
+ def.addAttribute(attr);
+ defs.put(def.getName(), def);
+
+ def = new ComponentDefinition();
+ def.setName("child.def1");
+ def.setExtends("parent.def1");
+ attr = new XmlAttribute();
+ attr.setName("attr1");
+ attr.setValue("New value");
+ def.addAttribute(attr);
+ defs.put(def.getName(), def);
+
+ ComponentDefinitions definitions = new ComponentDefinitionsImpl();
+ try {
+ definitions.addDefinitions(defs);
+ } catch (NoSuchDefinitionException e) {
+ fail("Test failure: " + e);
+ }
+
+ assertNotNull("Couldn't get parent.",
+ definitions.getDefinition("parent.def1"));
+ assertEquals("Incorrect path value." , "/test1.jsp",
+ definitions.getDefinition("parent.def1").getPath());
+ assertEquals("Incorrect attr1 value", "value1",
+ definitions.getDefinition("parent.def1").getAttribute("attr1"));
+
+ assertNotNull("Couldn't get child.",
+ definitions.getDefinition("child.def1"));
+ assertEquals("Incorrect path value." , "/test1.jsp",
+ definitions.getDefinition("child.def1").getPath());
+ assertEquals("Incorrect attr1 value", "New value",
+ definitions.getDefinition("child.def1").getAttribute("attr1"));
+ }
+
+ /**
+ * Tests the inheritance with localized definitions.
+ */
+ public void testLocalizedResolveInheritances() {
+ Map defs = new HashMap();
+ ComponentDefinition def = new ComponentDefinition();
+ def.setName("parent.def1");
+ def.setPath("/test1.jsp");
+ XmlAttribute attr = new XmlAttribute();
+ attr.setName("attr1");
+ attr.setValue("value1");
+ def.addAttribute(attr);
+ defs.put(def.getName(), def);
+
+ def = new ComponentDefinition();
+ def.setName("child.def1");
+ def.setExtends("parent.def1");
+ attr = new XmlAttribute();
+ attr.setName("attr1");
+ attr.setValue("New value");
+ def.addAttribute(attr);
+ defs.put(def.getName(), def);
+
+ Map localDefs = new HashMap();
+ def = new ComponentDefinition();
+ def.setName("child.def1");
+ def.setExtends("parent.def1");
+ attr = new XmlAttribute();
+ attr.setName("attr1");
+ attr.setValue("US Value");
+ def.addAttribute(attr);
+ localDefs.put(def.getName(), def);
+
+ ComponentDefinitions definitions = new ComponentDefinitionsImpl();
+ try {
+ definitions.addDefinitions(defs);
+ definitions.addDefinitions(localDefs, Locale.US);
+ } catch (NoSuchDefinitionException e) {
+ fail("Test failure: " + e);
+ }
+
+ assertNotNull("Couldn't get parent.",
+ definitions.getDefinition("parent.def1"));
+ assertEquals("Incorrect path value." , "/test1.jsp",
+ definitions.getDefinition("parent.def1").getPath());
+ assertEquals("Incorrect attr1 value", "value1",
+ definitions.getDefinition("parent.def1").getAttribute("attr1"));
+
+ assertNotNull("Couldn't get child.",
+ definitions.getDefinition("child.def1"));
+ assertEquals("Incorrect path value." , "/test1.jsp",
+ definitions.getDefinition("child.def1").getPath());
+ assertEquals("Incorrect attr1 value", "New value",
+ definitions.getDefinition("child.def1").getAttribute("attr1"));
+
+ assertNotNull("Couldn't get parent.",
+ definitions.getDefinition("parent.def1", Locale.US));
+ assertEquals("Incorrect path value." , "/test1.jsp",
+ definitions.getDefinition("parent.def1", Locale.US).getPath());
+ assertEquals("Incorrect attr1 value", "value1",
+ definitions.getDefinition("parent.def1", Locale.US).getAttribute("attr1"));
+
+ assertNotNull("Couldn't get child.",
+ definitions.getDefinition("child.def1", Locale.US));
+ assertEquals("Incorrect path value." , "/test1.jsp",
+ definitions.getDefinition("child.def1", Locale.US).getPath());
+ assertEquals("Incorrect attr1 value", "US Value",
+ definitions.getDefinition("child.def1", Locale.US).getAttribute("attr1"));
+ }
+
+ /**
+ * Tests the reset method.
+ */
+ public void testReset() {
+ Map defs = new HashMap();
+
+ ComponentDefinition def = new ComponentDefinition();
+ def.setName("parent.def1");
+ def.setPath("/test1.jsp");
+ XmlAttribute attr = new XmlAttribute();
+ attr.setName("attr1");
+ attr.setValue("value1");
+ def.addAttribute(attr);
+ defs.put(def.getName(), def);
+
+ def = new ComponentDefinition();
+ def.setName("child.def1");
+ def.setExtends("parent.def1");
+ attr = new XmlAttribute();
+ attr.setName("attr1");
+ attr.setValue("New value");
+ def.addAttribute(attr);
+ defs.put(def.getName(), def);
+
+ ComponentDefinitions definitions = new ComponentDefinitionsImpl();
+ try {
+ definitions.addDefinitions(defs);
+ } catch (NoSuchDefinitionException e) {
+ fail("Test failure: " + e);
+ }
+
+ assertNotNull("Couldn't get parent.",
+ definitions.getDefinition("parent.def1"));
+
+ definitions.reset();
+ assertNull("Definitions should be null.",
+ definitions.getDefinition("parent.def1"));
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org