[ http://mc4j.org/jira/browse/STS-268?page=comments#action_10572 ] Remi VANKEISBELCK commented on STS-268: ---------------------------------------
Hi there, Just wondering : isn't that issue a duplicate of STS-262 ? I'm working on clean/SEF URLs support in stripes and attach everything there : http://stripes.mc4j.org/jira/browse/STS-262 Maybe one of the two issues should be closed for the sake of clarity ? Also, Patrick, are you still working on this ? Are you interested in a joint effort ? Cheers > Cleaner URLs > ------------ > > Key: STS-268 > URL: http://mc4j.org/jira/browse/STS-268 > Project: Stripes > Issue Type: New Feature > Components: ActionBean Dispatching > Affects Versions: Release 1.4 > Reporter: Patrick Lightbody > Assigned To: Tim Fennell > Fix For: Release 1.5 > > > To implement "cleaner URLs", I had to set up both a filter and a servlet in > web.xml. I also had to create a custom ActionNameResolver. > web.xml: > --------------- > <filter> > <filter-name>StripesActionFilter</filter-name> > > <filter-class>com.cparty.stripes.util.CPartyActionBeanFilter</filter-class> > </filter> > <filter-mapping> > <filter-name>StripesActionFilter</filter-name> > <url-pattern>/*</url-pattern> > <dispatcher>REQUEST</dispatcher> > </filter-mapping> > <servlet> > <servlet-name>ServletHelper</servlet-name> > > <servlet-class>com.cparty.stripes.util.CPartyServletHelper</servlet-class> > <load-on-startup>1</load-on-startup> > </servlet> > --------------- > Servlet: > --------------- > package com.cparty.stripes.util; > import javax.servlet.http.HttpServlet; > import javax.servlet.ServletConfig; > import javax.servlet.ServletException; > public class CPartyServletHelper extends HttpServlet { > public static CPartyServletHelper servlet; > public void init(ServletConfig servletConfig) throws ServletException { > super.init(servletConfig); > CPartyServletHelper.servlet = this; > } > } > --------------- > Filter: > --------------- > package com.cparty.stripes.util; > import net.sourceforge.stripes.action.ActionBeanContext; > import net.sourceforge.stripes.action.Resolution; > import net.sourceforge.stripes.config.Configuration; > import net.sourceforge.stripes.controller.*; > import net.sourceforge.stripes.exception.StripesServletException; > import net.sourceforge.stripes.validation.BooleanTypeConverter; > import javax.servlet.*; > import javax.servlet.http.HttpServletRequest; > import javax.servlet.http.HttpServletResponse; > import javax.servlet.jsp.JspFactory; > import javax.servlet.jsp.PageContext; > import java.io.IOException; > import java.lang.reflect.InvocationTargetException; > import java.util.Stack; > public class CPartyActionBeanFilter implements Filter { > public static final String RUN_CUSTOM_VALIDATION_WHEN_ERRORS = > "Validation.InvokeValidateWhenErrorsExist"; > private Boolean alwaysInvokeValidate; > private FilterConfig filterConfig; > public void init(final FilterConfig filterConfig) throws ServletException > { > this.filterConfig = filterConfig; > } > public void doFilter(ServletRequest servletRequest, ServletResponse > servletResponse, FilterChain filterChain) throws IOException, > ServletException { > // It sucks that we have to do this here (in the request cycle), but > there doesn't > // seem to be a good way to get at the Configuration from the Filter > in init() > doOneTimeConfiguration(); > HttpServletRequest request = (HttpServletRequest) servletRequest; > HttpServletResponse response = (HttpServletResponse) servletResponse; > if ("/".equals(request.getServletPath())) { > filterChain.doFilter(request, response); > return; > } > Configuration config = StripesFilter.getConfiguration(); > ActionBeanContext context = > config.getActionBeanContextFactory().getContextInstance(request, response); > try { > // we look up the bean name to see if we should pass the request > through or not > > StripesFilter.getConfiguration().getActionResolver().getActionBean(context); > } catch (StripesServletException e) { > filterChain.doFilter(servletRequest, servletResponse); > return; > } > > /////////////////////////////////////////////////////////////////////// > // Here beings the reall processing of the request! > > /////////////////////////////////////////////////////////////////////// > PageContext pageContext = null; > try { > context.setServletContext(filterConfig.getServletContext()); > // Then setup the ExecutionContext that we'll use to process this > request > final ExecutionContext ctx = new ExecutionContext(); > > ctx.setInterceptors(config.getInterceptors(LifecycleStage.ActionBeanResolution)); > ctx.setLifecycleStage(LifecycleStage.ActionBeanResolution); > ctx.setActionBeanContext(context); > // It's unclear whether this usage of the JspFactory will work in > all containers. It looks > // like it should, but still, we should be careful not to screw > up regular request > // processing if it should fail. Why do we do this? So we can > have a container-agnostic > // way of getting an ExpressionEvaluator to do expression based > validation > try { > ActionBeanContext abc = ctx.getActionBeanContext(); > pageContext = > JspFactory.getDefaultFactory().getPageContext(CPartyServletHelper.servlet, // > the servlet inst > abc.getRequest(), // req > abc.getResponse(), // res > null, // error page url > true, // need session > abc.getResponse().getBufferSize(), > true); // autoflush > DispatcherHelper.setPageContext(pageContext); > } > catch (Exception e) { > // Don't even log this, this failure gets reported if action > beans actually > // try and make use of expression validation, otherwise this > is just noise > } > // Resolve the ActionBean, and if an interceptor returns a > resolution, bail now > Resolution resolution = resolveActionBean(ctx); > saveActionBean(request); > if (resolution == null) { > resolution = resolveHandler(ctx); > if (resolution == null) { > // Then run binding and validation > resolution = doBindingAndValidation(ctx); > if (resolution == null) { > // Then continue on to custom validation > resolution = doCustomValidation(ctx); > if (resolution == null) { > // And then validation error handling > resolution = handleValidationErrors(ctx); > if (resolution == null) { > // And finally(ish) invoking of the event > handler > resolution = invokeEventHandler(ctx); > // If the event produced errors, fill them in > DispatcherHelper.fillInValidationErrors(ctx); > } > } > } > } > } > // Whatever stage it came from, execute the resolution > if (resolution != null) { > executeResolution(ctx, resolution); > } > } > catch (ServletException se) { > throw se; > } > catch (RuntimeException re) { > throw re; > } > catch (InvocationTargetException ite) { > if (ite.getTargetException() instanceof ServletException) { > throw (ServletException) ite.getTargetException(); > } else if (ite.getTargetException() instanceof RuntimeException) { > throw (RuntimeException) ite.getTargetException(); > } else { > throw new StripesServletException > ("ActionBean execution threw an exception.", > ite.getTargetException()); > } > } > catch (Exception e) { > throw new StripesServletException("Exception encountered > processing request.", e); > } > finally { > // Make sure to release the page context > if (pageContext != null) { > > JspFactory.getDefaultFactory().releasePageContext(pageContext); > DispatcherHelper.setPageContext(null); > } > restoreActionBean(request); > } > } > public void destroy() { > } > /** > * Responsible for resolving the ActionBean for the current request. > Delegates to > * [EMAIL PROTECTED] > DispatcherHelper#resolveActionBean(ExecutionContext)}. > */ > protected Resolution resolveActionBean(ExecutionContext ctx) throws > Exception { > return DispatcherHelper.resolveActionBean(ctx); > } > /** > * Responsible for resolving the event handler method for the current > request. Delegates to > * [EMAIL PROTECTED] DispatcherHelper#resolveHandler(ExecutionContext)}. > */ > protected Resolution resolveHandler(ExecutionContext ctx) throws > Exception { > return DispatcherHelper.resolveHandler(ctx); > } > /** > * Responsible for executing binding and validation for the current > request. Delegates to > * [EMAIL PROTECTED] > DispatcherHelper#doBindingAndValidation(ExecutionContext, boolean)}. > */ > protected Resolution doBindingAndValidation(ExecutionContext ctx) throws > Exception { > return DispatcherHelper.doBindingAndValidation(ctx, true); > } > /** > * Responsible for executing custom validation methods for the current > request. Delegates to > * [EMAIL PROTECTED] > DispatcherHelper#doCustomValidation(ExecutionContext, boolean)}. > */ > protected Resolution doCustomValidation(ExecutionContext ctx) throws > Exception { > return DispatcherHelper.doCustomValidation(ctx, alwaysInvokeValidate); > } > /** > * Responsible for handling any validation errors that arise during > validation. Delegates to > * [EMAIL PROTECTED] > DispatcherHelper#handleValidationErrors(ExecutionContext)}. > */ > protected Resolution handleValidationErrors(ExecutionContext ctx) throws > Exception { > return DispatcherHelper.handleValidationErrors(ctx); > } > /** > * Responsible for invoking the event handler if no validation errors > occur. Delegates to > * [EMAIL PROTECTED] > DispatcherHelper#invokeEventHandler(ExecutionContext)}. > */ > protected Resolution invokeEventHandler(ExecutionContext ctx) throws > Exception { > return DispatcherHelper.invokeEventHandler(ctx); > } > /** > * Responsible for executing the Resolution for the current request. > Delegates to > * [EMAIL PROTECTED] DispatcherHelper#executeResolution(ExecutionContext, > Resolution)}. > */ > protected void executeResolution(ExecutionContext ctx, Resolution > resolution) throws Exception { > DispatcherHelper.executeResolution(ctx, resolution); > } > /** > * Performs a simple piece of one time configuration that requires access > to the > * Configuration object delivered through the Stripes Filter. > */ > private void doOneTimeConfiguration() { > if (alwaysInvokeValidate == null) { > // Check to see if, in this application, validate() methods > should always be run > // even when validation errors already exist > String callValidateWhenErrorsExist = > StripesFilter.getConfiguration() > > .getBootstrapPropertyResolver().getProperty(RUN_CUSTOM_VALIDATION_WHEN_ERRORS); > if (callValidateWhenErrorsExist != null) { > BooleanTypeConverter c = new BooleanTypeConverter(); > this.alwaysInvokeValidate = > c.convert(callValidateWhenErrorsExist, Boolean.class, null); > } > else { > this.alwaysInvokeValidate = false; // Default behaviour > } > } > } > /** > * Fetches, and lazily creates if required, a Stack in the request to > store ActionBeans > * should the current request involve forwards or includes to other > ActionBeans. > * > * @param request the current HttpServletRequest > * @return the Stack if present, or if creation is requested > */ > protected Stack getActionBeanStack(HttpServletRequest request, boolean > create) { > Stack stack = (Stack) > request.getAttribute(StripesConstants.REQ_ATTR_ACTION_BEAN_STACK); > if (stack == null && create) { > stack = new Stack(); > request.setAttribute(StripesConstants.REQ_ATTR_ACTION_BEAN_STACK, > stack); > } > return stack; > } > /** > * Saves the current value of the 'actionBean' attribute in the request > so that it > * can be restored at a later date by calling [EMAIL PROTECTED] > #restoreActionBean(HttpServletRequest)}. > * If no ActionBean is currently stored in the request, nothing is > changed. > * > * @param request the current HttpServletRequest > */ > protected void saveActionBean(HttpServletRequest request) { > if (request.getAttribute(StripesConstants.REQ_ATTR_ACTION_BEAN) != > null) { > Stack stack = getActionBeanStack(request, true); > > stack.push(request.getAttribute(StripesConstants.REQ_ATTR_ACTION_BEAN)); > } > } > /** > * Restores the previous value of the 'actionBean' attribute in the > request. If no > * ActionBeans have been saved using [EMAIL PROTECTED] > #saveActionBean(HttpServletRequest)} then this > * method has no effect. > * > * @param request the current HttpServletRequest > */ > protected void restoreActionBean(HttpServletRequest request) { > Stack stack = getActionBeanStack(request, false); > if (stack != null && !stack.empty()) { > request.setAttribute(StripesConstants.REQ_ATTR_ACTION_BEAN, > stack.pop()); > } > } > } > --------------- > ActionNameResolver: > --------------- > package com.cparty.stripes.util; > import net.sourceforge.stripes.controller.NameBasedActionResolver; > /** > * We prefer "home" rather than "Home.action", which this class takes care of. > */ > public class CPartyNameBasedActionResolver extends NameBasedActionResolver { > protected String getUrlBinding(String string) { > String original = super.getUrlBinding(string); > int end = original.indexOf(".action"); > String temp = original.substring(0, end); > int begin = temp.lastIndexOf("/"); > String name = original.substring(begin + 1, end); > name = name.substring(0, 1).toLowerCase() + name.substring(1); > return original.substring(0, begin + 1).toLowerCase() + name ; > } > } > --------------- -- This message is automatically generated by JIRA. - If you think it was sent incorrectly contact one of the administrators: http://mc4j.org/jira/secure/Administrators.jspa - For more information on JIRA, see: http://www.atlassian.com/software/jira ------------------------------------------------------------------------- Take Surveys. Earn Cash. Influence the Future of IT Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV _______________________________________________ Stripes-development mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/stripes-development
