001: /*
002: * $Id: FormRenderer.java 471754 2006-11-06 14:55:09Z husted $
003: *
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021:
022: package org.apache.struts.faces.renderer;
023:
024: import java.io.IOException;
025: import java.util.Map;
026:
027: import javax.faces.component.NamingContainer;
028: import javax.faces.component.UIComponent;
029: import javax.faces.context.FacesContext;
030: import javax.faces.context.ResponseWriter;
031: import javax.servlet.http.HttpSession;
032:
033: import org.apache.commons.logging.Log;
034: import org.apache.commons.logging.LogFactory;
035: import org.apache.struts.Globals;
036: import org.apache.struts.config.ActionConfig;
037: import org.apache.struts.config.ModuleConfig;
038: import org.apache.struts.faces.component.FormComponent;
039:
040: /**
041: * <p><code>Renderer</code> implementation for the <code>form</code> tag
042: * from the <em>Struts-Faces Integration Library</em>.</p>
043: *
044: * @version $Rev: 471754 $ $Date: 2006-11-06 08:55:09 -0600 (Mon, 06 Nov 2006) $
045: */
046:
047: public class FormRenderer extends AbstractRenderer {
048:
049: // -------------------------------------------------------- Static Variables
050:
051: /**
052: * <p>The <code>Log</code> instance for this class.</p>
053: */
054: private static Log log = LogFactory.getLog(FormRenderer.class);
055:
056: // ---------------------------------------------------------- Public Methods
057:
058: /**
059: * <p>Perform setup processing that will be required for decoding the
060: * incoming request.</p>
061: *
062: * @param context FacesContext for the request we are processing
063: * @param component UIComponent to be processed
064: *
065: * @exception NullPointerException if <code>context</code>
066: * or <code>component</code> is null
067: */
068: public void decode(FacesContext context, UIComponent component) {
069:
070: if ((context == null) || (component == null)) {
071: throw new NullPointerException();
072: }
073: String clientId = component.getClientId(context);
074: Map map = context.getExternalContext().getRequestParameterMap();
075: if (log.isDebugEnabled()) {
076: log.debug("decode(" + clientId + ") --> "
077: + map.containsKey(clientId));
078: }
079: component.getAttributes().put(
080: "submitted",
081: map.containsKey(clientId) ? Boolean.TRUE
082: : Boolean.FALSE);
083:
084: }
085:
086: private static String passThrough[] = { "enctype", "method",
087: "onreset", "onsubmit", "style", "target", };
088:
089: /**
090: * <p>Render the beginning of an HTML <code><form></code>
091: * control.</p>
092: *
093: * @param context FacesContext for the request we are processing
094: * @param component UIComponent to be rendered
095: *
096: * @exception IOException if an input/output error occurs while rendering
097: * @exception NullPointerException if <code>context</code>
098: * or <code>component</code> is null
099: */
100: public void encodeBegin(FacesContext context, UIComponent component)
101: throws IOException {
102:
103: if ((context == null) || (component == null)) {
104: throw new NullPointerException();
105: }
106:
107: // Calculate and cache the form name
108: FormComponent form = (FormComponent) component;
109: String action = form.getAction();
110: ModuleConfig moduleConfig = form.lookupModuleConfig(context);
111: ActionConfig actionConfig = moduleConfig
112: .findActionConfig(action);
113: if (actionConfig == null) {
114: throw new IllegalArgumentException("Cannot find action '"
115: + action + "' configuration");
116: }
117: String beanName = actionConfig.getAttribute();
118: if (beanName != null) {
119: form.getAttributes().put("beanName", beanName);
120: }
121:
122: // Look up attribute values we need
123: String clientId = component.getClientId(context);
124: if (log.isDebugEnabled()) {
125: log.debug("encodeBegin(" + clientId + ")");
126: }
127: String styleClass = (String) component.getAttributes().get(
128: "styleClass");
129:
130: // Render the beginning of this form
131: ResponseWriter writer = context.getResponseWriter();
132: writer.startElement("form", form);
133: writer.writeAttribute("id", clientId, "clientId");
134: if (beanName != null) {
135: writer.writeAttribute("name", beanName, null);
136: }
137: writer.writeAttribute("action", action(context, component),
138: "action");
139: if (styleClass != null) {
140: writer.writeAttribute("class", styleClass, "styleClass");
141: }
142: if (component.getAttributes().get("method") == null) {
143: writer.writeAttribute("method", "post", null);
144: }
145: renderPassThrough(context, component, writer, passThrough);
146: writer.writeText("\n", null);
147:
148: // Add a marker used by our decode() method to note this form is submitted
149: writer.startElement("input", form);
150: writer.writeAttribute("type", "hidden", null);
151: writer.writeAttribute("name", clientId, null);
152: writer.writeAttribute("value", clientId, null);
153: writer.endElement("input");
154: writer.writeText("\n", null);
155:
156: // Add a transaction token if necessary
157: HttpSession session = (HttpSession) context
158: .getExternalContext().getSession(false);
159: if (session != null) {
160: String token = (String) session
161: .getAttribute(Globals.TRANSACTION_TOKEN_KEY);
162: if (token != null) {
163: writer.startElement("input", form);
164: writer.writeAttribute("type", "hidden", null);
165: writer.writeAttribute("name",
166: "org.apache.struts.taglib.html.TOKEN", null);
167: writer.writeAttribute("value", token, null);
168: writer.endElement("input");
169: writer.writeText("\n", null);
170: }
171: }
172:
173: // Create an instance of the form bean if necessary
174: if (component instanceof FormComponent) {
175: ((FormComponent) component).createActionForm(context);
176: }
177:
178: }
179:
180: /**
181: * <p>Render the ending of an HTML <code><form></code>
182: * control.</p>
183: *
184: * @param context FacesContext for the request we are processing
185: * @param component UIComponent to be rendered
186: *
187: * @exception IOException if an input/output error occurs while rendering
188: * @exception NullPointerException if <code>context</code>
189: * or <code>component</code> is null
190: */
191: public void encodeEnd(FacesContext context, UIComponent component)
192: throws IOException {
193:
194: if ((context == null) || (component == null)) {
195: throw new NullPointerException();
196: }
197: String clientId = component.getClientId(context);
198: if (log.isDebugEnabled()) {
199: log.debug("encodeEnd(" + clientId + ")");
200: }
201: ResponseWriter writer = context.getResponseWriter();
202:
203: // Render the hidden variable our decode() method uses to detect submits
204: writer.startElement("input", component);
205: writer.writeAttribute("type", "hidden", null);
206: writer.writeAttribute("name", component.getClientId(context),
207: null);
208: writer.writeAttribute("value", component.getClientId(context),
209: null);
210: writer.endElement("input");
211: writer.write("\n");
212:
213: // Write our state information (if necessary)
214: context.getApplication().getViewHandler().writeState(context);
215:
216: // Render the ending of this form
217: writer.endElement("form");
218: writer.writeText("\n", null);
219:
220: // Render focus JavaScript if requested
221: if (!(component instanceof FormComponent)) {
222: return;
223: }
224: String focus = (String) component.getAttributes().get("focus");
225: if (focus == null) {
226: return;
227: }
228: String focusIndex = (String) component.getAttributes().get(
229: "focusIndex");
230: writer.writeText("\n", null);
231: FormComponent form = (FormComponent) component;
232: writer.startElement("script", form);
233: writer.writeAttribute("type", "text/javascript", null);
234: if (!isXhtml(component)) {
235: writer.writeAttribute("language", "JavaScript", null);
236: }
237: writer.writeText("\n", null);
238: if (!isXhtml(component)) {
239: writer.write("<!--\n");
240: }
241:
242: StringBuffer sb = new StringBuffer("document.forms[\"");
243: sb.append(clientId);
244: sb.append("\"].elements[\"");
245: sb.append(component.getClientId(context));
246: sb.append(NamingContainer.SEPARATOR_CHAR);
247: sb.append(focus);
248: sb.append("\"]");
249: String focusControl = sb.toString();
250:
251: writer.write(" var focusControl = ");
252: writer.write(focusControl);
253: writer.write(";\n");
254: writer.write(" if (focusControl.type != \"hidden\") {\n");
255: writer.write(" ");
256: writer.write(focusControl);
257: if (focusIndex != null) {
258: writer.write("[");
259: writer.write(focusIndex);
260: writer.write("]");
261: }
262: writer.write(".focus();\n");
263: writer.write(" }\n");
264:
265: if (!isXhtml(component)) {
266: writer.write("// -->\n");
267: }
268: writer.endElement("script");
269: writer.writeText("\n", null);
270:
271: }
272:
273: // ------------------------------------------------------- Protected Methods
274:
275: /**
276: * <p>Calculate and return the value to be specifed for the
277: * <code>action</action> attribute on the <code><form></code>
278: * element to be rendered.</p>
279: *
280: * @param context FacesContext for the current request
281: * @param component Component being processed
282: */
283: protected String action(FacesContext context, UIComponent component) {
284:
285: String actionURL = context.getApplication().getViewHandler()
286: .getActionURL(context,
287: context.getViewRoot().getViewId());
288: if (log.isTraceEnabled()) {
289: log.trace("getActionURL("
290: + context.getViewRoot().getViewId() + ") --> "
291: + actionURL);
292: }
293: return (context.getExternalContext().encodeActionURL(actionURL));
294:
295: }
296:
297: /**
298: * <p>Return <code>true</code> if we should render as XHTML.</p>
299: *
300: * @param component The component we are rendering
301: */
302: protected boolean isXhtml(UIComponent component) {
303:
304: return (false); // FIXME -- check up the hierarchy
305:
306: }
307:
308: }
|