Coverage Report - org.kuali.rice.krad.uif.util.ViewModelUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
ViewModelUtils
0%
0/59
0%
0/38
4.286
 
 1  
 /**
 2  
  * Copyright 2005-2011 The Kuali Foundation
 3  
  *
 4  
  * Licensed under the Educational Community License, Version 2.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/ecl2.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.uif.util;
 17  
 
 18  
 import org.apache.commons.lang.StringUtils;
 19  
 import org.kuali.rice.krad.uif.field.DataField;
 20  
 import org.kuali.rice.krad.uif.view.View;
 21  
 import org.springframework.beans.PropertyValues;
 22  
 import org.springframework.beans.factory.config.TypedStringValue;
 23  
 
 24  
 import java.util.Collection;
 25  
 import java.util.Map;
 26  
 
 27  
 /**
 28  
  * Provides methods for getting property values, types, and paths within the
 29  
  * context of a <code>View</code>
 30  
  *
 31  
  * <p>
 32  
  * The view provides a special map named 'abstractTypeClasses' that indicates
 33  
  * concrete classes that should be used in place of abstract property types that
 34  
  * are encountered on the object graph. This classes takes into account that map
 35  
  * while dealing with properties. e.g. suppose we have propertyPath
 36  
  * 'document.name' on the form, with the type of the document property set to
 37  
  * the interface Document. Using class introspection we would get back the
 38  
  * interface type for document and this would not be able to get the property
 39  
  * type for name. Using the view map, we can replace document with a concrete
 40  
  * class and then use it to get the name property
 41  
  * </p>
 42  
  *
 43  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 44  
  */
 45  0
 public class ViewModelUtils {
 46  
 
 47  
     /**
 48  
      * Determines the associated type for the property within the View context
 49  
      *
 50  
      * <p>
 51  
      * Property path is full path to property from the View Form class. The abstract type classes
 52  
      * map configured on the View will be consulted for any entries that match the property path. If the
 53  
      * property path given contains a partial match to an abstract class (somewhere on path is an abstract
 54  
      * class), the property type will be retrieved based on the given concrete class to use and the part
 55  
      * of the path remaining. If no matching entry is found, standard reflection is used to get the type
 56  
      * </p>
 57  
      *
 58  
      * @param view - view instance providing the context (abstract map)
 59  
      * @param propertyPath - full path to property to retrieve type for (relative to the form class)
 60  
      * @return Class<?> type of property in model, or Null if type could not be determined
 61  
      * @see org.kuali.rice.krad.uif.view.View#getAbstractTypeClasses()
 62  
      */
 63  
     public static Class<?> getPropertyTypeByClassAndView(View view, String propertyPath) {
 64  0
         Class<?> propertyType = null;
 65  
 
 66  0
         if (StringUtils.isBlank(propertyPath)) {
 67  0
             return propertyType;
 68  
         }
 69  
 
 70  
         // in case of partial match, holds the class that matched and the
 71  
         // property so we can get by reflection
 72  0
         Class<?> modelClass = view.getFormClass();
 73  0
         String modelProperty = propertyPath;
 74  
 
 75  0
         int bestMatchLength = 0;
 76  
 
 77  
         // removed collection indexes from path for matching
 78  0
         String flattenedPropertyPath = propertyPath.replaceAll("\\[.+\\]", "");
 79  
 
 80  
         // check if property path matches one of the modelClass entries
 81  0
         Map<String, Class<?>> modelClasses = view.getAbstractTypeClasses();
 82  0
         for (String path : modelClasses.keySet()) {
 83  
             // full match
 84  0
             if (StringUtils.equals(path, flattenedPropertyPath)) {
 85  0
                 propertyType = modelClasses.get(path);
 86  0
                 break;
 87  
             }
 88  
 
 89  
             // partial match
 90  0
             if (flattenedPropertyPath.startsWith(path) && (path.length() > bestMatchLength)) {
 91  0
                 bestMatchLength = path.length();
 92  
 
 93  0
                 modelClass = modelClasses.get(path);
 94  0
                 modelProperty = StringUtils.removeStart(flattenedPropertyPath, path);
 95  0
                 modelProperty = StringUtils.removeStart(modelProperty, ".");
 96  
             }
 97  
         }
 98  
 
 99  
         // if full match not found, get type based on reflection
 100  0
         if (propertyType == null) {
 101  0
             propertyType = ObjectPropertyUtils.getPropertyType(modelClass, modelProperty);
 102  
         }
 103  
 
 104  0
         return propertyType;
 105  
     }
 106  
 
 107  
     public static String getParentObjectPath(DataField field) {
 108  0
         String parentObjectPath = "";
 109  
 
 110  0
         String objectPath = field.getBindingInfo().getBindingObjectPath();
 111  0
         String propertyPrefix = field.getBindingInfo().getBindByNamePrefix();
 112  
 
 113  0
         if (!field.getBindingInfo().isBindToForm() && StringUtils.isNotBlank(objectPath)) {
 114  0
             parentObjectPath = objectPath;
 115  
         }
 116  
 
 117  0
         if (StringUtils.isNotBlank(propertyPrefix)) {
 118  0
             if (StringUtils.isNotBlank(parentObjectPath)) {
 119  0
                 parentObjectPath += ".";
 120  
             }
 121  
 
 122  0
             parentObjectPath += propertyPrefix;
 123  
         }
 124  
 
 125  0
         return parentObjectPath;
 126  
     }
 127  
 
 128  
     public static Class<?> getParentObjectClassForMetadata(View view, DataField field) {
 129  0
         String parentObjectPath = getParentObjectPath(field);
 130  
 
 131  0
         return getPropertyTypeByClassAndView(view, parentObjectPath);
 132  
     }
 133  
 
 134  
     public static Class<?> getParentObjectClassForMetadata(View view, Object model, DataField field) {
 135  0
         String parentObjectPath = getParentObjectPath(field);
 136  
 
 137  0
         return getObjectClassForMetadata(view, model, parentObjectPath);
 138  
     }
 139  
 
 140  
     public static Class<?> getObjectClassForMetadata(View view, Object model, String propertyPath) {
 141  
         // get class by object instance if not null
 142  0
         Object parentObject = ObjectPropertyUtils.getPropertyValue(model, propertyPath);
 143  0
         if (parentObject != null) {
 144  0
             return parentObject.getClass();
 145  
         }
 146  
 
 147  
         // get class by property type with abstract map check
 148  0
         return getPropertyTypeByClassAndView(view, propertyPath);
 149  
     }
 150  
 
 151  
     public static Object getParentObjectForMetadata(View view, Object model, DataField field) {
 152  
         // default to model as parent
 153  0
         Object parentObject = model;
 154  
 
 155  0
         String parentObjectPath = getParentObjectPath(field);
 156  0
         if (StringUtils.isNotBlank(parentObjectPath)) {
 157  0
             parentObject = ObjectPropertyUtils.getPropertyValue(model, parentObjectPath);
 158  
 
 159  
             // attempt to create new instance if parent is null or is a
 160  
             // collection or map
 161  0
             if ((parentObject == null) || Collection.class.isAssignableFrom(parentObject.getClass()) ||
 162  
                     Map.class.isAssignableFrom(parentObject.getClass())) {
 163  
                 try {
 164  0
                     Class<?> parentObjectClass = getPropertyTypeByClassAndView(view, parentObjectPath);
 165  0
                     parentObject = parentObjectClass.newInstance();
 166  0
                 } catch (InstantiationException e) {
 167  
                     // swallow exception and let null be returned
 168  0
                 } catch (IllegalAccessException e) {
 169  
                     // swallow exception and let null be returned
 170  0
                 }
 171  
             }
 172  
         }
 173  
 
 174  0
         return parentObject;
 175  
     }
 176  
 
 177  
     /**
 178  
      * Helper method for getting the string value of a property from a {@link PropertyValues}
 179  
      *
 180  
      * @param propertyValues - property values instance to pull from
 181  
      * @param propertyName - name of property whose value should be retrieved
 182  
      * @return String value for property or null if property was not found
 183  
      */
 184  
     public static String getStringValFromPVs(PropertyValues propertyValues, String propertyName) {
 185  0
         String propertyValue = null;
 186  
 
 187  0
         if ((propertyValues != null) && propertyValues.contains(propertyName)) {
 188  0
             Object pvValue = propertyValues.getPropertyValue(propertyName).getValue();
 189  0
             if (pvValue instanceof TypedStringValue) {
 190  0
                 TypedStringValue typedStringValue = (TypedStringValue) pvValue;
 191  0
                 propertyValue = typedStringValue.getValue();
 192  0
             } else if (pvValue instanceof String) {
 193  0
                 propertyValue = (String) pvValue;
 194  
             }
 195  
         }
 196  
 
 197  0
         return propertyValue;
 198  
     }
 199  
 }