1 /** 2 * Copyright 2005-2014 The Kuali Foundation 3 * 4 * Licensed under the Educational Community License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.opensource.org/licenses/ecl2.php 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package org.kuali.rice.krad.uif.component; 17 18 import java.io.Serializable; 19 import java.util.ArrayList; 20 import java.util.List; 21 import java.util.Map; 22 23 /** 24 * Configuration for replacing a property value based on a condition 25 * 26 * <p> 27 * A <code>Component</code> may be configured with one or more <code>PropertyReplacer</code> instances. Each defines 28 * a condition to evaluate during the apply model phase, and if that condition succeeds the property on the component 29 * given by {@link #getPropertyName()}, will be replaced with the value given by {@link #getReplacement()}. Conditions 30 * are defined using an expression language and may reference any variables available in the component's context. 31 * </p> 32 * 33 * <p> 34 * Property replacers can be used to change out an entire Component or List/Map of Components. For example, based on a 35 * condition you might want to display a <code>TextControl</code> or <code>RadioControl</code> for an 36 * <code>InputField</code>. You can define the field with a text control, then include a property replacer as 37 * follows: 38 * <pre> 39 <bean parent="PropertyReplacer" p:propertyName="control" 40 p:condition="field1 eq '10985'" p:replacement-ref="RadioControl"/> 41 * 42 * </pre> 43 * 44 * Note <code>Component</code> contains a <code>List</code> or property replacers which will be evaluated in the order 45 * contained within the list. So in the above example if we wanted to now add a further condition which sets the control 46 * to a checkbox, we would just add another property replacer bean. 47 * <pre> 48 * <property name="propertyReplacers"> 49 <list> 50 <bean parent="PropertyReplacer" p:propertyName="control" 51 p:condition="field1 eq '10985'" p:replacement-ref="RadioControl"/> 52 <bean parent="PropertyReplacer" p:propertyName="control" 53 p:condition="field1 eq '11456'" p:replacement-ref="CheckboxControl"/> 54 * </list> 55 * </property> 56 * </pre> 57 * 58 * Property replacers may be used to substitute primitive properties as well, such as Strings 59 * </p> 60 * 61 * @author Kuali Rice Team (rice.collab@kuali.org) 62 */ 63 public class PropertyReplacer extends ConfigurableBase implements Serializable { 64 private static final long serialVersionUID = -8405429643299461398L; 65 66 private String propertyName; 67 private String condition; 68 private Object replacement; 69 70 public PropertyReplacer() { 71 super(); 72 } 73 74 /** 75 * Returns a list of nested components 76 * 77 * <p> 78 * All nested components will be returned in the list. Current assumption is that 79 * <code>PropertyReplacer</code> can only contain a <code>Component</code>, <code>List</code> or 80 * <code>Map</code> for nested components 81 * </p> 82 * 83 * @return List<Component> nested components 84 */ 85 public List<Component> getNestedComponents() { 86 ArrayList<Component> nestedComponents = new ArrayList<Component>(); 87 if (replacement instanceof Component) { 88 nestedComponents.add(((Component) replacement)); 89 } else if (replacement instanceof List) { 90 for (Object replacementItem : (List<?>) replacement) { 91 if (replacementItem instanceof Component) { 92 nestedComponents.add((Component) replacementItem); 93 } 94 } 95 } else if (replacement instanceof Map) { 96 for (Object replacementItem : ((Map<?, ?>) replacement).values()) { 97 if (replacementItem instanceof Component) { 98 nestedComponents.add((Component) replacementItem); 99 } 100 } 101 } 102 103 return nestedComponents; 104 } 105 106 /** 107 * Name of the property on the Component the property replacer is associated with that 108 * will be set when the condition for the replacer succeeds 109 * 110 * <p> 111 * Note the property name must be readable/writable on the component. The property name may 112 * be nested, and include Map or List references. 113 * </p> 114 * 115 * @return String property name to set 116 */ 117 public String getPropertyName() { 118 return this.propertyName; 119 } 120 121 /** 122 * Setter for the property name that will be set 123 * 124 * @param propertyName 125 */ 126 public void setPropertyName(String propertyName) { 127 this.propertyName = propertyName; 128 } 129 130 /** 131 * Gives the expression that should be evaluated to determine whether or not 132 * the property replacement should be made 133 * 134 * <p> 135 * Expression follows SPEL and may access any model data along with any variables 136 * available in the context for the Component. The expression should evaluate to 137 * a boolean. If the resulting boolean is true, the object given by {@link #getReplacement()} 138 * will be set as the value for the associated property on the component. If the resulting 139 * boolean is false, no action will take place 140 * </p> 141 * 142 * <p> 143 * Note the value does not need to contain the expression placeholder @{} 144 * </p> 145 * 146 * @return String expression that should be evaluated 147 * @see org.kuali.rice.krad.uif.service.ExpressionEvaluatorService 148 * @see org.kuali.rice.krad.uif.UifConstants.ContextVariableNames 149 */ 150 public String getCondition() { 151 return this.condition; 152 } 153 154 /** 155 * Setter for the replacement condition 156 * 157 * @param condition 158 */ 159 public void setCondition(String condition) { 160 this.condition = condition; 161 } 162 163 /** 164 * Gives the Object that should be used to set the property value if the replacers condition 165 * evaluates to true 166 * 167 * <p> 168 * Note the configured Object must be valid for the type given by the property on the Component. Standard 169 * property editors will be used for setting the property value 170 * </p> 171 * 172 * @return Object instance to set 173 */ 174 public Object getReplacement() { 175 return this.replacement; 176 } 177 178 /** 179 * Setter for the replacement Object 180 * 181 * @param replacement 182 */ 183 public void setReplacement(Object replacement) { 184 this.replacement = replacement; 185 } 186 187 }