View Javadoc

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