Java tutorial
/** * License Agreement. * * Rich Faces - Natural Ajax for Java Server Faces (JSF) * * Copyright (C) 2007 Exadel, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package org.richfaces.component; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.el.ValueExpression; import javax.faces.FacesException; import javax.faces.application.Application; import javax.faces.application.FacesMessage; import javax.faces.component.EditableValueHolder; import javax.faces.component.UIComponent; import javax.faces.component.UIComponentBase; import javax.faces.component.UIInput; import javax.faces.context.FacesContext; import javax.faces.convert.Converter; import javax.faces.convert.ConverterException; import javax.faces.el.EvaluationException; import javax.faces.el.MethodBinding; import javax.faces.model.ArrayDataModel; import javax.faces.model.DataModel; import javax.faces.model.ListDataModel; import javax.faces.validator.Validator; import javax.faces.validator.ValidatorException; import org.ajax4jsf.component.UIDataAdaptor; import org.ajax4jsf.model.DataComponentState; import org.ajax4jsf.model.RepeatState; import org.ajax4jsf.util.ELUtils; import org.apache.commons.collections.Predicate; import org.apache.commons.collections.iterators.EmptyIterator; import org.apache.commons.collections.iterators.FilterIterator; import org.richfaces.component.util.MessageUtil; /** * @author Nick Belaevski * mailto:nbelaevski@exadel.com * created 16.11.2007 * @since 3.2 */ public abstract class UIOrderingBaseComponent extends UIDataAdaptor implements EditableValueHolder { private boolean localValueSet; private List validators = null; private MethodBinding validator; public static final Predicate isColumn = new Predicate() { public boolean evaluate(Object input) { return (input instanceof javax.faces.component.UIColumn || input instanceof Column) && ((UIComponent) input).isRendered(); } }; protected boolean isSuitableValue(Object value, Object restoredObject) { if (value instanceof Object[]) { Object[] objects = (Object[]) value; for (int i = 0; i < objects.length; i++) { Object object = objects[i]; if (object != null && object.equals(restoredObject)) { return true; } } return false; } else { if (value != null) { return ((Collection) value).contains(restoredObject); } else { return false; } } } public abstract boolean isOrderControlsVisible(); public abstract void setOrderControlsVisible(boolean visible); public abstract boolean isFastOrderControlsVisible(); public abstract void setFastOrderControlsVisible(boolean visible); public abstract String getRequiredMessage(); public abstract void setRequiredMessage(String requiredMessage); public Object saveState(FacesContext faces) { Object[] state = new Object[4]; state[0] = super.saveState(faces); state[1] = saveAttachedState(faces, validators); state[2] = saveAttachedState(faces, validator); state[3] = localValueSet ? Boolean.TRUE : Boolean.FALSE; return state; } public void restoreState(FacesContext faces, Object object) { Object[] state = (Object[]) object; super.restoreState(faces, state[0]); validators = (List) restoreAttachedState(faces, state[1]); validator = (MethodBinding) restoreAttachedState(faces, state[2]); localValueSet = ((Boolean) state[3]).booleanValue(); } protected DataComponentState createComponentState() { return new RepeatState(); } public Iterator columns() { return new FilterIterator(getChildren().iterator(), isColumn); } protected Iterator dataChildren() { if (getChildCount() != 0) { return columns(); } else { return EmptyIterator.INSTANCE; } } protected Iterator fixedChildren() { Map facets = getFacets(); if (facets != null) { return facets.values().iterator(); } else { return EmptyIterator.INSTANCE; } } //validators public MethodBinding getValidator() { return validator; } public void setValidator(MethodBinding validatorBinding) { this.validator = validatorBinding; } public Validator[] getValidators() { if (validators == null) { return new Validator[0]; } else { return (Validator[]) validators.toArray(new Validator[validators.size()]); } } public void addValidator(Validator validator) { if (validator == null) { throw new NullPointerException(); } if (validators == null) { validators = new ArrayList(); } validators.add(validator); } public void removeValidator(Validator validator) { if (validators != null) { validators.remove(validator); } } //validators end public boolean isLocalValueSet() { return localValueSet; } public void setLocalValueSet(boolean localValueSet) { this.localValueSet = localValueSet; } protected DataModel createDataModel(Object value) { DataModel dataModel; if (value == null) { dataModel = new ListDataModel(Collections.EMPTY_LIST); } else if (value instanceof List) { dataModel = new ListDataModel((List) value); } else if (Object[].class.isAssignableFrom(value.getClass())) { dataModel = new ArrayDataModel((Object[]) value); } else { throw new IllegalArgumentException(); } return dataModel; } /** * @exception NullPointerException {@inheritDoc} */ public void decode(FacesContext context) { if (context == null) { throw new NullPointerException(); } // Force validity back to "true" setValid(true); super.decode(context); } /** * <p>Specialized decode behavior on top of that provided by the * superclass. In addition to the standard * <code>processDecodes</code> behavior inherited from {@link * UIComponentBase}, calls <code>validate()</code> if the the * <code>immediate</code> property is true; if the component is * invalid afterwards or a <code>RuntimeException</code> is thrown, * calls {@link FacesContext#renderResponse}. </p> * @exception NullPointerException {@inheritDoc} */ public void processDecodes(FacesContext context) { if (context == null) { throw new NullPointerException(); } // Skip processing if our rendered flag is false if (!isRendered()) { return; } super.processDecodes(context); if (isImmediate()) { executeValidate(context); } } /** * Executes validation logic. */ protected void executeValidate(FacesContext context) { try { validate(context); } catch (RuntimeException e) { context.renderResponse(); throw e; } if (!isValid()) { context.renderResponse(); } } public abstract void validate(FacesContext context); /** * <p>In addition to the standard <code>processValidators</code> behavior * inherited from {@link UIComponentBase}, calls <code>validate()</code> * if the <code>immediate</code> property is false (which is the * default); if the component is invalid afterwards, calls * {@link FacesContext#renderResponse}. * If a <code>RuntimeException</code> is thrown during * validation processing, calls {@link FacesContext#renderResponse} * and re-throw the exception. * </p> * @exception NullPointerException {@inheritDoc} */ 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); } } protected void requiredInvalidate(FacesContext context) { String requiredMessage = getRequiredMessage(); FacesMessage message = null; if (requiredMessage != null) { message = new FacesMessage(FacesMessage.SEVERITY_ERROR, requiredMessage, requiredMessage); } else { message = MessageUtil.getMessage(context, UIInput.REQUIRED_MESSAGE_ID, new Object[] { MessageUtil.getLabel(context, this) }); message.setSeverity(FacesMessage.SEVERITY_ERROR); } context.addMessage(getClientId(context), message); setValid(false); } protected void validateValue(FacesContext context, Object newValue) { Validator[] validators = getValidators(); for (int i = 0; i < validators.length; i++) { Validator validator = (Validator) validators[i]; try { validator.validate(context, this, newValue); } catch (ValidatorException ve) { // If the validator throws an exception, we're // invalid, and we need to add a message setValid(false); FacesMessage message = ve.getFacesMessage(); if (message != null) { message.setSeverity(FacesMessage.SEVERITY_ERROR); context.addMessage(getClientId(context), message); } } } MethodBinding validator = getValidator(); if (validator != null) { try { validator.invoke(context, new Object[] { context, this, newValue }); } catch (EvaluationException ee) { if (ee.getCause() instanceof ValidatorException) { ValidatorException ve = (ValidatorException) ee.getCause(); // If the validator throws an exception, we're // invalid, and we need to add a message setValid(false); FacesMessage message = ve.getFacesMessage(); if (message != null) { message.setSeverity(FacesMessage.SEVERITY_ERROR); context.addMessage(getClientId(context), message); } } else { // Otherwise, rethrow the EvaluationException throw ee; } } } } /** * <p>In addition to the standard <code>processUpdates</code> behavior * inherited from {@link UIComponentBase}, calls * <code>updateModel()</code>. * If the component is invalid afterwards, calls * {@link FacesContext#renderResponse}. * If a <code>RuntimeException</code> is thrown during * update processing, calls {@link FacesContext#renderResponse} * and re-throw the exception. * </p> * @exception NullPointerException {@inheritDoc} */ public void processUpdates(FacesContext context) { if (context == null) { throw new NullPointerException(); } // Skip processing if our rendered flag is false if (!isRendered()) { return; } super.processUpdates(context); try { updateModel(context); } catch (RuntimeException e) { context.renderResponse(); throw e; } if (!isValid()) { context.renderResponse(); } } public abstract void updateModel(FacesContext context); protected interface UpdateModelCommand { public void execute(FacesContext context); } protected interface DataAdder { Object getContainer(); void add(Object object); } protected void updateModel(FacesContext context, UpdateModelCommand command) { try { command.execute(context); } catch (EvaluationException e) { String messageStr = e.getMessage(); FacesMessage message = null; if (null == messageStr) { message = MessageUtil.getMessage(context, UIInput.UPDATE_MESSAGE_ID, new Object[] { MessageUtil.getLabel(context, this) }); } else { message = new FacesMessage(messageStr); } message.setSeverity(FacesMessage.SEVERITY_ERROR); context.addMessage(getClientId(context), message); setValid(false); } catch (FacesException e) { FacesMessage message = MessageUtil.getMessage(context, UIInput.UPDATE_MESSAGE_ID, new Object[] { MessageUtil.getLabel(context, this) }); message.setSeverity(FacesMessage.SEVERITY_ERROR); context.addMessage(getClientId(context), message); setValid(false); } catch (IllegalArgumentException e) { FacesMessage message = MessageUtil.getMessage(context, UIInput.UPDATE_MESSAGE_ID, new Object[] { MessageUtil.getLabel(context, this) }); message.setSeverity(FacesMessage.SEVERITY_ERROR); context.addMessage(getClientId(context), message); setValid(false); } catch (Exception e) { FacesMessage message = MessageUtil.getMessage(context, UIInput.UPDATE_MESSAGE_ID, new Object[] { MessageUtil.getLabel(context, this) }); message.setSeverity(FacesMessage.SEVERITY_ERROR); context.addMessage(getClientId(context), message); setValid(false); } } /** * <p>Return <code>true</code> if the new value is different from the * previous value.</p> * * @param previous old value of this component (if any) * @param value new value of this component (if any) */ protected boolean compareValues(Object previous, Object value) { if (previous == null) { return (value != null); } else if (value == null) { return (true); } else { if (previous instanceof Object[]) { return !Arrays.equals((Object[]) previous, (Object[]) value); } else { return (!(previous.equals(value))); } } } protected void addConversionErrorMessage(FacesContext context, ConverterException ce, Object value) { FacesMessage message = ce.getFacesMessage(); if (message == null) { message = MessageUtil.getMessage(context, UIInput.CONVERSION_MESSAGE_ID, new Object[] { MessageUtil.getLabel(context, this) }); if (message.getDetail() == null) { message.setDetail(ce.getMessage()); } } message.setSeverity(FacesMessage.SEVERITY_ERROR); context.addMessage(getClientId(context), message); } protected boolean isEmpty(Object value) { if (value == null) { return (true); } else if ((value instanceof String) && (((String) value).length() < 1)) { return (true); } else if (value.getClass().isArray()) { if (0 == java.lang.reflect.Array.getLength(value)) { return (true); } } else if (value instanceof List) { if (0 == ((List) value).size()) { return (true); } } return (false); } protected Object createContainer(ArrayList data, Object object) { if (object != null) { Class objectClass = object.getClass(); Class componentType = objectClass.getComponentType(); if (componentType != null) { return data.toArray((Object[]) Array.newInstance(componentType, data.size())); } } data.trimToSize(); return data; } public abstract ItemState getItemState(); public interface ItemState { public boolean isSelected(); public boolean isActive(); } private Converter getConverterForType(FacesContext context, Class type) { if (!Object.class.equals(type) && type != null) { Application application = context.getApplication(); return application.createConverter(type); } return null; } private static final Converter noOpConverter = new Converter() { public Object getAsObject(FacesContext context, UIComponent component, String value) { return value; } public String getAsString(FacesContext context, UIComponent component, Object value) { return (String) value; } }; public Converter getConverterForValue(FacesContext context) { Converter converter = null; ValueExpression expression = this.getValueExpression("value"); if (expression != null) { Class<?> containerClass = ELUtils.getContainerClass(context, expression); converter = getConverterForType(context, containerClass); if (converter == null && String.class.equals(containerClass)) { converter = noOpConverter; } } return converter; } }