1 /**
2 * Copyright 2005-2011 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 }