Clover Coverage Report - Kuali Student 1.3.0-SNAPSHOT (Aggregated)
Coverage timestamp: Thu Apr 28 2011 05:03:32 EDT
../../../../../../../img/srcFileCovDistChart0.png 2% of files have more coverage
189   485   63   10.5
64   305   0.33   9
18     3.5  
2    
 
  MetadataServiceImpl       Line # 57 178 0% 59 254 0% 0.0
  MetadataServiceImpl.RecursionCounter       Line # 64 11 0% 4 17 0% 0.0
 
No Tests
 
1    /**
2    * Copyright 2010 The Kuali Foundation Licensed under the
3    * Educational Community License, Version 2.0 (the "License"); you may
4    * not use this file except in compliance with the License. You may
5    * obtain a copy of the License at
6    *
7    * http://www.osedu.org/licenses/ECL-2.0
8    *
9    * Unless required by applicable law or agreed to in writing,
10    * software distributed under the License is distributed on an "AS IS"
11    * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12    * or implied. See the License for the specific language governing
13    * permissions and limitations under the License.
14    */
15   
16    package org.kuali.student.common.assembly.dictionary.old;
17   
18    import java.text.DateFormat;
19    import java.text.ParseException;
20    import java.text.SimpleDateFormat;
21    import java.util.ArrayList;
22    import java.util.HashMap;
23    import java.util.List;
24    import java.util.Map;
25   
26    import org.apache.log4j.Logger;
27    import org.kuali.student.common.assembly.data.ConstraintMetadata;
28    import org.kuali.student.common.assembly.data.Data;
29    import org.kuali.student.common.assembly.data.Metadata;
30    import org.kuali.student.common.assembly.data.Data.DataType;
31    import org.kuali.student.common.assembly.data.Data.Value;
32    import org.kuali.student.common.assembly.data.Metadata.WriteAccess;
33    import org.kuali.student.common.dictionary.old.dto.ConstraintDescriptor;
34    import org.kuali.student.common.dictionary.old.dto.ConstraintSelector;
35    import org.kuali.student.common.dictionary.old.dto.Field;
36    import org.kuali.student.common.dictionary.old.dto.FieldDescriptor;
37    import org.kuali.student.common.dictionary.old.dto.ObjectStructure;
38    import org.kuali.student.common.dictionary.old.dto.State;
39    import org.kuali.student.common.dictionary.old.dto.Type;
40    import org.kuali.student.common.dictionary.service.old.DictionaryService;
41    import org.springframework.context.ConfigurableApplicationContext;
42    import org.springframework.context.support.ClassPathXmlApplicationContext;
43    import org.springframework.util.StringUtils;
44   
45    /**
46    * This class provides metadata lookup services for orchestration objects.
47    *
48    * TODO:
49    * 1) Handle type state configuration & better caching
50    * 2) Differentiate b/w metadata structure required for client vs. assemblers
51    * 3) Namespace collision b/w service dictionaries and orchestration dictionary?
52    *
53    * @author Kuali Student Team
54    *
55    */
56    @Deprecated
 
