001 package org.apache.myfaces.tobago.component;
002
003 /*
004 * Licensed to the Apache Software Foundation (ASF) under one or more
005 * contributor license agreements. See the NOTICE file distributed with
006 * this work for additional information regarding copyright ownership.
007 * The ASF licenses this file to You under the Apache License, Version 2.0
008 * (the "License"); you may not use this file except in compliance with
009 * the License. You may obtain a copy of the License at
010 *
011 * http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 */
019
020 import org.apache.commons.collections.KeyValue;
021 import org.apache.commons.collections.list.SetUniqueList;
022 import org.apache.commons.collections.set.ListOrderedSet;
023 import org.apache.commons.logging.Log;
024 import org.apache.commons.logging.LogFactory;
025 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_APPLICATION_ICON;
026 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_FOCUS_ID;
027 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_HEIGHT;
028 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_STATE;
029 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_WIDTH;
030 import static org.apache.myfaces.tobago.TobagoConstants.SUBCOMPONENT_SEP;
031 import org.apache.myfaces.tobago.layout.Box;
032 import org.apache.myfaces.tobago.model.PageState;
033 import org.apache.myfaces.tobago.model.PageStateImpl;
034 import org.apache.myfaces.tobago.webapp.TobagoMultipartFormdataRequest;
035
036 import javax.faces.application.FacesMessage;
037 import javax.faces.component.UIComponent;
038 import javax.faces.context.FacesContext;
039 import javax.faces.el.ValueBinding;
040 import javax.servlet.ServletRequest;
041 import javax.servlet.http.HttpServletRequestWrapper;
042 import java.io.IOException;
043 import java.util.ArrayList;
044 import java.util.Iterator;
045 import java.util.List;
046 import java.util.Set;
047
048 public class UIPage extends UIForm {
049
050 private static final Log LOG = LogFactory.getLog(UIPage.class);
051
052 public static final String COMPONENT_TYPE = "org.apache.myfaces.tobago.Page";
053 public static final String ENCTYPE_KEY = UIPanel.class.getName() + ".enctype";
054
055 public static final String DEFAULT_STYLE = "style/style.css";
056
057 private static final int DEFAULT_WIDTH = 1024;
058
059 private static final int DEFAULT_HEIGHT = 768;
060
061 private String formId;
062
063 private String focusId;
064
065 private String actionId;
066
067 private Box actionPosition;
068
069 private String defaultActionId;
070
071 private List<KeyValue> postfields;
072
073 private SetUniqueList scriptFiles;
074
075 private Set<String> scriptBlocks;
076
077 private Set<String> styleFiles;
078
079 private Set<String> styleBlocks;
080
081 private Set<String> onloadScripts;
082
083 private Set<String> onunloadScripts;
084
085 private Set<String> onexitScripts;
086
087 private Set<String> onsubmitScripts;
088
089 private Set<UIPopup> popups;
090
091 private Integer width;
092
093 private Integer height;
094
095 private String applicationIcon;
096
097 @SuppressWarnings("unchecked")
098 public UIPage() {
099 scriptFiles = SetUniqueList.decorate(new ArrayList());
100 scriptBlocks = new ListOrderedSet();
101 styleFiles = new ListOrderedSet();
102 styleFiles.add(DEFAULT_STYLE);
103 styleBlocks = new ListOrderedSet();
104 onloadScripts = new ListOrderedSet();
105 onunloadScripts = new ListOrderedSet();
106 onexitScripts = new ListOrderedSet();
107 onsubmitScripts = new ListOrderedSet();
108 popups = new ListOrderedSet();
109 }
110
111 @Override
112 public void encodeBegin(FacesContext facesContext) throws IOException {
113 // TODO change this should be renamed to DimensionUtils.prepare!!!
114 UILayout.getLayout(this).layoutBegin(facesContext, this);
115 super.encodeBegin(facesContext);
116 }
117
118
119 @Override
120 public void encodeChildren(FacesContext context) throws IOException {
121 }
122
123 public String getFormId(FacesContext facesContext) {
124 if (formId == null) {
125 formId = getClientId(facesContext)
126 + SUBCOMPONENT_SEP + "form";
127 }
128 return formId;
129 }
130
131 @Override
132 public void processDecodes(FacesContext facesContext) {
133
134 checkTobagoRequest(facesContext);
135
136 decode(facesContext);
137
138 clearScriptsAndPopups();
139
140 markSubmittedForm(facesContext);
141
142 // invoke processDecodes() on children
143 for (Iterator kids = getFacetsAndChildren(); kids.hasNext();) {
144 UIComponent kid = (UIComponent) kids.next();
145 kid.processDecodes(facesContext);
146 }
147 }
148
149 public void markSubmittedForm(FacesContext facesContext) {
150 // find the form of the action command and set submitted to it and all
151 // children
152
153 // reset old submitted state
154 setSubmitted(false);
155
156 String currentActionId = getActionId();
157 if (LOG.isDebugEnabled()) {
158 LOG.debug("actionId = '" + currentActionId + "'");
159 }
160
161 UIComponent command = null;
162 try {
163 command = findComponent(currentActionId);
164 } catch (Exception e) {
165 // ignore
166 }
167
168 // TODO: remove this if block if prooven this never happens anymore
169 if (command == null
170 && currentActionId != null && currentActionId.matches(".*:\\d+:.*")) {
171 // If currentActionId component was inside a sheet the id contains the
172 // rowindex and is therefore not found here.
173 // We do not need the row here because we want just to find the
174 // related form, so removing the rowindex will help here.
175 currentActionId = currentActionId.replaceAll(":\\d+:", ":");
176 try {
177 command = findComponent(currentActionId);
178 LOG.info("command = \"" + command + "\"", new Exception());
179 } catch (Exception e) {
180 // ignore
181 }
182 }
183
184 if (LOG.isTraceEnabled()) {
185 LOG.trace(currentActionId);
186 LOG.trace(command);
187 LOG.trace(ComponentUtil.toString(facesContext.getViewRoot(), 0));
188 }
189
190 if (command != null) {
191 UIForm form = ComponentUtil.findForm(command);
192 form.setSubmitted(true);
193
194 if (LOG.isTraceEnabled()) {
195 LOG.trace(form);
196 LOG.trace(form.getClientId(facesContext));
197 }
198 } else {
199 if (LOG.isDebugEnabled()) {
200 LOG.debug("Illegal actionId! Rerender the view.");
201 }
202 facesContext.renderResponse();
203 }
204 }
205
206 private void clearScriptsAndPopups() {
207 // clear script Set's
208 getOnloadScripts().clear();
209 getOnunloadScripts().clear();
210 getOnexitScripts().clear();
211 getScriptBlocks().clear();
212 getPopups().clear();
213 }
214
215 private void checkTobagoRequest(FacesContext facesContext) {
216 // multipart/form-data must use TobagoMultipartFormdataRequest
217 String contentType = (String) facesContext.getExternalContext()
218 .getRequestHeaderMap().get("content-type");
219 if (contentType != null && contentType.startsWith("multipart/form-data")) {
220 Object request = facesContext.getExternalContext().getRequest();
221 boolean okay = false;
222 if (request instanceof TobagoMultipartFormdataRequest) {
223 okay = true;
224 } else if (request instanceof HttpServletRequestWrapper) {
225 ServletRequest wrappedRequest
226 = ((HttpServletRequestWrapper) request).getRequest();
227 if (wrappedRequest instanceof TobagoMultipartFormdataRequest) {
228 okay = true;
229 }
230 }
231 // TODO PortletRequest ??
232 if (!okay) {
233 LOG.error("Can't process multipart/form-data without TobagoRequest. "
234 + "Please check the web.xml and define a TobagoMultipartFormdataFilter. "
235 + "See documentation for <tc:file>");
236 facesContext.addMessage(null, new FacesMessage("An error has occured!"));
237 }
238 }
239 }
240
241 public List<KeyValue> getPostfields() {
242 if (postfields == null) {
243 postfields = new ArrayList<KeyValue>();
244 }
245 return postfields;
246 }
247
248 @Override
249 public void processUpdates(FacesContext context) {
250 super.processUpdates(context);
251 }
252
253
254
255 public PageState getPageState(FacesContext facesContext) {
256 ValueBinding stateBinding = getValueBinding(ATTR_STATE);
257 if (stateBinding != null) {
258 PageState state = (PageState) stateBinding.getValue(facesContext);
259 if (state == null) {
260 state = new PageStateImpl();
261 stateBinding.setValue(facesContext, state);
262 }
263 return state;
264 } else {
265 return null;
266 }
267 }
268
269 // ///////////////////////////////////////////// bean getter + setter
270
271 public String getFocusId() {
272 if (focusId != null) {
273 return focusId;
274 }
275 ValueBinding vb = getValueBinding(ATTR_FOCUS_ID);
276 if (vb != null) {
277 return (String) vb.getValue(getFacesContext());
278 } else {
279 return null;
280 }
281 }
282
283 public void setFocusId(String focusId) {
284 this.focusId = focusId;
285 }
286
287 public String getActionId() {
288 return actionId;
289 }
290
291 public void setActionId(String actionId) {
292 this.actionId = actionId;
293 }
294
295 public Box getActionPosition() {
296 return actionPosition;
297 }
298
299 public void setActionPosition(Box actionPosition) {
300 this.actionPosition = actionPosition;
301 }
302
303 public String getDefaultActionId() {
304 return defaultActionId;
305 }
306
307 public void setDefaultActionId(String defaultActionId) {
308 this.defaultActionId = defaultActionId;
309 }
310
311 @SuppressWarnings("unchecked")
312 public List<String> getScriptFiles() {
313 return scriptFiles;
314 }
315
316 public Set<String> getScriptBlocks() {
317 return scriptBlocks;
318 }
319
320 public Set<String> getStyleFiles() {
321 return styleFiles;
322 }
323
324 public Set<String> getStyleBlocks() {
325 return styleBlocks;
326 }
327
328 public Set<String> getOnloadScripts() {
329 return onloadScripts;
330 }
331
332 public Set<String> getOnunloadScripts() {
333 return onunloadScripts;
334 }
335
336 public Set<String> getOnexitScripts() {
337 return onexitScripts;
338 }
339
340 public Set<String> getOnsubmitScripts() {
341 return onsubmitScripts;
342 }
343
344 public Set<UIPopup> getPopups() {
345 return popups;
346 }
347
348 public Integer getWidth() {
349 if (width != null) {
350 return width;
351 }
352 ValueBinding vb = getValueBinding(ATTR_WIDTH);
353 if (vb != null) {
354 return (Integer) vb.getValue(getFacesContext());
355 } else {
356 Integer requestWidth =
357 (Integer) FacesContext.getCurrentInstance().getExternalContext().
358 getRequestMap().get("tobago-page-clientDimension-width");
359 if (requestWidth != null) {
360 return requestWidth;
361 } else {
362 return DEFAULT_WIDTH;
363 }
364 }
365 }
366
367 public void setWidth(Integer width) {
368 this.width = width;
369 }
370
371 public Integer getHeight() {
372 if (height != null) {
373 return height;
374 }
375 ValueBinding vb = getValueBinding(ATTR_HEIGHT);
376 if (vb != null) {
377 return (Integer) vb.getValue(getFacesContext());
378 } else {
379 Integer requestHeight =
380 (Integer) FacesContext.getCurrentInstance().getExternalContext().
381 getRequestMap().get("tobago-page-clientDimension-height");
382 if (requestHeight != null) {
383 return requestHeight;
384 } else {
385 return DEFAULT_HEIGHT;
386 }
387 }
388 }
389
390 public void setHeight(Integer height) {
391 this.height = height;
392 }
393
394 public String getApplicationIcon() {
395 if (applicationIcon != null) {
396 return applicationIcon;
397 }
398 ValueBinding vb = getValueBinding(ATTR_APPLICATION_ICON);
399 if (vb != null) {
400 return (String) vb.getValue(getFacesContext());
401 } else {
402 return null;
403 }
404 }
405
406 public void setApplicationIcon(String applicationIcon) {
407 this.applicationIcon = applicationIcon;
408 }
409
410 public void restoreState(FacesContext context, Object state) {
411 Object[] values = (Object[]) state;
412 super.restoreState(context, values[0]);
413 this.width = (Integer) values[1];
414 this.height = (Integer) values[2];
415 this.focusId = (String) values[3];
416 this.applicationIcon = (String) values[4];
417 }
418
419 public Object saveState(FacesContext context) {
420 Object[] values = new Object[5];
421 values[0] = super.saveState(context);
422 values[1] = width;
423 values[2] = height;
424 values[3] = focusId;
425 values[4] = applicationIcon;
426 return values;
427 }
428 }