javax.faces.component.UIForm Maven / Gradle / Ivy
Show all versions of javax.faces-api Show documentation
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2011 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package javax.faces.component;
import java.util.Collection;
import java.util.Iterator;
import javax.faces.application.Application;
import javax.faces.component.visit.VisitCallback;
import javax.faces.component.visit.VisitContext;
import javax.faces.component.visit.VisitResult;
import javax.faces.context.FacesContext;
import javax.faces.event.PostValidateEvent;
import javax.faces.event.PreValidateEvent;
/**
* UIForm is a {@link
* UIComponent} that represents an input form to be presented to the
* user, and whose child components represent (among other things) the
* input fields to be included when the form is submitted.
* By default, the rendererType
property must be set to
* "javax.faces.Form
". This value can be changed by calling the
* setRendererType()
method.
*/
public class UIForm extends UIComponentBase implements NamingContainer, UniqueIdVendor {
// ------------------------------------------------------ Manifest Constants
/**
* The standard component type for this component.
*/
public static final String COMPONENT_TYPE = "javax.faces.Form";
/**
* The standard component family for this component.
*/
public static final String COMPONENT_FAMILY = "javax.faces.Form";
/**
* Properties that are tracked by state saving.
*/
enum PropertyKeys {
/**
* The prependId flag.
*/
prependId,
/**
* Last id vended by {@link UIForm#createUniqueId(javax.faces.context.FacesContext, String)}.
*/
lastId,
submitted,
}
// ------------------------------------------------------------ Constructors
/**
* Create a new {@link UIForm} instance with default property
* values.
*/
public UIForm() {
super();
setRendererType("javax.faces.Form");
}
// ------------------------------------------------------ Instance Variables
//private int lastId = 0;
// -------------------------------------------------------------- Properties
@Override
public String getFamily() {
return (COMPONENT_FAMILY);
}
/**
* The form submitted flag for this {@link UIForm}.
*/
//private boolean submitted = false;
/**
* Returns the current value
* of the submitted
property. The default value is
* false
. See {@link #setSubmitted} for details.
* This property must be kept as a
* transient property using the {@link
* UIComponent#getTransientStateHelper}.
*
* @return true
if the form was submitted, false
otherwise.
*/
public boolean isSubmitted() {
//return (this.submitted);
return (Boolean) getTransientStateHelper().getTransient(PropertyKeys.submitted, false);
}
/**
* If
* this UIForm
instance (as opposed to
* other forms in the page) is experiencing a submit during this
* request processing lifecycle, this method must be called, with
* true
as the argument, during the {@link
* UIComponent#decode} for this UIForm
instance. If
* this UIForm
instance is
* not experiencing a submit, this method must be
* called, with false
as the argument, during the
* {@link UIComponent#decode} for this UIForm
* instance.
*
* The value of a UIForm
's
* submitted property must not be saved as part of its state.
* This property must be kept as a
* transient property using the {@link
* UIComponent#getTransientStateHelper}.
*
* @param submitted the new value of the submitted flag.
*/
public void setSubmitted(boolean submitted) {
//this.submitted = submitted;
getTransientStateHelper().putTransient(PropertyKeys.submitted, submitted);
}
/**
* The prependId flag.
*/
//private Boolean prependId;
/**
* Is the id prepended.
*
* @return true
if it is, false
otherwise.
*/
public boolean isPrependId() {
return (Boolean) getStateHelper().eval(PropertyKeys.prependId, true);
}
public void setPrependId(boolean prependId) {
getStateHelper().put(PropertyKeys.prependId, prependId);
}
// ----------------------------------------------------- UIComponent Methods
/**
* Override {@link UIComponent#processDecodes} to ensure that the
* form is decoded before its children. This is
* necessary to allow the submitted
property to be
* correctly set.
*
* @throws NullPointerException {@inheritDoc}
*/
@Override
public void processDecodes(FacesContext context) {
if (context == null) {
throw new NullPointerException();
}
// Process this component itself
decode(context);
// if we're not the submitted form, don't process children.
if (!isSubmitted()) {
return;
}
// Process all facets and children of this component
Iterator kids = getFacetsAndChildren();
while (kids.hasNext()) {
UIComponent kid = (UIComponent) kids.next();
kid.processDecodes(context);
}
}
/**
* Override {@link UIComponent#processValidators} to ensure that
* the children of this UIForm
instance are only
* processed if {@link #isSubmitted} returns true
.
*
* @throws NullPointerException {@inheritDoc}
* @see javax.faces.event.PreValidateEvent
* @see javax.faces.event.PostValidateEvent
*/
@Override
public void processValidators(FacesContext context) {
if (context == null) {
throw new NullPointerException();
}
if (!isSubmitted()) {
return;
}
pushComponentToEL(context, this);
Application app = context.getApplication();
app.publishEvent(context, PreValidateEvent.class, this);
// Process all the facets and children of this component
Iterator kids = getFacetsAndChildren();
while (kids.hasNext()) {
UIComponent kid = (UIComponent) kids.next();
kid.processValidators(context);
}
app.publishEvent(context, PostValidateEvent.class, this);
popComponentFromEL(context);
}
/**
* Override {@link UIComponent#processUpdates} to ensure that the
* children of this UIForm
instance are only processed
* if {@link #isSubmitted} returns true
.
*
* @throws NullPointerException {@inheritDoc}
*/
@Override
public void processUpdates(FacesContext context) {
if (context == null) {
throw new NullPointerException();
}
if (!isSubmitted()) {
return;
}
pushComponentToEL(context, this);
try {
// Process all facets and children of this component
Iterator kids = getFacetsAndChildren();
while (kids.hasNext()) {
UIComponent kid = (UIComponent) kids.next();
kid.processUpdates(context);
}
} finally {
popComponentFromEL(context);
}
}
/**Generate an identifier for a component. The identifier
* will be prefixed with UNIQUE_ID_PREFIX, and will be unique
* within this component-container. Optionally, a unique seed value can
* be supplied by component creators which should be
* included in the generated unique id.
*
* If the prependId
property has the value false
,
* this method must call createUniqueId
on the next ancestor
* UniqueIdVendor
.
*
*
* @param context FacesContext
* @param seed an optional seed value - e.g. based on the position of the component in the VDL-template
* @return a unique-id in this component-container
*/
@Override
public String createUniqueId(FacesContext context, String seed) {
if (isPrependId()) {
Integer i = (Integer) getStateHelper().get(PropertyKeys.lastId);
int lastId = ((i != null) ? i : 0);
getStateHelper().put(PropertyKeys.lastId, ++lastId);
return UIViewRoot.UNIQUE_ID_PREFIX + (seed == null ? lastId : seed);
} else {
UIComponent ancestorNamingContainer = (getParent() == null) ? null : getParent().getNamingContainer();
String uid = null;
if (null != ancestorNamingContainer &&
ancestorNamingContainer instanceof UniqueIdVendor) {
uid = ((UniqueIdVendor) ancestorNamingContainer).createUniqueId(context, seed);
} else {
uid = context.getViewRoot().createUniqueId(context, seed);
}
return uid;
}
}
/**
* Override the {@link UIComponent#getContainerClientId} to allow
* users to disable this form from prepending its clientId
to
* its descendent's clientIds
depending on the value of
* this form's {@link #isPrependId} property.
*/
@Override
public String getContainerClientId(FacesContext context) {
if (this.isPrependId()) {
return super.getContainerClientId(context);
} else {
UIComponent parent = this.getParent();
while (parent != null) {
if (parent instanceof NamingContainer) {
return parent.getContainerClientId(context);
}
parent = parent.getParent();
}
}
return null;
}
/**
* @see UIComponent#visitTree
*/
@Override
public boolean visitTree(VisitContext context,
VisitCallback callback) {
// NamingContainers can optimize partial tree visits by taking advantage
// of the fact that it is possible to detect whether any ids to visit
// exist underneath the NamingContainer. If no such ids exist, there
// is no need to visit the subtree under the NamingContainer.
// UIForm is a bit different from other NamingContainers. It only acts
// as a NamingContainer when prependId is true. Note that if it
// weren't for this, we could push this implementation up in to
// UIComponent and share it across all NamingContainers. Instead,
// we currently duplicate this implementation in UIForm and
// UINamingContainer, so that we can check isPrependId() here.
if (!this.isPrependId()) {
return super.visitTree(context, callback);
}
Collection idsToVisit = context.getSubtreeIdsToVisit(this);
assert (idsToVisit != null);
// If we have ids to visit, let the superclass implementation
// handle the visit
if (!idsToVisit.isEmpty()) {
return super.visitTree(context, callback);
}
// If we have no child ids to visit, just visit ourselves, if
// we are visitable.
if (isVisitable(context)) {
FacesContext facesContext = context.getFacesContext();
pushComponentToEL(facesContext, null);
try {
VisitResult result = context.invokeVisitCallback(this, callback);
return (result == VisitResult.COMPLETE);
}
finally {
popComponentFromEL(facesContext);
}
}
// Done visiting this subtree. Return false to allow
// visit to continue.
return false;
}
}