blob: 1e10c64cc926f99d3799c3b328c4e045cb6f94b6 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 javax.faces.component;
import org.apache.myfaces.core.api.shared._ComponentUtils;
import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFComponent;
import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
import javax.faces.FacesException;
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;
import javax.faces.view.Location;
import java.util.Collection;
/**
* see Javadoc of <a href="http://java.sun.com/javaee/javaserverfaces/1.2/docs/api/index.html">JSF Specification</a>
*/
@JSFComponent(type = "javax.faces.Form", family = "javax.faces.Form")
public class UIForm extends UIComponentBase implements NamingContainer, UniqueIdVendor
{
/**
*
* {@inheritDoc}
*
* @since 2.0
*/
@Override
public String createUniqueId(FacesContext context, String seed)
{
StringBuilder bld = null;
// When prependId is set to false, it is necessary to append an unique
// prefix to ensure the generated ids are unique, but that's only necessary
// when no seed is provided. If a seed is provided, that one is already unique
// for all the view, so the following logic is not necessary.
if (!isPrependId() && seed == null)
{
bld = new StringBuilder();
UniqueIdVendor parentUniqueIdVendor = _ComponentUtils.closest(UniqueIdVendor.class, this);
if (parentUniqueIdVendor == null)
{
UIViewRoot viewRoot = context.getViewRoot();
if (viewRoot != null)
{
bld.append(viewRoot.createUniqueId());
bld.append('_');
}
else
{
// The RI throws a NPE
String location = getComponentLocation(this);
throw new FacesException("Cannot create clientId. No id is assigned for component"
+ " to create an id and UIViewRoot is not defined: "
+ _ComponentUtils.getPathToComponent(this)
+ (location != null ? " created from: " + location : ""));
}
}
else
{
bld.append(parentUniqueIdVendor.createUniqueId(context, null));
bld.append('_');
}
}
else
{
bld = _getSharedStringBuilder(context);
}
// Generate an identifier for a component. The identifier will be prefixed with
// UNIQUE_ID_PREFIX, and will be unique within this UIViewRoot.
if(seed == null)
{
Integer uniqueIdCounter = (Integer) getStateHelper().get(PropertyKeys.uniqueIdCounter);
uniqueIdCounter = (uniqueIdCounter == null) ? 0 : uniqueIdCounter;
getStateHelper().put(PropertyKeys.uniqueIdCounter, (uniqueIdCounter+1));
return bld.append(UIViewRoot.UNIQUE_ID_PREFIX).append(uniqueIdCounter).toString();
}
// Optionally, a unique seed value can be supplied by component creators
// which should be included in the generated unique id.
else
{
return bld.append(UIViewRoot.UNIQUE_ID_PREFIX).append(seed).toString();
}
}
public boolean isSubmitted()
{
return (Boolean) getTransientStateHelper().getTransient(PropertyKeys.submitted, false);
}
public void setSubmitted(boolean submitted)
{
getTransientStateHelper().putTransient(PropertyKeys.submitted, submitted);
}
@Override
public void processDecodes(FacesContext context)
{
if (context == null)
{
throw new NullPointerException("context");
}
try
{
setCachedFacesContext(context);
try
{
pushComponentToEL(context, this);
decode(context);
if (!isSubmitted())
{
return;
}
if (getFacetCount() > 0)
{
for (UIComponent facet : getFacets().values())
{
facet.processDecodes(context);
}
}
for (int i = 0, childCount = getChildCount(); i < childCount; i++)
{
UIComponent child = getChildren().get(i);
child.processDecodes(context);
}
}
finally
{
popComponentFromEL(context);
}
}
finally
{
setCachedFacesContext(null);
}
}
@Override
public void processValidators(FacesContext context)
{
if (context == null)
{
throw new NullPointerException("context");
}
try
{
setCachedFacesContext(context);
try
{
pushComponentToEL(context, this);
// SF issue #1050022: a form used within a datatable will loose it's submitted state
// as UIForm is no EditableValueHolder and therefore it's state is not saved/restored by UIData
// to restore the submitted state we call decode here again
if (!isSubmitted())
{
decode(context);
}
if (!isSubmitted())
{
return;
}
//Pre validation event dispatch for component
context.getApplication().publishEvent(context, PreValidateEvent.class, getClass(), this);
if (getFacetCount() > 0)
{
for (UIComponent facet : getFacets().values())
{
facet.processValidators(context);
}
}
for (int i = 0, childCount = getChildCount(); i < childCount; i++)
{
UIComponent child = getChildren().get(i);
child.processValidators(context);
}
}
finally
{
context.getApplication().publishEvent(context, PostValidateEvent.class, getClass(), this);
popComponentFromEL(context);
}
}
finally
{
setCachedFacesContext(null);
}
}
@Override
public void processUpdates(FacesContext context)
{
if (context == null)
{
throw new NullPointerException("context");
}
try
{
setCachedFacesContext(context);
try
{
pushComponentToEL(context, this);
// SF issue #1050022: a form used within a datatable will loose it's submitted state
// as UIForm is no EditableValueHolder and therefore it's state is not saved/restored by UIData
// to restore the submitted state we call decode here again
if (!isSubmitted())
{
decode(context);
}
if (!isSubmitted())
{
return;
}
if (getFacetCount() > 0)
{
for (UIComponent facet : getFacets().values())
{
facet.processUpdates(context);
}
}
for (int i = 0, childCount = getChildCount(); i < childCount; i++)
{
UIComponent child = getChildren().get(i);
child.processUpdates(context);
}
}
finally
{
popComponentFromEL(context);
}
}
finally
{
setCachedFacesContext(null);
}
}
enum PropertyKeys
{
prependId,
uniqueIdCounter,
submitted,
}
@Override
public boolean invokeOnComponent(FacesContext context, String clientId, ContextCallback callback) throws FacesException {
if (isPrependId()) {
String baseClientId = getClientId(context);
// skip if the component is not a children of the UIForm
if (!clientId.startsWith(baseClientId)) {
return false;
}
}
return super.invokeOnComponent(context, clientId, callback);
}
@Override
public boolean visitTree(VisitContext context, VisitCallback callback)
{
if (!isPrependId())
{
// Since the container client id will not be added to child clientId,
// It is not possible to take advantage of NamingContainer interface
// and prevent visit child nodes. Just do it as default.
return super.visitTree(context, callback);
}
else
{
pushComponentToEL(context.getFacesContext(), this);
boolean isCachedFacesContext = isCachedFacesContext();
try
{
if (!isCachedFacesContext)
{
setCachedFacesContext(context.getFacesContext());
}
if (!isVisitable(context))
{
return false;
}
VisitResult res = context.invokeVisitCallback(this, callback);
switch (res)
{
//we are done nothing has to be processed anymore
case COMPLETE:
return true;
case REJECT:
return false;
//accept
default:
// Take advantage of the fact this is a NamingContainer
// and we can know if there are ids to visit inside it
Collection<String> subtreeIdsToVisit = context.getSubtreeIdsToVisit(this);
if (subtreeIdsToVisit != null && !subtreeIdsToVisit.isEmpty())
{
if (getFacetCount() > 0)
{
for (UIComponent facet : getFacets().values())
{
if (facet.visitTree(context, callback))
{
return true;
}
}
}
for (int i = 0, childCount = getChildCount(); i < childCount; i++)
{
UIComponent child = getChildren().get(i);
if (child.visitTree(context, callback))
{
return true;
}
}
}
return false;
}
}
finally
{
//all components must call popComponentFromEl after visiting is finished
popComponentFromEL(context.getFacesContext());
if (!isCachedFacesContext)
{
setCachedFacesContext(null);
}
}
}
}
// ------------------ GENERATED CODE BEGIN (do not modify!) --------------------
public static final String COMPONENT_TYPE = "javax.faces.Form";
public static final String COMPONENT_FAMILY = "javax.faces.Form";
private static final String DEFAULT_RENDERER_TYPE = "javax.faces.Form";
public UIForm()
{
setRendererType(DEFAULT_RENDERER_TYPE);
}
@Override
public String getFamily()
{
return COMPONENT_FAMILY;
}
private String getComponentLocation(UIComponent component)
{
Location location = (Location) component.getAttributes().get(UIComponent.VIEW_LOCATION_KEY);
if (location != null)
{
return location.toString();
}
return null;
}
// ------------------ GENERATED CODE END ---------------------------------------
@Override
public String getContainerClientId(FacesContext ctx)
{
if (isPrependId())
{
return super.getContainerClientId(ctx);
}
UIComponent parentNamingContainer = _ComponentUtils.findParentNamingContainer(this, false);
if (parentNamingContainer != null)
{
return parentNamingContainer.getContainerClientId(ctx);
}
return null;
}
@JSFProperty(defaultValue = "true")
public boolean isPrependId()
{
return (Boolean) getStateHelper().eval(PropertyKeys.prependId, true);
}
public void setPrependId(boolean prependId)
{
getStateHelper().put(PropertyKeys.prependId, prependId );
}
}