57    public class MetadataServiceImpl {
58    final Logger LOG = Logger.getLogger(MetadataServiceImpl.class);
59   
60    private Map<String, Object> metadataRepository = null;
61   
62    private Map<String, DictionaryService> dictionaryServiceMap;
63   
 
64    private static class RecursionCounter{
65    public static final int MAX_DEPTH = 4;
66   
67    private Map<String, Integer> recursions = new HashMap<String, Integer>();
68   
 
69  0 toggle public int increment(String objectName){
70  0 Integer hits = recursions.get(objectName);
71   
72  0 if (hits == null){
73  0 hits = new Integer(1);
74    } else {
75  0 hits++;
76    }
77  0 recursions.put(objectName, hits);
78  0 return hits;
79    }
80   
 
81  0 toggle public int decrement(String objectName){
82  0 Integer hits = recursions.get(objectName);
83  0 if (hits >= 1){
84  0 hits--;
85    }
86   
87  0 recursions.put(objectName, hits);
88  0 return hits;
89    }
90    }
91   
92    /**
93    * Create a Metadata service initialized using a given classpath metadata context file
94    *
95    * @param metadataContext the classpath metadata context file
96    */
 
97  0 toggle public MetadataServiceImpl(String metadataContext){
98  0 init(metadataContext, (DictionaryService[])null);
99    }
100   
 
101  0 toggle public MetadataServiceImpl(DictionaryService...dictionaryServices){
102  0 init(null, dictionaryServices);
103    }
104   
 
105  0 toggle public MetadataServiceImpl(String metadataContext, DictionaryService...dictionaryServices){
106  0 init(metadataContext, dictionaryServices);
107    }
108   
 
109  0 toggle @SuppressWarnings("unchecked")
110    private void init(String metadataContext, DictionaryService...dictionaryServices){
111  0 if (metadataContext != null){
112  0 String[] locations = StringUtils.tokenizeToStringArray(metadataContext, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
113  0 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(locations);
114   
115  0 Map<String, DataObjectStructure> beansOfType = (Map<String, DataObjectStructure>) context.getBeansOfType(DataObjectStructure.class);
116  0 metadataRepository = new HashMap<String, Object>();
117  0 for (DataObjectStructure dataObjStr : beansOfType.values()){
118  0 metadataRepository.put(dataObjStr.getName(), getProperties(dataObjStr, new RecursionCounter()));
119    }
120    }
121   
122  0 if (dictionaryServices != null){
123  0 this.dictionaryServiceMap = new HashMap<String, DictionaryService>();
124  0 for (DictionaryService d:dictionaryServices){
125  0 List<String> objectTypes = d.getObjectTypes();
126  0 for(String objectType:objectTypes){
127  0 dictionaryServiceMap.put(objectType, d);
128    }
129    }
130    }
131   
132    }
133   
134    /**
135    * This method gets the metadata for the given object key
136    *
137    * @param objectKey
138    * @param type
139    * @param state
140    * @return
141    */
 
142  0 toggle @SuppressWarnings("unchecked")
143    public Metadata getMetadata(String objectKey, String type, String state){
144  0 if (metadataRepository == null || metadataRepository.get(objectKey) == null){
145  0 return getMetadataFromDictionaryService(objectKey, type, state);
146    } else {
147  0 Metadata metadata = new Metadata ();
148  0 metadata.setWriteAccess(WriteAccess.ALWAYS);
149  0 metadata.setOnChangeRefreshMetadata(false);
150  0 metadata.setDataType(DataType.DATA);
151   
152  0 metadata.setProperties((Map<String, Metadata>)metadataRepository.get(objectKey));
153   
154    //return the clone
155  0 return new Metadata(metadata);
156    }
157    }
158   
159    /**
160    * Retreives data object structure from the spring file and caches the properties
161    *
162    * @param properties
163    * @param fields
164    */
 
165  0 toggle protected void loadProperties(Map<String, Metadata> properties, List<DataFieldDescriptor> fields, RecursionCounter counter){
166   
167  0 for (DataFieldDescriptor field:fields){
168  0 Metadata metadata = new Metadata();
169  0 metadata.setWriteAccess(WriteAccess.valueOf(field.getWriteAccess()));
170  0 metadata.setDataType(DataType.valueOf(field.getDataType()));
171  0 metadata.setAdditionalLookups(field.getAdditionalLookups());
172  0 metadata.setLookupContextPath(field.getLookupContextPath());
173   
174  0 metadata.setNonServerConstraints(field.getConstraints());
175  0 metadata.setName(field.getName());
176  0 metadata.setCanEdit(field.isCanEdit());
177  0 metadata.setCanView(field.isCanView());
178  0 metadata.setCanUnmask(field.isCanUnmask());
179  0 metadata.setDefaultValue(convertDefaultValue(metadata.getDataType(), field.getDefaultValue()));
180  0 metadata.setInitialLookup(field.getInitialLookup());
181   
182  0 if (isRepeating(field)){
183  0 Metadata repeatingMetadata = new Metadata();
184  0 metadata.setDataType(DataType.LIST);
185   
186  0 repeatingMetadata.setWriteAccess(WriteAccess.ALWAYS);
187  0 repeatingMetadata.setOnChangeRefreshMetadata(false);
188  0 repeatingMetadata.setDataType(DataType.valueOf(field.getDataType()));
189   
190  0 if (field.getDataObjectStructure() != null){
191  0 repeatingMetadata.setProperties(getProperties(field.getDataObjectStructure(), counter));
192    }
193   
194  0 Map<String, Metadata> repeatingProperty = new HashMap<String, Metadata>();
195  0 repeatingProperty.put("*", repeatingMetadata);
196  0 metadata.setProperties(repeatingProperty);
197  0 } else if (field.getDataObjectStructure() != null){
198  0 metadata.setProperties(getProperties(field.getDataObjectStructure(), counter));
199    }
200   
201  0 properties.put(field.getName(), metadata);
202    }
203    }
204   
205    /**
206    * This method determines if a field is a repeating field
207    *
208    * @param field
209    * @return
210    */
 
211  0 toggle protected boolean isRepeating(DataFieldDescriptor field){
212  0 if (field.getConstraints() != null) {
213  0 for (ConstraintMetadata c : field.getConstraints()) {
214  0 if (c.getId() != null && c.getId().equals("repeating")) {
215  0 return true;
216    }
217    }
218    }
219  0 return false;
220    }
221   
 
222  0 toggle @SuppressWarnings("unchecked")
223    protected Map<String, Metadata> getProperties(DataObjectStructure dataObjectStructure, RecursionCounter counter){
224  0 String objectId = dataObjectStructure.getName();
225  0 int hits = counter.increment(objectId);
226   
227  0 Map<String, Metadata> properties = null;
228   
229  0 if (hits == 1 && metadataRepository.containsKey(objectId)){
230  0 properties = (Map<String, Metadata>)metadataRepository.get(objectId);
231  0 } else if (hits < RecursionCounter.MAX_DEPTH){
232  0 properties = new HashMap<String, Metadata>();
233  0 if (hits == 1){
234  0 metadataRepository.put(objectId, properties);
235    }
236  0 loadProperties(properties, dataObjectStructure.getFields(), counter);
237    }
238   
239  0 counter.decrement(objectId);
240  0 return properties;
241    }
242   
243   
244    /**
245    * This invokes the appropriate dictionary service to get the object structure and then
246    * converts it to a metadata structure.
247    *
248    * @param objectKey
249    * @param type
250    * @param state
251    * @return
252    */
 
253  0 toggle protected Metadata getMetadataFromDictionaryService(String objectKey, String type, String state){
254   
255  0 Metadata metadata = new Metadata();
256   
257  0 ObjectStructure objectStructure = getObjectStructure(objectKey);
258  0 State objectState = getObjectState(objectStructure, type, state);
259   
260  0 ConstraintDescriptor constraintDescriptor = objectState.getConstraintDescriptor();
261  0 metadata.setNonServerConstraints(copyConstraints(constraintDescriptor));
262   
263  0 List<Field> fields = objectState.getField();
264  0 metadata.setProperties(getProperties(fields, type, state));
265   
266  0 metadata.setWriteAccess(WriteAccess.ALWAYS);
267  0 metadata.setDataType(DataType.DATA);
268   
269  0 return metadata;
270    }
271   
272    /**
273    * This method is used to convert a list of dictionary fields into metadata properties
274    *
275    * @param fields
276    * @param type
277    * @param state
278    * @return
279    */
 
280  0 toggle private Map<String, Metadata> getProperties(List<Field> fields, String type, String state){
281  0 Map<String, Metadata> properties = new HashMap<String, Metadata>();
282   
283  0 for (Field field:fields){
284  0 FieldDescriptor fd = field.getFieldDescriptor();
285   
286  0 Metadata metadata = new Metadata();
287  0 metadata.setWriteAccess(WriteAccess.ALWAYS);
288  0 metadata.setDataType(convertDictionaryDataType(fd.getDataType()));
289  0 metadata.setNonServerConstraints(copyConstraints(field.getConstraintDescriptor()));
290   
291    //Where to get values for defaultValue, lookupMetdata (SearchSelector,fd.getSearch()),
292   
293  0 Map<String, Metadata> nestedProperties = null;
294  0 if (fd.getDataType().equals("complex")){
295  0 ObjectStructure objectStructure;
296  0 if (fd.getObjectStructure() != null){
297  0 objectStructure = fd.getObjectStructure();
298    } else {
299  0 String objectKey = fd.getObjectStructureRef();
300  0 objectStructure = getObjectStructure(objectKey);
301    }
302   
303  0 State objectState = getObjectState(objectStructure, type, state);
304  0 nestedProperties = getProperties(objectState.getField(), type, state);
305   
306    //Cross field constraints for nested object fields? What to do about them?
307    //ConstraintDescriptor constraintDescriptor = objectState.getConstraintDescriptor()
308   
309    }
310   
311   
312  0 if (isRepeating(field)){
313  0 Metadata repeatingMetadata = new Metadata();
314  0 metadata.setDataType(DataType.LIST);
315   
316  0 repeatingMetadata.setWriteAccess(WriteAccess.ALWAYS);
317  0 repeatingMetadata.setOnChangeRefreshMetadata(false);
318  0 repeatingMetadata.setDataType(convertDictionaryDataType(fd.getDataType()));
319   
320  0 if (nestedProperties != null){
321  0 repeatingMetadata.setProperties(nestedProperties);
322    }
323   
324  0 Map<String, Metadata> repeatingProperty = new HashMap<String, Metadata>();
325  0 repeatingProperty.put("*", repeatingMetadata);
326  0 metadata.setProperties(repeatingProperty);
327  0 } else if (nestedProperties != null){
328  0 metadata.setProperties(nestedProperties);
329    }
330   
331  0 properties.put(fd.getName(), metadata);
332   
333    }
334   
335  0 return properties;
336    }
337   
338   
339    /**
340    * This method determines if a field is repeating
341    *
342    * @param field
343    * @return
344    */
 
345  0 toggle protected boolean isRepeating(Field field){
346  0 if (field.getConstraintDescriptor() != null && field.getConstraintDescriptor().getConstraint() != null){
347  0 for (ConstraintSelector c:field.getConstraintDescriptor().getConstraint()){
348  0 if (c.getKey().equals("repeating")){
349  0 return true;
350    }
351    }
352    }
353  0 return false;
354    }
355   
356    /**
357    * This method gets the object structure for given objectKey from a dictionaryService
358    *
359    * @param objectKey
360    * @return
361    */
 
362  0 toggle protected ObjectStructure getObjectStructure(String objectKey){
363  0 DictionaryService dictionaryService = dictionaryServiceMap.get(objectKey);
364   
365  0 return dictionaryService.getObjectStructure(objectKey);
366    }
367   
368    /**
369    * This method retrieves the desire object state for the object structure.
370    *
371    * @param objectStructure
372    * @param type
373    * @param state
374    * @return
375    */
 
376  0 toggle protected State getObjectState(ObjectStructure objectStructure, String type, String state){
377    //This method would not be required if we could just get objectStructure for a particular
378    //type/state from the dictionary service
379  0 for (Type t:objectStructure.getType()){
380  0 if (t.getKey().equals(type)){
381  0 for (State s:t.getState()){
382  0 if (s.getKey().equals(state)){
383  0 return s;
384    }
385    }
386    }
387    }
388   
389  0 return null;
390    }
391   
 
392  0 toggle protected List<ConstraintMetadata> copyConstraints(ConstraintDescriptor constraintDescriptor){
393  0 List<ConstraintMetadata> constraints = null;
394   
395  0 if (constraintDescriptor != null && constraintDescriptor.getConstraint() != null){
396  0 constraints = new ArrayList<ConstraintMetadata>();
397   
398   
399  0 for (ConstraintSelector dictConstraint:constraintDescriptor.getConstraint()){
400  0 ConstraintMetadata constraintMetadata = new ConstraintMetadata();
401   
402  0 constraintMetadata.setId(dictConstraint.getKey());
403  0 if (dictConstraint.getMaxLength() != null){
404  0 constraintMetadata.setMaxLength(Integer.valueOf(dictConstraint.getMaxLength()));
405    }
406  0 constraintMetadata.setMinLength(dictConstraint.getMinLength());
407  0 constraintMetadata.setMinOccurs(dictConstraint.getMinOccurs());
408  0 constraintMetadata.setMinValue(dictConstraint.getMinValue());
409   
410  0 if (dictConstraint.getValidChars() != null){
411  0 constraintMetadata.setValidChars(dictConstraint.getValidChars().getValue());
412    }
413   
414    //constraintMetadata.setMessageId("kuali.msg.validation." + dictConstraint.getKey());
415   
416    //Skipping cross field constraints (eg. case, occurs, require)
417   
418  0 constraints.add(constraintMetadata);
419    }
420    }
421   
422  0 return constraints;
423    }
424   
425    /**
426    * Convert Object value to respective DataType. Method return null for object Value.
427    * @param dataType
428    * @param value
429    * @return
430    */
 
431  0 toggle protected Value convertDefaultValue(DataType dataType, Object value){
432  0 Value v = null;
433  0 if (value instanceof String){
434  0 String s = (String)value;
435  0 switch (dataType){
436  0 case STRING:
437  0 value = new Data.StringValue(s);
438  0 break;
439  0 case BOOLEAN:
440  0 value = new Data.BooleanValue(Boolean.valueOf(s));
441  0 break;
442  0 case FLOAT:
443  0 value = new Data.FloatValue(Float.valueOf(s));
444  0 break;
445  0 case DATE:
446  0 DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
447  0 try {
448  0 value = new Data.DateValue(format.parse(s));
449    } catch (ParseException e) {
450  0 LOG.error("Unable to get default date value from metadata definition");
451    }
452  0 break;
453  0 case LONG:
454  0 if (!s.isEmpty()){
455  0 value = new Data.LongValue(Long.valueOf(s));
456    }
457  0 break;
458  0 case DOUBLE:
459  0 value = new Data.DoubleValue(Double.valueOf(s));
460  0 break;
461  0 case INTEGER:
462  0 value = new Data.IntegerValue(Integer.valueOf(s));
463  0 break;
464    }
465    }
466   
467  0 return v;
468    }
469   
 
470  0 toggle protected DataType convertDictionaryDataType(String dataType){
471  0 if ("string".equals(dataType)){
472  0 return DataType.STRING;
473  0 } else if ("boolean".equals(dataType)){
474  0 return DataType.BOOLEAN;
475  0 } else if ("integer".equals(dataType)){
476  0 return DataType.INTEGER;
477  0 } else if ("datetime".equals(dataType)){
478  0 return DataType.DATE;
479  0 } else if ("complex".equals(dataType)){
480  0 return DataType.DATA;
481    }
482   
483  0 return null;
484    }
485    }