| /* |
| * Copyright 2004-2008 Malcolm A. Edgar |
| * |
| * 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. |
| */ |
| package net.sf.click; |
| |
| import java.text.MessageFormat; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import net.sf.click.util.Format; |
| import net.sf.click.util.MessagesMap; |
| |
| import org.apache.commons.lang.StringUtils; |
| |
| /** |
| * Provides the Page request event handler class. |
| * <p/> |
| * The Page class plays a central role in Click applications defining how the |
| * application's pages are processed and rendered. All application pages |
| * must extend the base Page class, and provide a no arguments constructor. |
| * |
| * <h4>Page Execution Sequence</h4> |
| * |
| * The default Page execution path for a GET request is: |
| * <ol> |
| * <li class="spaced"> |
| * no-args constructor invoked to create a new Page instance. |
| * At this point no dependencies have been injected into the Page, and any |
| * request information is not available. You should put any "static" |
| * page initialization code, which doesn't depend upon request information, |
| * in the constructor. This will enable subclasses to have this code |
| * automatically initialized when they are created. |
| * </li> |
| * <li class="spaced"> |
| * {@link #format} property is set |
| * </li> |
| * <li class="spaced"> |
| * {@link #headers} property is set |
| * </li> |
| * <li class="spaced"> |
| * {@link #path} property is set |
| * </li> |
| * <li class="spaced"> |
| * {@link #onSecurityCheck()} method called to check whether the page should |
| * be processed. This method should return true if the Page should continue |
| * to be processed, or false otherwise. |
| * </li> |
| * <li class="spaced"> |
| * {@link #onInit()} method called to complete the initialization of the page |
| * after all the dependencies have been set. This is where you should put |
| * any "dynamic" page initialization code which depends upon the request or any |
| * other dependencies. |
| * <p/> |
| * Form and field controls must be fully initialized by the time this method |
| * has completed. |
| * </li> |
| * <li class="spaced"> |
| * ClickServlet processes all the page {@link #controls} |
| * calling their {@link Control#onProcess()} method. If any of these |
| * controls return false, continued control and page processing will be aborted. |
| * </li> |
| * <li class="spaced"> |
| * {@link #onGet()} method called for any additional GET related processing. |
| * <p/> |
| * Form and field controls should <b>NOT</b> be created or initialized at this |
| * point as the control processing stage has already been completed. |
| * </li> |
| * <li class="spaced"> |
| * {@link #onRender()} method called for any pre-render processing. This |
| * method is often use to perform database queries to load information for |
| * rendering tables. |
| * <p/> |
| * Form and field controls should <b>NOT</b> be created or initialized at this |
| * point as the control processing stage has already been completed. |
| * </li> |
| * <li class="spaced"> |
| * ClickServlet renders the page merging the {@link #model} with the |
| * Velocity template defined by the {@link #getTemplate()} property. |
| * </li> |
| * <li class="spaced"> |
| * {@link #onDestroy()} method called to clean up any resources. This method |
| * is guaranteed to be called, even if an exception occurs. You can use |
| * this method to close resources like database connections or Hibernate |
| * sessions. |
| * </li> |
| * </ol> |
| * |
| * For POST requests the default execution path is identical, except the |
| * {@link #onPost()} method is called instead of {@link #onGet()}. The POST |
| * request page execution sequence is illustrated below: |
| * <p/> |
| * <img src="post-sequence-diagram.png"/> |
| * |
| * <p/> |
| * A good way to see the page event execution order is to view the log when |
| * the application mode is set to <tt>trace</tt>: |
| * |
| * <pre class="codeConfig" style="padding:1em;background-color:#f0f0f0;"> |
| * [Click] [debug] GET http://localhost:8080/quickstart/home.htm |
| * [Click] [trace] invoked: HomePage.<<init>> |
| * [Click] [trace] invoked: HomePage.onSecurityCheck() : true |
| * [Click] [trace] invoked: HomePage.onInit() |
| * [Click] [trace] invoked: HomePage.onGet() |
| * [Click] [trace] invoked: HomePage.onRender() |
| * [Click] [info ] renderTemplate: /home.htm - 6 ms |
| * [Click] [trace] invoked: HomePage.onDestroy() |
| * [Click] [info ] handleRequest: /home.htm - 24 ms </pre> |
| * |
| * <h4>Rendering Pages</h4> |
| * |
| * When a Velocity template is rendered the ClickServlet uses Pages: |
| * <ul> |
| * <li>{@link #getTemplate()} to find the Velocity template.</li> |
| * <li>{@link #model} to populate the Velocity Context</li> |
| * <li>{@link #format} to add to the Velocity Context</li> |
| * <li>{@link #getContentType()} to set as the HttpServletResponse content type</li> |
| * <li>{@link #headers} to set as the HttpServletResponse headers</li> |
| * </ul> |
| * |
| * These Page properties are also used when rendering JSP pages. |
| * |
| * @author Malcolm Edgar |
| */ |
| public class Page { |
| |
| private static final long serialVersionUID = 1L; |
| |
| /** |
| * The global page messages bundle name: <tt>click-page</tt>. |
| */ |
| public static final String PAGE_MESSAGES = "click-page"; |
| |
| // ----------------------------------------------------- Instance Variables |
| |
| /** The list of page controls. */ |
| protected List controls; |
| |
| /** The Velocity template formatter object. */ |
| protected Format format; |
| |
| /** The forward path. */ |
| protected String forward; |
| |
| /** The HTTP response headers. */ |
| protected Map headers; |
| |
| /** The headers have been edited flag, to support copy on write. */ |
| protected boolean headersEdited; |
| |
| /** The map of localized page resource messages. **/ |
| protected transient MessagesMap messages; |
| |
| /** |
| * The page model. For Velocity templates the model is used to populate the |
| * Velocity context. For JSP pages the model values are set as named |
| * request attributes. |
| */ |
| protected Map model = new HashMap(); |
| |
| /** The path of the page template to render. */ |
| protected String path; |
| |
| /** The redirect path. */ |
| protected String redirect; |
| |
| /** |
| * The page is stateful and should be save to the users HttpSession |
| * between requests. |
| */ |
| protected boolean stateful; |
| |
| // --------------------------------------------------------- Event Handlers |
| |
| /** |
| * The on Security Check event handler. This event handler is invoked after |
| * the pages constructor has been called and all the page properties have |
| * been set. |
| * <p/> |
| * Security check provides the Page an opportunity to check the users |
| * security credentials before processing the Page. |
| * <p/> |
| * If security check returns true the Page is processed as |
| * normal. If the method returns then no other event handlers are invoked |
| * (except <tt>onDestroy()</tt> and no page controls are processed. |
| * <p/> |
| * If the method returns false, the forward or redirect property should be |
| * set to send the request to another Page. |
| * <p/> |
| * By default this method returns true, subclass may override this method |
| * to provide their security authorization/authentication mechanism. |
| * |
| * @return true by default, subclasses may override this method |
| */ |
| public boolean onSecurityCheck() { |
| return true; |
| } |
| |
| /** |
| * The on Initialization event handler. This event handler is invoked after |
| * the {@link #onInit()} method has been called. |
| * <p/> |
| * Subclasses should place any initialization code which has dependencies |
| * on the context or other properties in this method. Generally light |
| * weight initialization code should be placed in the Pages constructor. |
| * <p/> |
| * Time consuming operations such as fetching the results of a database |
| * query should not be placed in this method. These operations should be |
| * performed in the {@link #onRender()}, {@link #onGet()} or |
| * {@link #onPost()} methods so that other event handlers may take |
| * alternative execution paths without performing these expensive operations. |
| * <p/> |
| * <b>Please Note</b> however the qualifier for the previous statement is |
| * that all form and field controls must be fully initialized before they |
| * are processed, which is after the <tt>onInit()</tt> method has |
| * completed. After this point their <tt>onProcess()</tt> methods will be |
| * invoked by the <tt>ClickServlet</tt>. |
| * <p/> |
| * Select controls in particular must have their option list values populated |
| * before the form is processed otherwise field validations cannot be performed. |
| * <p/> |
| * For initializing page controls the best practice is to place all the |
| * control creation code in the pages constructor, and only place any |
| * initialization code in the <tt>onInit()</tt> method which has an external |
| * dependency to the context or some other object. By following this practice |
| * it is easy to see what code is "design time" initialization code and what |
| * is "runtime initialization code". |
| * <p/> |
| * When subclassing pages which also use the <tt>onInit()</tt> method is |
| * is critical you call the <tt>super.onInit()</tt> method first, for |
| * example: |
| * <pre class="javaCode"> |
| * <span class="kw">public void</span> onInit() { |
| * <span class="kw">super</span>.onInit(); |
| * |
| * // Initialization code |
| * .. |
| * } </pre> |
| */ |
| public void onInit() { |
| } |
| |
| /** |
| * The on Get request event handler. This event handler is invoked if the |
| * HTTP request method is "GET". |
| * <p/> |
| * The event handler is invoked after {@link #onSecurityCheck()} has been |
| * called and all the Page {@link #controls} have been processed. If either |
| * the security check or one of the controls cancels continued event |
| * processing the <tt>onGet()</tt> method will not be invoked. |
| * |
| * <h4>Important Note</h4> |
| * |
| * Form and field controls should <b>NOT</b> be created |
| * or initialized at this point as the control processing stage has already |
| * been completed. Select option list values should also be populated |
| * before the control processing stage is performed so that they can |
| * validate the submitted values. |
| */ |
| public void onGet() { |
| } |
| |
| /** |
| * The on Post request event handler. This event handler is invoked if the |
| * HTTP request method is "POST". |
| * <p/> |
| * The event handler is invoked after {@link #onSecurityCheck()} has been |
| * called and all the Page {@link #controls} have been processed. If either |
| * the security check or one of the controls cancels continued event |
| * processing the <tt>onPost()</tt> method will not be invoked. |
| * |
| * <h4>Important Note</h4> |
| * |
| * Form and field controls should <b>NOT</b> be created |
| * or initialized at this point as the control processing stage has already |
| * been completed. Select option list values should also be populated |
| * before the control processing stage is performed so that they can |
| * validate the submitted values. |
| */ |
| public void onPost() { |
| } |
| |
| /** |
| * The on render event handler. This event handler is invoked prior to the |
| * page being rendered. |
| * <p/> |
| * This method will not be invoked if either the security check or one of |
| * the controls cancels continued event processing. |
| * <p/> |
| * The on render method is typically used to populate tables performing some |
| * database intensive operation. By putting the intensive operations in the |
| * on render method they will not be performed if the user navigates away |
| * to a different page. |
| * <p/> |
| * If you have code which you are using in both the <tt>onGet()</tt> and |
| * <tt>onPost()</tt> methods, use the <tt>onRender()</tt> method instead. |
| * |
| * <h4>Important Note</h4> |
| * |
| * Form and field controls should <b>NOT</b> be created |
| * or initialized at this point as the control processing stage has already |
| * been completed. Select option list values should also be populated |
| * before the control processing stage is performed so that they can |
| * validate the submitted values. |
| */ |
| public void onRender() { |
| } |
| |
| /** |
| * The on Destroy request event handler. Subclasses may override this method |
| * to add any resource clean up code. |
| * <p/> |
| * This method is guaranteed to be called before the Page object reference |
| * goes out of scope and is available for garbage collection. |
| * <p/> |
| * Stateful pages will have this method invoked before they are saved to |
| * the session. |
| */ |
| public void onDestroy() { |
| } |
| |
| // --------------------------------------------------------- Public Methods |
| |
| /** |
| * Add the control to the page. The control will be added to the pages model |
| * using the controls name as the key. The Controls context property will |
| * be set if the context is available. The Controls parent property will |
| * also be set to the page instance. |
| * |
| * @param control the control to add |
| * @throws IllegalArgumentException if the control is null, or if the name |
| * of the control is not defined |
| */ |
| public void addControl(Control control) { |
| if (control == null) { |
| throw new IllegalArgumentException("Null control parameter"); |
| } |
| if (StringUtils.isBlank(control.getName())) { |
| throw new IllegalArgumentException("Control name not defined"); |
| } |
| |
| getControls().add(control); |
| addModel(control.getName(), control); |
| |
| control.setParent(this); |
| } |
| |
| /** |
| * Return the list of page Controls. |
| * |
| * @return the list of page Controls |
| */ |
| public List getControls() { |
| if (controls == null) { |
| controls = new ArrayList(); |
| } |
| return controls; |
| } |
| |
| /** |
| * Return true if the page has any controls defined. |
| * |
| * @return true if the page has any controls defined |
| */ |
| public boolean hasControls() { |
| return (controls == null) ? false : !controls.isEmpty(); |
| } |
| |
| /** |
| * Return the request context of the page. |
| * |
| * @return the request context of the page |
| */ |
| public Context getContext() { |
| return Context.getThreadLocalContext(); |
| } |
| |
| /** |
| * Return the HTTP response content type. By default this method returns |
| * <tt>"text/html"</tt>. |
| * <p/> |
| * If the request specifies a character encoding via |
| * If {@link javax.servlet.ServletRequest#getCharacterEncoding()} |
| * then this method will return <tt>"text/html; charset=encoding"</tt>. |
| * <p/> |
| * The ClickServlet uses the pages content type for setting the |
| * HttpServletResponse content type. |
| * |
| * @return the HTTP response content type |
| */ |
| public String getContentType() { |
| String charset = getContext().getRequest().getCharacterEncoding(); |
| |
| if (charset == null) { |
| return "text/html"; |
| |
| } else { |
| return "text/html; charset=" + charset; |
| } |
| } |
| |
| /** |
| * Return the Velocity template formatter object. |
| * <p/> |
| * The ClickServlet adds the format object to the Velocity context using |
| * the key <tt>"format"</tt> so that it can be used in the page template. |
| * |
| * @return the Velocity template formatter object |
| */ |
| public Format getFormat() { |
| return format; |
| } |
| |
| /** |
| * Set the Velocity template formatter object. |
| * |
| * @param value the Velocity template formatter object. |
| */ |
| public void setFormat(Format value) { |
| format = value; |
| } |
| |
| /** |
| * Return the path to forward the request to. |
| * <p/> |
| * If the {@link #forward} property is not null it will be used to forward |
| * the request to in preference to rendering the template defined by the |
| * {@link #path} property. The request is forwarded using the |
| * RequestDispatcher. |
| * <p/> |
| * See also {@link #getPath()}, {@link #getRedirect()} |
| * |
| * @return the path to forward the request to |
| */ |
| public String getForward() { |
| return forward; |
| } |
| |
| /** |
| * Set the path to forward the request to. |
| * <p/> |
| * If the {@link #forward} property is not null it will be used to forward |
| * the request to in preference to rendering the template defined by the |
| * {@link #path} property. The request is forwarded using the |
| * RequestDispatcher. |
| * <p/> |
| * If forward paths start with a <span class="wr">"/"</span> |
| * character the forward path is |
| * relative to web applications root context, otherwise the path is |
| * relative to the requests current location. |
| * <p/> |
| * For example given a web application deployed to context <tt>mycorp</tt> |
| * with the pages: |
| * <pre class="codeConfig" style="color:navy"> |
| * /index.htm |
| * /customer/search.htm |
| * /customer/details.htm |
| * /customer/management/add-customer.htm </pre> |
| * |
| * To forward to the customer <tt class="wr">search.htm</tt> page from |
| * the web app root you could set forward as |
| * <tt>setFoward(<span class="navy">"/customer/search.htm"</span>)</tt> |
| * or <tt>setFoward(<span class="navy">"customer/search.htm"</span>)</tt>. |
| * <p/> |
| * If a user was currently viewing the <tt class="wr">add-customer.htm</tt> |
| * to forward to customer <span class="wr">details.htm</span> you could |
| * set forward as |
| * <tt>setFoward(<span class="navy">"/customer/details.htm"</span>)</tt> |
| * or <tt>setFoward(<span class="navy">"../details.htm"</span>)</tt>. |
| * <p/> |
| * See also {@link #setPath(String)}, {@link #setRedirect(String)} |
| * |
| * @param value the path to forward the request to |
| */ |
| public void setForward(String value) { |
| forward = value; |
| } |
| |
| /** |
| * The Page instance to forward the request to. The given Page object |
| * must have a valid path defined. |
| * |
| * @param page the Page object to forward the request to. |
| */ |
| public void setForward(Page page) { |
| if (page == null) { |
| throw new IllegalArgumentException("Null page parameter"); |
| } |
| if (page.getPath() == null) { |
| throw new IllegalArgumentException("Page has no path defined"); |
| } |
| setForward(page.getPath()); |
| getContext().setRequestAttribute(ClickServlet.FORWARD_PAGE, page); |
| } |
| |
| /** |
| * Set the request to forward to the give page class. |
| * |
| * @param pageClass the class of the Page to forward the request to |
| * @throws IllegalArgumentException if the Page Class is not configured |
| * with a unique path |
| */ |
| public void setForward(Class pageClass) { |
| String target = getContext().getPagePath(pageClass); |
| setForward(target); |
| } |
| |
| /** |
| * Return the map of HTTP header to be set in the HttpServletResponse. |
| * Note to edit header values use {@link #setHeader(String, Object)} as |
| * headers Map is initially unmodifiable. |
| * |
| * @return the map of HTTP header to be set in the HttpServletResponse |
| */ |
| public Map getHeaders() { |
| return headers; |
| } |
| |
| /** |
| * Set the named header with the given value. This method uses copy on |
| * write to the headers Map, as the initial loaded headers Map is |
| * unmodifiable. |
| * |
| * @param name the name of the header |
| * @param value the value of the header |
| */ |
| public void setHeader(String name, Object value) { |
| if (name == null) { |
| throw new IllegalArgumentException("Null header name parameter"); |
| } |
| if (!headersEdited) { |
| headersEdited = true; |
| headers = new HashMap(headers); |
| } |
| headers.put(name, value); |
| } |
| |
| /** |
| * Set the map of HTTP header to be set in the HttpServletResponse. |
| * |
| * @param value the map of HTTP header to be set in the HttpServletResponse |
| */ |
| public void setHeaders(Map value) { |
| headers = value; |
| } |
| |
| /** |
| * Return the localized Page resource message for the given resource |
| * property key. The resource message returned will use the Locale obtained |
| * from the Context. |
| * <p/> |
| * Pages can define text properties files to store localized messages. These |
| * properties files must be stored on the Page class path with a name |
| * matching the class name. For example: |
| * <p/> |
| * The page class: |
| * <pre class="codeJava"> |
| * <span class="kw">package</span> com.mycorp.pages; |
| * |
| * <span class="kw">public class</span> Login <span class="kw">extends</span> Page { |
| * .. </pre> |
| * |
| * The page class property filenames and their path: |
| * <pre class="codeConfig"> |
| * /com/mycorp/pages/Login.properties |
| * /com/mycorp/pages/Login_en.properties |
| * /com/mycorp/pages/Login_fr.properties </pre> |
| * |
| * Page messages can also be defined in the optional global messages |
| * bundle: |
| * |
| * <pre class="codeConfig"> |
| * /click-page.properties </pre> |
| * |
| * To define global page messages simply add <tt>click-page.properties</tt> |
| * file to your application's class path. Message defined in this properties |
| * file will be available to all of your application pages. |
| * <p/> |
| * Note messages in your page class properties file will override any |
| * messages in the global <tt>click-page.properties</tt> file. |
| * <p/> |
| * Page messages can be accessed directly in the page template using |
| * the <span class="st">$messages</span> reference. For examples: |
| * |
| * <pre class="codeHtml"> |
| * <span class="blue">$messages.title</span> </pre> |
| * |
| * Please see the {@link net.sf.click.util.MessagesMap} adaptor for more details. |
| * |
| * @param key the message property key name |
| * @return the Page message for the given message property key |
| */ |
| public String getMessage(String key) { |
| if (key == null) { |
| throw new IllegalArgumentException("Null key parameter"); |
| } |
| return (String) getMessages().get(key); |
| } |
| |
| /** |
| * Return the formatted page message for the given resource name |
| * and message format argument and for the context request locale. |
| * |
| * @param name resource name of the message |
| * @param arg the message argument to format |
| * @return the named localized message for the page |
| */ |
| public String getMessage(String name, Object arg) { |
| Object[] args = new Object[] { arg }; |
| return getMessage(name, args); |
| } |
| |
| /** |
| * Return the formatted page message for the given resource name and |
| * message format arguments and for the context request locale. |
| * |
| * @param name resource name of the message |
| * @param args the message arguments to format |
| * @return the named localized message for the page |
| */ |
| public String getMessage(String name, Object[] args) { |
| if (args == null) { |
| throw new IllegalArgumentException("Null args parameter"); |
| } |
| String value = getMessage(name); |
| |
| return MessageFormat.format(value, args); |
| } |
| |
| /** |
| * Return a Map of localized messages for the Page. |
| * |
| * @see #getMessage(String) |
| * |
| * @return a Map of localized messages for the Page |
| * @throws IllegalStateException if the context for the Page has not be set |
| */ |
| public Map getMessages() { |
| if (messages == null) { |
| if (getContext() != null) { |
| messages = new MessagesMap(getClass(), PAGE_MESSAGES); |
| |
| } else { |
| String msg = "Context not set cannot initialize messages"; |
| throw new IllegalStateException(msg); |
| } |
| } |
| return messages; |
| } |
| |
| /** |
| * Add the named object value to the Pages model map. |
| * |
| * @param name the key name of the object to add |
| * @param value the object to add |
| * @throws IllegalArgumentException if the name or value parameters are |
| * null, or if there is already a named value in the model |
| */ |
| public void addModel(String name, Object value) { |
| if (name == null) { |
| String msg = "Cannot add null parameter name to " |
| + getClass().getName() + " model"; |
| throw new IllegalArgumentException(msg); |
| } |
| if (value == null) { |
| String msg = "Cannot add null " + name + " parameter " |
| + "to " + getClass().getName() + " model"; |
| throw new IllegalArgumentException(msg); |
| } |
| if (getModel().containsKey(name)) { |
| String msg = getClass().getName() + " model already contains " |
| + "value named " + name; |
| throw new IllegalArgumentException(msg); |
| } else { |
| getModel().put(name, value); |
| } |
| } |
| |
| /** |
| * Return the Page's model map. The model is used populate the |
| * Velocity Context with is merged with the page template before rendering. |
| * |
| * @return the Page's model map |
| */ |
| public Map getModel() { |
| return model; |
| } |
| |
| /** |
| * Return the path of the Velocity template to render. |
| * <p/> |
| * See also {@link #getForward()}, {@link #getRedirect()} |
| * |
| * @return the path of the Velocity template to render |
| */ |
| public String getPath() { |
| return path; |
| } |
| |
| /** |
| * Set the path of the Velocity template to render. |
| * <p/> |
| * See also {@link #setForward(String)}, {@link #setRedirect(String)} |
| * |
| * @param value the path of the Velocity template to render |
| */ |
| public void setPath(String value) { |
| path = value; |
| } |
| |
| /** |
| * Return the path to redirect the request to. |
| * <p/> |
| * If the {@link #redirect} property is not null it will be used to redirect |
| * the request in preference to {@link #forward} or {@link #path} properties. |
| * The request is redirected to using the HttpServletResponse.setRedirect() |
| * method. |
| * <p/> |
| * See also {@link #getForward()}, {@link #getPath()} |
| * |
| * @return the path to redirect the request to |
| */ |
| public String getRedirect() { |
| return redirect; |
| } |
| |
| /** |
| * Return true if the page is stateful and should be saved in the users |
| * HttpSession between requests. |
| * |
| * @return true if the page is stateful and should be save in the users session |
| */ |
| public boolean isStateful() { |
| return stateful; |
| } |
| |
| /** |
| * Set whether the page is stateful and should be saved in the users |
| * HttpSession between requests. |
| * |
| * @param stateful the flag indicating whether the page should be saved |
| * between user requests |
| */ |
| public void setStateful(boolean stateful) { |
| this.stateful = stateful; |
| if (isStateful()) { |
| getContext().getSession(); |
| } |
| } |
| |
| /** |
| * Set the location to redirect the request to. |
| * <p/> |
| * If the {@link #redirect} property is not null it will be used to redirect |
| * the request in preference to {@link #forward} or {@link #path} properties. |
| * The request is redirected to using the HttpServletResponse.setRedirect() |
| * method. |
| * <p/> |
| * If the redirect location begins with a <tt class="wr">"/"</tt> |
| * character the redirect location will be prefixed with the web applications |
| * context path. Also if the location has a <tt>.jsp</tt> extension it will |
| * be changed to <tt>.htm</tt>. |
| * <p/> |
| * For example if an application is deployed to the context |
| * <tt class="wr">"mycorp"</tt> calling |
| * <tt>setRedirect(<span class="navy">"/customer/details.htm"</span>)</tt> |
| * will redirect the request to: |
| * <tt class="wr">"/mycorp/customer/details.htm"</tt> |
| * <p/> |
| * See also {@link #setForward(String)}, {@link #setPath(String)} |
| * |
| * @param location the path to redirect the request to |
| */ |
| public void setRedirect(String location) { |
| redirect = location; |
| } |
| |
| /** |
| * Set the request to redirect to the give page class. |
| * |
| * @param pageClass the class of the Page to redirect the request to |
| * @throws IllegalArgumentException if the Page Class is not configured |
| * with a unique path |
| */ |
| public void setRedirect(Class pageClass) { |
| String target = getContext().getPagePath(pageClass); |
| setRedirect(target); |
| } |
| |
| /** |
| * Return the path of the page template to render, by default this method |
| * returns {@link #getPath()}. |
| * <p/> |
| * Pages can override this method to return an alternative page template. |
| * This is very useful when implementing an standardized look and feel for |
| * a web site. The example below provides a BorderedPage base Page which |
| * other site templated Pages should extend. |
| * |
| * <pre class="codeJava"> |
| * <span class="kw">public class</span> BorderedPage <span class="kw">extends</span> Page { |
| * <span class="kw">public</span> String getTemplate() { |
| * <span class="kw">return</span> <span class="st">"border.htm"</span>; |
| * } |
| * } </pre> |
| * |
| * The BorderedPage returns the page border template <span class="st">"border.htm"</span>: |
| * |
| * <pre class="codeHtml"> |
| * <html> |
| * <head> |
| * <title> <span class="blue">$title</span> </title> |
| * <link rel="stylesheet" type="text/css" href="style.css" title="Style"/> |
| * </head> |
| * <body> |
| * |
| * <h1> <span class="blue">$title</span> </h1> |
| * <hr/> |
| * |
| * <span class="red">#parse</span>( <span class="blue">$path</span> ) |
| * |
| * </body> |
| * </html> </pre> |
| * |
| * Other pages insert their content into this template, via their |
| * {@link #path} property using the Velocity |
| * <a href="../../../../velocity/vtl-reference-guide.html#parse">#parse</a> |
| * directive. Note the <span class="blue">$path</span> value is automatically |
| * added to the VelocityContext by the ClickServlet. |
| * |
| * @return the path of the page template to render, by default returns |
| * {@link #getPath()}. |
| */ |
| public String getTemplate() { |
| return getPath(); |
| } |
| |
| } |