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 }