001: /* ***** BEGIN LICENSE BLOCK *****
002: * Version: MPL 1.1
003: * The contents of this file are subject to the Mozilla Public License Version
004: * 1.1 (the "License"); you may not use this file except in compliance with
005: * the License. You may obtain a copy of the License at
006: * http://www.mozilla.org/MPL/
007: *
008: * Software distributed under the License is distributed on an "AS IS" basis,
009: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
010: * for the specific language governing rights and limitations under the
011: * License.
012: *
013: * The Original Code is Riot.
014: *
015: * The Initial Developer of the Original Code is
016: * Neteye GmbH.
017: * Portions created by the Initial Developer are Copyright (C) 2006
018: * the Initial Developer. All Rights Reserved.
019: *
020: * Contributor(s):
021: * Felix Gnass [fgnass at neteye dot de]
022: *
023: * ***** END LICENSE BLOCK ***** */
024: package org.riotfamily.forms.controller;
025:
026: import java.io.IOException;
027: import java.io.PrintWriter;
028: import java.util.ArrayList;
029: import java.util.Iterator;
030: import java.util.List;
031:
032: import javax.servlet.http.HttpServletRequest;
033: import javax.servlet.http.HttpServletResponse;
034: import javax.servlet.http.HttpSession;
035:
036: import org.apache.commons.logging.Log;
037: import org.apache.commons.logging.LogFactory;
038: import org.riotfamily.forms.Container;
039: import org.riotfamily.forms.ContentElement;
040: import org.riotfamily.forms.Element;
041: import org.riotfamily.forms.Form;
042: import org.springframework.web.servlet.ModelAndView;
043: import org.springframework.web.servlet.mvc.Controller;
044:
045: /**
046: * Abstract base class for controllers that display a form.
047: *
048: * @author Felix Gnass [fgnass at neteye dot de]
049: */
050: public abstract class AbstractFormController implements Controller {
051:
052: public static final String FORM_SUBMISSION_HANDLER = "formSubmissionHandler";
053:
054: protected static final String BUTTON_CONTAINER_ID = "buttons";
055:
056: private static final String CONTENT_PARAM = "_content";
057:
058: private static final String EXCLUSIVE_PARAM = "_exclusive";
059:
060: protected Log log = LogFactory.getLog(getClass());
061:
062: private FormContextFactory formContextFactory;
063:
064: private boolean processNewForms;
065:
066: private List buttonFactories;
067:
068: public void setFormContextFactory(FormContextFactory contextFactory) {
069: this .formContextFactory = contextFactory;
070: }
071:
072: public final void setProcessNewForms(boolean processNewForms) {
073: this .processNewForms = processNewForms;
074: }
075:
076: public void setButtonFactories(List buttonFactories) {
077: this .buttonFactories = buttonFactories;
078: }
079:
080: protected void addButton(ButtonFactory buttonFactory) {
081: if (buttonFactories == null) {
082: buttonFactories = new ArrayList();
083: }
084: buttonFactories.add(buttonFactory);
085: }
086:
087: protected final void initController() {
088: }
089:
090: /**
091: * Handles a HTTP request. The workflow is:
092: * <ol>
093: * <li>
094: * Check if a new Form needs to be created by calling
095: * {@link #isInitialRequest}.
096: * </li>
097: * <li>
098: * Call to {@link #createAndInitForm} in case of an initial request
099: * or {@link #getForm} otherwise.
100: * </li>
101: * <li>
102: * Check if the request is request for additional content (an
103: * image or iframe for example) and call {@link #handleContentRequest}
104: * or {@link #handleFormRequest}.
105: * </li>
106: * </ol>
107: */
108: public ModelAndView handleRequest(HttpServletRequest request,
109: HttpServletResponse response) throws Exception {
110:
111: Form form = null;
112: if (!isInitialRequest(request)) {
113: form = getForm(request);
114: }
115: if (form == null) {
116: form = createAndInitForm(request, response);
117: }
118:
119: if (isContentRequest(request)) {
120: return handleContentRequest(form, request, response);
121: } else {
122: return handleFormRequest(form, request, response);
123: }
124: }
125:
126: protected ModelAndView handleFormRequest(Form form,
127: HttpServletRequest request, HttpServletResponse response)
128: throws Exception {
129:
130: if (!isInitialRequest(request) || processNewForms) {
131: processForm(form, request);
132: }
133: return createModelAndView(form, request, response);
134: }
135:
136: /**
137: * Returns the {@link Form Form} for the given request. By
138: * default this method looks for an existing instance in the HTTP session
139: * under the key returned by {@link #getSessionAttribute} and
140: * returns it.
141: */
142: protected Form getForm(HttpServletRequest request) {
143: log.debug("Retrieving Form from session");
144: HttpSession session = request.getSession();
145: String attrName = getSessionAttribute(request);
146: Form form = (Form) session.getAttribute(attrName);
147: return form;
148: }
149:
150: protected ModelAndView showForm(Form form,
151: HttpServletRequest request, HttpServletResponse response)
152: throws Exception {
153:
154: PrintWriter writer = getWriter(request, response);
155: renderForm(form, writer);
156: return null;
157: }
158:
159: protected PrintWriter getWriter(HttpServletRequest request,
160: HttpServletResponse response) throws IOException {
161:
162: return response.getWriter();
163: }
164:
165: protected void renderForm(Form form, PrintWriter writer) {
166: form.render(writer);
167: }
168:
169: /**
170: * Returns whether the given request is an initial form request. By
171: * default it is checked whether the request method is <tt>GET</tt> and
172: * {@link #isContentRequest} returns <code>false</code>.
173: */
174: protected boolean isInitialRequest(HttpServletRequest request) {
175: return "GET".equals(request.getMethod())
176: && !isContentRequest(request);
177: }
178:
179: /**
180: * Returns whether the request is to be handled by a {@link ContentElement}.
181: */
182: protected boolean isContentRequest(HttpServletRequest request) {
183: return request.getParameter(CONTENT_PARAM) != null;
184: }
185:
186: protected boolean isExclusiveRequest(HttpServletRequest request) {
187: return request.getParameter(EXCLUSIVE_PARAM) != null;
188: }
189:
190: protected ModelAndView handleContentRequest(Form form,
191: HttpServletRequest request, HttpServletResponse response)
192: throws IOException {
193:
194: if (form != null) {
195: String id = request.getParameter(CONTENT_PARAM);
196: Element element = form.getElementById(id);
197: if (element instanceof ContentElement) {
198: ContentElement ce = (ContentElement) element;
199: ce.handleContentRequest(request, response);
200: return null;
201: }
202: }
203: response.sendError(HttpServletResponse.SC_NOT_FOUND);
204: return null;
205: }
206:
207: /**
208: * Creates and initializes a form.
209: */
210: protected Form createAndInitForm(HttpServletRequest request,
211: HttpServletResponse response) throws Exception {
212:
213: Form form = createForm(request);
214: form.setFormContext(formContextFactory.createFormContext(
215: request, response));
216:
217: if (buttonFactories != null && !buttonFactories.isEmpty()) {
218: Container container = form
219: .createContainer(BUTTON_CONTAINER_ID);
220: Iterator it = buttonFactories.iterator();
221: while (it.hasNext()) {
222: ButtonFactory buttonFactory = (ButtonFactory) it.next();
223: container.addElement(buttonFactory.createButton());
224: }
225: }
226:
227: populateForm(form, request);
228: form.init();
229: initForm(form, request);
230:
231: String attrName = getSessionAttribute(request);
232: request.getSession().setAttribute(attrName, form);
233:
234: return form;
235: }
236:
237: protected void processForm(Form form, HttpServletRequest request) {
238: if (isExclusiveRequest(request)) {
239: String id = request.getParameter(EXCLUSIVE_PARAM);
240: form.processExclusiveRequest(id, request);
241: } else {
242: form.processRequest(request);
243: }
244: }
245:
246: /**
247: * Populates newly created forms. The default implementation invokes
248: * {@link Form#setValue(Object)} with the object returned by
249: * {@link #getFormBackingObject(HttpServletRequest)}.
250: */
251: protected void populateForm(Form form, HttpServletRequest request)
252: throws Exception {
253:
254: form.setValue(getFormBackingObject(request));
255: }
256:
257: /**
258: * Returns the object backing the form. Subclasses may overwrite this method
259: * to retrieve a persistent object. The default implementation returns
260: * <code>null</code>.
261: */
262: protected Object getFormBackingObject(HttpServletRequest request)
263: throws Exception {
264:
265: return null;
266: }
267:
268: /**
269: * Subclasses must implement this method and return a fresh
270: * {@link Form} instance.
271: */
272: protected abstract Form createForm(HttpServletRequest request);
273:
274: /**
275: * Subclasses may overwite this method to inialize forms after they have
276: * been populated. The default implementation does nothing.
277: */
278: protected void initForm(Form form, HttpServletRequest request) {
279: }
280:
281: protected final ModelAndView createModelAndView(Form form,
282: HttpServletRequest request, HttpServletResponse response)
283: throws Exception {
284:
285: FormSubmissionHandler handler = (FormSubmissionHandler) form
286: .getAttribute(FORM_SUBMISSION_HANDLER);
287:
288: form.setAttribute(FORM_SUBMISSION_HANDLER, null);
289:
290: if (handler != null && !form.hasErrors()) {
291: return handler
292: .handleFormSubmission(form, request, response);
293: }
294: return showForm(form, request, response);
295: }
296:
297: protected String getSessionAttribute(HttpServletRequest request) {
298: return AbstractFormController.class.getName() + ".form";
299: }
300:
301: }
|