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