Author: tmjee Date: Sun Nov 5 06:22:54 2006 New Revision: 471435 URL: http://svn.apache.org/viewvc?view=rev&rev=471435 Log: WW-1490 - Have a composite ActionMapper that decides which ActionMapper it contains should be used
Added: struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/mapper/CompositeActionMapper.java struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/mapper/CompositeActionMapperTest.java Modified: struts/struts2/trunk/core/src/main/java/org/apache/struts2/StrutsConstants.java struts/struts2/trunk/core/src/main/java/org/apache/struts2/config/Settings.java struts/struts2/trunk/core/src/main/resources/org/apache/struts2/default.properties Modified: struts/struts2/trunk/core/src/main/java/org/apache/struts2/StrutsConstants.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/StrutsConstants.java?view=diff&rev=471435&r1=471434&r2=471435 ============================================================================== --- struts/struts2/trunk/core/src/main/java/org/apache/struts2/StrutsConstants.java (original) +++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/StrutsConstants.java Sun Nov 5 06:22:54 2006 @@ -17,6 +17,8 @@ */ package org.apache.struts2; +import org.apache.struts2.dispatcher.mapper.CompositeActionMapper; + /** * This class provides a central location for framework configuration keys * used to retrieve and store Struts configuration settings. @@ -134,4 +136,6 @@ /** Whether slashes in action names are allowed or not */ public static final String STRUTS_ENABLE_SLASHES_IN_ACTION_NAMES = "struts.enable.SlashesInActionNames"; + /** Prefix used by [EMAIL PROTECTED] CompositeActionMapper} to identified its containing [EMAIL PROTECTED] ActionMapper} class. */ + public static final String STRUTS_MAPPER_COMPOSITE = "struts.mapper.composite."; } Modified: struts/struts2/trunk/core/src/main/java/org/apache/struts2/config/Settings.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/config/Settings.java?view=diff&rev=471435&r1=471434&r2=471435 ============================================================================== --- struts/struts2/trunk/core/src/main/java/org/apache/struts2/config/Settings.java (original) +++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/config/Settings.java Sun Nov 5 06:22:54 2006 @@ -135,7 +135,7 @@ return val; } - + /** * Returns an Iterator of all properties names. * Added: struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/mapper/CompositeActionMapper.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/mapper/CompositeActionMapper.java?view=auto&rev=471435 ============================================================================== --- struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/mapper/CompositeActionMapper.java (added) +++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/mapper/CompositeActionMapper.java Sun Nov 5 06:22:54 2006 @@ -0,0 +1,254 @@ +/* + * $Id: ActionMapper.java 449367 2006-09-24 06:49:04Z mrdon $ + * + * Copyright 2006 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.struts2.dispatcher.mapper; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.struts2.StrutsConstants; +import org.apache.struts2.config.Settings; + +import com.opensymphony.xwork2.ObjectFactory; +import com.opensymphony.xwork2.config.ConfigurationManager; +import com.opensymphony.xwork2.util.FileManager; + +/** + * A composite action mapper that is capable of delegating to a series of [EMAIL PROTECTED] ActionMapper} if the former + * failed to obtained a valid [EMAIL PROTECTED] ActionMapping} or uri. + * <p/> + * It is configured through struts.properties. + * <p/> + * For example, with the following entries in struts.properties + * <pre> + * struts.mapper.class=org.apache.struts2.dispatcher.mapper.CompositeActionMapper + * struts.mapper.composite.1=org.apache.struts2.dispatcher.mapper.DefaultActionMapper + * struts.mapper.composite.2=org.apache.struts2.dispatcher.mapper.RestfulActionMapper + * struts.mapper.composite.3=org.apache.struts2.dispatcher.mapper.Restful2ActionMapper + * </pre> + * When [EMAIL PROTECTED] CompositeActionMapper#getMapping(HttpServletRequest, ConfigurationManager)} or + * [EMAIL PROTECTED] CompositeActionMapper#getUriFromActionMapping(ActionMapping)} is invoked, + * [EMAIL PROTECTED] CompositeActionMapper} would go through these [EMAIL PROTECTED] ActionMapper}s in sequence + * starting from [EMAIL PROTECTED] ActionMapper} identified by 'struts.mapper.composite.1', followed by + * 'struts.mapper.composite.2' and finally 'struts.mapper.composite.3' (in this case) until either + * one of the [EMAIL PROTECTED] ActionMapper} return a valid result (not null) or it runs out of [EMAIL PROTECTED] ActionMapper} + * in which case it will just return null for both + * [EMAIL PROTECTED] CompositeActionMapper#getMapping(HttpServletRequest, ConfigurationManager)} and + * [EMAIL PROTECTED] CompositeActionMapper#getUriFromActionMapping(ActionMapping)} methods. + * + * <p/> + * + * @see ActionMapper + * @see ActionMapperFactory + * @see ActionMapping + * @see IndividualActionMapperEntry + * + * @version $Date$ $Id$ + */ +public class CompositeActionMapper implements ActionMapper { + + private static final Log LOG = LogFactory.getLog(CompositeActionMapper.class); + + protected List<IndividualActionMapperEntry> orderedActionMappers; + + + public ActionMapping getMapping(HttpServletRequest request, ConfigurationManager configManager) { + + for (IndividualActionMapperEntry actionMapperEntry: getOrderedActionMapperEntries()) { + ActionMapping actionMapping = actionMapperEntry.actionMapper.getMapping(request, configManager); + if (LOG.isDebugEnabled()) { + LOG.debug("Using ActionMapper from entry ["+actionMapperEntry.propertyName+"="+actionMapperEntry.propertyValue+"]"); + } + if (actionMapping == null) { + if (LOG.isDebugEnabled()) { + LOG.debug("ActionMapper from entry ["+actionMapperEntry.propertyName+"="+actionMapperEntry.propertyValue+"] failed to return an ActionMapping (null)"); + } + } + else { + return actionMapping; + } + } + if (LOG.isDebugEnabled()) { + LOG.debug("exhausted from ActionMapper that could return an ActionMapping"); + } + return null; + } + + public String getUriFromActionMapping(ActionMapping mapping) { + + for (IndividualActionMapperEntry actionMapperEntry: getOrderedActionMapperEntries()) { + String uri = actionMapperEntry.actionMapper.getUriFromActionMapping(mapping); + if (LOG.isDebugEnabled()) { + LOG.debug("Using ActionMapper from entry ["+actionMapperEntry.propertyName+"="+actionMapperEntry.propertyValue+"]"); + } + if (uri == null) { + if (LOG.isDebugEnabled()) { + LOG.debug("ActionMapper from entry ["+actionMapperEntry.propertyName+"="+actionMapperEntry.propertyValue+"] failed to return a uri (null)"); + } + } + else { + return uri; + } + } + if (LOG.isDebugEnabled()) { + LOG.debug("exhausted from ActionMapper that could return a uri"); + } + return null; + } + + + protected List<IndividualActionMapperEntry> getOrderedActionMapperEntries() { + if (this.orderedActionMappers == null || FileManager.isReloadingConfigs()) { + + List<IndividualActionMapperEntry> actionMapperEntriesContainer = new ArrayList<IndividualActionMapperEntry>(); + Iterator settings = Settings.list(); + while(settings.hasNext()) { + String setting = settings.next().toString(); + if (setting.startsWith(StrutsConstants.STRUTS_MAPPER_COMPOSITE)) { + try { + int order = Integer.valueOf(setting.substring(StrutsConstants.STRUTS_MAPPER_COMPOSITE.length(), setting.length())); + String propertyValue = Settings.get(setting); + if (propertyValue != null && propertyValue.trim().length() > 0) { + actionMapperEntriesContainer.add( + new IndividualActionMapperEntry(order, setting, propertyValue)); + } + else { + LOG.warn("Ignoring property "+setting+" that contains no value"); + } + } + catch(NumberFormatException e) { + LOG.warn("Ignoring malformed property "+setting); + } + } + } + + Collections.sort(actionMapperEntriesContainer, new Comparator<IndividualActionMapperEntry>() { + public int compare(IndividualActionMapperEntry o1, IndividualActionMapperEntry o2) { + return o1.compareTo(o2); + } + }); + + + ObjectFactory objectFactory = ObjectFactory.getObjectFactory(); + List<IndividualActionMapperEntry> result = new ArrayList<IndividualActionMapperEntry>(); + for (IndividualActionMapperEntry entry: actionMapperEntriesContainer) { + String actionMapperClassName = entry.propertyValue; + try { + // Let us get ClassCastException if it does not implement ActionMapper + ActionMapper actionMapper = (ActionMapper) objectFactory.buildBean(actionMapperClassName, null); + result.add(new IndividualActionMapperEntry(entry.order, entry.propertyName, entry.propertyValue, actionMapper)); + } + catch(Exception e) { + LOG.warn("failed to create action mapper "+actionMapperClassName+", ignoring it", e); + } + } + + this.orderedActionMappers = result; + } + + return this.orderedActionMappers; + } + + + /** + * A value object (holder) that holds information regarding [EMAIL PROTECTED] ActionMapper} this [EMAIL PROTECTED] CompositeActionMapper} + * is capable of delegating to. + * <p/> + * The information stored are :- + * <ul> + * <li> order</li> + * <li> propertyValue</li> + * <li> propertyName</li> + * <li> actionMapper</li> + * </ul> + * + * eg. if we have the following entry in struts.properties + * <pre> + * struts.mapper.composite.1=foo.bar.ActionMapper1 + * struts.mapper.composite.2=foo.bar.ActionMapper2 + * struts.mapper.composite.3=foo.bar.ActionMapper3 + * </pre> + * + * <table border="1"> + * <tr> + * <td>order</td> + * <td>propertyName</td> + * <td>propertyValue</td> + * <td>actionMapper</td> + * </tr> + * <tr> + * <td>1</td> + * <td>struts.mapper.composite.1</td> + * <td>foo.bar.ActionMapper1</td> + * <td>instance of foo.bar.ActionMapper1</td> + * </tr> + * <tr> + * <td>2</td> + * <td>struts.mapper.composite.2</td> + * <td>foo.bar.ActionMapper2</td> + * <td>instance of foo.bar.ActionMapper2</td> + * </tr> + * <tr> + * <td>3</td> + * <td>struts.mapper.composite.3</td> + * <td>foo.bar.ActionMapper3</td> + * <td>instance of foo.bar.ActionMapper3</td> + * </tr> + * </table> + * + * @version $Date$ $Id$ + */ + public class IndividualActionMapperEntry implements Comparable<IndividualActionMapperEntry> { + + public Integer order; + public String propertyValue; + public String propertyName; + public ActionMapper actionMapper; + + + private IndividualActionMapperEntry(Integer order, String propertyName, String propertyValue) { + assert(order != null); + assert(propertyValue != null); + assert(propertyName != null); + this.order = order; + this.propertyValue = propertyValue; + this.propertyName = propertyName; + } + + public IndividualActionMapperEntry(Integer order, String propertyName, String propertyValue, ActionMapper actionMapper) { + assert(order != null); + assert(propertyValue != null); + assert(propertyName != null); + assert(actionMapper != null); + this.order = order; + this.propertyValue = propertyValue; + this.propertyName = propertyName; + this.actionMapper = actionMapper; + } + + public int compareTo(IndividualActionMapperEntry o) { + return order - o.order; + } + } +} Modified: struts/struts2/trunk/core/src/main/resources/org/apache/struts2/default.properties URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/resources/org/apache/struts2/default.properties?view=diff&rev=471435&r1=471434&r2=471435 ============================================================================== --- struts/struts2/trunk/core/src/main/resources/org/apache/struts2/default.properties (original) +++ struts/struts2/trunk/core/src/main/resources/org/apache/struts2/default.properties Sun Nov 5 06:22:54 2006 @@ -49,6 +49,15 @@ ### How request URLs are mapped to and from actions struts.mapper.class=org.apache.struts2.dispatcher.mapper.DefaultActionMapper +### The above line is to be commented and following are to be uncommented to +### enable CompositeActionMapper +### - With CompositeActionMapper one could specified many ActionMapper instance, where +### each of them will be chosen according to the order. Lower order number has +### higher precedence +#struts.mapper.class=org.apache.struts2.dispatcher.mapper.CompositeActionMapper +#struts.mapper.composite.1=org.apache.struts2.dispatcher.mapper.DefaultActionMapper +#struts.mapper.composite.2=foo.bar.MyActionMapper +#struts.mapper.composite.3=foo.bar.MyAnotherActionMapper ### Used by the DefaultActionMapper ### You may provide a comma separated list, e.g. struts.action.extension=action,jnlp,do Added: struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/mapper/CompositeActionMapperTest.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/mapper/CompositeActionMapperTest.java?view=auto&rev=471435 ============================================================================== --- struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/mapper/CompositeActionMapperTest.java (added) +++ struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/mapper/CompositeActionMapperTest.java Sun Nov 5 06:22:54 2006 @@ -0,0 +1,347 @@ +/* + * $Id: ActionMapper.java 449367 2006-09-24 06:49:04Z mrdon $ + * + * Copyright 2006 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.struts2.dispatcher.mapper; + +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.struts2.StrutsConstants; +import org.apache.struts2.config.Settings; +import org.apache.struts2.dispatcher.mapper.CompositeActionMapper.IndividualActionMapperEntry; +import org.springframework.mock.web.MockHttpServletRequest; + +import com.opensymphony.xwork2.config.ConfigurationManager; + +import junit.framework.TestCase; + +/** + * + * @version $Date$ $Id$ + */ +public class CompositeActionMapperTest extends TestCase { + + /** + * Test with empty settings (settings with no entries of interest) + * + * @throws Exception + */ + public void testGetOrderActionMapperEntries1() throws Exception { + CompositeActionMapper compositeActionMapper = new CompositeActionMapper(); + List<IndividualActionMapperEntry> result = + compositeActionMapper.getOrderedActionMapperEntries(); + + assertEquals(result.size(), 0); + } + + /** + * Test with a normal settings. + * + * @throws Exception + */ + public void testGetOrderActionMapperEntries2() throws Exception { + CompositeActionMapper compositeActionMapper = new CompositeActionMapper(); + + Settings old = Settings.getInstance(); + try { + Settings.setInstance(new InnerSettings()); + Settings.set(StrutsConstants.STRUTS_MAPPER_COMPOSITE+"1", InnerActionMapper1.class.getName()); + Settings.set(StrutsConstants.STRUTS_MAPPER_COMPOSITE+"2", InnerActionMapper2.class.getName()); + Settings.set(StrutsConstants.STRUTS_MAPPER_COMPOSITE+"3", InnerActionMapper3.class.getName()); + + List<IndividualActionMapperEntry> result = + compositeActionMapper.getOrderedActionMapperEntries(); + + assertEquals(result.size(), 3); + + IndividualActionMapperEntry e = null; + Iterator<IndividualActionMapperEntry> i = result.iterator(); + + // 1 + e = i.next(); + + assertEquals(e.order, new Integer(1)); + assertEquals(e.propertyName, StrutsConstants.STRUTS_MAPPER_COMPOSITE+"1"); + assertEquals(e.propertyValue, InnerActionMapper1.class.getName()); + assertEquals(e.actionMapper.getClass(), InnerActionMapper1.class); + + // 2 + e = i.next(); + + assertEquals(e.order, new Integer(2)); + assertEquals(e.propertyName, StrutsConstants.STRUTS_MAPPER_COMPOSITE+"2"); + assertEquals(e.propertyValue, InnerActionMapper2.class.getName()); + assertEquals(e.actionMapper.getClass(), InnerActionMapper2.class); + + // 3 + e = i.next(); + assertEquals(e.order, new Integer(3)); + assertEquals(e.propertyName, StrutsConstants.STRUTS_MAPPER_COMPOSITE+"3"); + assertEquals(e.propertyValue, InnerActionMapper3.class.getName()); + assertEquals(e.actionMapper.getClass(), InnerActionMapper3.class); + } + finally { + Settings.setInstance(old); + } + } + + /** + * Test with settings where entries are out-of-order, it needs to be able to retrieve them + * back in proper order. + * + * @throws Exception + */ + public void testGetOrderActionMapperEntries3() throws Exception { + CompositeActionMapper compositeActionMapper = new CompositeActionMapper(); + + Settings old = Settings.getInstance(); + try { + Settings.setInstance(new InnerSettings()); + Settings.set(StrutsConstants.STRUTS_MAPPER_COMPOSITE+"3", InnerActionMapper3.class.getName()); + Settings.set(StrutsConstants.STRUTS_MAPPER_COMPOSITE+"2", InnerActionMapper2.class.getName()); + Settings.set(StrutsConstants.STRUTS_MAPPER_COMPOSITE+"1", InnerActionMapper1.class.getName()); + + List<IndividualActionMapperEntry> result = + compositeActionMapper.getOrderedActionMapperEntries(); + + assertEquals(result.size(), 3); + + IndividualActionMapperEntry e = null; + Iterator<IndividualActionMapperEntry> i = result.iterator(); + + // 1 + e = i.next(); + + assertEquals(e.order, new Integer(1)); + assertEquals(e.propertyName, StrutsConstants.STRUTS_MAPPER_COMPOSITE+"1"); + assertEquals(e.propertyValue, InnerActionMapper1.class.getName()); + assertEquals(e.actionMapper.getClass(), InnerActionMapper1.class); + + // 2 + e = i.next(); + + assertEquals(e.order, new Integer(2)); + assertEquals(e.propertyName, StrutsConstants.STRUTS_MAPPER_COMPOSITE+"2"); + assertEquals(e.propertyValue, InnerActionMapper2.class.getName()); + assertEquals(e.actionMapper.getClass(), InnerActionMapper2.class); + + // 3 + e = i.next(); + assertEquals(e.order, new Integer(3)); + assertEquals(e.propertyName, StrutsConstants.STRUTS_MAPPER_COMPOSITE+"3"); + assertEquals(e.propertyValue, InnerActionMapper3.class.getName()); + assertEquals(e.actionMapper.getClass(), InnerActionMapper3.class); + } + finally { + Settings.setInstance(old); + } + } + + /** + * Test with a bad entry + * + * @throws Exception + */ + public void testGetOrderActionMapperEntries4() throws Exception { + CompositeActionMapper compositeActionMapper = new CompositeActionMapper(); + + Settings old = Settings.getInstance(); + try { + Settings.setInstance(new InnerSettings()); + Settings.set(StrutsConstants.STRUTS_MAPPER_COMPOSITE+"1", InnerActionMapper1.class.getName()); + Settings.set(StrutsConstants.STRUTS_MAPPER_COMPOSITE+"NotANumber", InnerActionMapper2.class.getName()); + Settings.set(StrutsConstants.STRUTS_MAPPER_COMPOSITE+"3", InnerActionMapper3.class.getName()); + + List<IndividualActionMapperEntry> result = + compositeActionMapper.getOrderedActionMapperEntries(); + + assertEquals(result.size(), 2); + + IndividualActionMapperEntry e = null; + Iterator<IndividualActionMapperEntry> i = result.iterator(); + + // 1 + e = i.next(); + + assertEquals(e.order, new Integer(1)); + assertEquals(e.propertyName, StrutsConstants.STRUTS_MAPPER_COMPOSITE+"1"); + assertEquals(e.propertyValue, InnerActionMapper1.class.getName()); + assertEquals(e.actionMapper.getClass(), InnerActionMapper1.class); + + // 2 + e = i.next(); + assertEquals(e.order, new Integer(3)); + assertEquals(e.propertyName, StrutsConstants.STRUTS_MAPPER_COMPOSITE+"3"); + assertEquals(e.propertyValue, InnerActionMapper3.class.getName()); + assertEquals(e.actionMapper.getClass(), InnerActionMapper3.class); + } + finally { + Settings.setInstance(old); + } + } + + /** + * Test with an entry where the action mapper class is bogus. + * @throws Exception + */ + public void testGetOrderActionMapperEntries5() throws Exception { + CompositeActionMapper compositeActionMapper = new CompositeActionMapper(); + + Settings old = Settings.getInstance(); + try { + Settings.setInstance(new InnerSettings()); + Settings.set(StrutsConstants.STRUTS_MAPPER_COMPOSITE+"1", InnerActionMapper1.class.getName()); + Settings.set(StrutsConstants.STRUTS_MAPPER_COMPOSITE+"2", "bogus.class.name"); + Settings.set(StrutsConstants.STRUTS_MAPPER_COMPOSITE+"3", InnerActionMapper3.class.getName()); + + List<IndividualActionMapperEntry> result = + compositeActionMapper.getOrderedActionMapperEntries(); + + assertEquals(result.size(), 2); + + IndividualActionMapperEntry e = null; + Iterator<IndividualActionMapperEntry> i = result.iterator(); + + // 1 + e = i.next(); + + assertEquals(e.order, new Integer(1)); + assertEquals(e.propertyName, StrutsConstants.STRUTS_MAPPER_COMPOSITE+"1"); + assertEquals(e.propertyValue, InnerActionMapper1.class.getName()); + assertEquals(e.actionMapper.getClass(), InnerActionMapper1.class); + + + // 2 + e = i.next(); + assertEquals(e.order, new Integer(3)); + assertEquals(e.propertyName, StrutsConstants.STRUTS_MAPPER_COMPOSITE+"3"); + assertEquals(e.propertyValue, InnerActionMapper3.class.getName()); + assertEquals(e.actionMapper.getClass(), InnerActionMapper3.class); + } + finally { + Settings.setInstance(old); + } + } + + + + public void testGetActionMappingAndUri1() throws Exception { + CompositeActionMapper compositeActionMapper = new CompositeActionMapper(); + + Settings old = Settings.getInstance(); + try { + Settings.setInstance(new InnerSettings()); + Settings.set(StrutsConstants.STRUTS_MAPPER_COMPOSITE+"1", InnerActionMapper1.class.getName()); + Settings.set(StrutsConstants.STRUTS_MAPPER_COMPOSITE+"2", InnerActionMapper2.class.getName()); + Settings.set(StrutsConstants.STRUTS_MAPPER_COMPOSITE+"3", InnerActionMapper3.class.getName()); + + + ActionMapping actionMapping = compositeActionMapper.getMapping(new MockHttpServletRequest(), new ConfigurationManager()); + String uri = compositeActionMapper.getUriFromActionMapping(new ActionMapping()); + + assertNotNull(actionMapping); + assertNotNull(uri); + assertTrue(actionMapping == InnerActionMapper3.actionMapping); + assertTrue(uri == InnerActionMapper3.uri); + } + finally { + Settings.setInstance(old); + } + } + + public void testGetActionMappingAndUri2() throws Exception { + CompositeActionMapper compositeActionMapper = new CompositeActionMapper(); + + Settings old = Settings.getInstance(); + try { + Settings.setInstance(new InnerSettings()); + Settings.set(StrutsConstants.STRUTS_MAPPER_COMPOSITE+"1", InnerActionMapper1.class.getName()); + Settings.set(StrutsConstants.STRUTS_MAPPER_COMPOSITE+"2", InnerActionMapper2.class.getName()); + + + ActionMapping actionMapping = compositeActionMapper.getMapping(new MockHttpServletRequest(), new ConfigurationManager()); + String uri = compositeActionMapper.getUriFromActionMapping(new ActionMapping()); + + assertNull(actionMapping); + assertNull(uri); + } + finally { + Settings.setInstance(old); + } + } + + + public static class InnerActionMapper1 implements ActionMapper { + public static ActionMapping actionMapping = new ActionMapping(); + public static String uri="uri1"; + + public ActionMapping getMapping(HttpServletRequest request, ConfigurationManager configManager) { + return null; + } + public String getUriFromActionMapping(ActionMapping mapping) { + return null; + } + } + public static class InnerActionMapper2 implements ActionMapper { + public static ActionMapping actionMapping = new ActionMapping(); + public static String uri="uri2"; + + public ActionMapping getMapping(HttpServletRequest request, ConfigurationManager configManager) { + return null; + } + public String getUriFromActionMapping(ActionMapping mapping) { + return null; + } + } + public static class InnerActionMapper3 implements ActionMapper { + public static ActionMapping actionMapping = new ActionMapping(); + public static String uri = "uri3"; + + public ActionMapping getMapping(HttpServletRequest request, ConfigurationManager configManager) { + return actionMapping; + } + public String getUriFromActionMapping(ActionMapping mapping) { + return uri; + } + } + + class InnerSettings extends Settings { + private Map<String, String> _impl = new LinkedHashMap<String, String>(); + + @Override + public boolean isSetImpl(String name) { + return _impl.containsKey(name); + } + @Override + public void setImpl(String name, String value) throws IllegalArgumentException, UnsupportedOperationException { + _impl.put(name, value); + } + @Override + public String getImpl(String name) throws IllegalArgumentException { + return (String) _impl.get(name); + } + @Override + public Iterator listImpl() { + return _impl.keySet().iterator(); + } + } + +}