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.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;
/**
* <br />
@ -23,6 +27,9 @@ import org.zkoss.zk.ui.Execution;
*/
public class URLHandler<T> {
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<T> {
}
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<T> {
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<T> {
}
public <S extends T> void applyIfMatches(S controller) {
String uri = getRequest().getRequestURI();
applyIfMatches(controller, uri);
}
private HttpServletRequest getRequest() {
Execution current = executorRetriever.getCurrent();
Map<String, String> matrixParams = MatrixParameters
.extract((HttpServletRequest) current.getNativeRequest());
HttpServletRequest request = (HttpServletRequest) current
.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();
for (Entry<String, EntryPointMetadata> entry : metadata.entrySet()) {
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,
EntryPoint linkToStateAnnotation, Class<?>[] parameterTypes) {
Object[] result = new Object[parameterTypes.length];

View file

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

View file

@ -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<IWorkerCRUDControllerEntryPoints> handler = URLHandlerRegistry
final URLHandler<IWorkerCRUDControllerEntryPoints> 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;
}
}

View file

@ -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();