Clover Coverage Report - KS Common 1.2-M4-SNAPSHOT (Aggregated)
Coverage timestamp: Wed Jul 20 2011 12:23:34 EDT
../../../../../../../img/srcFileCovDistChart8.png 13% 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 69 72.8% 0.72834647
  MetadataServiceImpl.RecursionCounter       Line # 64 11 0% 4 1 94.1% 0.9411765
 
  (2)
 
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  57 toggle public int increment(String objectName){
70  57 Integer hits = recursions.get(objectName);
71   
72  57 if (hits == null){
73  35 hits = new Integer(1);
74    } else {
75  22 hits++;
76    }
77  57 recursions.put(objectName, hits);
78  57 return hits;
79    }
80   
 
81  57 toggle public int decrement(String objectName){
82  57 Integer hits = recursions.get(objectName);
83  57 if (hits >= 1){
84  57 hits--;
85    }
86   
87  57 recursions.put(objectName, hits);
88  57 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  1 toggle public MetadataServiceImpl(String metadataContext){
98  1 init(metadataContext, (DictionaryService[])null);
99    }
100   
 
101  1 toggle public MetadataServiceImpl(DictionaryService...dictionaryServices){
102  1 init(null, dictionaryServices);
103    }
104   
 
105  0 toggle public MetadataServiceImpl(String metadataContext, DictionaryService...dictionaryServices){
106  0 init(metadataContext, dictionaryServices);
107    }
108   
 
109  2 toggle @SuppressWarnings("unchecked")
110    private void init(String metadataContext, DictionaryService...dictionaryServices){
111  2 if (metadataContext != null){
112  1 String[] locations = StringUtils.tokenizeToStringArray(metadataContext, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
113  1 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(locations);
114   
115  1 Map<String, DataObjectStructure> beansOfType = (Map<String, DataObjectStructure>) context.getBeansOfType(DataObjectStructure.class);
116  1 metadataRepository = new HashMap<String, Object>();
117  1 for (DataObjectStructure dataObjStr : beansOfType.values()){
118  18 metadataRepository.put(dataObjStr.getName(), getProperties(dataObjStr, new RecursionCounter()));
119    }
120    }
121   
122  2 if (dictionaryServices != null){
123  1 this.dictionaryServiceMap = new HashMap<String, DictionaryService>();
124  1 for (DictionaryService d:dictionaryServices){
125  1 List<String> objectTypes = d.getObjectTypes();
126  1 for(String objectType:objectTypes){
127  5 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  3 toggle @SuppressWarnings("unchecked")
143    public Metadata getMetadata(String objectKey, String type, String state){
144  3 if (metadataRepository == null || metadataRepository.get(objectKey) == null){
145  1 return getMetadataFromDictionaryService(objectKey, type, state);
146    } else {
147  2 Metadata metadata = new Metadata ();
148  2 metadata.setWriteAccess(WriteAccess.ALWAYS);
149  2 metadata.setOnChangeRefreshMetadata(false);
150  2 metadata.setDataType(DataType.DATA);
151   
152  2 metadata.setProperties((Map<String, Metadata>)metadataRepository.get(objectKey));
153   
154    //return the clone
155  2 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  22 toggle protected void loadProperties(Map<String, Metadata> properties, List<DataFieldDescriptor> fields, RecursionCounter counter){
166   
167  22 for (DataFieldDescriptor field:fields){
168  145 Metadata metadata = new Metadata();
169  145 metadata.setWriteAccess(WriteAccess.valueOf(field.getWriteAccess()));
170  145 metadata.setDataType(DataType.valueOf(field.getDataType()));
171  145 metadata.setAdditionalLookups(field.getAdditionalLookups());
172  145 metadata.setLookupContextPath(field.getLookupContextPath());
173   
174  145 metadata.setNonServerConstraints(field.getConstraints());
175  145 metadata.setName(field.getName());
176  145 metadata.setCanEdit(field.isCanEdit());
177  145 metadata.setCanView(field.isCanView());
178  145 metadata.setCanUnmask(field.isCanUnmask());
179  145 metadata.setDefaultValue(convertDefaultValue(metadata.getDataType(), field.getDefaultValue()));
180  145 metadata.setInitialLookup(field.getInitialLookup());
181   
182  145 if (isRepeating(field)){
183  19 Metadata repeatingMetadata = new Metadata();
184  19 metadata.setDataType(DataType.LIST);
185   
186  19 repeatingMetadata.setWriteAccess(WriteAccess.ALWAYS);
187  19 repeatingMetadata.setOnChangeRefreshMetadata(false);
188  19 repeatingMetadata.setDataType(DataType.valueOf(field.getDataType()));
189   
190  19 if (field.getDataObjectStructure() != null){
191  14 repeatingMetadata.setProperties(getProperties(field.getDataObjectStructure(), counter));
192    }
193   
194  19 Map<String, Metadata> repeatingProperty = new HashMap<String, Metadata>();
195  19 repeatingProperty.put("*", repeatingMetadata);
196  19 metadata.setProperties(repeatingProperty);
197  126 } else if (field.getDataObjectStructure() != null){
198  25 metadata.setProperties(getProperties(field.getDataObjectStructure(), counter));
199    }
200   
201  145 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  145 toggle protected boolean isRepeating(DataFieldDescriptor field){
212  145 if (field.getConstraints() != null) {
213  145 for (ConstraintMetadata c : field.getConstraints()) {
214  493 if (c.getId() != null && c.getId().equals("repeating")) {
215  19 return true;
216    }
217    }
218    }
219  126 return false;
220    }
221   
 
222  57 toggle @SuppressWarnings("unchecked")
223    protected Map<String, Metadata> getProperties(DataObjectStructure dataObjectStructure, RecursionCounter counter){
224  57 String objectId = dataObjectStructure.getName();
225  57 int hits = counter.increment(objectId);
226   
227  57 Map<String, Metadata> properties = null;
228   
229  57 if (hits == 1 && metadataRepository.containsKey(objectId)){
230  34 properties = (Map<String, Metadata>)metadataRepository.get(objectId);
231  23 } else if (hits < RecursionCounter.MAX_DEPTH){
232  22 properties = new HashMap<String, Metadata>();
233  22 if (hits == 1){
234  18 metadataRepository.put(objectId, properties);
235    }
236  22 loadProperties(properties, dataObjectStructure.getFields(), counter);
237    }
238   
239  57 counter.decrement(objectId);
240  57 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  1 toggle protected Metadata getMetadataFromDictionaryService(String objectKey, String type, String state){
254   
255  1 Metadata metadata = new Metadata();
256   
257  1 ObjectStructure objectStructure = getObjectStructure(objectKey);
258  1 State objectState = getObjectState(objectStructure, type, state);
259   
260  1 ConstraintDescriptor constraintDescriptor = objectState.getConstraintDescriptor();
261  1 metadata.setNonServerConstraints(copyConstraints(constraintDescriptor));
262   
263  1 List<Field> fields = objectState.getField();
264  1 metadata.setProperties(getProperties(fields, type, state));
265   
266  1 metadata.setWriteAccess(WriteAccess.ALWAYS);
267  1 metadata.setDataType(DataType.DATA);
268   
269  1 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  1 toggle private Map<String, Metadata> getProperties(List<Field> fields, String type, String state){
281  1 Map<String, Metadata> properties = new HashMap<String, Metadata>();
282   
283  1 for (Field field:fields){
284  3 FieldDescriptor fd = field.getFieldDescriptor();
285   
286  3 Metadata metadata = new Metadata();
287  3 metadata.setWriteAccess(WriteAccess.ALWAYS);
288  3 metadata.setDataType(convertDictionaryDataType(fd.getDataType()));
289  3 metadata.setNonServerConstraints(copyConstraints(field.getConstraintDescriptor()));
290   
291    //Where to get values for defaultValue, lookupMetdata (SearchSelector,fd.getSearch()),
292   
293  3 Map<String, Metadata> nestedProperties = null;
294  3 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  3 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  3 } else if (nestedProperties != null){
328  0 metadata.setProperties(nestedProperties);
329    }
330   
331  3 properties.put(fd.getName(), metadata);
332   
333    }
334   
335  1 return properties;
336    }
337   
338   
339    /**
340    * This method determines if a field is repeating
341    *
342    * @param field
343    * @return
344    */
 
345  3 toggle protected boolean isRepeating(Field field){
346  3 if (field.getConstraintDescriptor() != null && field.getConstraintDescriptor().getConstraint() != null){
347  3 for (ConstraintSelector c:field.getConstraintDescriptor().getConstraint()){
348  3 if (c.getKey().equals("repeating")){
349  0 return true;
350    }
351    }
352    }
353  3 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  1 toggle protected ObjectStructure getObjectStructure(String objectKey){
363  1 DictionaryService dictionaryService = dictionaryServiceMap.get(objectKey);
364   
365  1 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  1 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  1 for (Type t:objectStructure.getType()){
380  1 if (t.getKey().equals(type)){
381  1 for (State s:t.getState()){
382  1 if (s.getKey().equals(state)){
383  1 return s;
384    }
385    }
386    }
387    }
388   
389  0 return null;
390    }
391   
 
392  4 toggle protected List<ConstraintMetadata> copyConstraints(ConstraintDescriptor constraintDescriptor){
393  4 List<ConstraintMetadata> constraints = null;
394   
395  4 if (constraintDescriptor != null && constraintDescriptor.getConstraint() != null){
396  3 constraints = new ArrayList<ConstraintMetadata>();
397   
398   
399  3 for (ConstraintSelector dictConstraint:constraintDescriptor.getConstraint()){
400  3 ConstraintMetadata constraintMetadata = new ConstraintMetadata();
401   
402  3 constraintMetadata.setId(dictConstraint.getKey());
403  3 if (dictConstraint.getMaxLength() != null){
404  0 constraintMetadata.setMaxLength(Integer.valueOf(dictConstraint.getMaxLength()));
405    }
406  3 constraintMetadata.setMinLength(dictConstraint.getMinLength());
407  3 constraintMetadata.setMinOccurs(dictConstraint.getMinOccurs());
408  3 constraintMetadata.setMinValue(dictConstraint.getMinValue());
409   
410  3 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  3 constraints.add(constraintMetadata);
419    }
420    }
421   
422  4 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  145 toggle protected Value convertDefaultValue(DataType dataType, Object value){
432  145 Value v = null;
433  145 if (value instanceof String){
434  32 String s = (String)value;
435  32 switch (dataType){
436  29 case STRING:
437  29 value = new Data.StringValue(s);
438  29 break;
439  3 case BOOLEAN:
440  3 value = new Data.BooleanValue(Boolean.valueOf(s));
441  3 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  145 return v;
468    }
469   
 
470  3 toggle protected DataType convertDictionaryDataType(String dataType){
471  3 if ("string".equals(dataType)){
472  0 return DataType.STRING;
473  3 } else if ("boolean".equals(dataType)){
474  0 return DataType.BOOLEAN;
475  3 } else if ("integer".equals(dataType)){
476  0 return DataType.INTEGER;
477  3 } else if ("datetime".equals(dataType)){
478  0 return DataType.DATE;
479  3 } else if ("complex".equals(dataType)){
480  0 return DataType.DATA;
481    }
482   
483  3 return null;
484    }
485    }