/sitebricks/src/main/java/com/google/sitebricks/routing/WidgetRoutingDispatcher.java
http://github.com/dhanji/sitebricks · Java · 178 lines · 122 code · 29 blank · 27 comment · 17 complexity · 29080f0d9957d2d020a34d410cc01a21 MD5 · raw file
- package com.google.sitebricks.routing;
- import java.io.IOException;
- import java.util.List;
- import java.util.Set;
- import javax.servlet.http.HttpServletRequest;
- import javax.validation.ConstraintViolation;
- import javax.validation.ConstraintViolationException;
- import javax.validation.ValidationException;
- import net.jcip.annotations.Immutable;
- import com.google.inject.Inject;
- import com.google.inject.Provider;
- import com.google.inject.Singleton;
- import com.google.sitebricks.Respond;
- import com.google.sitebricks.StringBuilderRespond;
- import com.google.sitebricks.binding.FlashCache;
- import com.google.sitebricks.binding.RequestBinder;
- import com.google.sitebricks.client.transport.Json;
- import com.google.sitebricks.conversion.ValidationConverter;
- import com.google.sitebricks.headless.HeadlessRenderer;
- import com.google.sitebricks.headless.Reply;
- import com.google.sitebricks.headless.Request;
- import com.google.sitebricks.rendering.resource.ResourcesService;
- import com.google.sitebricks.routing.PageBook.Page;
- /**
- * @author Dhanji R. Prasanna (dhanji@gmail.com)
- */
- @Immutable
- @Singleton
- class WidgetRoutingDispatcher implements RoutingDispatcher {
- private final PageBook book;
- private final RequestBinder binder;
- private final ResourcesService resourcesService;
- private final Provider<FlashCache> flashCacheProvider;
- private final HeadlessRenderer headlessRenderer;
- @Inject
- Provider<HttpServletRequest> httpServletRequestProvider;
-
- @Inject
- private ValidationConverter validationConvertor;
- @Inject
- public WidgetRoutingDispatcher(PageBook book, RequestBinder binder,
- ResourcesService resourcesService,
- Provider<FlashCache> flashCacheProvider,
- HeadlessRenderer headlessRenderer) {
- this.headlessRenderer = headlessRenderer;
- this.book = book;
- this.binder = binder;
- this.resourcesService = resourcesService;
- this.flashCacheProvider = flashCacheProvider;
- }
- public Object dispatch(Request request, Events event) throws IOException {
- String uri = request.path();
- //first try dispatching as a static resource service
- Respond respond = resourcesService.serve(uri);
- if (null != respond)
- return respond;
- // Otherwise try to dispatch as a widget/page
- // Check if there is a page chain link sitting here
- // for this page.
- // NOTE(dhanji): we must use remove, to atomically
- // remove the page and process it in one go. It is
- // also worth coordinating this with conversation request
- // queueing.
- // TODO(dhanji): Change flashcache to use temporary cookies instead.
- PageBook.Page page = flashCacheProvider.get().remove(uri);
- // If there is no link, obtain page via Guice as normal.
- if (null == page)
- page = book.get(uri);
- //could not dispatch as there was no match
- if (null == page)
- return null;
- final Object instance = page.instantiate();
- if (page.isHeadless()) {
- return bindAndReply(request, page, instance);
- } else {
- //fire events and render responder
- return bindAndRespond(request, page, instance);
- }
- }
- private Object bindAndReply(Request request, Page page, Object instance) throws IOException {
- // bind request (sets request params, etc).
- binder.bind(request, instance);
-
- Object response = null;
- try {
- // call the appropriate handler.
- response = fireEvent(request, page, instance);
- }
- catch (ValidationException ve) {
- ConstraintViolationException cve = (ConstraintViolationException) ve.getCause();
- Set<? extends ConstraintViolation<?>> scv = (Set<? extends ConstraintViolation<?>>) cve.getConstraintViolations();
- List<String> errors = validationConvertor.to(scv);
- response = Reply.with(errors).as(Json.class).badRequest();
- }
- return response;
- }
- private Object bindAndRespond(Request request, PageBook.Page page, Object instance)
- throws IOException {
- //bind request
- binder.bind(request, instance);
- // fire get/post events
- Object redirect = null;
- List<String> errors = null;
- try {
- redirect = fireEvent(request, page, instance);
- }
- catch (ValidationException ve) {
- ve.getCause().printStackTrace();
- ConstraintViolationException cve = (ConstraintViolationException) ve.getCause();
- Set<? extends ConstraintViolation<?>> scv = (Set<? extends ConstraintViolation<?>>) cve.getConstraintViolations();
- errors = validationConvertor.to(scv);
- }
-
- //render to respond
- Respond respond = new StringBuilderRespond(instance);
- respond.setErrors(errors);
- if (null != redirect) {
- if (redirect instanceof String)
- respond.redirect((String) redirect);
- else if (redirect instanceof Class) {
- PageBook.Page targetPage = book.forClass((Class<?>) redirect);
- // should never be null coz it is validated on compile.
- respond.redirect(contextualize(request, targetPage.getUri()));
- } else if (redirect instanceof Reply<?>) {
- // To allow non-headless pages to use Reply<?> for more advanced HTTP responses
- return redirect;
- } else {
- // Handle page-chaining driven redirection.
- PageBook.Page targetPage = book.forInstance(redirect);
- // should never be null coz it will be validated at compile time.
- flashCacheProvider.get().put(targetPage.getUri(), targetPage);
- // Send to the canonical address of the page. This is also
- // verified at compile, not be a variablized matcher.
- respond.redirect(contextualize(request, targetPage.getUri()));
- }
- } else {
- page.widget().render(instance, respond);
- }
-
- return respond;
- }
- // We're sure the request parameter map is a Map<String, String[]>
- @SuppressWarnings("unchecked")
- private Object fireEvent(Request request, PageBook.Page page, Object instance)
- throws IOException {
- final String method = request.method();
- final String pathInfo = request.path();
- return page.doMethod(method.toLowerCase(), instance, pathInfo, request);
- }
- private static String contextualize(Request request, String targetUri) {
- return request.context() + targetUri;
- }
-
- }