Coverage Report - org.kuali.rice.krad.uif.util.ViewModelUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
ViewModelUtils
0%
0/50
0%
0/30
4.167
 
 1  
 /*
 2  
  * Copyright 2007 The Kuali Foundation Licensed under the Educational Community
 3  
  * License, Version 1.0 (the "License"); you may not use this file except in
 4  
  * compliance with the License. You may obtain a copy of the License at
 5  
  * http://www.opensource.org/licenses/ecl1.php Unless required by applicable law
 6  
  * or agreed to in writing, software distributed under the License is
 7  
  * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 8  
  * KIND, either express or implied. See the License for the specific language
 9  
  * governing permissions and limitations under the License.
 10  
  */
 11  
 package org.kuali.rice.krad.uif.util;
 12  
 
 13  
 import org.apache.commons.lang.StringUtils;
 14  
 import org.kuali.rice.krad.uif.container.View;
 15  
 import org.kuali.rice.krad.uif.field.AttributeField;
 16  
 
 17  
 import java.util.Collection;
 18  
 import java.util.Map;
 19  
 
 20  
 /**
 21  
  * Provides methods for getting property values, types, and paths within the
 22  
  * context of a <code>View</code>
 23  
  *
 24  
  * <p>
 25  
  * The view provides a special map named 'abstractTypeClasses' that indicates
 26  
  * concrete classes that should be used in place of abstract property types that
 27  
  * are encountered on the object graph. This classes takes into account that map
 28  
  * while dealing with properties. e.g. suppose we have propertyPath
 29  
  * 'document.name' on the form, with the type of the document property set to
 30  
  * the interface Document. Using class introspection we would get back the
 31  
  * interface type for document and this would not be able to get the property
 32  
  * type for name. Using the view map, we can replace document with a concrete
 33  
  * class and then use it to get the name property
 34  
  * </p>
 35  
  *
 36  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 37  
  */
 38  0
 public class ViewModelUtils {
 39  
 
 40  
     /**
 41  
      * Determines the associated type for the property within the View context
 42  
      *
 43  
      * <p>
 44  
      * Property path is full path to property from the View Form class. The abstract type classes
 45  
      * map configured on the View will be consulted for any entries that match the property path. If the
 46  
      * property path given contains a partial match to an abstract class (somewhere on path is an abstract
 47  
      * class), the property type will be retrieved based on the given concrete class to use and the part
 48  
      * of the path remaining. If no matching entry is found, standard reflection is used to get the type
 49  
      * </p>
 50  
      *
 51  
      * @param view - view instance providing the context (abstract map)
 52  
      * @param propertyPath - full path to property to retrieve type for (relative to the form class)
 53  
      * @return Class<?> type of property in model, or Null if type could not be determined
 54  
      * @see org.kuali.rice.krad.uif.container.View#getAbstractTypeClasses()
 55  
      */
 56  
     public static Class<?> getPropertyTypeByClassAndView(View view, String propertyPath) {
 57  0
         Class<?> propertyType = null;
 58  
 
 59  0
         if (StringUtils.isBlank(propertyPath)) {
 60  0
             return propertyType;
 61  
         }
 62  
 
 63  
         // in case of partial match, holds the class that matched and the
 64  
         // property so we can get by reflection
 65  0
         Class<?> modelClass = view.getFormClass();
 66  0
         String modelProperty = propertyPath;
 67  
 
 68  0
         int bestMatchLength = 0;
 69  
 
 70  
         // removed collection indexes from path for matching
 71  0
         String flattenedPropertyPath = propertyPath.replaceAll("\\[.+\\]", "");
 72  
 
 73  
         // check if property path matches one of the modelClass entries
 74  0
         Map<String, Class<?>> modelClasses = view.getAbstractTypeClasses();
 75  0
         for (String path : modelClasses.keySet()) {
 76  
             // full match
 77  0
             if (StringUtils.equals(path, flattenedPropertyPath)) {
 78  0
                 propertyType = modelClasses.get(path);
 79  0
                 break;
 80  
             }
 81  
 
 82  
             // partial match
 83  0
             if (flattenedPropertyPath.startsWith(path) && (path.length() > bestMatchLength)) {
 84  0
                 bestMatchLength = path.length();
 85  
 
 86  0
                 modelClass = modelClasses.get(path);
 87  0
                 modelProperty = StringUtils.removeStart(flattenedPropertyPath, path);
 88  0
                 modelProperty = StringUtils.removeStart(modelProperty, ".");
 89  
             }
 90  
         }
 91  
 
 92  
         // if full match not found, get type based on reflection
 93  0
         if (propertyType == null) {
 94  0
             propertyType = ObjectPropertyUtils.getPropertyType(modelClass, modelProperty);
 95  
         }
 96  
 
 97  0
         return propertyType;
 98  
     }
 99  
 
 100  
     public static String getParentObjectPath(AttributeField field) {
 101  0
         String parentObjectPath = "";
 102  
 
 103  0
         String objectPath = field.getBindingInfo().getBindingObjectPath();
 104  0
         String propertyPrefix = field.getBindingInfo().getBindByNamePrefix();
 105  
 
 106  0
         if (!field.getBindingInfo().isBindToForm() && StringUtils.isNotBlank(objectPath)) {
 107  0
             parentObjectPath = objectPath;
 108  
         }
 109  
 
 110  0
         if (StringUtils.isNotBlank(propertyPrefix)) {
 111  0
             if (StringUtils.isNotBlank(parentObjectPath)) {
 112  0
                 parentObjectPath += ".";
 113  
             }
 114  
 
 115  0
             parentObjectPath += propertyPrefix;
 116  
         }
 117  
 
 118  0
         return parentObjectPath;
 119  
     }
 120  
 
 121  
     public static Class<?> getParentObjectClassForMetadata(View view, AttributeField field) {
 122  0
         String parentObjectPath = getParentObjectPath(field);
 123  
 
 124  0
         return getPropertyTypeByClassAndView(view, parentObjectPath);
 125  
     }
 126  
 
 127  
     public static Class<?> getParentObjectClassForMetadata(View view, Object model, AttributeField field) {
 128  0
         String parentObjectPath = getParentObjectPath(field);
 129  
 
 130  0
         return getObjectClassForMetadata(view, model, parentObjectPath);
 131  
     }
 132  
 
 133  
     public static Class<?> getObjectClassForMetadata(View view, Object model, String propertyPath) {
 134  
         // get class by object instance if not null
 135  0
         Object parentObject = ObjectPropertyUtils.getPropertyValue(model, propertyPath);
 136  0
         if (parentObject != null) {
 137  0
             return parentObject.getClass();
 138  
         }
 139  
 
 140  
         // get class by property type with abstract map check
 141  0
         return getPropertyTypeByClassAndView(view, propertyPath);
 142  
     }
 143  
 
 144  
     public static Object getParentObjectForMetadata(View view, Object model, AttributeField field) {
 145  
         // default to model as parent
 146  0
         Object parentObject = model;
 147  
 
 148  0
         String parentObjectPath = getParentObjectPath(field);
 149  0
         if (StringUtils.isNotBlank(parentObjectPath)) {
 150  0
             parentObject = ObjectPropertyUtils.getPropertyValue(model, parentObjectPath);
 151  
 
 152  
             // attempt to create new instance if parent is null or is a
 153  
             // collection or map
 154  0
             if ((parentObject == null) || Collection.class.isAssignableFrom(parentObject.getClass()) ||
 155  
                     Map.class.isAssignableFrom(parentObject.getClass())) {
 156  
                 try {
 157  0
                     Class<?> parentObjectClass = getPropertyTypeByClassAndView(view, parentObjectPath);
 158  0
                     parentObject = parentObjectClass.newInstance();
 159  0
                 } catch (InstantiationException e) {
 160  
                     // swallow exception and let null be returned
 161  0
                 } catch (IllegalAccessException e) {
 162  
                     // swallow exception and let null be returned
 163  0
                 }
 164  
             }
 165  
         }
 166  
 
 167  0
         return parentObject;
 168  
     }
 169  
 }