org.apache.myfaces.trinidad.component.UIXComponent Maven / Gradle / Ivy
Show all versions of trinidad-api Show documentation
/*
* 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 org.apache.myfaces.trinidad.component;
import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import javax.el.MethodExpression;
import javax.faces.FactoryFinder;
import javax.faces.application.Application;
import javax.faces.application.ApplicationFactory;
import javax.faces.application.ProjectStage;
import javax.faces.component.NamingContainer;
import javax.faces.component.StateHelper;
import javax.faces.component.UIComponent;
import javax.faces.component.UINamingContainer;
import javax.faces.component.UIPanel;
import javax.faces.component.visit.VisitCallback;
import javax.faces.component.visit.VisitContext;
import javax.faces.component.visit.VisitHint;
import javax.faces.component.visit.VisitResult;
import javax.faces.context.FacesContext;
import javax.faces.event.FacesEvent;
import javax.faces.event.PhaseId;
import javax.faces.render.Renderer;
import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFComponent;
import org.apache.myfaces.trinidad.bean.FacesBean;
import org.apache.myfaces.trinidad.context.ComponentContextChange;
import org.apache.myfaces.trinidad.context.ComponentContextManager;
import org.apache.myfaces.trinidad.context.PartialPageContext;
import org.apache.myfaces.trinidad.context.RenderingContext;
import org.apache.myfaces.trinidad.context.RequestContext;
import org.apache.myfaces.trinidad.event.AttributeChangeListener;
import org.apache.myfaces.trinidad.logging.TrinidadLogger;
import org.apache.myfaces.trinidad.render.CoreRenderer;
/**
* Pure abstract base class for all UIX components.
*/
@JSFComponent
abstract public class UIXComponent extends UIComponent
{
/**
* Helper function called by Renderers to iterate over a flattened view of a group of
* potentially FlattenedComponent instances rooted at a single child of the component to collect
* information about these children prior to encoding the children using
* encodeFlattenedChild(FacesContext, ComponentProcessor, UIComponent, Object)
.
*
* If the child is a FlattenedComponent, the childProcessor
will
* be called on each of that FlattenedComponent's children, recursing if those children are
* themselves FlattenedComponents, otherwise, the childProcessor
will be called on
* the child itself.
*
* If the Renderer accidentally passes in the component to be processed instead of one
* of its children, the result will almost certainly be an infinite recursion and stack overflow.
* @see UIXComponent#processFlattenedChildren(FacesContext, ComponentProcessor, Iterable, Object)
* @see UIXComponent#processFlattenedChildren(FacesContext, ComponentProcessingContext, ComponentProcessor, UIComponent, Object)
* @see UIXComponent#processFlattenedChildren(FacesContext, ComponentProcessingContext, ComponentProcessor, Iterable, Object)
* @see FlattenedComponent
*/
public static boolean processFlattenedChildren(
FacesContext context,
ComponentProcessor childProcessor,
UIComponent child,
S callbackContext) throws IOException
{
return processFlattenedChildren(context,
new ComponentProcessingContext(),
childProcessor,
child,
callbackContext);
}
/**
* Helper function called by Renderers to encode a flattened view of a group of
* potentially FlattenedComponent instances rooted at a single child of the component,
* invoking the childProcessor
with its
* callbackContext
on each renderable instance. This method must be called
* when the childProcessor is actually encoding and the childProcessor must not attempt
* to encode the same component instances more than once per request.
*
* If a Renderer needs to
* collect information about its possibly flattened children before calling
* encodeFlattenedChild(FacesContext, ComponentProcessor, UIComponent, Object)
,
* it should call processFlattenedChildren(FacesContext, ComponentProcessor, UIComponent, Object)
* to collect the information.
*
* If the child is a FlattenedComponent, the childProcessor
will
* be called on each of that FlattenedComponent's children, recursing if those children are
* themselves FlattenedComponents, otherwise, the childProcessor
will be called on
* the child itself.
*
* FlattenedComponents that wish to check whether they are processed for the purpose of
* encoding can check the ProcessingHints of the ComponentProcessingContext for the
* presence of PROCESS_FOR_ENCODING hint
.
*
* If the Renderer accidentally passes in the component to be encoded instead of one
* of its children, the result will almost certainly be an infinite recursion and stack overflow.
* @return true
If any children were processed
* @see UIXComponent#processFlattenedChildren(FacesContext, ComponentProcessor, UIComponent, Object)
* @see FlattenedComponent
*/
public static boolean encodeFlattenedChild(
FacesContext context,
ComponentProcessor childProcessor,
UIComponent child,
S callbackContext) throws IOException
{
ComponentProcessingContext processingContext = new ComponentProcessingContext();
processingContext.__setIsRendering();
return processFlattenedChildren(context,
processingContext,
childProcessor,
child,
callbackContext);
}
/**
* Helper function called by FlattenedComponent to iterate over a flattened view of a group of
* potentially FlattenedComponent instances rooted at a single child of the FlattenedComponent,
* invoking the childProcessor
with its
* callbackContext
on each renderable instance.
*
* If the child is a FlattenedComponent, the childProcessor
will
* be called on each of that FlattenedComponent's children, recursing if those children are
* themselves FlattenedComponents, otherwise, the childProcessor
will be called on
* the child itself.
*
* This method is typically used to flatten the contents of a facet of the FlattenedComponent.
* If the FlattenedComponent accidentally passes in itself instead of one
* of its children, the result will almost certainly be an infinite recursion and stack overflow.
* @return true
If any children were processed
* @see UIXComponent#processFlattenedChildren(FacesContext, ComponentProcessor, UIComponent, Object)
* @see UIXComponent#processFlattenedChildren(FacesContext, ComponentProcessor, Iterable, Object)
* @see UIXComponent#processFlattenedChildren(FacesContext, ComponentProcessingContext, ComponentProcessor, Iterable, Object)
* @see FlattenedComponent
*/
public static boolean processFlattenedChildren(
FacesContext context,
ComponentProcessingContext cpContext,
ComponentProcessor childProcessor,
UIComponent child,
S callbackContext) throws IOException
{
if (child.isRendered())
{
// component is an action FlattenedComponent. Ask it to flatten its children
if ((child instanceof FlattenedComponent) &&
((FlattenedComponent)child).isFlatteningChildren(context))
{
return ((FlattenedComponent)child).processFlattenedChildren(context,
cpContext,
childProcessor,
callbackContext);
}
else
{
boolean processed = true;
RequestContext requestContext = cpContext.getRequestContext();
requestContext.pushCurrentComponent(context, child);
child.pushComponentToEL(context, null);
try
{
if (isFlattenableCoreComponent(child))
{
processed =
processFlattenedChildren(context, cpContext, childProcessor,
child.getChildren(),
callbackContext);
}
else
{
try
{
// not a FlattenedComponent, pass the component directly to the ComponentProcessor
childProcessor.processComponent(context, cpContext, child,
callbackContext);
}
finally
{
// if startDepth is > 0, only the first visible child will be marked as starting a group
cpContext.resetStartDepth();
}
}
}
finally
{
child.popComponentFromEL(context);
requestContext.popCurrentComponent(context, child);
}
return processed;
}
}
else
{
// component not rendered
return false;
}
}
/**
* Helper function called by Renderers to iterate over a flattened view of the
* children, potentially containing FlattenedComponents, of the component the Renderer is
* encoding, invoking the childProcessor
with its
* callbackContext
on each renderable instance.
*
* For each FlattenedComponent child, the childProcessor
will
* be called on each of that FlattenedComponent's children, recursing if those children are
* themselves FlattenedComponents, otherwise, the childProcessor
will be called on
* the child itself.
*
* This method is typically used to flatten the children of the FlattenedComponent to
* be encoded.
* @return true
If any children were processed
* @see UIXComponent#processFlattenedChildren(FacesContext, ComponentProcessor, UIComponent, Object)
* @see UIXComponent#processFlattenedChildren(FacesContext, ComponentProcessingContext, ComponentProcessor, UIComponent, Object)
* @see UIXComponent#processFlattenedChildren(FacesContext, ComponentProcessingContext, ComponentProcessor, Iterable, Object)
* @see FlattenedComponent
*/
public static boolean processFlattenedChildren(
FacesContext context,
ComponentProcessor childProcessor,
Iterable children,
S callbackContext) throws IOException
{
return processFlattenedChildren(context,
new ComponentProcessingContext(),
childProcessor,
children,
callbackContext);
}
/**
* Helper function called by Renderers to encode a flattened view of their children,
* invoking the childProcessor
with its
* callbackContext
on each renderable instance. This method must be called
* when the childProcessor is actually encoding and the childProcessor must not attempt
* to encode the same component instances more than once per request.
*
* If a Renderer needs to
* collect information about its possibly flattened children before calling
* encodeFlattenedChild(FacesContext, ComponentProcessor, Iterable<UIComponent>, Object)
,
* it should call
* processFlattenedChildren(FacesContext, ComponentProcessor, Iterable<UIComponent>, Object)
* to collect the information.
*
* For each FlattenedComponent child, the childProcessor
will
* be called on each of that FlattenedComponent's children, recursing if those children are
* themselves FlattenedComponents, otherwise, the childProcessor
will be called on
* the child itself.
*
* FlattenedComponents that wish to check whether they are processed for the purpose of
* encoding can check the ProcessingHints of the ComponentProcessingContext for the
* presence of PROCESS_FOR_ENCODING hint
.
* @param context FacesContext
* @param childProcessor ComponentProcessor to call on each flattened child
* @param children Initial set of children to flatten
* @param callbackContext context object to pass to the childProcessor on each invocation
* @return true
If any children were processed
* @see UIXComponent#processFlattenedChildren(FacesContext, ComponentProcessor, Iterable, Object)
* @see FlattenedComponent
*/
public static boolean encodeFlattenedChildren(
FacesContext context,
ComponentProcessor childProcessor,
Iterable children,
S callbackContext) throws IOException
{
ComponentProcessingContext processingContext = new ComponentProcessingContext();
processingContext.__setIsRendering();
return processFlattenedChildren(context,
processingContext,
childProcessor,
children,
callbackContext);
}
/**
* Helper function called by FlattenedComponents to iterate over a flattened view of their
* children, potentially themselves FlattenedComponents, invoking the childProcessor
* with its callbackContext
on each renderable instance.
*
* For each FlattenedComponent child, the childProcessor
will
* be called on each of that FlattenedComponent's children, recursing if those children are
* themselves FlattenedComponents, otherwise, the childProcessor
will be called on
* the child itself.
* @see UIXComponent#processFlattenedChildren(FacesContext, ComponentProcessor, UIComponent, Object)
* @see UIXComponent#processFlattenedChildren(FacesContext, ComponentProcessor, Iterable, Object)
* @see UIXComponent#processFlattenedChildren(FacesContext, ComponentProcessingContext, ComponentProcessor, UIComponent, Object)
* @see FlattenedComponent
*/
public static boolean processFlattenedChildren(
FacesContext context,
ComponentProcessingContext cpContext,
ComponentProcessor childProcessor,
Iterable children,
S callbackContext) throws IOException
{
// we haven't processed a child yet
boolean processedChild = false;
for (UIComponent currChild : children)
{
// latch processed child to the first child processed
processedChild |= processFlattenedChildren(context,
cpContext, childProcessor,
currChild,
callbackContext);
}
return processedChild;
}
/**
* Broadcast the FacesEvent after updating the current component and
* current composite component
*
* @param context The current instance of FacesContext
* @param event The FacesEvent to be broadcasted
*/
public static void broadcastInContext(FacesContext context, FacesEvent event)
{
UIComponent component = event.getComponent();
UIComponent compositeParent = null;
RequestContext requestContext = RequestContext.getCurrentInstance();
if (!UIComponent.isCompositeComponent(component))
{
compositeParent = UIComponent.getCompositeComponentParent(component);
if (compositeParent != null)
{
requestContext.pushCurrentComponent(context, compositeParent);
compositeParent.pushComponentToEL(context, null);
}
}
requestContext.pushCurrentComponent(context, component);
component.pushComponentToEL(context, null);
try
{
component.broadcast(event);
}
finally
{
component.popComponentFromEL(context);
requestContext.popCurrentComponent(context, component);
if (compositeParent != null)
{
compositeParent.popComponentFromEL(context);
requestContext.popCurrentComponent(context, compositeParent);
}
}
}
/**
* Perform a tree visit starting at
* this node in the tree.
*
* UIXComponent.visitTree() implementations do not invoke the
* {@code VisitCallback}directly, but instead call
* {@code VisitContext.invokeVisitCallback()}to invoke the
* callback. This allows {@code VisitContext}implementations
* to provide optimized tree traversals, for example by only
* calling the {@code VisitCallback}for a subset of components.
*
* @param visitContext the VisitContext
for this visit
* @param callback the VisitCallback
instance
* whose visit
method will be called
* for each node visited.
* @return component implementations may return true
* to indicate that the tree visit is complete (eg. all components
* that need to be visited have been visited). This results in
* the tree visit being short-circuited such that no more components
* are visited.
*
* @see VisitContext#invokeVisitCallback VisitContext.invokeVisitCallback()
*/
public boolean visitTree(
VisitContext visitContext,
VisitCallback callback)
{
return visitTree(visitContext, this, callback);
}
/**
* Specifies what facets and children components should be processed as rendered for life-cycle
* methods. Any components not returned will not be processed during methods such as decoding,
* validating, updating the model, rendered-only tree visiting, etc.
*
* @param facesContext the facesContext
* @return An iterator of components to process. Must not return null (return an empty iterator
* if no children components should be processed).
*/
protected Iterator getRenderedFacetsAndChildren(
FacesContext facesContext)
{
return defaultGetRenderedFacetsAndChildren(facesContext);
}
/**
* Default implementation of getRenderedFacetsAndChildren for cases where a
* UIXComponent subclass wants to restore the default implementation that one of its
* superclasses have overridden.
*
*
* @param facesContext the facesContext
* @return An iterator of components to process. Must not return null (return an empty iterator
* if no children components should be processed).
*/
protected final Iterator defaultGetRenderedFacetsAndChildren(
FacesContext facesContext)
{
Renderer renderer = getRenderer(facesContext);
if (renderer instanceof CoreRenderer)
{
return ((CoreRenderer)renderer).getRenderedFacetsAndChildren(facesContext, this);
}
else
{
return getFacetsAndChildren();
}
}
/**
* Hook for subclasses to override the manner in which the component's children are visited. The default
* implementation visits all of the children and facets of the Component.
* setupChildrenVisitingContext
will have been called before this method is
* invoked and tearDownChildrenVisitingContext
will be called after.
* respectively. If the purpose of this visit was to encode the component and the
* component uses a CoreRenderer, the CoreRenderer's
* setupChildrenEncodingContext
and tearDownChildrenEncodingContext
* will be called before and after this method is invoked, respectively.
* @param visitContext the VisitContext
for this visit
* @param callback the VisitCallback
instance
* @return true
if the visit is complete.
* @see #setupChildrenVisitingContext
* @see #tearDownChildrenVisitingContext
* @see org.apache.myfaces.trinidad.render.CoreRenderer#setupChildrenEncodingContext
* @see org.apache.myfaces.trinidad.render.CoreRenderer#tearDownChildrenEncodingContext
*/
protected boolean visitChildren(
VisitContext visitContext,
VisitCallback callback)
{
// See if this is during encoding, if so, allow the renderer to control the visitation of
// the children so that any special encoding context may be applied around the visitation
// of each child.
if (_isEncodingVisit(visitContext))
{
Renderer renderer = getRenderer(visitContext.getFacesContext());
if (renderer instanceof CoreRenderer)
{
CoreRenderer coreRenderer = (CoreRenderer)renderer;
return coreRenderer.visitChildrenForEncoding(this, visitContext, callback);
}
}
// visit all of the children of the component
return visitAllChildren(visitContext, callback);
}
/**
* Default implementation of visiting children that visits all children without iterating
* @param visitContext the VisitContext
for this visit
* @param callback the VisitCallback
instance
* @return true
if the visit is complete.
*/
protected final boolean visitAllChildren(
VisitContext visitContext,
VisitCallback callback)
{
// visit the children of the component
Iterator kids =
visitContext.getHints().contains(VisitHint.SKIP_UNRENDERED) ?
getRenderedFacetsAndChildren(visitContext.getFacesContext()) :
getFacetsAndChildren();
while (kids.hasNext())
{
// If any kid visit returns true, we are done.
if (kids.next().visitTree(visitContext, callback))
{
return true;
}
}
return false;
}
/**
* Returns true
if the components are being visited
* for the purpose of encoding.
*/
private static boolean _isEncodingVisit(VisitContext visitContext)
{
return(visitContext.getHints().contains(VisitHint.EXECUTE_LIFECYCLE) &&
FacesContext.getCurrentInstance().getCurrentPhaseId() == PhaseId.RENDER_RESPONSE);
}
/**
* Perform a tree visit starting at the specified node in the tree.
*
* UIXComponent.visitTree() implementations do not invoke the
* {@code VisitCallback}directly, but instead call
* {@code VisitContext.invokeVisitCallback()}to invoke the
* callback. This allows {@code VisitContext}implementations
* to provide optimized tree traversals, for example by only
* calling the {@code VisitCallback}for a subset of components.
*
* @param visitContext the VisitContext
for this visit
* @param component the UIComponent
to start the visit from
* @param callback the VisitCallback
instance
* whose visit
method will be called
* for each node visited.
* @return component implementations may return true
* to indicate that the tree visit is complete (eg. all components
* that need to be visited have been visited). This results in
* the tree visit being short-circuited such that no more components
* are visited.
*
* @see VisitContext#invokeVisitCallback VisitContext.invokeVisitCallback()
*/
public static boolean visitTree(
VisitContext visitContext,
UIComponent component,
VisitCallback callback)
{
// push component on to the stack at the beginning of visiting tree.
RequestContext requestContext = RequestContext.getCurrentInstance();
requestContext.pushCurrentComponent(visitContext.getFacesContext(), component);
FacesContext context = visitContext.getFacesContext();
// set up the EL Context with the component. Note that since we do this before call
// isVisitable, any attributes retrieved (like rendered) that are bound with EL referring
// to the current component will be evaluated correctly,
// TODO check the however case however, in the specific case
// of rendered, rendered already has this problem in normal JSF traversal since it
// is evaluated by the parent component
component.pushComponentToEL(context, null);
try
{
if (!(component instanceof UIXComponent))
{
// hopefully the subview implementations have the subId optimization
return component.visitTree(visitContext, callback);
}
else
{
UIXComponent uixComponent = (UIXComponent)component;
// delegate to the UIXComponent
if (!uixComponent.isVisitable(visitContext))
return false;
boolean doneVisiting = false;
RuntimeException re = null;
try
{
RenderingContext rc = (_isEncodingVisit(visitContext))
? RenderingContext.getCurrentInstance()
: null;
// UIXComponents are allowed to set up their context differently for encoding
// than normal processing, so behave differently if this is the RenderResponse
// phase. In order to allow the visitcallback to call encodeAll in the ppr case,
// we don't call setupEncodingContext before we call the visitContext, since this
// would result in setupEncodingContext being called twice on the partial roots,
// instead we only do so if the visitCallback returns ACCEPT
if (rc == null)
{
uixComponent.setupVisitingContext(context);
}
VisitResult visitResult = VisitResult.REJECT;
try
{
// invoke the callback for this component
visitResult = visitContext.invokeVisitCallback(component, callback);
if (visitResult == VisitResult.COMPLETE)
doneVisiting = true;
else if (visitResult == VisitResult.ACCEPT)
{
// now determine whether we need to visit the children
// assume that all UIXComponent NamingContainers always act as NamingContainers,
// (unlike ) and this it is OK to put the optimization where we
// don't visit the children if we know that we don't have any ids in this
// subtree to visit
boolean skipChildren = (uixComponent instanceof NamingContainer) &&
visitContext.getSubtreeIdsToVisit(uixComponent).isEmpty();
// visit the children of the component if we aren't supposed to skip them
if (!skipChildren)
{
// setup encoding context before visiting children, since we didn't do so
// before calling the visitCallback
if (rc != null)
{
uixComponent.setupEncodingContext(context, rc);
}
try
{
doneVisiting = visitChildren(visitContext, uixComponent, callback);
}
finally
{
// teardown the encoding context if we set it up
if (rc != null)
{
uixComponent.tearDownEncodingContext(context, rc);
}
}
}
}
else
{
// don't visit the children
assert(visitResult == VisitResult.REJECT);
}
}
catch (RuntimeException ex)
{
re = ex;
}
finally
{
try
{
// tear down the context we set up in order to visit our component
if (rc == null)
{
uixComponent.tearDownVisitingContext(context);
}
}
catch (RuntimeException ex)
{
if (re == null)
{
throw ex;
}
else
{
_LOG.warning(ex);
}
}
}
}
finally
{
if (re != null)
{
throw re;
}
}
// if we got this far, we're not done
return doneVisiting;
}
}
finally
{
// pop component out after visiting tree.
requestContext.popCurrentComponent(visitContext.getFacesContext(), component);
component.popComponentFromEL(context);
}
}
/**
* Utility method to allow the visiting of children components while visiting a parent using
* a new visit callback or visit context. The method may only be called when the parent is
* is the target of a visitation to ensure that it is properly in context.
* Example usage:
* @Override
* public VisitResult visit(
* VisitContext visitContext,
* UIComponent target)
* {
* if (someCondition)
* {
* UIXComponent.visitChildren(target, visitContext, new VisitCallback() {...});
* return VisitResult.COMPLETE;
* }
* ...
* }
*
* @param visitContext the VisitContext
for this visit
* @param parentComponent the UIComponent
to visit the children. The parent component
* must be actively being visited in order to call this method.
* @param callback the VisitCallback
instance
* whose visit
method will be called
* for each node visited.
* @return component implementations may return true
* to indicate that the tree visit is complete (eg. all components
* that need to be visited have been visited). This results in
* the tree visit being short-circuited such that no more components
* are visited.
*/
public static boolean visitChildren(
VisitContext visitContext,
UIComponent parentComponent,
VisitCallback callback)
{
if (!(parentComponent instanceof UIXComponent))
{
// Not a UIXComponent, there is no extra functionality necessary in order to visit the
// children.
for (Iterator iter = parentComponent.getFacetsAndChildren(); iter.hasNext();)
{
UIComponent child = iter.next();
if (child.visitTree(visitContext, callback))
{
return true;
}
}
return false;
}
UIXComponent uixParentComponent = (UIXComponent)parentComponent;
FacesContext context = visitContext.getFacesContext();
RenderingContext rc = (_isEncodingVisit(visitContext))
? RenderingContext.getCurrentInstance()
: null;
boolean doneVisiting = false;
RuntimeException re = null;
// setup any context needed for visiting the children of the component as opposed
// to the component itself
if (parentComponent instanceof UIXComponent)
{
if (rc != null)
{
uixParentComponent.setupChildrenEncodingContext(context, rc);
}
else
{
uixParentComponent.setupChildrenVisitingContext(context);
}
}
try
{
doneVisiting = uixParentComponent.visitChildren(visitContext, callback);
}
catch (RuntimeException ex)
{
re = ex;
}
finally
{
try
{
// teardown any context initialized above
if (rc != null)
{
uixParentComponent.tearDownChildrenEncodingContext(context, rc);
}
else
{
uixParentComponent.tearDownChildrenVisitingContext(context);
}
}
catch (RuntimeException ex)
{
if (re == null)
{
throw ex;
}
else
{
_LOG.warning(ex);
}
}
if (re != null)
{
throw re;
}
}
return doneVisiting;
}
/**
* Add a component as a partial target to the current request. This code handles the
* delegation to {@link #setPartialTarget(FacesContext, PartialPageContext)}
* for UIXComponents or assumes for {@link UIComponent} that components with a renderer
* type are able to produce DOM elements that have IDs that can be replaced.
*
* @param facesContext the faces context
* @param partialContext the partial page context
* @param component the component to add as a target
*/
public static void addPartialTarget(FacesContext facesContext,
PartialPageContext partialContext, UIComponent component)
{
if(component == null)
{
throw new NullPointerException("UIComponent is null");
}
if (component instanceof UIXComponent)
{
((UIXComponent)component).setPartialTarget(facesContext, partialContext);
}
else
{
// default to using the renderer type implementation
_addPartialTargetImpl(facesContext, partialContext, component);
}
}
/**
* Clears all of the cached clientIds in this component subtree
*/
public void clearCachedClientIds()
{
clearCachedClientIds(this);
}
/**
* Clears all of the cached clientIds in the component's subtree
* @param component Component subtree to clear the cached client ids for
*/
public static void clearCachedClientIds(UIComponent component)
{
if (component instanceof UIXComponent)
{
((UIXComponent)component).clearCachedClientIds();
}
else
{
_clearCachedClientIds(component);
}
}
/**
* Default implementation of clearing the cached client ids
*/
private static void _clearCachedClientIds(UIComponent component)
{
// clear this component
String id = component.getId();
component.setId(id);
// clear the children
Iterator allChildren = component.getFacetsAndChildren();
while (allChildren.hasNext())
{
clearCachedClientIds(allChildren.next());
}
}
/**
* Marks this component as a partial target for this request. Typically called
* by the {@link org.apache.myfaces.trinidad.context.RequestContext RequestContext}.
* The component should add the client ID the desired rendered component to the context.
* This allows components that do not render a replacable DOM element with an ID
* to choose an alternative component, like a parent.
*
* @param facesContext the faces context
* @param partialContext the partial page context
*/
protected void setPartialTarget(FacesContext facesContext,
PartialPageContext partialContext)
{
UIXComponent._addPartialTargetImpl(facesContext, partialContext, this);
}
/**
* Called by
* {@link UIXComponent#visitTree(VisitContext,VisitCallback) UIXComponent.visitTree()}to determine
* whether this component is "visitable" - ie. whether this component
* satisfies the {@link VisitHint}returned by
* {@link VisitContext#getHints VisitContext.getHints()}.
* If this component is not visitable (ie. if this method returns
* false), the tree visited is short-circuited such that neither the
* component nor any of its descendents will be visited>
* Custom {@code treeVisit()}implementations may call this method
* to determine whether the component is visitable before performing
* any visit-related processing.
* @param visitContext VisitingContext to use to determine if the component is visitable
* @return true if this component should be visited, false otherwise.
*/
protected boolean isVisitable(VisitContext visitContext)
{
return _isVisitable(visitContext, this);
}
/**
* @see #addPartialTarget(FacesContext, PartialPageContext, UIComponent)
* @see #setPartialTarget(FacesContext, PartialPageContext)
*/
private static void _addPartialTargetImpl(
FacesContext facesContext, PartialPageContext partialContext, UIComponent component)
{
if (component.getRendererType() == null)
{
if (component.getParent() != null)
{
// delegate to the parent component, assuming that no renderer type means that
// there is no suitable replacable DOM element for this component
addPartialTarget(facesContext, partialContext, component.getParent());
}
}
else
{
partialContext.addPartialTarget(component.getClientId(facesContext));
}
}
/**
* default implementation checking the VisitHint.SKIP_TRANSIENT
and
* VisitHint.SKIP_UNRENDERED
hints.
*/
private static boolean _isVisitable(VisitContext visitContext, UIComponent component)
{
Collection hints = visitContext.getHints();
if (hints.contains(VisitHint.SKIP_TRANSIENT) && component.isTransient())
return false;
if (hints.contains(VisitHint.SKIP_UNRENDERED) && !component.isRendered())
return false;
return true;
}
/**
*
* Called when visiting the component during optimized partial page encoding so that the
* component can modify what is actually encoded. For example tab controls often
* render the tabs for the ShowDetailItems in the tab bar before delegating to the
* disclosed ShowDetailItem to render the tab content. As a result, the tab control
* needs to encode its tab bar if any of its ShowDetailItems are partial targets so that
* the tab labels, for example, are up-to-date.
*
*
* The default implementation delegates to the CoreRenderer if this component has one, otherwise
* it calls the VisitCallback and returns its result if this UIXComponent is a partial
* target of the current encoding.
*
* @param visitContext VisitContext to pass to the VisitCallback
* @param partialContext PartialPageContext for the current partial encoding
* @param callback VisitCallback to call if this component is a partial target
* @return The VisitResult controlling continued iteration of the visit.
*/
public VisitResult partialEncodeVisit(
VisitContext visitContext,
PartialPageContext partialContext,
VisitCallback callback)
{
FacesContext context = visitContext.getFacesContext();
Renderer renderer = getRenderer(context);
if (renderer instanceof CoreRenderer)
{
// delegate to the CoreRenderer
return ((CoreRenderer)renderer).partialEncodeVisit(visitContext,
partialContext,
this,
callback);
}
else
{
// check that this is a component instance that should be encoded
if (partialContext.isPossiblePartialTarget(getId()) &&
partialContext.isPartialTarget(getClientId(context)))
{
// visit the component instance
return callback.visit(visitContext, this);
}
else
{
// Not visiting this component, but allow visit to
// continue into this subtree in case we've got
// visit targets there.
return VisitResult.ACCEPT;
}
}
}
/**
* Sets up the context necessary to visit or invoke the component for all phases.
* The default implementation does nothing.
* If a subclass overrides this method, it should override
* tearDownVisitingContext
as well.
* It is guaranteed that if setupVisitingContext
completes
* tearDownVisitingContext
will be called for this component
* @param context FacesContext
* @see #tearDownVisitingContext
* @see #setupEncodingContext
* @see #tearDownEncodingContext
* @see #setupChildrenVistingContext
*/
protected void setupVisitingContext(@SuppressWarnings("unused") FacesContext context)
{
// If in testing phase, add code to determine if this function is being used correctly.
if (_inTestingPhase)
{
// First, check to ensure that we are not already in context
if (_inVisitingContext)
{
_handleInvalidContextUsage("COMPONENT_ALREADY_IN_VISITING_CONTEXT", _setupVisitingCaller);
}
// Next, add a context change so that the flags are reset during an
// invokeOnComponent(context, clientId, callback), or a visitTree call:
ComponentContextManager componentContextManager =
RequestContext.getCurrentInstance().getComponentContextManager();
componentContextManager.pushChange(new VisitDebugContextChange(this));
_inVisitingContext = true;
_setupVisitingCaller = _getStackTraceElementForCaller();
}
}
/**
* Sets up the context necessary to visit or invoke the children of a component for all phases.
*
* The default implementation does nothing.
* If a subclass overrides this method, it should override
* tearDownChildrenVisitingContext
as well.
* It is guaranteed that if setupChildrenVisitingContext
completes
* tearDownChildrenVisitingContext
will be called for this component
* @param context FacesContext
* @see #visitChildren
* @see #tearDownChildrenVisitingContext
* @see setupVisitingContext
*/
protected void setupChildrenVisitingContext(@SuppressWarnings("unused") FacesContext context)
{
// If in testing phase, add code to determine if this function is being used correctly.
if (_inTestingPhase)
{
// Check to ensure that we are not already in context
if (_inChildrenVisitingContext)
{
_handleInvalidContextUsage("COMPONENT_ALREADY_IN_CHILDREN_VISITING_CONTEXT",
_setupChildrenVisitingCaller);
}
// Next, add a context change so that the flags are reset during an
// invokeOnComponent(context, clientId, callback), or a visitTree call
// (Note that a separate one is needed for the children due to the fact that currently
// the encoding context / visiting context is not set up during normal tree traversal,
// but the children encoding context is setup by the renderers):
ComponentContextManager componentContextManager =
RequestContext.getCurrentInstance().getComponentContextManager();
componentContextManager.pushChange(new VisitChildrenDebugContextChange(this));
_inChildrenVisitingContext = true;
_setupChildrenVisitingCaller = _getStackTraceElementForCaller();
}
}
/**
* Tears down context created in order to visit or invoke the component
* for all phases.
* The default implementation does nothing.
* A subclass should only override this method if it overrode
* setupVisitingContext
as well
* It is guaranteed that tearDownVisitingContext
will be called only after
* setupVisitingContext
has been called for this component
* @param context FacesContext
* @see #setupVisitingContext
* @see #setupEncodingContext
* @see #tearDownEncodingContext
*/
protected void tearDownVisitingContext(@SuppressWarnings("unused") FacesContext context)
{
// If in testing phase, add code to determine if this function is being used correctly.
if (_inTestingPhase)
{
// First, check to ensure that we are not already in context
if (!_inVisitingContext)
{
_handleInvalidContextUsage("COMPONENT_NOT_IN_VISITING_CONTEXT", _tearDownVisitingCaller);
}
// Next, remove the context change that was added in setupVisitingContext:
ComponentContextManager componentContextManager =
RequestContext.getCurrentInstance().getComponentContextManager();
ComponentContextChange contextChange = componentContextManager.popChange();
// Validate the state of the context change stack:
if (!(contextChange instanceof VisitDebugContextChange) ||
((VisitDebugContextChange)contextChange)._component != this)
{
throw new IllegalStateException(_getInvalidContextChangeMessage(
VisitDebugContextChange.class,
contextChange));
}
_inVisitingContext = false;
_tearDownVisitingCaller = _getStackTraceElementForCaller();
}
}
/**
* Tears down context created in order to visit or invoke the children of a component
* for all phases.
* The default implementation does nothing.
* A subclass should only override this method if it overrode
* setupChildrenVisitingContext
as well
* It is guaranteed that tearDownChildrenVisitingContext
will be called only after
* setupChildrenVisitingContext
has been called for this component
* @param context FacesContext
* @see #setupChildrenVisitingContext
* @see #visitChildren
*/
protected void tearDownChildrenVisitingContext(@SuppressWarnings("unused") FacesContext context)
{
// If in testing phase, add code to determine if this function is being used correctly.
if (_inTestingPhase)
{
// Check to ensure that we are not already in context
if (!_inChildrenVisitingContext)
{
_handleInvalidContextUsage("COMPONENT_NOT_IN_CHILDREN_VISITING_CONTEXT",
_tearDownChildrenVisitingCaller);
}
// Next, remove the context change that was added in setupChildrenVisitingContext:
ComponentContextManager componentContextManager =
RequestContext.getCurrentInstance().getComponentContextManager();
ComponentContextChange contextChange = componentContextManager.popChange();
// Validate the state of the context change stack:
if (!(contextChange instanceof VisitChildrenDebugContextChange) ||
((VisitChildrenDebugContextChange)contextChange)._component != this)
{
throw new IllegalStateException(_getInvalidContextChangeMessage(
VisitChildrenDebugContextChange.class,
contextChange));
}
_inChildrenVisitingContext = false;
_tearDownChildrenVisitingCaller = _getStackTraceElementForCaller();
}
}
@Deprecated
protected final void setUpEncodingContext(FacesContext context, RenderingContext rc)
{
setupEncodingContext(context, rc);
}
/**
* Sets up the context necessary to encode the component.
* The default implementation delegates to
* CoreRenderer.setupEncodingContext
and then calls
* setupVisitingContext
* If a subclass overrides this method, it should override
* tearDownEncodingContext
as well.
* It is guaranteed that if setUpEncodingContext
completes
* tearDownEncodingContext
will be called for this component
*
* During partial page rendering traversals, setupEncodingContext
is not called
* before the VisitCallback
is invoked. This behavior is different than for
* setupVisitingContext
, which is always called before the VisitCallback
* is invoked for non-partial page rendering visits. This difference in behavior allows the
* VisitCallback
in a partial page rendering visit to safely call
* UIComponent.encodeAll
, which in the case of a UIXComponent, will call
* UIXComponent.setupEncodeContext
.
*
* @param context The FacesContext
* @param rc RenderingContext to use for encoding
* @see #setupVisitingContext
* @see #setupChildrenEncodingContext
* @see #tearDownVisitingContext
* @see #tearDownEncodingContext
* @see org.apache.myfaces.trinidad.render.CoreRenderer#setupEncodingContext(FacesContext, RenderingContext, UIComponent)
*/
protected void setupEncodingContext(FacesContext context, RenderingContext rc)
{
setupVisitingContext(context);
// If in testing phase, add code to determine if this function is being used correctly.
if (_inTestingPhase)
{
// Check to ensure that we are not already in context
if (_inEncodingContext)
{
_handleInvalidContextUsage("COMPONENT_ALREADY_IN_ENCODING_CONTEXT", _setupEncodingCaller);
}
_inEncodingContext = true;
_setupEncodingCaller = _getStackTraceElementForCaller();
}
Renderer renderer = getRenderer(context);
if (renderer instanceof CoreRenderer)
{
CoreRenderer coreRenderer = (CoreRenderer)renderer;
coreRenderer.setupEncodingContext(context, rc, (UIComponent)this);
}
_inEncodingContext = true;
}
/**
* Sets the context necessary to encode the children of a component.
* @param context The FacesContext
* @param rc RenderingContext to use for encoding
* @see #setupChildrenVisitingContext
* @see #tearDownChildrenEncodingContext
* @see #setupEncodingContext
* @see org.apache.myfaces.trinidad.render.CoreRenderer#setupChildrenEncodingContext
*/
public void setupChildrenEncodingContext(FacesContext context, RenderingContext rc)
{
setupChildrenVisitingContext(context);
// If in testing phase, add code to determine if this function is being used correctly.
if (_inTestingPhase)
{
// Check to ensure that we are not already in context
if (_inChildrenEncodingContext)
{
_handleInvalidContextUsage("COMPONENT_ALREADY_IN_CHILDREN_ENCODING_CONTEXT",
_setupChildrenEncodingCaller);
}
_inChildrenEncodingContext = true;
_setupChildrenEncodingCaller = _getStackTraceElementForCaller();
}
Renderer renderer = getRenderer(context);
if (renderer instanceof CoreRenderer)
{
CoreRenderer coreRenderer = (CoreRenderer)renderer;
coreRenderer.setupChildrenEncodingContext(context, rc, this);
}
_inChildrenEncodingContext = true;
}
/**
* Tears down the context created in order to encode the component
* The default implementation delegates to
* CoreRenderer.tearDownEncodingContext
and then calls
* tearDownVisitingContext
* A subclass should only override this method if it overrode
* setupEncodingContext
as well
* It is guaranteed that tearDownEncodingContext
will be called only after
* setupEncodingContext
has been called for this component
* @param context The FacesContext
* @param rc RenderingContext to use for encoding
* @see #setupEncodingContext
* @see #tearDownVisitingContext
* @see #setupEncodingContext
* @see #tearDownChildrenEncodingContext
* @see org.apache.myfaces.trinidad.render.CoreRenderer#tearDownEncodingContext(FacesContext, RenderingContext, UIComponent)
*/
protected void tearDownEncodingContext(
FacesContext context,
RenderingContext rc)
{
// If in testing phase, add code to determine if this function is being used correctly.
if (_inTestingPhase)
{
// Check to ensure that we are not already in context
if (!_inEncodingContext)
{
_handleInvalidContextUsage("COMPONENT_NOT_IN_ENCODING_CONTEXT", _tearDownEncodingCaller);
}
_inEncodingContext = false;
_tearDownEncodingCaller = _getStackTraceElementForCaller();
}
Renderer renderer = getRenderer(context);
try
{
if (renderer instanceof CoreRenderer)
{
CoreRenderer coreRenderer = (CoreRenderer)renderer;
coreRenderer.tearDownEncodingContext(context, rc, (UIComponent)this);
}
}
finally
{
tearDownVisitingContext(context);
}
}
/**
* Tears down the context necessary to encode the children of a component.
* @param context The FacesContext
* @param rc RenderingContext to use for encoding
* @see #setupChildrenVisitingContext
* @see #tearDownChildrenEncodingContext
* @see #tearDownEncodingContext
* @see org.apache.myfaces.trinidad.render.CoreRenderer#setupChildrenEncodingContext
*/
public void tearDownChildrenEncodingContext(
FacesContext context,
RenderingContext rc)
{
// If in testing phase, add code to determine if this function is being used correctly.
if (_inTestingPhase)
{
// Check to ensure that we are not already in context
if (!_inChildrenEncodingContext)
{
_handleInvalidContextUsage("COMPONENT_NOT_IN_CHILDREN_ENCODING_CONTEXT",
_tearDownChildrenEncodingCaller);
}
_inChildrenEncodingContext = false;
_tearDownChildrenEncodingCaller = _getStackTraceElementForCaller();
}
Renderer renderer = getRenderer(context);
try
{
if (renderer instanceof CoreRenderer)
{
CoreRenderer coreRenderer = (CoreRenderer)renderer;
coreRenderer.tearDownChildrenEncodingContext(context, rc, this);
}
}
finally
{
tearDownChildrenVisitingContext(context);
_inChildrenEncodingContext = false;
}
}
/**
* Returns the FacesBean used for storing the component's state.
*/
abstract public FacesBean getFacesBean();
/**
* Adds an AttributeChangeListener. Attribute change events are not
* delivered for any programmatic change to a property. They are only
* delivered when a renderer changes a property without the application's
* specific request. An example of an attribute change events might
* include the width of a column that supported client-side resizing.
*/
abstract public void addAttributeChangeListener(AttributeChangeListener acl);
/**
* Removes an AttributeChangeListener. Attribute change events are not
* delivered for any programmatic change to a property. They are only
* delivered when a renderer changes a property without the application's
* specific request. An example of an attribute change events might
* include the width of a column that supported client-side resizing.
*/
abstract public void removeAttributeChangeListener(AttributeChangeListener acl);
/**
* Gets the registered AttributeChangeListeners.
*/
abstract public AttributeChangeListener[] getAttributeChangeListeners();
/**
* Sets a method binding to an AttributeChangeListener. Attribute
* change events are not
* delivered for any programmatic change to a property. They are only
* delivered when a renderer changes a property without the application's
* specific request. An example of an attribute change events might
* include the width of a column that supported client-side resizing.
*/
abstract public void setAttributeChangeListener(MethodExpression me);
/**
* Gets the method binding to an AttributeChangeListener. Attribute
* change events are not
* delivered for any programmatic change to a property. They are only
* delivered when a renderer changes a property without the application's
* specific request. An example of an attribute change events might
* include the width of a column that supported client-side resizing.
*/
abstract public MethodExpression getAttributeChangeListener();
abstract public void markInitialState();
/**
* Provides additional context (the target child component for which the container
* client ID is requested) to a naming container for constructing a client ID.
* This is useful for components such as @link UIXTable and @link UIXTreeTable which need
* to return different container client IDs for stamped and non-stamped child components.
* @see UIXComponentBase#getClientId(FacesContext context)
*/
abstract public String getContainerClientId(FacesContext context, UIComponent child);
/**
* Provides a logical parent for this component (a parent in the context of the document where this component was
* defined). The default implementation will simply call getParent(). Components that get relocated during
* tag execution will return their original parent
* @return logical parent component
*/
public UIComponent getLogicalParent()
{
return getParent();
}
/**
* Provides a logical parent for the component (a parent in the context of the document where the component was
* defined). The default implementation will simply call getParent() on the component. Components that get relocated during
* tag execution should have their original parent returned (if available).
* @param component - child component whose parent is being retrieved
* @return logical parent component
*/
public static UIComponent getLogicalParent(UIComponent component)
{
if (component instanceof UIXComponent)
{
return ((UIXComponent)component).getLogicalParent();
}
return component.getParent();
}
/**
* We are using FacesBean to save state, which does not implement StateHelper, so
* calling this method will call UnsupportedOperationException
*/
@Override
protected StateHelper getStateHelper()
{
throw new UnsupportedOperationException();
}
/**
* We are using FacesBean to save state, which does not implement StateHelper, so
* calling this method will call UnsupportedOperationException
*/
@Override
protected StateHelper getStateHelper(boolean create)
{
throw new UnsupportedOperationException();
}
private String _getStackTraceElementForCaller()
{
StackTraceElement[] elements = Thread.currentThread().getStackTrace();
// 0 is the call to getStackTrace, 1 is this method, 2 is the calling method in UIXComponent
// so 3 (4th element) is the caller to the UIXComponent method, the one that is desired.
String lineSep = System.getProperty("line.separator");
StringBuilder stack = new StringBuilder();
for (int i = 3, size = elements.length; i < size && i < 10; ++i)
{
stack.append(elements[i].toString());
stack.append(lineSep);
}
return stack.toString();
}
/**
* Determine if we can flatten a core JSF component.
* @param component The component
* @return true if the component is a core JSF component and we can
* flatten it successfully.
*/
private static boolean isFlattenableCoreComponent(UIComponent component)
{
// Optimize the cases of UINamingContainer () and UIPanel -
// we will treat these components as FlattenedComponents because they do not render
// any DOM.
// Also note that as of JSF 2.0, UINamingContainer components are built
// by f:subview, as well as composite components.
Class extends UIComponent> componentClass = component.getClass();
if (UINamingContainer.class == componentClass)
{
// Check to see if this component was created as a composite
// component, which we cannot flatten
return component.getFacet(UIComponent.COMPOSITE_FACET_NAME) == null;
}
// Note that JSF 2.0 creates UIPanel wrappers around multiple components
// inside of
return UIPanel.class == componentClass;
}
private void _handleInvalidContextUsage(
String bundleKey,
String originalStackTrace
) throws IllegalStateException
{
String errorMessage = _LOG.getMessage(bundleKey,
new Object[] { getClientId(), originalStackTrace });
if (_treatContextualIssuesAsErrors)
{
throw new IllegalStateException(errorMessage);
}
else
{
_LOG.warning(errorMessage);
}
}
private String _getInvalidContextChangeMessage(
Class extends ComponentContextChange> expectedClass,
ComponentContextChange foundChange)
{
String type = expectedClass.getName();
String id = (getParent() == null) ? getId() : getClientId();
return _LOG.getMessage("INVALID_CONTEXT_CHANGE_FOUND",
new Object[] { type, id, foundChange });
}
private static class VisitDebugContextChange
extends ComponentContextChange
{
private VisitDebugContextChange(
UIXComponent component)
{
_component = component;
}
@Override
public void resume(FacesContext facesContext)
{
_component._inVisitingContext = _inVisitingContext;
_component._inEncodingContext = _inEncodingContext;
_component._setupVisitingCaller = _setupVisitingCaller;
_component._tearDownVisitingCaller = _tearDownVisitingCaller;
_component._setupEncodingCaller = _setupEncodingCaller;
_component._tearDownEncodingCaller = _tearDownEncodingCaller;
}
@Override
public void suspend(FacesContext facesContext)
{
_inVisitingContext = _component._inVisitingContext;
_inEncodingContext = _component._inEncodingContext;
_setupVisitingCaller = _component._setupVisitingCaller;
_tearDownVisitingCaller = _component._tearDownVisitingCaller;
_setupEncodingCaller = _component._setupEncodingCaller;
_tearDownEncodingCaller = _component._tearDownEncodingCaller;
_component._inVisitingContext = false;
_component._inEncodingContext = false;
_component._setupVisitingCaller = null;
_component._tearDownVisitingCaller = null;
_component._setupEncodingCaller = null;
_component._tearDownEncodingCaller = null;
}
@Override
public String toString()
{
return String.format("VisitDebugContextChange(component: %s, id: %s)",
_component,
_component == null ? null :
_component.getParent() == null ? _component.getId() : _component.getClientId());
}
private final UIXComponent _component;
private boolean _inVisitingContext;
private boolean _inEncodingContext;
private String _setupVisitingCaller;
private String _tearDownVisitingCaller;
private String _setupEncodingCaller;
private String _tearDownEncodingCaller;
}
private static class VisitChildrenDebugContextChange
extends ComponentContextChange
{
private VisitChildrenDebugContextChange(
UIXComponent component)
{
_component = component;
}
@Override
public void resume(FacesContext facesContext)
{
_component._inChildrenVisitingContext = _inChildrenVisitingContext;
_component._inChildrenEncodingContext = _inChildrenEncodingContext;
_component._setupChildrenEncodingCaller = _setupChildrenEncodingCaller;
_component._tearDownChildrenEncodingCaller = _tearDownChildrenEncodingCaller;
_component._setupChildrenVisitingCaller = _setupChildrenVisitingCaller;
_component._tearDownChildrenVisitingCaller = _tearDownChildrenVisitingCaller;
}
@Override
public void suspend(FacesContext facesContext)
{
_inChildrenVisitingContext = _component._inChildrenVisitingContext;
_inChildrenEncodingContext = _component._inChildrenEncodingContext;
_setupChildrenEncodingCaller = _component._setupChildrenEncodingCaller;
_tearDownChildrenEncodingCaller = _component._tearDownChildrenEncodingCaller;
_setupChildrenVisitingCaller = _component._setupChildrenVisitingCaller;
_tearDownChildrenVisitingCaller = _component._tearDownChildrenVisitingCaller;
_component._inChildrenVisitingContext = false;
_component._inChildrenEncodingContext = false;
_component._setupChildrenEncodingCaller = null;
_component._tearDownChildrenEncodingCaller = null;
_component._setupChildrenVisitingCaller = null;
_component._tearDownChildrenVisitingCaller = null;
}
@Override
public String toString()
{
return String.format("VisitChildrenDebugContextChange(component: %s, id: %s)",
_component,
_component == null ? null :
_component.getParent() == null ? _component.getId() : _component.getClientId());
}
private final UIXComponent _component;
private boolean _inChildrenVisitingContext;
private boolean _inChildrenEncodingContext;
private String _setupChildrenEncodingCaller;
private String _tearDownChildrenEncodingCaller;
private String _setupChildrenVisitingCaller;
private String _tearDownChildrenVisitingCaller;
}
// Use logging for now until all issues are resolved
private final static boolean _treatContextualIssuesAsErrors;
private final static boolean _inTestingPhase;
private static final TrinidadLogger _LOG =
TrinidadLogger.createTrinidadLogger(UIXComponent.class);
static
{
// If Trinidad is to be ever shared with a shared class loader, we should change this
// static boolean flag to be non-class loader bound.
Application app = null;
try
{
FacesContext facesContext = FacesContext.getCurrentInstance();
app = facesContext == null ? null : facesContext.getApplication();
if (app == null)
{
ApplicationFactory appFactory = (ApplicationFactory)
FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY);
app = appFactory.getApplication();
}
}
catch (Throwable t)
{
// This occurs during unit testing without a full JSF environment, ignore
;
}
_inTestingPhase = app == null ? false : app.getProjectStage() == ProjectStage.UnitTest;
if (_inTestingPhase)
{
_LOG.info("Application is running in testing phase, UIXComponent will " +
"perform extra validation steps to ensure proper component usage");
}
_treatContextualIssuesAsErrors = "true".equals(
System.getProperty("uixcomponent.contextual.issue.throw"));
};
private String _setupVisitingCaller;
private String _tearDownVisitingCaller;
private String _setupEncodingCaller;
private String _tearDownEncodingCaller;
private String _setupChildrenEncodingCaller;
private String _tearDownChildrenEncodingCaller;
private String _setupChildrenVisitingCaller;
private String _tearDownChildrenVisitingCaller;
private boolean _inVisitingContext;
private boolean _inChildrenVisitingContext;
private boolean _inEncodingContext;
private boolean _inChildrenEncodingContext;
}