/* * (C) Copyright 2006-2008 Nuxeo SA (http://nuxeo.com/) and others. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Contributors: * bstefanescu */ package org.nuxeo.ecm.webengine.ui.wizard; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpSession; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.nuxeo.ecm.webengine.forms.validation.Form; import org.nuxeo.ecm.webengine.forms.validation.ValidationException; import org.nuxeo.ecm.webengine.model.impl.DefaultObject; /** * The following actions are available: * <ul> * <li>GET * <li>POST next * <li>POST ok * <li>POST cancel * <li>POST back * </ul> * * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> */ public abstract class Wizard extends DefaultObject { private static final Log log = LogFactory.getLog(Wizard.class); public static final String[] EMPTY = new String[0]; protected WizardSession session; protected WizardPage page; // current wizard page protected ValidationException error; protected Map<String, String[]> initialFields; protected abstract WizardPage[] createPages(); protected Map<String, String[]> createInitialFields() { return null; } @Override protected void initialize(Object... args) { super.initialize(args); HttpSession httpSession = ctx.getRequest().getSession(true); String key = createSessionId(); session = (WizardSession) httpSession.getAttribute(key); if (session == null) { session = new WizardSession(key, createPages()); httpSession.setAttribute(key, session); initialFields = createInitialFields(); if (initialFields == null) { initialFields = new HashMap<String, String[]>(); } } page = (WizardPage) session.getPage(); // the current page } protected void destroySession() { HttpSession httpSession = ctx.getRequest().getSession(false); if (httpSession != null) { httpSession.removeAttribute(session.getId()); } } protected String createSessionId() { return "wizard:" + getClass(); } public WizardSession getSession() { return session; } public WizardPage getPage() { return page; } public boolean isNextEnabled() { return page.isNextEnabled(); } public boolean isBackEnabled() { return page.isBackEnabled(); } public boolean isOkEnabled() { return page.isOkEnabled(); } public boolean isCancelEnabled() { return page.isCancelEnabled(); } public ValidationException getError() { return error; } @SuppressWarnings("unchecked") public Map<String, String[]> getFormFields() { Form form = session.getPage().getForm(); if (form != null) { return form.fields(); } return initialFields == null ? Collections.EMPTY_MAP : initialFields; } public String getField(String key) { String[] v = getFormFields().get(key); return v != null && v.length > 0 ? v[0] : null; } public String[] getFields(String key) { String[] fields = getFormFields().get(key); return fields == null ? EMPTY : fields; } public Collection<String> getInvalidFields() { if (error != null) { return error.getInvalidFields(); } return null; } public Collection<String> getRequireddFields() { if (error != null) { return error.getRequiredFields(); } return null; } public boolean hasErrors() { return error != null; } public boolean hasErrors(String key) { if (error != null) { return error.hasErrors(key); } return false; } protected Object redirectOnOk() { return redirect(getPrevious().getPath()); } protected Object redirectOnCancel() { return redirect(getPrevious().getPath()); } public <T extends Form> T getForm(Class<T> formType) { return session.getForm(formType); } protected abstract void performOk() throws ValidationException; protected void performCancel() { destroySession(); } protected Object handleValidationError(ValidationException e) { // set the error and redisplay the current page session.setError(e); return redirect(getPath()); } protected Object handleError(Throwable e) { // set the error and redisplay the current page log.error("Processing failed in wizard page: " + session.getPage().getId(), e); session.setError(new ValidationException("Processing failed: " + e.getMessage(), e)); return redirect(getPath()); } @SuppressWarnings("unchecked") public <T extends Form> T validate(WizardPage page) throws ValidationException { try { Form form = ctx.getForm().validate(page.getFormType()); page.setForm(form); return (T) form; } catch (ValidationException e) { page.setForm(e.getForm()); throw e; } } @POST @Path("next") public Object handleNext() { String pageId = null; try { // process page pageId = page.getNextPage(this, validate(page)); if (pageId == WizardPage.NEXT_PAGE) { pageId = session.getPageAt(page.getIndex() + 1); } if (pageId == null) { // finish the wizard performOk(); destroySession(); return redirectOnOk(); } else { // go to the next page session.pushPage(pageId); return redirect(getPath()); } } catch (ValidationException e) { return handleValidationError(e); } catch (RuntimeException e) { return handleError(e); } } @POST @Path("back") public Object handleBack() { session.popPage(); // go to previous page return redirect(getPath()); } @POST @Path("cancel") public Object handleCancel() { performCancel(); return redirectOnCancel(); } @POST @Path("ok") public Object handleOk() { try { validate(page);// don't matter if there is a next page performOk(); destroySession(); return redirectOnOk(); } catch (ValidationException e) { return handleValidationError(e); } catch (RuntimeException e) { return handleError(e); } } /** * Get the content of the current wizard page. */ @GET public Object doGet() { error = session.removeError(); return getView(page.getId()); } }