Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
ViewIndex |
|
| 2.272727272727273;2.273 |
1 | /* | |
2 | * Copyright 2007 The Kuali Foundation | |
3 | * | |
4 | * Licensed under the Educational Community License, Version 1.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/ecl1.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.container; | |
17 | ||
18 | import org.apache.commons.lang.StringUtils; | |
19 | import org.kuali.rice.krad.uif.core.BindingInfo; | |
20 | import org.kuali.rice.krad.uif.core.Component; | |
21 | import org.kuali.rice.krad.uif.field.AttributeField; | |
22 | ||
23 | import java.io.Serializable; | |
24 | import java.util.HashMap; | |
25 | import java.util.Map; | |
26 | ||
27 | /** | |
28 | * Holds field indexes of a <code>View</code> instance for retrieval | |
29 | * | |
30 | * @author Kuali Rice Team (rice.collab@kuali.org) | |
31 | */ | |
32 | public class ViewIndex implements Serializable { | |
33 | private static final long serialVersionUID = 4700818801272201371L; | |
34 | ||
35 | private Map<String, Component> index; | |
36 | private Map<String, AttributeField> attributeFieldIndex; | |
37 | private Map<String, CollectionGroup> collectionsIndex; | |
38 | ||
39 | /** | |
40 | * Constructs new instance and performs indexing on View instance | |
41 | * | |
42 | * @param view - view instance to index | |
43 | */ | |
44 | 0 | public ViewIndex(View view) { |
45 | 0 | index(view); |
46 | 0 | } |
47 | ||
48 | /** | |
49 | * Walks through the View tree and indexes all components found. All components | |
50 | * are indexed by their IDs with the special indexing done for certain components | |
51 | * | |
52 | * <p> | |
53 | * <code>AttributeField</code> instances are indexed by the attribute path. | |
54 | * This is useful for retrieving the AttributeField based on the incoming | |
55 | * request parameter | |
56 | * </p> | |
57 | * | |
58 | * <p> | |
59 | * <code>CollectionGroup</code> instances are indexed by the collection | |
60 | * path. This is useful for retrieving the CollectionGroup based on the | |
61 | * incoming request parameter | |
62 | * </p> | |
63 | */ | |
64 | protected void index(View view) { | |
65 | 0 | index = new HashMap<String, Component>(); |
66 | 0 | attributeFieldIndex = new HashMap<String, AttributeField>(); |
67 | 0 | collectionsIndex = new HashMap<String, CollectionGroup>(); |
68 | ||
69 | 0 | indexComponent(view); |
70 | 0 | } |
71 | ||
72 | /** | |
73 | * Adds an entry to the main index for the given component. If the component | |
74 | * is of type <code>AttributeField</code> or <code>CollectionGroup</code> an | |
75 | * entry is created in the corresponding indexes for those types as well. Then | |
76 | * the #indexComponent method is called for each of the component's children | |
77 | * | |
78 | * <p> | |
79 | * If the component is already contained in the indexes, it will be replaced | |
80 | * </p> | |
81 | * | |
82 | * @param component - component instance to index | |
83 | */ | |
84 | public void indexComponent(Component component) { | |
85 | 0 | if (component == null) { |
86 | 0 | return; |
87 | } | |
88 | ||
89 | 0 | index.put(component.getId(), component); |
90 | ||
91 | 0 | if (component instanceof AttributeField) { |
92 | 0 | AttributeField field = (AttributeField) component; |
93 | 0 | attributeFieldIndex.put(field.getBindingInfo().getBindingPath(), field); |
94 | 0 | } else if (component instanceof CollectionGroup) { |
95 | 0 | CollectionGroup collectionGroup = (CollectionGroup) component; |
96 | 0 | collectionsIndex.put(collectionGroup.getBindingInfo().getBindingPath(), collectionGroup); |
97 | } | |
98 | ||
99 | 0 | for (Component nestedComponent : component.getNestedComponents()) { |
100 | 0 | indexComponent(nestedComponent); |
101 | } | |
102 | 0 | } |
103 | ||
104 | /** | |
105 | * Retrieves a <code>Component</code> from the view index by Id | |
106 | * | |
107 | * @param id - id for the component to retrieve | |
108 | * @return Component instance found in index, or null if no such component exists | |
109 | */ | |
110 | public Component getComponentById(String id) { | |
111 | 0 | return index.get(id); |
112 | } | |
113 | ||
114 | /** | |
115 | * Retrieves a <code>AttributeField</code> instance from the index | |
116 | * | |
117 | * @param attributePath - full path of the attribute (from the form) | |
118 | * @return AttributeField instance for the path or Null if not found | |
119 | */ | |
120 | public AttributeField getAttributeFieldByPath(String attributePath) { | |
121 | 0 | return attributeFieldIndex.get(attributePath); |
122 | } | |
123 | ||
124 | /** | |
125 | * Retrieves a <code>AttributeField</code> instance that has the given property name | |
126 | * specified (note this is not the full binding path and first match is returned) | |
127 | * | |
128 | * @param propertyName - property name for field to retrieve | |
129 | * @return AttributeField instance found or null if not found | |
130 | */ | |
131 | public AttributeField getAttributeFieldByPropertyName(String propertyName) { | |
132 | 0 | AttributeField attributeField = null; |
133 | ||
134 | 0 | for (AttributeField field : attributeFieldIndex.values()) { |
135 | 0 | if (StringUtils.equals(propertyName, field.getPropertyName())) { |
136 | 0 | attributeField = field; |
137 | 0 | break; |
138 | } | |
139 | } | |
140 | ||
141 | 0 | return attributeField; |
142 | } | |
143 | ||
144 | /** | |
145 | * Gets the Map that contains attribute field indexing information. The Map | |
146 | * key points to an attribute binding path, and the Map value is the | |
147 | * <code>AttributeField</code> instance | |
148 | * | |
149 | * @return Map<String, AttributeField> attribute fields index map | |
150 | */ | |
151 | public Map<String, AttributeField> getAttributeFieldIndex() { | |
152 | 0 | return this.attributeFieldIndex; |
153 | } | |
154 | ||
155 | /** | |
156 | * Gets the Map that contains collection indexing information. The Map key | |
157 | * gives the binding path to the collection, and the Map value givens the | |
158 | * <code>CollectionGroup</code> instance | |
159 | * | |
160 | * @return Map<String, CollectionGroup> collection index map | |
161 | */ | |
162 | public Map<String, CollectionGroup> getCollectionsIndex() { | |
163 | 0 | return this.collectionsIndex; |
164 | } | |
165 | ||
166 | /** | |
167 | * Retrieves a <code>CollectionGroup</code> instance from the index | |
168 | * | |
169 | * @param collectionPath - full path of the collection (from the form) | |
170 | * @return CollectionGroup instance for the collection path or Null if not | |
171 | * found | |
172 | */ | |
173 | public CollectionGroup getCollectionGroupByPath(String collectionPath) { | |
174 | 0 | return collectionsIndex.get(collectionPath); |
175 | } | |
176 | ||
177 | /** | |
178 | * Searches for the <code>AttributeField</code> based on the given binding path. | |
179 | * | |
180 | * <p>It first searches for the matching <code>AttributeField</code> by path. If not | |
181 | * matching field found, it searches in the <code>CollectionGroup</code> | |
182 | * </p> | |
183 | * | |
184 | * @param bindingInfo - <code>AttributeField</code> will be searched based on this binding path | |
185 | * @return the attribute field for the binding path | |
186 | */ | |
187 | public AttributeField getAttributeField(BindingInfo bindingInfo) { | |
188 | // Find in the attribute index first. | |
189 | 0 | AttributeField attributeField = getAttributeFieldByPath(bindingInfo.getBindingPath()); |
190 | ||
191 | 0 | if (attributeField == null) { |
192 | // Lets search the collections (by collection's binding path) | |
193 | 0 | String path = bindingInfo.getBindingObjectPath() + "." + bindingInfo.getBindByNamePrefix(); |
194 | ||
195 | 0 | CollectionGroup collectionGroup = getCollectionGroupByPath(stripIndexesFromPropertyPath(path)); |
196 | 0 | if (collectionGroup != null) { |
197 | 0 | for (Component item : ((CollectionGroup) collectionGroup).getItems()) { |
198 | 0 | if (item instanceof AttributeField) { |
199 | 0 | if (StringUtils |
200 | .equals(((AttributeField) item).getPropertyName(), bindingInfo.getBindingName())) { | |
201 | 0 | attributeField = (AttributeField) item; |
202 | 0 | break; |
203 | } | |
204 | } | |
205 | } | |
206 | } | |
207 | } | |
208 | ||
209 | 0 | return attributeField; |
210 | } | |
211 | ||
212 | /** | |
213 | * Strips indexes from the property path. | |
214 | * | |
215 | * <p> For example, it returns bo.fiscalOfficer.accounts.name for the input bo.fiscalOfficer.accounts[0].name, | |
216 | * which can be used to find the components from the CollectionGroup index | |
217 | * </p> | |
218 | * | |
219 | * @param propertyPath - property path | |
220 | * @return the stripped index path | |
221 | */ | |
222 | private String stripIndexesFromPropertyPath(String propertyPath) { | |
223 | ||
224 | 0 | String returnValue = propertyPath; |
225 | 0 | String index = StringUtils.substringBetween(propertyPath, "[", "]"); |
226 | ||
227 | 0 | if (StringUtils.isNotBlank(index)) { |
228 | 0 | returnValue = StringUtils.remove(propertyPath, "[" + index + "]"); |
229 | 0 | return stripIndexesFromPropertyPath(returnValue); |
230 | } else { | |
231 | 0 | return returnValue; |
232 | } | |
233 | } | |
234 | } |