diff --git a/src/main/java/org/tynamo/routing/Behavior.java b/src/main/java/org/tynamo/routing/Behavior.java new file mode 100644 index 0000000..58c0fce --- /dev/null +++ b/src/main/java/org/tynamo/routing/Behavior.java @@ -0,0 +1,5 @@ +package org.tynamo.routing; + +public enum Behavior { + DEFAULT, REDIRECT, NOT_FOUND +} diff --git a/src/main/java/org/tynamo/routing/Route.java b/src/main/java/org/tynamo/routing/Route.java index 6b98112..749927c 100644 --- a/src/main/java/org/tynamo/routing/Route.java +++ b/src/main/java/org/tynamo/routing/Route.java @@ -1,5 +1,7 @@ package org.tynamo.routing; +import org.apache.tapestry5.services.LocalizationSetter; + import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -12,13 +14,14 @@ public class Route { private static final String URI_PARAM_REGEX = "\\{\\s*(" + URI_PARAM_NAME_REGEX + ")\\s*(:\\s*(" + URI_PARAM_REGEX_REGEX + "))?\\}"; private static final Pattern URI_PARAM_PATTERN = Pattern.compile(URI_PARAM_REGEX); - private final String canonicalizedPageName; private final String pathExpression; + private final String canonicalizedPageName; + private final Behavior behavior; private final Pattern pattern; - public Route(final String pathExpression, final String canonicalizedPageName) { - + public Route(final String pathExpression, final String canonicalizedPageName, final Behavior behavior) { this.canonicalizedPageName = canonicalizedPageName; + this.behavior = behavior; // remove ending slash unless it's the root path this.pathExpression = pathExpression.length() > 1 && pathExpression.charAt(pathExpression.length() - 1) == SLASH ? pathExpression.substring(0, pathExpression.length() - 1) : pathExpression; @@ -31,11 +34,9 @@ public Route(final String pathExpression, final String canonicalizedPageName) { String regex = buildExpression(this.pathExpression); pattern = Pattern.compile(regex); - } static String buildExpression(String expression) { - String[] split = URI_PARAM_PATTERN.split(expression); Matcher withPathParam = URI_PARAM_PATTERN.matcher(expression); int i = 0; @@ -66,6 +67,10 @@ public String getCanonicalizedPageName() { return canonicalizedPageName; } + public Behavior getBehavior() { + return behavior; + } + public Pattern getPattern() { return pattern; } diff --git a/src/main/java/org/tynamo/routing/annotations/At.java b/src/main/java/org/tynamo/routing/annotations/At.java index 9721367..b469c2c 100644 --- a/src/main/java/org/tynamo/routing/annotations/At.java +++ b/src/main/java/org/tynamo/routing/annotations/At.java @@ -5,6 +5,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.tynamo.routing.Behavior; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @@ -12,6 +13,8 @@ String value(); + Behavior behavior() default Behavior.DEFAULT; + String[] order() default {}; } diff --git a/src/main/java/org/tynamo/routing/annotations/Route.java b/src/main/java/org/tynamo/routing/annotations/Route.java index 7392b05..47a2b0f 100644 --- a/src/main/java/org/tynamo/routing/annotations/Route.java +++ b/src/main/java/org/tynamo/routing/annotations/Route.java @@ -5,6 +5,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.tynamo.routing.Behavior; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @@ -12,6 +13,8 @@ String value(); + Behavior behavior() default Behavior.DEFAULT; + String[] order() default {}; } diff --git a/src/main/java/org/tynamo/routing/services/RouteDecoderImpl.java b/src/main/java/org/tynamo/routing/services/RouteDecoderImpl.java index 3bd7580..d3a414d 100644 --- a/src/main/java/org/tynamo/routing/services/RouteDecoderImpl.java +++ b/src/main/java/org/tynamo/routing/services/RouteDecoderImpl.java @@ -30,7 +30,6 @@ public RouteDecoderImpl(LocalizationSetter localizationSetter, ContextValueEncoder valueEncoder, Logger logger) { - this.localizationSetter = localizationSetter; this.encodeLocaleIntoPath = encodeLocaleIntoPath; @@ -56,7 +55,6 @@ private String getLocaleFromPath(String path) { } private String removeAppFolderAndLocaleFromPath(final Request request) { - String path = request.getPath(); if (this.applicationFolder.length() > 0) { @@ -74,7 +72,6 @@ private String removeAppFolderAndLocaleFromPath(final Request request) { @Override public PageRenderRequestParameters decodePageRenderRequest(final Route route, final Request request) { - Matcher matcher = route.getPattern().matcher(removeAppFolderAndLocaleFromPath(request)); if (!matcher.matches()) return null; diff --git a/src/main/java/org/tynamo/routing/services/RouteFactory.java b/src/main/java/org/tynamo/routing/services/RouteFactory.java index cd3f231..80a09e0 100644 --- a/src/main/java/org/tynamo/routing/services/RouteFactory.java +++ b/src/main/java/org/tynamo/routing/services/RouteFactory.java @@ -1,12 +1,18 @@ package org.tynamo.routing.services; import org.tynamo.routing.Route; +import org.tynamo.routing.Behavior; public interface RouteFactory { Route create(String pathExpression, String canonicalized); + Route create(String pathExpression, String canonicalized, Behavior behavior); + @Deprecated Route create(String pathExpression, Class page); + @Deprecated + Route create(String pathExpression, Class page, Behavior behavior); + } diff --git a/src/main/java/org/tynamo/routing/services/RouteFactoryImpl.java b/src/main/java/org/tynamo/routing/services/RouteFactoryImpl.java index c2c00d4..92cd2f2 100644 --- a/src/main/java/org/tynamo/routing/services/RouteFactoryImpl.java +++ b/src/main/java/org/tynamo/routing/services/RouteFactoryImpl.java @@ -2,6 +2,7 @@ import org.apache.tapestry5.services.ComponentClassResolver; import org.tynamo.routing.Route; +import org.tynamo.routing.Behavior; public class RouteFactoryImpl implements RouteFactory { @@ -13,11 +14,21 @@ public RouteFactoryImpl(ComponentClassResolver componentClassResolver) { @Override public Route create(String pathExpression, String canonicalized) { - return new Route(pathExpression, canonicalized); + return create(pathExpression, canonicalized, Behavior.DEFAULT); + } + + @Override + public Route create(String pathExpression, String canonicalized, Behavior behavior) { + return new Route(pathExpression, canonicalized, behavior); } @Override public Route create(String pathExpression, Class page) { + return create(pathExpression, page, Behavior.DEFAULT); + } + + @Override + public Route create(String pathExpression, Class page, Behavior behavior) { String pageName = componentClassResolver.resolvePageClassNameToPageName(page.getName()); String canonicalized = componentClassResolver.canonicalizePageName(pageName); return create(pathExpression, canonicalized); diff --git a/src/main/java/org/tynamo/routing/services/RouteWorker.java b/src/main/java/org/tynamo/routing/services/RouteWorker.java index 82c41e2..9280fbc 100644 --- a/src/main/java/org/tynamo/routing/services/RouteWorker.java +++ b/src/main/java/org/tynamo/routing/services/RouteWorker.java @@ -7,6 +7,7 @@ import org.apache.tapestry5.services.transform.TransformationSupport; import org.tynamo.routing.annotations.At; import org.tynamo.routing.annotations.Route; +import org.tynamo.routing.Behavior; public class RouteWorker implements ComponentClassTransformWorker2 { @@ -25,14 +26,17 @@ public void transform(PlasticClass plasticClass, TransformationSupport support, String pathExpression = null; String[] order = {}; + Behavior behavior = Behavior.DEFAULT; if (plasticClass.hasAnnotation(At.class)) { At ann = plasticClass.getAnnotation(At.class); pathExpression = ann.value(); + behavior = ann.behavior(); order = ann.order(); } else if (plasticClass.hasAnnotation(Route.class)) { Route ann = plasticClass.getAnnotation(Route.class); pathExpression = ann.value(); + behavior = ann.behavior(); order = ann.order(); } @@ -40,7 +44,7 @@ public void transform(PlasticClass plasticClass, TransformationSupport support, String pageName = componentClassResolver.resolvePageClassNameToPageName(plasticClass.getClassName()); String canonicalized = componentClassResolver.canonicalizePageName(pageName); - org.tynamo.routing.Route route = routeFactory.create(pathExpression, canonicalized); + org.tynamo.routing.Route route = routeFactory.create(pathExpression, canonicalized, behavior); annotatedPagesManager.add(route, order); } diff --git a/src/main/java/org/tynamo/routing/services/RouterDispatcher.java b/src/main/java/org/tynamo/routing/services/RouterDispatcher.java index 25c8748..c3a7f36 100644 --- a/src/main/java/org/tynamo/routing/services/RouterDispatcher.java +++ b/src/main/java/org/tynamo/routing/services/RouterDispatcher.java @@ -1,8 +1,13 @@ package org.tynamo.routing.services; import org.apache.tapestry5.annotations.Log; -import org.apache.tapestry5.ioc.annotations.Primary; -import org.apache.tapestry5.services.*; +import org.apache.tapestry5.services.ComponentEventLinkEncoder; +import org.apache.tapestry5.services.ComponentRequestHandler; +import org.apache.tapestry5.services.Dispatcher; +import org.apache.tapestry5.services.PageRenderRequestParameters; +import org.apache.tapestry5.services.Request; +import org.apache.tapestry5.services.Response; +import org.tynamo.routing.Route; import java.io.IOException; @@ -12,20 +17,51 @@ public class RouterDispatcher implements Dispatcher { private final ComponentRequestHandler componentRequestHandler; + private final ComponentEventLinkEncoder linkEncoder; private final RouteSource routeSource; - public RouterDispatcher(ComponentRequestHandler componentRequestHandler, RouteSource routeSource) { + public RouterDispatcher(final ComponentRequestHandler componentRequestHandler, final ComponentEventLinkEncoder linkEncoder, final RouteSource routeSource) { this.componentRequestHandler = componentRequestHandler; + this.linkEncoder = linkEncoder; this.routeSource = routeSource; } @Log - public boolean dispatch(Request request, final Response response) throws IOException { - PageRenderRequestParameters parameters = routeSource.decodePageRenderRequest(request); - if (parameters != null) { - componentRequestHandler.handlePageRender(parameters); + public boolean dispatch(final Request request, final Response response) throws IOException { + PageRenderRequestParameters pageParameters = linkEncoder.decodePageRenderRequest(request); + PageRenderRequestParameters routeParameters = routeSource.decodePageRenderRequest(request); + Route pageParametersRoute = pageParameters == null ? null : routeSource.getRoute(pageParameters.getLogicalPageName()); + Route routeParametersRoute = routeParameters == null ? null : routeSource.getRoute(routeParameters.getLogicalPageName()); + + if (pageParameters != null && pageParametersRoute == null) { + return false; + } + if (pageParameters != null && pageParametersRoute != null && !pageParameters.getLogicalPageName().endsWith("Index")) { + return handleRoute(pageParametersRoute, pageParameters, request, response); + } + if (routeParametersRoute != null) { + componentRequestHandler.handlePageRender(routeParameters); return true; } + if (pageParametersRoute != null) { + boolean handled = handleRoute(pageParametersRoute, pageParameters, request, response); + if (handled) return true; + } + return false; } + + private boolean handleRoute(Route route, PageRenderRequestParameters parameters, Request request, Response response) throws IOException { + switch (route.getBehavior()) { + case REDIRECT: + response.sendRedirect(linkEncoder.createPageRenderLink(parameters).toAbsoluteURI()); + return true; + case NOT_FOUND: + response.sendError(404, "Not Found"); + return true; + case DEFAULT: + default: + return false; + } + } } \ No newline at end of file diff --git a/src/main/java/org/tynamo/routing/services/RouterLinkTransformer.java b/src/main/java/org/tynamo/routing/services/RouterLinkTransformer.java index 9c0c678..f56e11e 100644 --- a/src/main/java/org/tynamo/routing/services/RouterLinkTransformer.java +++ b/src/main/java/org/tynamo/routing/services/RouterLinkTransformer.java @@ -7,7 +7,12 @@ import org.apache.tapestry5.internal.services.LinkImpl; import org.apache.tapestry5.internal.services.RequestSecurityManager; import org.apache.tapestry5.ioc.annotations.Symbol; -import org.apache.tapestry5.services.*; +import org.apache.tapestry5.services.BaseURLSource; +import org.apache.tapestry5.services.ContextPathEncoder; +import org.apache.tapestry5.services.PageRenderRequestParameters; +import org.apache.tapestry5.services.PersistentLocale; +import org.apache.tapestry5.services.Request; +import org.apache.tapestry5.services.Response; import org.apache.tapestry5.services.linktransform.PageRenderLinkTransformer; import org.tynamo.routing.Route; @@ -17,6 +22,7 @@ public class RouterLinkTransformer implements PageRenderLinkTransformer { private static final char SLASH = '/'; + private static final int BUFFER_SIZE = 100; private final RouteSource routeSource; private final Request request; @@ -24,17 +30,17 @@ public class RouterLinkTransformer implements PageRenderLinkTransformer { private final Response response; private final ContextPathEncoder contextPathEncoder; private final BaseURLSource baseURLSource; + private final PersistentLocale persistentLocale; + private final String contextPath; + private final boolean encodeLocaleIntoPath; private final String applicationFolder; - private static final int BUFFER_SIZE = 100; - private PersistentLocale persistentLocale; - private boolean encodeLocaleIntoPath; - public RouterLinkTransformer(RouteSource routeSource, Request request, RequestSecurityManager requestSecurityManager, Response response, ContextPathEncoder contextPathEncoder, BaseURLSource baseURLSource, PersistentLocale persistentLocale, + @Symbol(SymbolConstants.CONTEXT_PATH) final String contextPath, @Symbol(SymbolConstants.ENCODE_LOCALE_INTO_PATH) boolean encodeLocaleIntoPath, @Symbol(SymbolConstants.APPLICATION_FOLDER) final String applicationFolder) { this.routeSource = routeSource; @@ -44,6 +50,7 @@ public RouterLinkTransformer(RouteSource routeSource, this.contextPathEncoder = contextPathEncoder; this.baseURLSource = baseURLSource; this.persistentLocale = persistentLocale; + this.contextPath = contextPath; this.encodeLocaleIntoPath = encodeLocaleIntoPath; this.applicationFolder = applicationFolder; } @@ -54,7 +61,6 @@ public PageRenderRequestParameters decodePageRenderRequest(Request request) { } public Link transformPageRenderLink(Link defaultLink, PageRenderRequestParameters parameters) { - String activePageName = parameters.getLogicalPageName(); Route route = routeSource.getRoute(activePageName); @@ -62,9 +68,9 @@ public Link transformPageRenderLink(Link defaultLink, PageRenderRequestParameter if (route != null) { StringBuilder builder = new StringBuilder(BUFFER_SIZE); - if (!"".equals(request.getContextPath())) { + if (!"".equals(contextPath)) { // Build up the absolute URI. - builder.append(request.getContextPath()); + builder.append(contextPath); } encodeAppFolderAndLocale(builder); @@ -86,8 +92,7 @@ public Link transformPageRenderLink(Link defaultLink, PageRenderRequestParameter return null; } - private void encodeAppFolderAndLocale(StringBuilder builder) - { + private void encodeAppFolderAndLocale(StringBuilder builder) { if (!applicationFolder.equals("")) { builder.append(SLASH).append(applicationFolder); @@ -106,7 +111,6 @@ private void encodeAppFolderAndLocale(StringBuilder builder) } private String[] encode(EventContext context) { - assert context != null; int count = context.getCount(); diff --git a/src/main/java/org/tynamo/routing/services/RoutingModule.java b/src/main/java/org/tynamo/routing/services/RoutingModule.java index 4b898bc..2c4aece 100644 --- a/src/main/java/org/tynamo/routing/services/RoutingModule.java +++ b/src/main/java/org/tynamo/routing/services/RoutingModule.java @@ -33,7 +33,7 @@ public static void provideURLRewriting(OrderedConfiguration configuration, @Autobuild RouterDispatcher dispatcher) { - configuration.add(RouterDispatcher.class.getSimpleName(), dispatcher, "after:PageRender"); + configuration.add(RouterDispatcher.class.getSimpleName(), dispatcher, "after:ComponentEvent", "before:PageRender"); } @Contribute(SymbolProvider.class) diff --git a/src/test/java/org/tynamo/routing/RouteTest.java b/src/test/java/org/tynamo/routing/RouteTest.java index e254d46..1fb8bf5 100644 --- a/src/test/java/org/tynamo/routing/RouteTest.java +++ b/src/test/java/org/tynamo/routing/RouteTest.java @@ -5,6 +5,7 @@ import org.apache.tapestry5.internal.services.PageRenderDispatcher; import org.apache.tapestry5.ioc.RegistryBuilder; import org.apache.tapestry5.services.*; +import org.apache.tapestry5.Link; import org.easymock.Capture; import org.easymock.EasyMock; import org.testng.Assert; @@ -27,6 +28,8 @@ public class RouteTest extends RoutingTestCase { + private static final String SERVER_NAME = "test"; + private static final int SERVER_PORT = 8080; private static final String EMPTY_PATH = ""; private static final int NO_CONTEXT = 0; private static final String APPLICATION_FOLDER = ""; @@ -39,7 +42,6 @@ protected void addAdditionalModules(RegistryBuilder builder) { @Test public void regular_expressions() { - String path = "/foo/52"; String routeExpression = Route.buildExpression("/foo/{0}"); @@ -75,7 +77,6 @@ public void decode_page_render_request() { Assert.assertEquals(parameters.getActivationContext().getCount(), 2); Assert.assertEquals(parameters.getActivationContext().get(Integer.class, 0).intValue(), 45); Assert.assertEquals(parameters.getActivationContext().get(Integer.class, 1).intValue(), 24); - } @Test @@ -165,30 +166,62 @@ public void link_to_unannotatedpage() { @Test public void order() throws IOException { + ComponentRequestHandler requestHandler = mockComponentRequestHandler(); + ComponentEventLinkEncoder linkEncoder = getService(ComponentEventLinkEncoder.class); - Request request = mockRequest(); - expect(request.getPath()).andReturn("/subpackage/inventedpath").atLeastOnce(); + RouterDispatcher routerDispatcher = new RouterDispatcher(requestHandler, linkEncoder, routeSource); + Request request = mockRequest(); + Response response = null; PageRenderRequestParameters expectedParameters = new PageRenderRequestParameters("subpackage/SubPageFirst", new EmptyEventContext(), false); - ComponentRequestHandler requestHandler = mockComponentRequestHandler(); - requestHandler.handlePageRender(expectedParameters); - RouterDispatcher routerDispatcher = new RouterDispatcher(requestHandler, routeSource); + expect(request.getPath()).andReturn("/subpackage/inventedpath").atLeastOnce(); + expect(request.getParameter("t:lb")).andReturn(null).atLeastOnce(); + expect(request.getLocale()).andReturn(FI).atLeastOnce(); + requestHandler.handlePageRender(expectedParameters); replay(); + RequestGlobals globals = registry.getService(RequestGlobals.class); + globals.storeRequestResponse(request, response); + routerDispatcher.dispatch(request, null); verify(); } @Test - public void PageRender_precedence_over_RouterDispatcher() throws IOException { + public void page_without_route_is_not_dispatched() throws IOException { + ComponentEventLinkEncoder linkEncoder = getService(ComponentEventLinkEncoder.class); + ComponentRequestHandler requestHandler = mockComponentRequestHandler(); + + Dispatcher dispatcher = new RouterDispatcher(requestHandler, linkEncoder, routeSource); + + Request request = mockRequest(); + Response response = null; + + expect(request.getPath()).andReturn("/subpackage/unannotated").atLeastOnce(); + expect(request.getParameter("t:lb")).andReturn(null).atLeastOnce(); + expect(request.getLocale()).andReturn(FI).atLeastOnce(); + + EasyMock.expectLastCall(); + + replay(); + + RequestGlobals globals = registry.getService(RequestGlobals.class); + globals.storeRequestResponse(request, response); + Assert.assertFalse(dispatcher.dispatch(request, response), "Unannotated page should not be dispatched"); + + verify(); + } + + @Test + public void page_precede_over_route() throws IOException { ComponentEventLinkEncoder linkEncoder = getService(ComponentEventLinkEncoder.class); - ComponentRequestHandler handler = mockComponentRequestHandler(); + ComponentRequestHandler requestHandler = mockComponentRequestHandler(); - Dispatcher dispatcher = new PageRenderDispatcher(handler, linkEncoder); + Dispatcher dispatcher = new RouterDispatcher(requestHandler, linkEncoder, routeSource); Request request = mockRequest(); Response response = null; @@ -196,11 +229,136 @@ public void PageRender_precedence_over_RouterDispatcher() throws IOException { expect(request.getPath()).andReturn("/home").atLeastOnce(); expect(request.getParameter("t:lb")).andReturn(null).atLeastOnce(); expect(request.getLocale()).andReturn(FI).atLeastOnce(); - expect(request.getAttribute(InternalConstants.REFERENCED_COMPONENT_NOT_FOUND)).andReturn(null).once(); + + EasyMock.expectLastCall(); + + replay(); + + RequestGlobals globals = registry.getService(RequestGlobals.class); + globals.storeRequestResponse(request, response); + + Assert.assertFalse(dispatcher.dispatch(request, response), "Home page should take precedence over the '/home' route in the Inaccessible page"); + + verify(); + } + + @Test + public void route_precede_over_index() throws IOException { + ComponentEventLinkEncoder linkEncoder = getService(ComponentEventLinkEncoder.class); + ComponentRequestHandler requestHandler = mockComponentRequestHandler(); + + Dispatcher dispatcher = new RouterDispatcher(requestHandler, linkEncoder, routeSource); + + Request request = mockRequest(); + Response response = null; + + expect(request.getPath()).andReturn("/foo/45/bar/24").atLeastOnce(); + expect(request.getParameter("t:lb")).andReturn(null).atLeastOnce(); + expect(request.getLocale()).andReturn(FI).atLeastOnce(); + + Capture parameters = newCapture(); + + requestHandler.handlePageRender(EasyMock.capture(parameters)); + EasyMock.expectLastCall(); + + replay(); + + RequestGlobals globals = registry.getService(RequestGlobals.class); + globals.storeRequestResponse(request, response); + + Assert.assertTrue(dispatcher.dispatch(request, response), "Simple should take precedence over the Index page"); + Assert.assertEquals(parameters.getValue().getLogicalPageName(), "Simple", "Simple should take precedence over the Index page"); + Assert.assertEquals(parameters.getValue().getActivationContext().getCount(), 2, "Simple should receive activation context parameters"); + Assert.assertEquals((int) parameters.getValue().getActivationContext().get(Integer.class, 0), 45, "Simple should receive activation context parameters"); + Assert.assertEquals((int) parameters.getValue().getActivationContext().get(Integer.class, 1), 24, "Simple should receive activation context parameters"); + + verify(); + } + + @Test + public void route_path_is_dispatched() throws IOException { + ComponentEventLinkEncoder linkEncoder = getService(ComponentEventLinkEncoder.class); + ComponentRequestHandler requestHandler = mockComponentRequestHandler(); + + Dispatcher dispatcher = new RouterDispatcher(requestHandler, linkEncoder, routeSource); + + Request request = mockRequest(); + Response response = null; + + expect(request.getPath()).andReturn("/subpackage").atLeastOnce(); + expect(request.getParameter("t:lb")).andReturn(null).atLeastOnce(); + expect(request.getLocale()).andReturn(FI).atLeastOnce(); Capture parameters = newCapture(); - handler.handlePageRender(EasyMock.capture(parameters)); EasyMock.expectLastCall(); + requestHandler.handlePageRender(EasyMock.capture(parameters)); + EasyMock.expectLastCall(); + + replay(); + + RequestGlobals globals = registry.getService(RequestGlobals.class); + globals.storeRequestResponse(request, response); + + Assert.assertTrue(dispatcher.dispatch(request, response), "SubPackageMain route should be dispatched"); + Assert.assertEquals(parameters.getValue().getLogicalPageName(), "subpackage/Main", "SubPackageMain route should be dispatched"); + + verify(); + } + + @Test + public void redirect_behavior() throws IOException { + ComponentEventLinkEncoder linkEncoder = getService(ComponentEventLinkEncoder.class); + ComponentRequestHandler requestHandler = mockComponentRequestHandler(); + + Dispatcher dispatcher = new RouterDispatcher(requestHandler, linkEncoder, routeSource); + + Request request = mockRequest(); + Response response = mockResponse(); + String expectedURL = String.format("https://%s:%d/redirect-behavior", SERVER_NAME, SERVER_PORT); + + expect(request.getPath()).andReturn("/redirectbehavior").atLeastOnce(); + expect(request.getParameter("t:lb")).andReturn(null).atLeastOnce(); + expect(request.getLocale()).andReturn(FI).atLeastOnce(); + expect(request.isSecure()).andReturn(true).atLeastOnce(); + expect(request.getServerName()).andReturn(SERVER_NAME).atLeastOnce(); + expect(request.getServerPort()).andReturn(SERVER_PORT).atLeastOnce(); + expect(response.encodeURL(expectedURL)).andReturn(expectedURL).atLeastOnce(); + + Capture url = newCapture(); + + response.sendRedirect(EasyMock.capture(url)); + EasyMock.expectLastCall(); + + replay(); + + RequestGlobals globals = registry.getService(RequestGlobals.class); + globals.storeRequestResponse(request, response); + + Assert.assertTrue(dispatcher.dispatch(request, response)); + Assert.assertEquals(url.getValue(), expectedURL, "Redirect behavior is applied when page default convention path is provided"); + + verify(); + } + + @Test + public void not_found_behavior() throws IOException { + ComponentEventLinkEncoder linkEncoder = getService(ComponentEventLinkEncoder.class); + ComponentRequestHandler requestHandler = mockComponentRequestHandler(); + + Dispatcher dispatcher = new RouterDispatcher(requestHandler, linkEncoder, routeSource); + + Request request = mockRequest(); + Response response = mockResponse(); + + expect(request.getPath()).andReturn("/notfoundbehavior").atLeastOnce(); + expect(request.getParameter("t:lb")).andReturn(null).atLeastOnce(); + expect(request.getLocale()).andReturn(FI).atLeastOnce(); + + Capture errorCode = newCapture(); + Capture message = newCapture(); + + response.sendError(EasyMock.captureInt(errorCode), EasyMock.capture(message)); + EasyMock.expectLastCall(); replay(); @@ -208,8 +366,7 @@ public void PageRender_precedence_over_RouterDispatcher() throws IOException { globals.storeRequestResponse(request, response); Assert.assertTrue(dispatcher.dispatch(request, response)); - Assert.assertEquals(parameters.getValue().getLogicalPageName(), "Home", "Home page should take precedence over the '/home' route in the Inaccessible page"); - Assert.assertEquals(parameters.getValue().getActivationContext().getCount(), 0); + Assert.assertEquals((int) errorCode.getValue(), 404, "Not found behavior is applied when page default convention path is provided"); verify(); } diff --git a/src/test/java/org/tynamo/routing/RoutingTestCase.java b/src/test/java/org/tynamo/routing/RoutingTestCase.java index 7534df3..fdde0fd 100644 --- a/src/test/java/org/tynamo/routing/RoutingTestCase.java +++ b/src/test/java/org/tynamo/routing/RoutingTestCase.java @@ -114,7 +114,6 @@ public void testPageRenderLinkGeneration(String expectedURI, Request request = mockRequest(); expect(request.getPath()).andReturn(requestPath).atLeastOnce(); - expect(request.getContextPath()).andReturn(contextPath).atLeastOnce(); Response response = mockResponse(); train_encodeURL(response, expectedURI, expectedURI); @@ -132,7 +131,7 @@ public void testPageRenderLinkGeneration(String expectedURI, Assert.assertEquals(parameters.getActivationContext().getCount(), activationContextCount); RouterLinkTransformer linkTransformer = new RouterLinkTransformer(routeSource, request, securityManager, - response, contextPathEncoder, null, persistentLocale, encodeLocaleIntoPath, applicationFolder); + response, contextPathEncoder, null, persistentLocale, contextPath, encodeLocaleIntoPath, applicationFolder); Assert.assertEquals(linkTransformer.transformPageRenderLink(null, parameters).toURI(), expectedURI); } diff --git a/src/test/java/org/tynamo/routing/modules/TestsModule.java b/src/test/java/org/tynamo/routing/modules/TestsModule.java index 808685c..4d7030d 100644 --- a/src/test/java/org/tynamo/routing/modules/TestsModule.java +++ b/src/test/java/org/tynamo/routing/modules/TestsModule.java @@ -28,10 +28,7 @@ public static void provideApplicationDefaults(MappedConfiguration configuration, RouteFactory routeFactory) { - String canonicalized = "subpackage/Unannotated"; configuration.add(canonicalized.toLowerCase(), routeFactory.create("/not/annotated/{0}", canonicalized)); - } - } \ No newline at end of file diff --git a/src/test/java/org/tynamo/routing/pages/Index.java b/src/test/java/org/tynamo/routing/pages/Index.java new file mode 100644 index 0000000..a400608 --- /dev/null +++ b/src/test/java/org/tynamo/routing/pages/Index.java @@ -0,0 +1,9 @@ +package org.tynamo.routing.pages; + +import org.tynamo.routing.annotations.At; + +@At("/root-index") +public class Index { + protected void onActivate() { + } +} \ No newline at end of file diff --git a/src/test/java/org/tynamo/routing/pages/NotFoundBehavior.java b/src/test/java/org/tynamo/routing/pages/NotFoundBehavior.java new file mode 100644 index 0000000..8eb4414 --- /dev/null +++ b/src/test/java/org/tynamo/routing/pages/NotFoundBehavior.java @@ -0,0 +1,9 @@ +package org.tynamo.routing.pages; + +import org.tynamo.routing.annotations.At; +import org.tynamo.routing.Behavior; + +@At(value = "/not-found-behavior/", behavior = Behavior.NOT_FOUND) +public class NotFoundBehavior { + protected void onActivate() {} +} \ No newline at end of file diff --git a/src/test/java/org/tynamo/routing/pages/RedirectBehavior.java b/src/test/java/org/tynamo/routing/pages/RedirectBehavior.java new file mode 100644 index 0000000..9508ce7 --- /dev/null +++ b/src/test/java/org/tynamo/routing/pages/RedirectBehavior.java @@ -0,0 +1,9 @@ +package org.tynamo.routing.pages; + +import org.tynamo.routing.annotations.At; +import org.tynamo.routing.Behavior; + +@At(value = "/redirect-behavior", behavior = Behavior.REDIRECT) +public class RedirectBehavior { + protected void onActivate() {} +} \ No newline at end of file diff --git a/src/test/java/org/tynamo/routing/pages/subpackage/SubPageFirst.java b/src/test/java/org/tynamo/routing/pages/subpackage/SubPageFirst.java index a87c348..5b7c8d7 100644 --- a/src/test/java/org/tynamo/routing/pages/subpackage/SubPageFirst.java +++ b/src/test/java/org/tynamo/routing/pages/subpackage/SubPageFirst.java @@ -1,6 +1,5 @@ package org.tynamo.routing.pages.subpackage; - import org.tynamo.routing.annotations.At; @At(value = "/subpackage/inventedpath", order = "before:subpackage/SubPage1") diff --git a/src/test/java/org/tynamo/routing/services/RouterDispatcherWithAutoDiscoveryTest.java b/src/test/java/org/tynamo/routing/services/RouterDispatcherWithAutoDiscoveryTest.java index fa04a6a..58192cc 100644 --- a/src/test/java/org/tynamo/routing/services/RouterDispatcherWithAutoDiscoveryTest.java +++ b/src/test/java/org/tynamo/routing/services/RouterDispatcherWithAutoDiscoveryTest.java @@ -20,7 +20,7 @@ public void auto_discovery_enabled() { Registry registry = getRegistry(TapestryModule.class, RoutingModule.class, TestsModule.class); AnnotatedPagesManager provider = registry.getService(AnnotatedPagesManager.class); - Assert.assertEquals(provider.getRoutes().size(), 7, "there are seven pages with Routes in org/tynamo/routing"); + Assert.assertEquals(provider.getRoutes().size(), 10, "there are ten pages with Routes in org/tynamo/routing"); registry.cleanupThread(); registry.shutdown(); diff --git a/src/test/resources/org/tynamo/routing/pages/subpackage/SubPage.tml b/src/test/resources/org/tynamo/routing/pages/Inaccessible.tml similarity index 100% rename from src/test/resources/org/tynamo/routing/pages/subpackage/SubPage.tml rename to src/test/resources/org/tynamo/routing/pages/Inaccessible.tml diff --git a/src/test/resources/org/tynamo/routing/pages/Index.tml b/src/test/resources/org/tynamo/routing/pages/Index.tml new file mode 100644 index 0000000..1f551ea --- /dev/null +++ b/src/test/resources/org/tynamo/routing/pages/Index.tml @@ -0,0 +1 @@ + diff --git a/src/test/resources/org/tynamo/routing/pages/NotFoundBehavior.tml b/src/test/resources/org/tynamo/routing/pages/NotFoundBehavior.tml new file mode 100644 index 0000000..1f551ea --- /dev/null +++ b/src/test/resources/org/tynamo/routing/pages/NotFoundBehavior.tml @@ -0,0 +1 @@ + diff --git a/src/test/resources/org/tynamo/routing/pages/RedirectBehavior.tml b/src/test/resources/org/tynamo/routing/pages/RedirectBehavior.tml new file mode 100644 index 0000000..1f551ea --- /dev/null +++ b/src/test/resources/org/tynamo/routing/pages/RedirectBehavior.tml @@ -0,0 +1 @@ + diff --git a/src/test/resources/org/tynamo/routing/pages/subpackage/SubPage1.tml b/src/test/resources/org/tynamo/routing/pages/subpackage/SubPage1.tml new file mode 100644 index 0000000..1f551ea --- /dev/null +++ b/src/test/resources/org/tynamo/routing/pages/subpackage/SubPage1.tml @@ -0,0 +1 @@ +