1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.kuali.student.lum.ui;
16
17 import java.util.ArrayList;
18 import java.util.List;
19 import java.util.Map;
20
21 import org.kuali.student.common.assembly.data.Data;
22 import org.kuali.student.common.assembly.data.LookupMetadata;
23 import org.kuali.student.common.assembly.data.LookupParamMetadata;
24 import org.kuali.student.common.assembly.data.LookupResultMetadata;
25 import org.kuali.student.common.assembly.data.Metadata;
26 import org.kuali.student.common.search.dto.CrossSearchTypeInfo;
27 import org.kuali.student.common.search.dto.JoinResultMappingInfo;
28 import org.kuali.student.common.search.dto.QueryParamInfo;
29 import org.kuali.student.common.search.dto.ResultColumnInfo;
30 import org.kuali.student.common.search.dto.SearchTypeInfo;
31 import org.kuali.student.common.search.dto.SubSearchInfo;
32 import org.kuali.student.core.personsearch.service.impl.QuickViewByGivenNameSearchTypeCreator;
33 import org.springframework.context.ApplicationContext;
34 import org.springframework.context.support.ClassPathXmlApplicationContext;
35
36 public class MetadataServiceDictionaryValidator
37 {
38
39 private SearchTypeInfo getSearchTypeInfo (String searchType)
40 {
41 return this.getSearchInfoTypeMap ().get (searchType);
42 }
43 private Map<String, SearchTypeInfo> searchInfoTypeMap = null;
44
45 private Map<String, SearchTypeInfo> getSearchInfoTypeMap ()
46 {
47 if (this.searchInfoTypeMap != null)
48 {
49 return this.searchInfoTypeMap;
50 }
51 String[] searchConfigFiles =
52 {
53 "lu", "lo", "lrc", "proposal", "organization", "atp", "em"
54 };
55 for (int i = 0; i < searchConfigFiles.length; i ++)
56 {
57 System.out.println ("loading search configurations for "
58 + searchConfigFiles[i]);
59 ApplicationContext ac = new ClassPathXmlApplicationContext (
60 "classpath:" + searchConfigFiles[i] + "-search-config.xml");
61 if (searchInfoTypeMap == null)
62 {
63 searchInfoTypeMap = ac.getBeansOfType (SearchTypeInfo.class);
64 }
65 else
66 {
67 searchInfoTypeMap.putAll (ac.getBeansOfType (SearchTypeInfo.class));
68 }
69 }
70 SearchTypeInfo personSearchType =
71 new QuickViewByGivenNameSearchTypeCreator ().get ();
72 searchInfoTypeMap.put (personSearchType.getKey (), personSearchType);
73
74 return searchInfoTypeMap;
75 }
76
77 public List<String> validateMetadata (Metadata md, String name, String type)
78 {
79 List<String> errors = new ArrayList ();
80 if (md.getInitialLookup () != null && md.getInitialLookup ().getSearchTypeId () != null)
81 {
82 errors.addAll (validateLookup (md.getInitialLookup (), name, type, "initial"));
83 }
84 if (md.getAdditionalLookups () != null)
85 {
86 for (LookupMetadata lookup : md.getAdditionalLookups ())
87 {
88 errors.addAll (validateLookup (lookup, name, type, "additional"));
89 }
90 }
91 if (md.getDataType ().equals (Data.DataType.DATA))
92 {
93 if (md.getProperties () == null)
94 {
95 errors.add (buildErrorPrefix1 (name, type)
96 + " is of type DATA but it has null for it's properties");
97 }
98 else if (md.getProperties ().size () == 0)
99 {
100 errors.add (buildErrorPrefix1 (name, type)
101 + " is of type DATA but it has no properties");
102 }
103 }
104
105 if (md.getProperties () != null && md.getProperties ().size () != 0)
106 {
107 if ( ! (md.getDataType ().equals (Data.DataType.DATA)
108 || md.getDataType ().equals (Data.DataType.LIST)))
109 {
110 errors.add (buildErrorPrefix1 (name, type)
111 + " is NOT of type DATA or LIST but it does have properties");
112 }
113 for (String key : md.getProperties ().keySet ())
114 {
115 Metadata childMd = md.getProperties ().get (key);
116 errors.addAll (this.validateMetadata (childMd, name + "." + key, type));
117 }
118 }
119 return errors;
120 }
121
122 private List<String> validateLookup (LookupMetadata lookup, String name,
123 String type, String lookupType)
124 {
125 System.out.println ("Validating lookup " + name + "(" + type + ") "
126 + lookupType);
127 List<String> errors = new ArrayList ();
128 SearchTypeInfo st = getSearchTypeInfo (lookup.getSearchTypeId ());
129 if (st == null)
130 {
131 errors.add (buildErrorPrefix3 (lookup, name, type, lookupType)
132 + " that has an underlying search type "
133 + lookup.getSearchTypeId ()
134 + " that does not exist");
135 return errors;
136 }
137 if (lookup.getResultDisplayKey () != null)
138 {
139 String key = lookup.getResultDisplayKey ().trim ();
140 if ( ! key.equals (""))
141 {
142 ResultColumnInfo rc = findResultColumn (st, key);
143 if (rc == null)
144 {
145 errors.add (buildErrorPrefix3 (lookup, name, type, lookupType)
146 + " that has a result display column " + key
147 + " that does not exist in the underlying search "
148 + lookup.getSearchTypeId ());
149 }
150 }
151 }
152 if (lookup.getResultReturnKey () != null)
153 {
154 String key = lookup.getResultReturnKey ().trim ();
155 if (( ! key.equals ("")))
156 {
157 ResultColumnInfo rc = findResultColumn (st, key);
158 if (rc == null)
159 {
160 errors.add (buildErrorPrefix3 (lookup, name, type, lookupType)
161 + " that has a result return key " + key
162 + " that does not exist in the underlying search "
163 + lookup.getSearchTypeId ());
164 }
165 }
166 }
167 if (lookup.getResultSortKey () != null)
168 {
169 String key = lookup.getResultSortKey ().trim ();
170 if ( ! key.equals (""))
171 {
172 ResultColumnInfo rc = findResultColumn (st, key);
173 if (rc == null)
174 {
175 errors.add (buildErrorPrefix3 (lookup, name, type, lookupType)
176 + " that has a result sort key " + key
177 + " that does not exist in the underlying search "
178 + lookup.getSearchTypeId ());
179 }
180 }
181 }
182
183 for (LookupParamMetadata param : lookup.getParams ())
184 {
185 QueryParamInfo qp = findQueryParam (st, param.getKey ());
186 if (qp == null)
187 {
188 errors.add (buildErrorPrefix3 (lookup, name, type, lookupType)
189 + " that has a parameter " + param.getKey ()
190 + " that does not exist in the underlying search "
191 + lookup.getSearchTypeId ());
192 continue;
193 }
194 if ( ! dataTypeMatches (qp.getFieldDescriptor ().getDataType (),
195 param.getDataType ()))
196 {
197 errors.add (buildErrorPrefix3 (lookup, name, type, lookupType)
198 + " that has a parameter " + param.getKey ()
199 + " that who's datatype does not match the underlying parameter "
200 + qp.getFieldDescriptor ().getDataType () + " vs. "
201 + param.getDataType ());
202 continue;
203 }
204 }
205
206 for (LookupResultMetadata result : lookup.getResults ())
207 {
208 ResultColumnInfo rc = findResultColumn (st, result.getKey ());
209 if (rc == null)
210 {
211 errors.add (buildErrorPrefix3 (lookup, name, type, lookupType)
212 + " that has a result column " + result.getKey ()
213 + " that does not exist in the underlying search "
214 + lookup.getSearchTypeId ());
215 continue;
216 }
217 if ( ! dataTypeMatches (rc.getDataType (),
218 result.getDataType ()))
219 {
220 errors.add (buildErrorPrefix3 (lookup, name, type, lookupType)
221 + " that has a result column " + result.getKey ()
222 + " that who's datatype does not match the underlying result column "
223 + rc.getDataType () + " vs. "
224 + result.getDataType ());
225 continue;
226 }
227 }
228 return errors;
229 }
230
231 private boolean dataTypeMatches (String qp, Data.DataType dt)
232 {
233 if (dt == null)
234 {
235 dt = Data.DataType.STRING;
236 }
237 if (qp == null)
238 {
239 qp = "string";
240 }
241 switch (dt)
242 {
243 case STRING:
244 if (qp.equalsIgnoreCase ("string"))
245 {
246 return true;
247 }
248 if (qp == null)
249 {
250 return true;
251 }
252 return false;
253 case INTEGER:
254 if (qp.equalsIgnoreCase ("int"))
255 {
256 return true;
257 }
258 return false;
259 case LONG:
260 case FLOAT:
261 case DOUBLE:
262 case BOOLEAN:
263 if (qp.equalsIgnoreCase ("boolean"))
264 {
265 return true;
266 }
267 return false;
268 case DATE:
269 case TRUNCATED_DATE:
270 if (qp.equalsIgnoreCase ("date"))
271 {
272 return true;
273 }
274 if (qp.equalsIgnoreCase ("dateTime"))
275 {
276 return true;
277 }
278 return false;
279 case DATA:
280 if (qp.equalsIgnoreCase ("complex"))
281 {
282 return true;
283 }
284 return false;
285 case LIST:
286 return true;
287 }
288 return true;
289 }
290
291 private ResultColumnInfo findResultColumn (SearchTypeInfo st, String paramKey)
292 {
293 for (ResultColumnInfo rc : st.getSearchResultTypeInfo ().getResultColumns ())
294 {
295 if (rc.getKey ().equals (paramKey))
296 {
297 return rc;
298 }
299 }
300 if (st instanceof CrossSearchTypeInfo)
301 {
302
303
304 CrossSearchTypeInfo cst = (CrossSearchTypeInfo) st;
305 if (cst.getJoinResultMappings () != null)
306 {
307 for (JoinResultMappingInfo jrm : cst.getJoinResultMappings ())
308 {
309 if (jrm.getResultParam ().equalsIgnoreCase (paramKey))
310 {
311 for (SubSearchInfo ss : cst.getSubSearches ())
312 {
313 if (ss.getKey ().equalsIgnoreCase (jrm.getSubSearchKey ()))
314 {
315 SearchTypeInfo subSearchType = this.getSearchTypeInfo (
316 ss.getSearchkey ());
317 if (subSearchType == null)
318 {
319 return null;
320 }
321 ResultColumnInfo rc = findResultColumn (subSearchType, jrm.getSubSearchResultParam ());
322 if (rc == null)
323 {
324 throw new RuntimeException ("Cross-Search " + st.getKey () + " is not configured properly "
325 + jrm.getSubSearchResultParam () + " is not defined as a result in the subSearchTyp e" + ss.getSearchkey ());
326 }
327 }
328 }
329 }
330 }
331 }
332 }
333 return null;
334 }
335
336 private QueryParamInfo findQueryParam (SearchTypeInfo st, String paramKey)
337 {
338 for (QueryParamInfo qp : st.getSearchCriteriaTypeInfo ().getQueryParams ())
339 {
340 if (qp.getKey ().equals (paramKey))
341 {
342 return qp;
343 }
344 }
345 return null;
346 }
347
348 private String buildErrorPrefix3 (LookupMetadata lookup, String name,
349 String type, String lookupType)
350 {
351 return buildErrorPrefix2 (name, type, lookupType) + ": " + lookup.getId ();
352 }
353
354 private String buildErrorPrefix2 (String name, String type, String lookupType)
355 {
356 String msg = buildErrorPrefix1 (name, type);
357 msg += " has an " + lookupType + " lookup ";
358 return msg;
359 }
360
361 private String buildErrorPrefix1 (String name, String type)
362 {
363 String msg = name;
364 if (type != null)
365 {
366 msg += " with type " + type;
367 }
368
369
370 return msg;
371 }
372 }