ItEr11S12ArquitecturaClientesItEr09S11: EntryPoints mechanism now used to keep track of browser history, AKA back button support.

This commit is contained in:
Óscar González Fernández 2009-06-08 13:44:40 +02:00 committed by Javier Moran Rua
parent 5dea68fa30
commit 9633509dbb
4 changed files with 125 additions and 19 deletions

View file

@ -16,6 +16,10 @@ import org.apache.commons.logging.LogFactory;
import org.navalplanner.web.common.converters.Converter; import org.navalplanner.web.common.converters.Converter;
import org.navalplanner.web.common.converters.IConverterFactory; import org.navalplanner.web.common.converters.IConverterFactory;
import org.zkoss.zk.ui.Execution; 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;
/** /**
* <br /> * <br />
@ -23,6 +27,9 @@ import org.zkoss.zk.ui.Execution;
*/ */
public class URLHandler<T> { public class URLHandler<T> {
private static final String FLAG_ATTRIBUTE = URLHandler.class.getName()
+ "_";
private static final Log LOG = LogFactory.getLog(URLHandler.class); private static final Log LOG = LogFactory.getLog(URLHandler.class);
private static class EntryPointMetadata { private static class EntryPointMetadata {
@ -66,6 +73,9 @@ public class URLHandler<T> {
} }
public void doTransition(String methodName, Object... values) { public void doTransition(String methodName, Object... values) {
if (isFlagedInThisRequest())
return;
flagAlreadyExecutedInThisRequest();
if (!metadata.containsKey(methodName)) { if (!metadata.containsKey(methodName)) {
LOG.error("Method " + methodName LOG.error("Method " + methodName
+ "doesn't represent a state(It doesn't have a " + "doesn't represent a state(It doesn't have a "
@ -83,15 +93,55 @@ public class URLHandler<T> {
stringRepresentations[i] = converterFor stringRepresentations[i] = converterFor
.asStringUngeneric(values[i]); .asStringUngeneric(values[i]);
} }
StringBuilder linkValue = new StringBuilder(page); String fragment = getFragment(parameterNames, stringRepresentations);
for (int i = 0; i < parameterNames.length; i++) { String requestPath = executorRetriever.getCurrent().getDesktop()
linkValue.append(";").append(parameterNames[i]); .getRequestPath();
if (stringRepresentations[i] != null) if (requestPath.contains(page)) {
linkValue.append("=").append(stringRepresentations[i]); 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()); 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, private static void callMethod(Object target, Method superclassMethod,
Object[] params) { Object[] params) {
try { try {
@ -105,9 +155,24 @@ public class URLHandler<T> {
} }
public <S extends T> void applyIfMatches(S controller) { public <S extends T> void applyIfMatches(S controller) {
String uri = getRequest().getRequestURI();
applyIfMatches(controller, uri);
}
private HttpServletRequest getRequest() {
Execution current = executorRetriever.getCurrent(); Execution current = executorRetriever.getCurrent();
Map<String, String> matrixParams = MatrixParameters HttpServletRequest request = (HttpServletRequest) current
.extract((HttpServletRequest) current.getNativeRequest()); .getNativeRequest();
return request;
}
public <S extends T> void applyIfMatches(S controller, String fragment) {
if (isFlagedInThisRequest()) {
return;
}
flagAlreadyExecutedInThisRequest();
String string = insertSemicolonIfNeeded(fragment);
Map<String, String> matrixParams = MatrixParameters.extract(string);
Set<String> matrixParamsNames = matrixParams.keySet(); Set<String> matrixParamsNames = matrixParams.keySet();
for (Entry<String, EntryPointMetadata> entry : metadata.entrySet()) { for (Entry<String, EntryPointMetadata> entry : metadata.entrySet()) {
EntryPointMetadata entryPointMetadata = entry.getValue(); EntryPointMetadata entryPointMetadata = entry.getValue();
@ -124,6 +189,24 @@ public class URLHandler<T> {
} }
} }
public <S extends T> 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<String, String> matrixParams, private Object[] retrieveArguments(Map<String, String> matrixParams,
EntryPoint linkToStateAnnotation, Class<?>[] parameterTypes) { EntryPoint linkToStateAnnotation, Class<?>[] parameterTypes) {
Object[] result = new Object[parameterTypes.length]; Object[] result = new Object[parameterTypes.length];

View file

@ -20,4 +20,7 @@ public interface IWorkerCRUDControllerEntryPoints {
@EntryPoint("create") @EntryPoint("create")
public abstract void goToCreateForm(); public abstract void goToCreateForm();
@EntryPoint("list")
void goToList();
} }

View file

@ -57,6 +57,8 @@ public class WorkerCRUDController extends GenericForwardComposer implements
private WorkRelationshipsController editWorkRelationship; private WorkRelationshipsController editWorkRelationship;
private IWorkerCRUDControllerEntryPoints workerCRUD;
public WorkerCRUDController() { public WorkerCRUDController() {
} }
@ -64,7 +66,8 @@ public class WorkerCRUDController extends GenericForwardComposer implements
Window editWindow, Window workRelationshipsWindow, Window editWindow, Window workRelationshipsWindow,
Window addWorkRelationshipWindow, Window addWorkRelationshipWindow,
Window editWorkRelationshipWindow, IWorkerModel workerModel, Window editWorkRelationshipWindow, IWorkerModel workerModel,
IMessagesForUser messages) { IMessagesForUser messages,
IWorkerCRUDControllerEntryPoints workerCRUD) {
this.createWindow = createWindow; this.createWindow = createWindow;
this.listWindow = listWindow; this.listWindow = listWindow;
this.editWindow = editWindow; this.editWindow = editWindow;
@ -73,6 +76,7 @@ public class WorkerCRUDController extends GenericForwardComposer implements
this.editWorkRelationshipWindow = editWorkRelationshipWindow; this.editWorkRelationshipWindow = editWorkRelationshipWindow;
this.workerModel = workerModel; this.workerModel = workerModel;
this.messages = messages; this.messages = messages;
this.workerCRUD = workerCRUD;
} }
public Worker getWorker() { public Worker getWorker() {
@ -92,7 +96,7 @@ public class WorkerCRUDController extends GenericForwardComposer implements
public void save() { public void save() {
try { try {
workerModel.save(); workerModel.save();
getVisibility().showOnly(listWindow); goToList();
Util.reloadBindings(listWindow); Util.reloadBindings(listWindow);
messages.showMessage(Level.INFO, "traballador gardado"); messages.showMessage(Level.INFO, "traballador gardado");
} catch (ValidationException e) { } catch (ValidationException e) {
@ -103,10 +107,16 @@ public class WorkerCRUDController extends GenericForwardComposer implements
} }
public void cancel() { public void cancel() {
goToList();
}
public void goToList() {
getBookmarker().goToList();
getVisibility().showOnly(listWindow); getVisibility().showOnly(listWindow);
} }
public void goToEditForm(Worker worker) { public void goToEditForm(Worker worker) {
getBookmarker().goToEditForm(worker);
workerModel.prepareEditFor(worker); workerModel.prepareEditFor(worker);
getVisibility().showOnly(editWindow); getVisibility().showOnly(editWindow);
Util.reloadBindings(editWindow); Util.reloadBindings(editWindow);
@ -133,6 +143,7 @@ public class WorkerCRUDController extends GenericForwardComposer implements
} }
public void goToCreateForm() { public void goToCreateForm() {
getBookmarker().goToCreateForm();
workerModel.prepareForCreate(); workerModel.prepareForCreate();
getVisibility().showOnly(createWindow); getVisibility().showOnly(createWindow);
Util.reloadBindings(createWindow); Util.reloadBindings(createWindow);
@ -151,7 +162,6 @@ public class WorkerCRUDController extends GenericForwardComposer implements
localizationsForCreationController = createLocalizationsController( localizationsForCreationController = createLocalizationsController(
comp, "createWindow"); comp, "createWindow");
comp.setVariable("controller", this, true); comp.setVariable("controller", this, true);
getVisibility().showOnly(listWindow);
if (messagesContainer == null) if (messagesContainer == null)
throw new RuntimeException("messagesContainer is needed"); throw new RuntimeException("messagesContainer is needed");
messages = new MessagesForUser(messagesContainer); messages = new MessagesForUser(messagesContainer);
@ -164,9 +174,12 @@ public class WorkerCRUDController extends GenericForwardComposer implements
this.workerModel, this, messages), this.workerModel, this, messages),
editWorkRelationshipWindow); editWorkRelationshipWindow);
URLHandler<IWorkerCRUDControllerEntryPoints> handler = URLHandlerRegistry final URLHandler<IWorkerCRUDControllerEntryPoints> handler = URLHandlerRegistry
.getRedirectorFor(IWorkerCRUDControllerEntryPoints.class); .getRedirectorFor(IWorkerCRUDControllerEntryPoints.class);
handler.applyIfMatches(this); handler.registerListener(this, page);
getVisibility().showOnly(listWindow);
handler.registerListener(this, page);
getVisibility().showOnly(listWindow);
} }
private void setupWorkRelationshipController( private void setupWorkRelationshipController(
@ -200,4 +213,8 @@ public class WorkerCRUDController extends GenericForwardComposer implements
return this.addWorkRelationship; return this.addWorkRelationship;
} }
private IWorkerCRUDControllerEntryPoints getBookmarker() {
return workerCRUD;
}
} }

View file

@ -17,6 +17,7 @@ import org.junit.Test;
import org.navalplanner.business.resources.entities.Worker; import org.navalplanner.business.resources.entities.Worker;
import org.navalplanner.web.common.IMessagesForUser; import org.navalplanner.web.common.IMessagesForUser;
import org.navalplanner.web.common.Level; 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.IWorkerModel;
import org.navalplanner.web.resources.worker.WorkerCRUDController; import org.navalplanner.web.resources.worker.WorkerCRUDController;
import org.zkoss.zul.api.Window; import org.zkoss.zul.api.Window;
@ -33,6 +34,7 @@ public class WorkerCRUDControllerTest {
private Window workRelationshipsWindow; private Window workRelationshipsWindow;
private Window addWorkRelationshipWindow; private Window addWorkRelationshipWindow;
private Window editWorkRelationshipWindow; private Window editWorkRelationshipWindow;
private WorkerCRUDController createControllerForModel( private WorkerCRUDController createControllerForModel(
IWorkerModel workerModel) { IWorkerModel workerModel) {
return createControllerForModel(workerModel, null); return createControllerForModel(workerModel, null);
@ -44,17 +46,16 @@ public class WorkerCRUDControllerTest {
listWindow = createNiceMock(Window.class); listWindow = createNiceMock(Window.class);
editWindow = createNiceMock(Window.class); editWindow = createNiceMock(Window.class);
workRelationshipsWindow = createNiceMock(Window.class); workRelationshipsWindow = createNiceMock(Window.class);
addWorkRelationshipWindow = createNiceMock(Window.class); addWorkRelationshipWindow = createNiceMock(Window.class);
editWorkRelationshipWindow = createNiceMock(Window.class); editWorkRelationshipWindow = createNiceMock(Window.class);
WorkerCRUDController workerCRUDController = new WorkerCRUDController( WorkerCRUDController workerCRUDController = new WorkerCRUDController(
createWindow, listWindow, editWindow, workRelationshipsWindow, createWindow, listWindow, editWindow, workRelationshipsWindow,
addWorkRelationshipWindow, editWorkRelationshipWindow ,workerModel, messages); addWorkRelationshipWindow, editWorkRelationshipWindow,
workerModel, messages, createNiceMock(IWorkerCRUDControllerEntryPoints.class));
return workerCRUDController; return workerCRUDController;
} }
@Test @Test
public void testSave() throws Exception { public void testSave() throws Exception {
IWorkerModel workerModel = createMock(IWorkerModel.class); IWorkerModel workerModel = createMock(IWorkerModel.class);
@ -81,6 +82,7 @@ public class WorkerCRUDControllerTest {
// verify // verify
verify(workerModel, messagesForUser); verify(workerModel, messagesForUser);
} }
@Test @Test
public void testGoToSaveAndThenCancel() { public void testGoToSaveAndThenCancel() {
IWorkerModel workerModel = createMock(IWorkerModel.class); IWorkerModel workerModel = createMock(IWorkerModel.class);
@ -95,7 +97,8 @@ public class WorkerCRUDControllerTest {
expect(workRelationshipsWindow.setVisible(true)).andReturn(false); expect(workRelationshipsWindow.setVisible(true)).andReturn(false);
expect(addWorkRelationshipWindow.setVisible(true)).andReturn(false); expect(addWorkRelationshipWindow.setVisible(true)).andReturn(false);
replay(createWindow, listWindow, editWindow, workRelationshipsWindow, replay(createWindow, listWindow, editWindow, workRelationshipsWindow,
addWorkRelationshipWindow, editWorkRelationshipWindow, workerModel); addWorkRelationshipWindow, editWorkRelationshipWindow,
workerModel);
// actions // actions
workerCRUDController.goToCreateForm(); workerCRUDController.goToCreateForm();
workerCRUDController.cancel(); workerCRUDController.cancel();