From 9633509dbb07e6f13c171879e44c64037d2f89f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20Gonz=C3=A1lez=20Fern=C3=A1ndez?= Date: Mon, 8 Jun 2009 13:44:40 +0200 Subject: [PATCH] ItEr11S12ArquitecturaClientesItEr09S11: EntryPoints mechanism now used to keep track of browser history, AKA back button support. --- .../web/common/entrypoints/URLHandler.java | 99 +++++++++++++++++-- .../IWorkerCRUDControllerEntryPoints.java | 3 + .../worker/WorkerCRUDController.java | 27 ++++- .../resources/WorkerCRUDControllerTest.java | 15 +-- 4 files changed, 125 insertions(+), 19 deletions(-) diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/common/entrypoints/URLHandler.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/common/entrypoints/URLHandler.java index efdd45e5e..9a556ac6c 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/common/entrypoints/URLHandler.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/common/entrypoints/URLHandler.java @@ -16,6 +16,10 @@ import org.apache.commons.logging.LogFactory; import org.navalplanner.web.common.converters.Converter; import org.navalplanner.web.common.converters.IConverterFactory; import org.zkoss.zk.ui.Execution; +import org.zkoss.zk.ui.Page; +import org.zkoss.zk.ui.event.BookmarkEvent; +import org.zkoss.zk.ui.event.Event; +import org.zkoss.zk.ui.event.EventListener; /** *
@@ -23,6 +27,9 @@ import org.zkoss.zk.ui.Execution; */ public class URLHandler { + private static final String FLAG_ATTRIBUTE = URLHandler.class.getName() + + "_"; + private static final Log LOG = LogFactory.getLog(URLHandler.class); private static class EntryPointMetadata { @@ -66,6 +73,9 @@ public class URLHandler { } public void doTransition(String methodName, Object... values) { + if (isFlagedInThisRequest()) + return; + flagAlreadyExecutedInThisRequest(); if (!metadata.containsKey(methodName)) { LOG.error("Method " + methodName + "doesn't represent a state(It doesn't have a " @@ -83,15 +93,55 @@ public class URLHandler { stringRepresentations[i] = converterFor .asStringUngeneric(values[i]); } - StringBuilder linkValue = new StringBuilder(page); - for (int i = 0; i < parameterNames.length; i++) { - linkValue.append(";").append(parameterNames[i]); - if (stringRepresentations[i] != null) - linkValue.append("=").append(stringRepresentations[i]); - } + String fragment = getFragment(parameterNames, stringRepresentations); + String requestPath = executorRetriever.getCurrent().getDesktop() + .getRequestPath(); + if (requestPath.contains(page)) { + doBookmark(fragment); + } else + sendRedirect(fragment); + } + + private boolean isFlagedInThisRequest() { + return getRequest().getAttribute(FLAG_ATTRIBUTE) == this; + } + + private void flagAlreadyExecutedInThisRequest() { + getRequest().setAttribute(FLAG_ATTRIBUTE, this); + } + + private void doBookmark(String fragment) { + executorRetriever.getCurrent().getDesktop().setBookmark( + stripHash(fragment)); + } + + private String stripHash(String fragment) { + if (fragment.startsWith("#")) + return fragment.substring(1); + return fragment; + } + + private void sendRedirect(String fragment) { + StringBuilder linkValue = new StringBuilder(page).append(fragment); executorRetriever.getCurrent().sendRedirect(linkValue.toString()); } + private String getFragment(String[] parameterNames, + String[] stringRepresentations) { + StringBuilder result = new StringBuilder(); + if (parameterNames.length > 0) + result.append("#"); + for (int i = 0; i < parameterNames.length; i++) { + result.append(parameterNames[i]); + if (stringRepresentations[i] != null) + result.append("=").append(stringRepresentations[i]); + if (i < parameterNames.length - 1) { + result.append(";"); + } + } + return result.toString(); + } + private static void callMethod(Object target, Method superclassMethod, Object[] params) { try { @@ -105,9 +155,24 @@ public class URLHandler { } public void applyIfMatches(S controller) { + String uri = getRequest().getRequestURI(); + applyIfMatches(controller, uri); + } + + private HttpServletRequest getRequest() { Execution current = executorRetriever.getCurrent(); - Map matrixParams = MatrixParameters - .extract((HttpServletRequest) current.getNativeRequest()); + HttpServletRequest request = (HttpServletRequest) current + .getNativeRequest(); + return request; + } + + public void applyIfMatches(S controller, String fragment) { + if (isFlagedInThisRequest()) { + return; + } + flagAlreadyExecutedInThisRequest(); + String string = insertSemicolonIfNeeded(fragment); + Map matrixParams = MatrixParameters.extract(string); Set matrixParamsNames = matrixParams.keySet(); for (Entry entry : metadata.entrySet()) { EntryPointMetadata entryPointMetadata = entry.getValue(); @@ -124,6 +189,24 @@ public class URLHandler { } } + public void registerListener(final S controller, Page page) { + page.addEventListener("onBookmarkChange", new EventListener() { + + @Override + public void onEvent(Event event) throws Exception { + BookmarkEvent bookmarkEvent = (BookmarkEvent) event; + String bookmark = bookmarkEvent.getBookmark(); + applyIfMatches(controller, bookmark); + } + }); + } + + private String insertSemicolonIfNeeded(String uri) { + if (!uri.startsWith(";")) + return ";" + uri; + return uri; + } + private Object[] retrieveArguments(Map matrixParams, EntryPoint linkToStateAnnotation, Class[] parameterTypes) { Object[] result = new Object[parameterTypes.length]; diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/worker/IWorkerCRUDControllerEntryPoints.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/worker/IWorkerCRUDControllerEntryPoints.java index 60cd7581d..79991f707 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/worker/IWorkerCRUDControllerEntryPoints.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/worker/IWorkerCRUDControllerEntryPoints.java @@ -20,4 +20,7 @@ public interface IWorkerCRUDControllerEntryPoints { @EntryPoint("create") public abstract void goToCreateForm(); + @EntryPoint("list") + void goToList(); + } \ No newline at end of file diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/worker/WorkerCRUDController.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/worker/WorkerCRUDController.java index 8edfb4091..cbc4e1e67 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/worker/WorkerCRUDController.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/worker/WorkerCRUDController.java @@ -57,6 +57,8 @@ public class WorkerCRUDController extends GenericForwardComposer implements private WorkRelationshipsController editWorkRelationship; + private IWorkerCRUDControllerEntryPoints workerCRUD; + public WorkerCRUDController() { } @@ -64,7 +66,8 @@ public class WorkerCRUDController extends GenericForwardComposer implements Window editWindow, Window workRelationshipsWindow, Window addWorkRelationshipWindow, Window editWorkRelationshipWindow, IWorkerModel workerModel, - IMessagesForUser messages) { + IMessagesForUser messages, + IWorkerCRUDControllerEntryPoints workerCRUD) { this.createWindow = createWindow; this.listWindow = listWindow; this.editWindow = editWindow; @@ -73,6 +76,7 @@ public class WorkerCRUDController extends GenericForwardComposer implements this.editWorkRelationshipWindow = editWorkRelationshipWindow; this.workerModel = workerModel; this.messages = messages; + this.workerCRUD = workerCRUD; } public Worker getWorker() { @@ -92,7 +96,7 @@ public class WorkerCRUDController extends GenericForwardComposer implements public void save() { try { workerModel.save(); - getVisibility().showOnly(listWindow); + goToList(); Util.reloadBindings(listWindow); messages.showMessage(Level.INFO, "traballador gardado"); } catch (ValidationException e) { @@ -103,10 +107,16 @@ public class WorkerCRUDController extends GenericForwardComposer implements } public void cancel() { + goToList(); + } + + public void goToList() { + getBookmarker().goToList(); getVisibility().showOnly(listWindow); } public void goToEditForm(Worker worker) { + getBookmarker().goToEditForm(worker); workerModel.prepareEditFor(worker); getVisibility().showOnly(editWindow); Util.reloadBindings(editWindow); @@ -133,6 +143,7 @@ public class WorkerCRUDController extends GenericForwardComposer implements } public void goToCreateForm() { + getBookmarker().goToCreateForm(); workerModel.prepareForCreate(); getVisibility().showOnly(createWindow); Util.reloadBindings(createWindow); @@ -151,7 +162,6 @@ public class WorkerCRUDController extends GenericForwardComposer implements localizationsForCreationController = createLocalizationsController( comp, "createWindow"); comp.setVariable("controller", this, true); - getVisibility().showOnly(listWindow); if (messagesContainer == null) throw new RuntimeException("messagesContainer is needed"); messages = new MessagesForUser(messagesContainer); @@ -164,9 +174,12 @@ public class WorkerCRUDController extends GenericForwardComposer implements this.workerModel, this, messages), editWorkRelationshipWindow); - URLHandler handler = URLHandlerRegistry + final URLHandler handler = URLHandlerRegistry .getRedirectorFor(IWorkerCRUDControllerEntryPoints.class); - handler.applyIfMatches(this); + handler.registerListener(this, page); + getVisibility().showOnly(listWindow); + handler.registerListener(this, page); + getVisibility().showOnly(listWindow); } private void setupWorkRelationshipController( @@ -200,4 +213,8 @@ public class WorkerCRUDController extends GenericForwardComposer implements return this.addWorkRelationship; } + private IWorkerCRUDControllerEntryPoints getBookmarker() { + return workerCRUD; + } + } diff --git a/navalplanner-webapp/src/test/java/org/navalplanner/web/resources/WorkerCRUDControllerTest.java b/navalplanner-webapp/src/test/java/org/navalplanner/web/resources/WorkerCRUDControllerTest.java index c21dff6fe..ffc550881 100644 --- a/navalplanner-webapp/src/test/java/org/navalplanner/web/resources/WorkerCRUDControllerTest.java +++ b/navalplanner-webapp/src/test/java/org/navalplanner/web/resources/WorkerCRUDControllerTest.java @@ -17,6 +17,7 @@ import org.junit.Test; import org.navalplanner.business.resources.entities.Worker; import org.navalplanner.web.common.IMessagesForUser; import org.navalplanner.web.common.Level; +import org.navalplanner.web.resources.worker.IWorkerCRUDControllerEntryPoints; import org.navalplanner.web.resources.worker.IWorkerModel; import org.navalplanner.web.resources.worker.WorkerCRUDController; import org.zkoss.zul.api.Window; @@ -33,6 +34,7 @@ public class WorkerCRUDControllerTest { private Window workRelationshipsWindow; private Window addWorkRelationshipWindow; private Window editWorkRelationshipWindow; + private WorkerCRUDController createControllerForModel( IWorkerModel workerModel) { return createControllerForModel(workerModel, null); @@ -44,17 +46,16 @@ public class WorkerCRUDControllerTest { listWindow = createNiceMock(Window.class); editWindow = createNiceMock(Window.class); workRelationshipsWindow = createNiceMock(Window.class); - addWorkRelationshipWindow = createNiceMock(Window.class); - editWorkRelationshipWindow = createNiceMock(Window.class); - + addWorkRelationshipWindow = createNiceMock(Window.class); + editWorkRelationshipWindow = createNiceMock(Window.class); WorkerCRUDController workerCRUDController = new WorkerCRUDController( createWindow, listWindow, editWindow, workRelationshipsWindow, - addWorkRelationshipWindow, editWorkRelationshipWindow ,workerModel, messages); + addWorkRelationshipWindow, editWorkRelationshipWindow, + workerModel, messages, createNiceMock(IWorkerCRUDControllerEntryPoints.class)); return workerCRUDController; } - @Test public void testSave() throws Exception { IWorkerModel workerModel = createMock(IWorkerModel.class); @@ -81,6 +82,7 @@ public class WorkerCRUDControllerTest { // verify verify(workerModel, messagesForUser); } + @Test public void testGoToSaveAndThenCancel() { IWorkerModel workerModel = createMock(IWorkerModel.class); @@ -95,7 +97,8 @@ public class WorkerCRUDControllerTest { expect(workRelationshipsWindow.setVisible(true)).andReturn(false); expect(addWorkRelationshipWindow.setVisible(true)).andReturn(false); replay(createWindow, listWindow, editWindow, workRelationshipsWindow, - addWorkRelationshipWindow, editWorkRelationshipWindow, workerModel); + addWorkRelationshipWindow, editWorkRelationshipWindow, + workerModel); // actions workerCRUDController.goToCreateForm(); workerCRUDController.cancel();