001/** 002 * Copyright 2005-2016 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.krad.uif.component; 017 018import java.io.Serializable; 019import java.util.ArrayList; 020import java.util.List; 021import java.util.Map; 022 023/** 024 * Configuration for replacing a property value based on a condition 025 * 026 * <p> 027 * A <code>Component</code> may be configured with one or more <code>PropertyReplacer</code> instances. Each defines 028 * a condition to evaluate during the apply model phase, and if that condition succeeds the property on the component 029 * given by {@link #getPropertyName()}, will be replaced with the value given by {@link #getReplacement()}. Conditions 030 * are defined using an expression language and may reference any variables available in the component's context. 031 * </p> 032 * 033 * <p> 034 * Property replacers can be used to change out an entire Component or List/Map of Components. For example, based on a 035 * condition you might want to display a <code>TextControl</code> or <code>RadioControl</code> for an 036 * <code>InputField</code>. You can define the field with a text control, then include a property replacer as 037 * follows: 038 * <pre> 039 <bean parent="PropertyReplacer" p:propertyName="control" 040 p:condition="field1 eq '10985'" p:replacement-ref="RadioControl"/> 041 * 042 * </pre> 043 * 044 * Note <code>Component</code> contains a <code>List</code> or property replacers which will be evaluated in the order 045 * contained within the list. So in the above example if we wanted to now add a further condition which sets the control 046 * to a checkbox, we would just add another property replacer bean. 047 * <pre> 048 * <property name="propertyReplacers"> 049 <list> 050 <bean parent="PropertyReplacer" p:propertyName="control" 051 p:condition="field1 eq '10985'" p:replacement-ref="RadioControl"/> 052 <bean parent="PropertyReplacer" p:propertyName="control" 053 p:condition="field1 eq '11456'" p:replacement-ref="CheckboxControl"/> 054 * </list> 055 * </property> 056 * </pre> 057 * 058 * Property replacers may be used to substitute primitive properties as well, such as Strings 059 * </p> 060 * 061 * @author Kuali Rice Team (rice.collab@kuali.org) 062 */ 063public class PropertyReplacer extends ConfigurableBase implements Serializable { 064 private static final long serialVersionUID = -8405429643299461398L; 065 066 private String propertyName; 067 private String condition; 068 private Object replacement; 069 070 public PropertyReplacer() { 071 super(); 072 } 073 074 /** 075 * Returns a list of nested components 076 * 077 * <p> 078 * All nested components will be returned in the list. Current assumption is that 079 * <code>PropertyReplacer</code> can only contain a <code>Component</code>, <code>List</code> or 080 * <code>Map</code> for nested components 081 * </p> 082 * 083 * @return List<Component> nested components 084 */ 085 public List<Component> getNestedComponents() { 086 ArrayList<Component> nestedComponents = new ArrayList<Component>(); 087 if (replacement instanceof Component) { 088 nestedComponents.add(((Component) replacement)); 089 } else if (replacement instanceof List) { 090 for (Object replacementItem : (List<?>) replacement) { 091 if (replacementItem instanceof Component) { 092 nestedComponents.add((Component) replacementItem); 093 } 094 } 095 } else if (replacement instanceof Map) { 096 for (Object replacementItem : ((Map<?, ?>) replacement).values()) { 097 if (replacementItem instanceof Component) { 098 nestedComponents.add((Component) replacementItem); 099 } 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}