com.sun.webui.jsf.component.Tree Maven / Gradle / Ivy
/*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the License). You may not use this file except in
* compliance with the License.
*
* You can obtain a copy of the license at
* https://woodstock.dev.java.net/public/CDDLv1.0.html.
* See the License for the specific language governing
* permissions and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* at https://woodstock.dev.java.net/public/CDDLv1.0.html.
* If applicable, add the following below the CDDL Header,
* with the fields enclosed by brackets [] replaced by
* you own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
*/
package com.sun.webui.jsf.component;
import com.sun.faces.annotation.Component;
import com.sun.faces.annotation.Property;
import com.sun.webui.jsf.util.CookieUtils;
import com.sun.webui.jsf.util.LogUtil;
import com.sun.webui.jsf.util.RenderingUtilities;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.el.MethodExpression;
import javax.el.ValueExpression;
import javax.faces.application.FacesMessage;
import javax.faces.component.EditableValueHolder;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.el.MethodBinding;
import javax.faces.el.ValueBinding;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.FacesEvent;
import javax.faces.event.ValueChangeEvent;
import javax.faces.event.ValueChangeListener;
import javax.faces.validator.Validator;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
/**
* The Tree component is used to display a tree structure in the rendered HTML
* page.
*/
@Component(type = "com.sun.webui.jsf.Tree", family = "com.sun.webui.jsf.Tree",
displayName = "Tree", tagName = "tree",
helpKey = "projrave_ui_elements_palette_wdstk-jsf1.2_tree",
propertiesHelpKey = "projrave_ui_elements_palette_wdstk-jsf1.2_propsheets_tree_props")
public class Tree extends TreeNode implements EditableValueHolder {
private static final long serialVersionUID = -3186310519238174661L;
/**
* Constructor.
*/
public Tree() {
super();
setRendererType("com.sun.webui.jsf.Tree");
}
/**
* Return the family for this component.
*/
@Override
public String getFamily() {
return "com.sun.webui.jsf.Tree";
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Tag attribute methods
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* The component identifier for this component. This value must be unique
* within the closest parent component that is a naming container.
*/
@Property(name = "id")
@Override
public void setId(String id) {
super.setId(id);
}
/**
* Use the rendered attribute to indicate whether the HTML code for the
* component should be included in the rendered HTML page. If set to false,
* the rendered HTML page does not include the HTML for the component. If
* the component is not rendered, it is also not processed on any subsequent
* form submission.
*/
@Property(name = "rendered")
@Override
public void setRendered(boolean rendered) {
super.setRendered(rendered);
}
/**
* The resource at the specified URL is displayed in the frame that is
* specified with the target attribute. Values such as "_blank" that are
* valid for the target attribute of the HTML element are also valid for
* this attribute in the tree components. The target attribute is useful
* only with the url attribute, and does not apply when a facet is used.
*/
@Property(isHidden = true, isAttribute = true)
@Override
public String getTarget() {
return super.getTarget();
}
/**
* Indicates that the text that is specified with the text attribute
* should be rendered as a hyperlink that resolves to the specified URL.
* If the imageURL attribute is used with the url attribute, the image is
* hyperlinked. The url attribute does not apply to facets.
*/
@Property(isHidden = true, isAttribute = true)
@Override
public String getUrl() {
return super.getUrl();
}
/**
* Absolute or relative URL to the image to be rendered for the tree node.
* Note that you cannot use the imageURL to display a theme image in the
* tree. You should use an image facet that contains a ui:image or
* ui:imageHyperlink tag to use a theme image. The imageURL attribute is
* overridden by the image
facet.
* When the imageURL attribute is used with the url attribute, the image
* is hyperlinked.
*/
@Property(isHidden = true, isAttribute = true)
@Override
public String getImageURL() {
return super.getImageURL();
}
/**
* The actionListener attribute is used to specify a method to handle an
* action event that is triggered when a component is activated by the user.
* The actionListener attribute value must be a JavaServer Faces EL
* expression that resolves to a method in a backing bean. The method must
* take a single parameter that is an ActionEvent, and its return type must
* be void
. The class that defines the method must implement
* the java.io.Serializable
interface or
* javax.faces.component.StateHolder
interface.
* In the TreeNode component, the method specified with the actionListener
* atttribute is invoked when the node's handle icon is clicked.
*/
@Property(isHidden = true, isAttribute = true)
@Override
public MethodExpression getActionListenerExpression() {
return super.getActionListenerExpression();
}
/**
* The action attribute is used to specify the action to take when this
* component is activated by the user. The value of the action attribute
* must be one of the following:
*
* - an outcome string, used to indicate which page to display next,
* as defined by a navigation rule in the application configuration
* resource file
(faces-config.xml)
.
*
* - a JavaServer Faces EL expression that resolves to a backing bean
* method. The method must take no parameters and return an outcome string.
* The class that defines the method must implement the
*
java.io.Serializable
interface or
* javax.faces.component.StateHolder
interface.
*
* In the Tree and TreeNode components, the action applies only when
* attributes are used to define the tree and tree nodes. When facets are
* used, the action attribute does not apply to the facets.
*/
@Property(isHidden = true, isAttribute = true)
@Override
public MethodExpression getActionExpression() {
return super.getActionExpression();
}
// Hide expanded
@Property(isHidden = true, isAttribute = false)
@Override
public boolean isExpanded() {
return super.isExpanded();
}
// clientSide
/**
*
* Set the clientSide attribute to true to specify that the Tree component
* should run on the client. By default, this attribute is false, so the
* Tree component interacts
* with the server. In a client-side tree, expanding and collapsing of the
* tree nodes happens only in the browser. In a server-side tree, a request
* is made to the server each time the tree nodes are expanded or collapsed.
* If you use the actionListener attribute to fire events, you must use a
* server side tree so that the event can be processed.
*
*/
@Property(name = "clientSide", displayName = "ClientSide", category = "Behavior")
private boolean clientSide = false;
private boolean clientSide_set = false;
/**
*
* Set the clientSide attribute to true to specify that the Tree component
* should run on the client. By default, this attribute is false, so the
* Tree component interacts
* with the server. In a client-side tree, expanding and collapsing of the
* tree nodes happens only in the browser. In a server-side tree, a request
* is made to the server each time the tree nodes are expanded or collapsed.
* If you use the actionListener attribute to fire events, you must use a
* server side tree so that the event can be processed.
*
*/
public boolean isClientSide() {
if (this.clientSide_set) {
return this.clientSide;
}
ValueExpression _vb = getValueExpression("clientSide");
if (_vb != null) {
Object _result = _vb.getValue(getFacesContext().getELContext());
if (_result == null) {
return false;
} else {
return ((Boolean) _result).booleanValue();
}
}
return false;
}
/**
*
* Set the clientSide attribute to true to specify that the Tree component
* should run on the client. By default, this attribute is false, so the
* Tree component interacts
* with the server. In a client-side tree, expanding and collapsing of the
* tree nodes happens only in the browser. In a server-side tree, a request
* is made to the server each time the tree nodes are expanded or collapsed.
* If you use the actionListener attribute to fire events, you must use a
* server side tree so that the event can be processed.
*
* @see #isClientSide()
*/
public void setClientSide(boolean clientSide) {
this.clientSide = clientSide;
this.clientSide_set = true;
}
// expandOnSelect
/**
* Flag indicating that folder / container nodes will automatically expand
* when they are selected. This attribute is true by default. If you want a tree's container
* nodes to expand only when the handle icons are clicked, set expandOnSelect to false.
*/
@Property(name = "expandOnSelect", displayName = "Expand On Select", category = "Behavior")
private boolean expandOnSelect = false;
private boolean expandOnSelect_set = false;
/**
* Flag indicating that folder / container nodes will automatically expand
* when they are selected. This attribute is true by default. If you want a tree's container
* nodes to expand only when the handle icons are clicked, set expandOnSelect to false.
*/
public boolean isExpandOnSelect() {
if (this.expandOnSelect_set) {
return this.expandOnSelect;
}
ValueExpression _vb = getValueExpression("expandOnSelect");
if (_vb != null) {
Object _result = _vb.getValue(getFacesContext().getELContext());
if (_result == null) {
return false;
} else {
return ((Boolean) _result).booleanValue();
}
}
return true;
}
/**
* Flag indicating that folder / container nodes will automatically expand
* when they are selected. This attribute is true by default. If you want a tree's container
* nodes to expand only when the handle icons are clicked, set expandOnSelect to false.
* @see #isExpandOnSelect()
*/
public void setExpandOnSelect(boolean expandOnSelect) {
this.expandOnSelect = expandOnSelect;
this.expandOnSelect_set = true;
}
// immediate
/**
* Flag indicating that event handling for this component should be
* handled immediately (in Apply Request Values phase) rather than
* waiting until Invoke Application phase.
* May be desired for this component when required is true (although most
* likely not).
*/
@Property(name = "immediate", displayName = "Immediate", category = "Advanced")
private boolean immediate = false;
private boolean immediate_set = false;
/**
* Flag indicating that event handling for this component should be
* handled immediately (in Apply Request Values phase) rather than
* waiting until Invoke Application phase.
* May be desired for this component when required is true (although most
* likely not).
*/
public boolean isImmediate() {
if (this.immediate_set) {
return this.immediate;
}
ValueExpression _vb = getValueExpression("immediate");
if (_vb != null) {
Object _result = _vb.getValue(getFacesContext().getELContext());
if (_result == null) {
return false;
} else {
return ((Boolean) _result).booleanValue();
}
}
return false;
}
/**
* Flag indicating that event handling for this component should be
* handled immediately (in Apply Request Values phase) rather than
* waiting until Invoke Application phase.
* May be desired for this component when required is true (although most
* likely not).
* @see #isImmediate()
*/
public void setImmediate(boolean immediate) {
this.immediate = immediate;
this.immediate_set = true;
}
// required
/**
* Flag indicating that the user must select a value for this tree.
* Default value is false.
*/
@Property(name = "required", displayName = "Required", category = "Behavior")
private boolean required = false;
private boolean required_set = false;
/**
* Flag indicating that the user must select a value for this tree.
* Default value is false.
*/
public boolean isRequired() {
if (this.required_set) {
return this.required;
}
ValueExpression _vb = getValueExpression("required");
if (_vb != null) {
Object _result = _vb.getValue(getFacesContext().getELContext());
if (_result == null) {
return false;
} else {
return ((Boolean) _result).booleanValue();
}
}
return false;
}
/**
* Flag indicating that the user must select a value for this tree.
* Default value is false.
* @see #isRequired()
*/
public void setRequired(boolean required) {
this.required = required;
this.required_set = true;
}
// style
/**
* CSS style(s) to be applied to the outermost HTML element when this
* component is rendered.
*/
@Property(name = "style", displayName = "CSS Style(s)", category = "Appearance",
editorClassName = "com.sun.jsfcl.std.css.CssStylePropertyEditor")
private String style = null;
/**
* CSS style(s) to be applied to the outermost HTML element when this
* component is rendered.
*/
@Override
public String getStyle() {
if (this.style != null) {
return this.style;
}
ValueExpression _vb = getValueExpression("style");
if (_vb != null) {
return (String) _vb.getValue(getFacesContext().getELContext());
}
return null;
}
/**
* CSS style(s) to be applied to the outermost HTML element when this
* component is rendered.
* @see #getStyle()
*/
@Override
public void setStyle(String style) {
this.style = style;
}
// styleClass
/**
* CSS style class(es) to be applied to the outermost HTML element when this
* component is rendered.
*/
@Property(name = "styleClass", displayName = "CSS Style Class(es)", category = "Appearance",
editorClassName = "com.sun.rave.propertyeditors.StyleClassPropertyEditor")
private String styleClass = null;
/**
* CSS style class(es) to be applied to the outermost HTML element when this
* component is rendered.
*/
@Override
public String getStyleClass() {
if (this.styleClass != null) {
return this.styleClass;
}
ValueExpression _vb = getValueExpression("styleClass");
if (_vb != null) {
return (String) _vb.getValue(getFacesContext().getELContext());
}
return null;
}
/**
* CSS style class(es) to be applied to the outermost HTML element when this
* component is rendered.
* @see #getStyleClass()
*/
@Override
public void setStyleClass(String styleClass) {
this.styleClass = styleClass;
}
// visible
/**
* Use the visible attribute to indicate whether the component should be
* viewable by the user in the rendered HTML page. If set to false, the
* HTML code for the component is present in the page, but the component
* is hidden with style attributes. By default, visible is set to true, so
* HTML for the component HTML is included and visible to the user. If the
* component is not visible, it can still be processed on subsequent form
* submissions because the HTML is present.
*/
@Property(name = "visible", displayName = "Visible", category = "Behavior")
private boolean visible = false;
private boolean visible_set = false;
/**
* Use the visible attribute to indicate whether the component should be
* viewable by the user in the rendered HTML page. If set to false, the
* HTML code for the component is present in the page, but the component
* is hidden with style attributes. By default, visible is set to true, so
* HTML for the component HTML is included and visible to the user. If the
* component is not visible, it can still be processed on subsequent form
* submissions because the HTML is present.
*/
@Override
public boolean isVisible() {
if (this.visible_set) {
return this.visible;
}
ValueExpression _vb = getValueExpression("visible");
if (_vb != null) {
Object _result = _vb.getValue(getFacesContext().getELContext());
if (_result == null) {
return false;
} else {
return ((Boolean) _result).booleanValue();
}
}
return true;
}
/**
* Use the visible attribute to indicate whether the component should be
* viewable by the user in the rendered HTML page. If set to false, the
* HTML code for the component is present in the page, but the component
* is hidden with style attributes. By default, visible is set to true, so
* HTML for the component HTML is included and visible to the user. If the
* component is not visible, it can still be processed on subsequent form
* submissions because the HTML is present.
* @see #isVisible()
*/
@Override
public void setVisible(boolean visible) {
this.visible = visible;
this.visible_set = true;
}
/**
* This component renders its children
*/
@Override
public boolean getRendersChildren() {
return true;
}
/**
* Returns the id of the selected tree node. Should be cast to a String and
* nothing else.
*/
@Property(name = "selected", displayName = "Selected", category = "Data",
editorClassName = "com.sun.webui.jsf.component.propertyeditors.TreeNodeIdsEditor")
public String getSelected() {
return (String) getValue();
}
/**
* Specify the id of the selected tree node. Should specify a String object.
* Also note that this should NOT be the client ID of the selected node.
* @see #getSelected()
*/
public void setSelected(String selected) {
if (selected == null || selected.length() == 0) {
FacesContext context = FacesContext.getCurrentInstance();
Cookie cookie = CookieUtils.getCookieValue(context,
getClientId(context) + COOKIE_SUFFIX);
if (cookie != null) {
if (!RenderingUtilities.isPortlet(context)) {
ExternalContext extCtx = context.getExternalContext();
HttpServletResponse res =
(HttpServletResponse) extCtx.getResponse();
cookie.setMaxAge(0);
cookie.setPath("/");
res.addCookie(cookie);
setValue(null);
}
}
}
setValue(selected);
}
/**
* Return the ValueExpression
stored for the
* specified name (if any), respecting any property aliases.
*
* @param name Name of value binding to retrieve
*/
@Override
public ValueExpression getValueExpression(String name) {
if (name.equals("selected")) {
return super.getValueExpression("value");
}
return super.getValueExpression(name);
}
/**
* Set the ValueExpression
stored for the
* specified name (if any), respecting any property
* aliases.
*
* @param name Name of value binding to set
* @param binding ValueBinding to set, or null to remove
*/
@Override
public void setValueExpression(String name, ValueExpression binding) {
if (name.equals("selected")) {
super.setValueExpression("value", binding);
return;
}
super.setValueExpression(name, binding);
}
//////////////////////////////////////////////////////////////////////
// ValueHolder Methods
//////////////////////////////////////////////////////////////////////
/**
* Return the Converter
(if any) that is registered for
* this UIComponent
.
*
* Not implemented for this component.
*/
public Converter getConverter() {
return converter;
}
/**
* Set the Converter
(if any) that is registered for
* this UIComponent
.
*
* Not implemented for this component.
*
* @param conv New Converter
(or null
)
*/
public void setConverter(Converter conv) {
converter = conv;
// Do nothing... throw exception?
}
/**
* Return the local value of this UIComponent
(if any),
* without evaluating any associated ValueBinding
.
*/
public Object getLocalValue() {
return value;
}
/**
* Gets the value of this UIComponent
. First, consult the
* local value property of this component. If non-null
* return it. If non-null, see if we have a ValueBinding
* for the value
property. If so, return the result of
* evaluating the property, otherwise return null.
*/
public Object getValue() {
if (value != null) {
return value;
}
ValueExpression _vb = getValueExpression("value");
if (_vb != null) {
Object _result = _vb.getValue(getFacesContext().getELContext());
return _result;
}
return null;
}
/**
* Set the value of this UIComponent
(if any).
*
* @param val The new local value
*/
public void setValue(Object val) {
value = val;
// Mark the local value as set.
setLocalValueSet(true);
}
//////////////////////////////////////////////////////////////////////
// EditableValueHolder Methods
//////////////////////////////////////////////////////////////////////
/**
* Return the submittedValue value of this component. This method
* should only be used by the encodeBegin()
and/or
* encodeEnd()
methods of this component, or its
* corresponding Renderer
.
*/
public Object getSubmittedValue() {
return submittedValue;
}
/**
* Set the submittedValue value of this component. This method should
* only be used by the decode()
and
* validate()
method of this component, or its
* corresponding Renderer
.
*
* @param value The new submitted value.
*/
public void setSubmittedValue(Object value) {
submittedValue = value;
}
/**
* Return the "local value set" state for this component. Calls to
* setValue()
automatically reset this property to
* true
.
*/
public boolean isLocalValueSet() {
return localValueSet;
}
/**
*
Sets the "local value set" state for this component.
*/
public void setLocalValueSet(boolean value) {
localValueSet = value;
}
/**
* Return a flag indicating whether the local value of this component
* is valid (no conversion error has occurred).
*/
public boolean isValid() {
return valid;
}
/**
* Set a flag indicating whether the local value of this component
* is valid (no conversion error has occurred).
*
* @param value The new valid flag.
*/
public void setValid(boolean value) {
valid = value;
}
/**
* Return a MethodBinding
pointing at a method that will
* be used to validate the current value of this component. This
* method will be called during the Process Validations or
* Apply Request Values phases (depending on the value of
* the immediate
property).
*
* Not implemented for this component.
*/
public MethodBinding getValidator() {
return validatorBinding;
}
/**
* Set a MethodBinding
pointing at a method that will be
* used to validate the current value of this component. This method
* will be called during the Process Validations or
* Apply Request Values phases (depending on the value of
* the immediate
property).
*
* Any method referenced by such an expression must be public, with a
* return type of void
, and accept parameters of type
* FacesContext
, UIComponent
, and
* Object
.
*
* Not implemented for this component.
*
* @param valBinding The new MethodBinding
instance.
*/
public void setValidator(MethodBinding valBinding) {
validatorBinding = valBinding;
}
/**
* Add a Validator
instance to the set associated with
* this component.
*
* Not implemented for this component.
*
* @param validator The Validator
to add.
*/
public void addValidator(Validator validator) {
if (validator == null) {
throw new NullPointerException();
}
if (validators == null) {
validators = new ArrayList();
}
validators.add(validator);
}
/**
* Return the set of registered Validator
s for this
* component instance. If there are no registered validators, a
* zero-length array is returned.
*
* Not implemented for this component.
*/
public Validator[] getValidators() {
if (validators == null) {
return (new Validator[0]);
}
return ((Validator[]) validators.toArray(
new Validator[validators.size()]));
}
/**
* Remove a Validator
instance from the set associated
* with this component, if it was previously associated. Otherwise,
* do nothing.
*
* Not implemented for this component.
*
* @param validator The Validator
to remove.
*/
public void removeValidator(Validator validator) {
if (validators != null) {
validators.remove(validator);
}
}
/**
* Return a MethodBinding
instance method that will be
* called after any registered ValueChangeListener
s have
* been notified of a value change. This method will be called during
* the Process Validations or Apply Request Values
* phases (depending on the value of the immediate
* property).
*/
public MethodBinding getValueChangeListener() {
return valueChangeMethod;
}
/**
* Set a MethodBinding
instance method that will be
* called after any registered ValueChangeListener
s have
* been notified of a value change. This method will be called
* during the Process Validations or Apply Request
* Values phases (depending on the value of the
* immediate
property).
*
* @param method The new MethodBinding instance.
*/
public void setValueChangeListener(MethodBinding method) {
valueChangeMethod = method;
}
/**
* Add a new ValueChangeListener
to the set of listeners
* interested in being notified when ValueChangeEvent
s
* occur.
*
* @param listener The ValueChangeListener
to be added.
*/
public void addValueChangeListener(ValueChangeListener listener) {
addFacesListener(listener);
}
/**
* Return the set of registered ValueChangeListener
s for
* this component instance. If there are no registered listeners, a
* zero-length array is returned.
*/
public ValueChangeListener[] getValueChangeListeners() {
return (ValueChangeListener[]) getFacesListeners(ValueChangeListener.class);
}
/**
* Remove an existing ValueChangeListener
(if any) from
* the set of listeners interested in being notified when
* ValueChangeEvent
s occur.
*
* @param listener The ValueChangeListener
to be removed.
*/
public void removeValueChangeListener(ValueChangeListener listener) {
removeFacesListener(listener);
}
//////////////////////////////////////////////////////////////////////
// Other Methods
//////////////////////////////////////////////////////////////////////
/**
* Decode any new state of this UIComponent
from the
* request contained in the specified FacesContext
, and
* store this state as needed.
*
* During decoding, events may be enqueued for later processing (by
* event listeners who have registered an interest), by calling
* queueEvent()
.
*
* @param context {@link FacesContext} for the request we are processing.
*/
@Override
public void decode(FacesContext context) {
setValid(true);
super.decode(context);
}
/**
* In addition to to the default UIComponent#broadcast
* processing, pass the ValueChangeEvent
being broadcast
* to the method referenced by valueChangeListener
.
*
* @param event FacesEvent
to be broadcast
*
* @exception AbortProcessingException Signal the JSF implementation
* that no further processing on the current event should be performed
*/
@Override
public void broadcast(FacesEvent event) throws AbortProcessingException {
// Perform standard superclass processing
super.broadcast(event);
if (event instanceof ValueChangeEvent) {
MethodBinding method = getValueChangeListener();
if (method != null) {
FacesContext context = getFacesContext();
method.invoke(context, new Object[]{event});
}
}
}
/**
* Perform the component tree processing required by the Update
* Model Values phase of the request processing lifecycle for
* all facets of this component, all children of this component,
* and this component itself, as follows.
*
* - If the
rendered
property of this
* UIComponent
is false
, skip
* further processing.
* - Call the
processUpdates()
method of all
* facets and children of this UIComponent
, in the
* order determined by a call to
* getFacetsAndChildren()
.
*
* @param context FacesContext
for this request
*/
@Override
public void processUpdates(FacesContext context) {
// Skip processing if our rendered flag is false
if (!isRendered()) {
return;
}
// Do the super stuff...
super.processUpdates(context);
// Save model stuff...
try {
updateModel(context);
} catch (RuntimeException ex) {
context.renderResponse();
throw new RuntimeException(ex);
}
}
/**
* Perform the following algorithm to update the model data
* associated with this component, if any, as appropriate.
*
* - If the
valid
property of this component is
* false
, take no further action.
* - If the
localValueSet
property of this
* component is false
, take no further action.
* - If no
ValueBinding
for value
* exists, take no further action.
* - Call
setValue()
method of the
* ValueBinding
to update the value that the
* ValueBinding
points at.
* - If the
setValue()
method returns successfully:
* - Clear the local value of this component.
* - Set the
localValueSet
property of
* this component to false.
* - If the
setValue()
method call fails:
* - Queue an error message by calling
*
addMessage()
on the specified
* FacesContext
instance.
* - Set the
valid
property of this
* component to false
.
*
*
* @param context FacesContext
for the request we are
* processing.
*/
public void updateModel(FacesContext context) {
// Sanity Checks...
if (context == null) {
throw new NullPointerException();
}
if (!isValid() || !isLocalValueSet()) {
return;
}
ValueBinding vb = getValueBinding("value");
if (vb == null) {
return;
}
try {
vb.setValue(context, getLocalValue());
setValue(null);
setLocalValueSet(false);
return;
} catch (Exception ex) {
String messageStr = ex.getMessage();
if (messageStr != null) {
FacesMessage message = null;
message = new FacesMessage(messageStr);
message.setSeverity(FacesMessage.SEVERITY_ERROR);
context.addMessage(getClientId(context), message);
}
setValid(false);
if (LogUtil.configEnabled()) {
LogUtil.config("Unable to update Model!", ex); // NOI18N
}
}
}
/**
* Perform the component tree processing required by the Apply
* Request Values phase of the request processing lifecycle for
* all facets of this component, all children of this component, and
* this component itself, as follows.
*
* - If the
rendered
property of this
* UIComponent
is false
, skip
* further processing.
* - Call the
processDecodes()
method of all
* facets and children of this UIComponent
, in the
* order determined by a call to
* getFacetsAndChildren()
.
* - Call the
decode()
method of this
* component.
* - If a
RuntimeException
is thrown during decode
* processing, call FacesContext.renderResponse
* and re-throw the exception.
*
* @param context FacesContext
for the request.
*/
@Override
public void processDecodes(FacesContext context) {
// Skip processing if our rendered flag is false
if (!isRendered()) {
return;
}
super.processDecodes(context);
if (isImmediate()) {
executeValidate(context);
}
}
/**
* In addition to the standard processValidators
behavior
* inherited from UIComponentBases
, calls
* validate()
if the immediate
property is
* false (which is the default); if the component is invalid
* afterwards, calls FacesContext.renderResponse
. If a
* RuntimeException
is thrown during validation
* processing, calls FacesContext.renderResponse
and
* re-throws the exception.
*/
@Override
public void processValidators(FacesContext context) {
if (context == null) {
throw new NullPointerException();
}
// Skip processing if our rendered flag is false
if (!isRendered()) {
return;
}
super.processValidators(context);
if (!isImmediate()) {
executeValidate(context);
}
}
/**
* Executes validation logic.
*/
private void executeValidate(FacesContext context) {
try {
validate(context);
} catch (RuntimeException e) {
context.renderResponse();
throw e;
}
if (!isValid()) {
context.renderResponse();
}
}
/**
* Perform the following algorithm to validate the local value of
* this UIInput
.
*
* - Retrieve the submitted value with
*
getSubmittedValue()
. If this returns null,
* exit without further processing. (This indicates that no
* value was submitted for this component.)
*
* - Convert the submitted value into a "local value" of the
* appropriate data type by calling
*
getConvertedValue
.
*
* - Validate the property by calling
*
validateValue
.
*
* - If the
valid
property of this component is
* still true
, retrieve the previous value of
* the component (with getValue()
), store the new
* local value using setValue()
, and reset the
* submitted value to null. If the local value is different
* from the previous value of this component, fire a
* ValueChangeEvent
to be broadcast to all
* interested listeners.
*
* @param context FacesContext
for the current request.
*/
public void validate(FacesContext context) {
if (context == null) {
throw new NullPointerException();
}
// Submitted value == null means "the component was not submitted
// at all"; validation should not continue
Object submittedValue = getSubmittedValue();
if (submittedValue == null) {
return;
}
Object newValue = submittedValue;
/*
FIXME: Decide if we ever want to the Tree to support Converters
try {
newValue = getConvertedValue(context, submittedValue);
}
catch (ConverterException ce) {
addConversionErrorMessage(context, ce, submittedValue);
setValid(false);
}
*/
// Validate the value (check for required for now)
validateValue(context, newValue);
// If our value is valid, store the new value, erase the
// "submitted" value, and emit a ValueChangeEvent if appropriate
if (isValid()) {
Object previous = getValue();
setValue(newValue);
setSubmittedValue(null);
if (isDifferent(previous, newValue)) {
queueEvent(new ValueChangeEvent(this, previous, newValue));
}
}
}
/**
* Return true
if the objects are not equal.
*
* @param val1 Value 1
* @param val1 Value 2
*
* @return true if the 2 values are not equal
*/
protected boolean isDifferent(Object val1, Object val2) {
if (val1 == val2) {
// Same object, they're equal
return false;
}
if (val1 == null) {
// Not equal, and one is null
return true;
}
return !val1.equals(val2);
}
protected void validateValue(FacesContext context, Object newValue) {
if (!isValid()) {
return;
}
if (isRequired() && ((newValue == null) || (newValue.toString().trim().equals("")))) {
// FIXME: Add a message
// FacesMessage message =
// message.setSeverity(FacesMessage.SEVERITY_ERROR);
// context.addMessage(getClientId(context), message);
setValid(false);
}
// FIXME: Decide if we ever want to the Tree to support Validators (See UIInput)
}
/**
* This method accepts the {@link TreeNode} which is to be selected.
* The previous {@link TreeNode} that was selected will unselected.
* No state is saved with this operation, the state is maintained on
* the client.
*
* @deprecated Use #setValue(Object)
*
* @param treeNode The {@link TreeNode} to be selected.
*/
public void selectTreeNode(TreeNode treeNode) {
setSelected(treeNode.getId());
// selectTreeNode(treeNode.getClientId(FacesContext.getCurrentInstance()));
}
/**
* This method accepts the clientId of a {@link TreeNode} which is to
* be selected. The previous {@link TreeNode} that was selected will
* unselected. No state is saved with this operation, the state is
* maintained on the client-side.
*
* @deprecated Use #setValue(Object)
*
* @param id The id of the {@link TreeNode} to be selected.
*/
public void selectTreeNode(String id) {
setSelected(id);
}
/**
* This method returns the {@link TreeNode} client ID that is
* selected according the browser cookie. This method is generally
* only useful during the decode process.
*
* @return The selected tree node (according to the cookie).
*/
public String getCookieSelectedTreeNode() {
FacesContext context = FacesContext.getCurrentInstance();
// If look at cookies...
Cookie cookie = CookieUtils.getCookieValue(context,
getClientId(context) + COOKIE_SUFFIX);
if (cookie != null) {
return cookie.getValue();
}
// Not found, return null
return null;
}
/**
* This method will return the {@link TreeNode} client ID that is
* selected according the browser cookie. This method is only
* useful during the decode process as the cookie will typically be
* reset to null immediately after the request is processed.
*
* @return The selected tree node (according to the cookie).
*/
public String getCookieExpandNode() {
FacesContext context = FacesContext.getCurrentInstance();
Cookie cookie = CookieUtils.getCookieValue(context,
getClientId(context) + COOKIE_SUFFIX_EXPAND);
if (cookie != null) {
return cookie.getValue();
}
// Not found, return null
return null;
}
//////////////////////////////////////////////////////////////////////
// ValueHolder Methods
//////////////////////////////////////////////////////////////////////
/**
*
*/
@Override
public Object saveState(FacesContext context) {
Object _values[] = new Object[20];
_values[0] = super.saveState(context);
_values[1] = this.clientSide ? Boolean.TRUE : Boolean.FALSE;
_values[2] = this.clientSide_set ? Boolean.TRUE : Boolean.FALSE;
_values[3] = this.expandOnSelect ? Boolean.TRUE : Boolean.FALSE;
_values[4] = this.expandOnSelect_set ? Boolean.TRUE : Boolean.FALSE;
_values[5] = this.immediate ? Boolean.TRUE : Boolean.FALSE;
_values[6] = this.immediate_set ? Boolean.TRUE : Boolean.FALSE;
_values[7] = this.required ? Boolean.TRUE : Boolean.FALSE;
_values[8] = this.required_set ? Boolean.TRUE : Boolean.FALSE;
_values[9] = this.style;
_values[10] = this.styleClass;
_values[11] = this.visible ? Boolean.TRUE : Boolean.FALSE;
_values[12] = this.visible_set ? Boolean.TRUE : Boolean.FALSE;
_values[13] = saveAttachedState(context, converter);
_values[14] = this.value;
_values[15] = localValueSet ? Boolean.TRUE : Boolean.FALSE;
_values[16] = this.valid ? Boolean.TRUE : Boolean.FALSE;
_values[17] = saveAttachedState(context, validators);
_values[18] = saveAttachedState(context, validatorBinding);
_values[19] = saveAttachedState(context, valueChangeMethod);
return (_values);
}
/**
* Restore the state of this component.
*/
@Override
public void restoreState(FacesContext _context, Object _state) {
Object _values[] = (Object[]) _state;
super.restoreState(_context, _values[0]);
this.clientSide = ((Boolean) _values[1]).booleanValue();
this.clientSide_set = ((Boolean) _values[2]).booleanValue();
this.expandOnSelect = ((Boolean) _values[3]).booleanValue();
this.expandOnSelect_set = ((Boolean) _values[4]).booleanValue();
this.immediate = ((Boolean) _values[5]).booleanValue();
this.immediate_set = ((Boolean) _values[6]).booleanValue();
this.required = ((Boolean) _values[7]).booleanValue();
this.required_set = ((Boolean) _values[8]).booleanValue();
this.style = (String) _values[9];
this.styleClass = (String) _values[10];
this.visible = ((Boolean) _values[11]).booleanValue();
this.visible_set = ((Boolean) _values[12]).booleanValue();
converter = (Converter) restoreAttachedState(_context, _values[13]);
this.value = _values[14];
localValueSet = ((Boolean) _values[15]).booleanValue();
valid = ((Boolean) _values[16]).booleanValue();
List restoredValidators = null;
Iterator iter = null;
if (null != (restoredValidators = (List) restoreAttachedState(_context, _values[17]))) {
// if there were some validators registered prior to this
// method being invoked, merge them with the list to be
// restored.
if (null != validators) {
iter = restoredValidators.iterator();
while (iter.hasNext()) {
validators.add(iter.next());
}
} else {
validators = restoredValidators;
}
}
validatorBinding = (MethodBinding) restoreAttachedState(_context,
_values[18]);
valueChangeMethod = (MethodBinding) restoreAttachedState(_context,
_values[19]);
}
/**
* Converter.
*/
private Converter converter = null;
/**
* The set of {@link Validator}s associated with this
* UIComponent
.
*/
private List validators = null;
/**
*
*/
private MethodBinding validatorBinding = null;
/**
* The submittedValue value of this component.
*/
private Object submittedValue = null;
/**
* Toggle indicating validity of this component.
*/
private boolean valid = true;
/**
* The "localValueSet" state for this component.
*/
private boolean localValueSet;
/**
* The "valueChange" MethodBinding for this component.
*/
private MethodBinding valueChangeMethod = null;
/**
*
The value of the Tree
. This should be a String
* representing the client id of the selected
* TreeNode
.
*/
private Object value = null;
/**
* This is the {@link com.sun.webui.theme.Theme} key used to retrieve
* the JavaScript needed for this component.
*
* @see com.sun.webui.theme.Theme#getPathToJSFile(String)
*/
public static final String JAVA_SCRIPT_THEME_KEY = "tree";
/**
* This is the suffix appended to the client id when forming a request
* attribute key. The value associated with the generated key
* indicates which node should be selected. The renderer uses this
* information to generate JavaScript to select this node, overriding
* the previous selection.
*/
public static final String SELECTED_SUFFIX = "_select";
/**
* This is the suffix appended to the client id to form the key to the
* cookie Map needed to retrieve the tree selection.
*/
public static final String COOKIE_SUFFIX = "-hi";
/**
* This is the suffix appended to the client id to form the key to the
* cookie Map needed to retrieve the node that may need to be
* expanded (because it was just selected).
*/
public static final String COOKIE_SUFFIX_EXPAND = "-expand";
/**
* String constant representing the content facet name.
*/
public static final String TREE_CONTENT_FACET_NAME = "content";
/**
* String constant representing the image facet name.
*/
public static final String TREE_IMAGE_FACET_NAME = "image";
}