Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
UifDictionaryIndex |
|
| 2.7777777777777777;2.778 |
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.kns.datadictionary.uif; | |
17 | ||
18 | import java.util.ArrayList; | |
19 | import java.util.HashMap; | |
20 | import java.util.List; | |
21 | import java.util.Map; | |
22 | import java.util.Map.Entry; | |
23 | ||
24 | import org.apache.commons.lang.StringUtils; | |
25 | import org.apache.commons.logging.Log; | |
26 | import org.apache.commons.logging.LogFactory; | |
27 | import org.kuali.rice.kns.datadictionary.DataDictionaryException; | |
28 | import org.kuali.rice.kns.service.KNSServiceLocatorWeb; | |
29 | import org.kuali.rice.kns.uif.container.View; | |
30 | import org.kuali.rice.kns.uif.core.Component; | |
31 | import org.kuali.rice.kns.uif.service.ViewTypeService; | |
32 | import org.springframework.beans.factory.support.DefaultListableBeanFactory; | |
33 | ||
34 | /** | |
35 | * Indexes <code>View</code> bean entries for retrieval | |
36 | * | |
37 | * <p> | |
38 | * This is used to retrieve a <code>View</code> instance by its unique id. | |
39 | * Furthermore, view of certain types (that have a <code>ViewTypeService</code> | |
40 | * are indexed by their type to support retrieval of views based on parameters. | |
41 | * </p> | |
42 | * | |
43 | * @author Kuali Rice Team (rice.collab@kuali.org) | |
44 | */ | |
45 | public class UifDictionaryIndex implements Runnable { | |
46 | 0 | private static final Log LOG = LogFactory.getLog(UifDictionaryIndex.class); |
47 | ||
48 | private DefaultListableBeanFactory ddBeans; | |
49 | ||
50 | // view entries keyed by view id with value the spring bean name | |
51 | private Map<String, String> viewBeanEntriesById; | |
52 | ||
53 | // view entries keyed by bean name with value the view prototype | |
54 | private Map<String, View> viewEntriesByBean; | |
55 | ||
56 | // view entries indexed by type | |
57 | private Map<String, ViewTypeDictionaryIndex> viewEntriesByType; | |
58 | ||
59 | 0 | public UifDictionaryIndex(DefaultListableBeanFactory ddBeans) { |
60 | 0 | this.ddBeans = ddBeans; |
61 | 0 | } |
62 | ||
63 | public void run() { | |
64 | 0 | LOG.info("Starting View Index Building"); |
65 | 0 | buildViewIndicies(); |
66 | 0 | LOG.info("Completed View Index Building"); |
67 | 0 | } |
68 | ||
69 | /** | |
70 | * Retrieves the View instance with the given id from the bean factory. | |
71 | * Since View instances are stateful, we need to get a new instance from | |
72 | * Spring each time. | |
73 | * | |
74 | * @param viewId | |
75 | * - the unique id for the view | |
76 | * @return <code>View</code> instance | |
77 | */ | |
78 | public View getViewById(String viewId) { | |
79 | 0 | String beanName = viewBeanEntriesById.get(viewId); |
80 | 0 | if (StringUtils.isBlank(beanName)) { |
81 | 0 | throw new DataDictionaryException("Unable to find View with id: " + viewId); |
82 | } | |
83 | ||
84 | 0 | return ddBeans.getBean(beanName, View.class); |
85 | } | |
86 | ||
87 | /** | |
88 | * Retrieves a <code>View</code> instance that is of the given type based on | |
89 | * the index key | |
90 | * | |
91 | * @param viewTypeName | |
92 | * - type name for the view | |
93 | * @param indexKey | |
94 | * - Map of index key parameters, these are the parameters the | |
95 | * indexer used to index the view initially and needs to identify | |
96 | * an unique view instance | |
97 | * @return View instance that matches the given index or Null if one is not | |
98 | * found | |
99 | */ | |
100 | public View getViewByTypeIndex(String viewTypeName, Map<String, String> indexKey) { | |
101 | 0 | String index = buildTypeIndex(indexKey); |
102 | ||
103 | 0 | ViewTypeDictionaryIndex typeIndex = getTypeIndex(viewTypeName); |
104 | ||
105 | 0 | String beanName = typeIndex.get(index); |
106 | 0 | if (StringUtils.isBlank(beanName)) { |
107 | 0 | throw new DataDictionaryException("Unable to find View with index: " + index); |
108 | } | |
109 | ||
110 | 0 | return ddBeans.getBean(beanName, View.class); |
111 | } | |
112 | ||
113 | /** | |
114 | * Gets all <code>View</code> prototypes configured for the given view type | |
115 | * name | |
116 | * | |
117 | * @param viewTypeName | |
118 | * - view type name to retrieve | |
119 | * @return List<View> view prototypes with the given type name, or empty | |
120 | * list | |
121 | */ | |
122 | public List<View> getViewsForType(String viewTypeName) { | |
123 | 0 | List<View> typeViews = new ArrayList<View>(); |
124 | ||
125 | // get view ids for the type | |
126 | 0 | if (viewEntriesByType.containsKey(viewTypeName)) { |
127 | 0 | ViewTypeDictionaryIndex typeIndex = viewEntriesByType.get(viewTypeName); |
128 | 0 | for (Entry<String, String> typeEntry : typeIndex.getViewIndex().entrySet()) { |
129 | // get the view prototype by bean name | |
130 | 0 | if (viewEntriesByBean.containsKey(typeEntry.getValue())) { |
131 | 0 | View typeView = viewEntriesByBean.get(typeEntry.getValue()); |
132 | 0 | typeViews.add(typeView); |
133 | 0 | } |
134 | } | |
135 | 0 | } |
136 | else { | |
137 | 0 | throw new DataDictionaryException("Unable to find view index for type: " + viewTypeName); |
138 | } | |
139 | ||
140 | 0 | return typeViews; |
141 | } | |
142 | ||
143 | /** | |
144 | * Initializes the view index <code>Map</code> then iterates through all the | |
145 | * beans in the factory that implement <code>View</code>, adding them to the | |
146 | * index | |
147 | */ | |
148 | protected void buildViewIndicies() { | |
149 | 0 | viewBeanEntriesById = new HashMap<String, String>(); |
150 | 0 | viewEntriesByBean = new HashMap<String, View>(); |
151 | 0 | viewEntriesByType = new HashMap<String, ViewTypeDictionaryIndex>(); |
152 | ||
153 | 0 | Map<String, View> viewBeans = ddBeans.getBeansOfType(View.class); |
154 | 0 | for (String beanName : viewBeans.keySet()) { |
155 | 0 | View view = viewBeans.get(beanName); |
156 | 0 | if (viewBeanEntriesById.containsKey(view.getId())) { |
157 | 0 | throw new DataDictionaryException("Two views must not share the same id. Found duplicate id: " |
158 | + view.getId()); | |
159 | } | |
160 | ||
161 | 0 | viewBeanEntriesById.put(view.getId(), beanName); |
162 | 0 | viewEntriesByBean.put(beanName, view); |
163 | ||
164 | 0 | indexViewForType(view, beanName); |
165 | 0 | } |
166 | ||
167 | // trigger a load of all component so they will get indexed in the component factory | |
168 | 0 | Map<String, Component> componentBeans = ddBeans.getBeansOfType(Component.class); |
169 | 0 | } |
170 | ||
171 | /** | |
172 | * Performs additional indexing based on the view type associated with the | |
173 | * view instance. The <code>ViewTypeService</code> associated with the view | |
174 | * type name on the instance is invoked to retrieve the parameter key/value | |
175 | * pairs from the view instance, which are then used to build up an index | |
176 | * which will key the entry | |
177 | * | |
178 | * @param view | |
179 | * - view instance to index | |
180 | * @param beanName | |
181 | * - name of the view's bean in Spring | |
182 | */ | |
183 | protected void indexViewForType(View view, String beanName) { | |
184 | 0 | String viewType = view.getViewTypeName(); |
185 | ||
186 | 0 | ViewTypeService typeService = KNSServiceLocatorWeb.getViewService().getViewTypeService(viewType); |
187 | 0 | if (typeService == null) { |
188 | // don't do any further indexing | |
189 | 0 | return; |
190 | } | |
191 | ||
192 | // invoke type service to retrieve it parameter name/value pairs from | |
193 | // the view | |
194 | 0 | Map<String, String> typeParameters = typeService.getParametersFromView(view); |
195 | ||
196 | // build the index string from the parameters | |
197 | 0 | String index = buildTypeIndex(typeParameters); |
198 | ||
199 | // get the index for the type and add the view entry | |
200 | 0 | ViewTypeDictionaryIndex typeIndex = getTypeIndex(viewType); |
201 | ||
202 | 0 | typeIndex.put(index, beanName); |
203 | 0 | } |
204 | ||
205 | /** | |
206 | * Retrieves the <code>ViewTypeDictionaryIndex</code> instance for the given | |
207 | * view type name. If one does not exist yet for the given name, a new | |
208 | * instance is created | |
209 | * | |
210 | * @param viewType | |
211 | * - name of the view type to retrieve index for | |
212 | * @return ViewTypeDictionaryIndex instance | |
213 | */ | |
214 | protected ViewTypeDictionaryIndex getTypeIndex(String viewType) { | |
215 | 0 | ViewTypeDictionaryIndex typeIndex = null; |
216 | ||
217 | 0 | if (viewEntriesByType.containsKey(viewType)) { |
218 | 0 | typeIndex = viewEntriesByType.get(viewType); |
219 | } | |
220 | else { | |
221 | 0 | typeIndex = new ViewTypeDictionaryIndex(); |
222 | 0 | viewEntriesByType.put(viewType, typeIndex); |
223 | } | |
224 | ||
225 | 0 | return typeIndex; |
226 | } | |
227 | ||
228 | /** | |
229 | * Builds up an index string from the given Map of parameters | |
230 | * | |
231 | * @param typeParameters | |
232 | * - Map of parameters to use for index | |
233 | * @return String index | |
234 | */ | |
235 | protected String buildTypeIndex(Map<String, String> typeParameters) { | |
236 | 0 | String index = ""; |
237 | ||
238 | 0 | for (String parameterName : typeParameters.keySet()) { |
239 | 0 | if (StringUtils.isNotBlank(index)) { |
240 | 0 | index += "|||"; |
241 | } | |
242 | 0 | index += parameterName + "^^" + typeParameters.get(parameterName); |
243 | } | |
244 | ||
245 | 0 | return index; |
246 | } | |
247 | ||
248 | } |