Coverage Report - org.kuali.rice.krad.datadictionary.UifDictionaryIndex
 
Classes in this File Line Coverage Branch Coverage Complexity
UifDictionaryIndex
4%
4/86
0%
0/30
2.917
 
 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.datadictionary;
 17  
 
 18  
 import org.apache.commons.lang.StringUtils;
 19  
 import org.apache.commons.logging.Log;
 20  
 import org.apache.commons.logging.LogFactory;
 21  
 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
 22  
 import org.kuali.rice.krad.uif.UifConstants;
 23  
 import org.kuali.rice.krad.uif.component.Component;
 24  
 import org.kuali.rice.krad.uif.util.ComponentUtils;
 25  
 import org.kuali.rice.krad.uif.util.ViewModelUtils;
 26  
 import org.kuali.rice.krad.uif.view.View;
 27  
 import org.kuali.rice.krad.uif.service.ViewTypeService;
 28  
 import org.springframework.beans.PropertyValues;
 29  
 import org.springframework.beans.factory.config.BeanDefinition;
 30  
 import org.springframework.beans.factory.support.DefaultListableBeanFactory;
 31  
 import org.kuali.rice.krad.uif.UifConstants.ViewType;
 32  
 
 33  
 import java.util.ArrayList;
 34  
 import java.util.HashMap;
 35  
 import java.util.List;
 36  
 import java.util.Map;
 37  
 import java.util.Map.Entry;
 38  
 
 39  
 /**
 40  
  * Indexes <code>View</code> bean entries for retrieval
 41  
  *
 42  
  * <p>
 43  
  * This is used to retrieve a <code>View</code> instance by its unique id.
 44  
  * Furthermore, view of certain types (that have a <code>ViewTypeService</code>
 45  
  * are indexed by their type to support retrieval of views based on parameters.
 46  
  * </p>
 47  
  *
 48  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 49  
  */
 50  
 public class UifDictionaryIndex implements Runnable {
 51  1
     private static final Log LOG = LogFactory.getLog(UifDictionaryIndex.class);
 52  
 
 53  
     private DefaultListableBeanFactory ddBeans;
 54  
 
 55  
     // view entries keyed by view id with value the spring bean name
 56  
     private Map<String, String> viewBeanEntriesById;
 57  
 
 58  
     // view entries indexed by type
 59  
     private Map<String, ViewTypeDictionaryIndex> viewEntriesByType;
 60  
 
 61  5
     public UifDictionaryIndex(DefaultListableBeanFactory ddBeans) {
 62  5
         this.ddBeans = ddBeans;
 63  5
     }
 64  
 
 65  
     public void run() {
 66  0
         LOG.info("Starting View Index Building");
 67  0
         buildViewIndicies();
 68  0
         LOG.info("Completed View Index Building");
 69  0
     }
 70  
 
 71  
     /**
 72  
      * Retrieves the View instance with the given id from the bean factory.
 73  
      * Since View instances are stateful, we need to get a new instance from
 74  
      * Spring each time.
 75  
      *
 76  
      * @param viewId - the unique id for the view
 77  
      * @return <code>View</code> instance
 78  
      */
 79  
     public View getViewById(String viewId) {
 80  0
         String beanName = viewBeanEntriesById.get(viewId);
 81  0
         if (StringUtils.isBlank(beanName)) {
 82  0
             throw new DataDictionaryException("Unable to find View with id: " + viewId);
 83  
         }
 84  
 
 85  0
         return ddBeans.getBean(beanName, View.class);
 86  
     }
 87  
 
 88  
     /**
 89  
      * Retrieves a <code>View</code> instance that is of the given type based on
 90  
      * the index key
 91  
      *
 92  
      * @param viewTypeName - type name for the view
 93  
      * @param indexKey - Map of index key parameters, these are the parameters the
 94  
      * indexer used to index the view initially and needs to identify
 95  
      * an unique view instance
 96  
      * @return View instance that matches the given index or Null if one is not
 97  
      *         found
 98  
      */
 99  
     public View getViewByTypeIndex(ViewType viewTypeName, Map<String, String> indexKey) {
 100  0
         String index = buildTypeIndex(indexKey);
 101  
 
 102  0
         ViewTypeDictionaryIndex typeIndex = getTypeIndex(viewTypeName);
 103  
 
 104  0
         String beanName = typeIndex.get(index);
 105  0
         if (StringUtils.isNotBlank(beanName)) {
 106  0
             return ddBeans.getBean(beanName, View.class);
 107  
         }
 108  
 
 109  0
         return null;
 110  
     }
 111  
 
 112  
     /**
 113  
      * Indicates whether a <code>View</code> exists for the given view type and index information
 114  
      *
 115  
      * @param viewTypeName - type name for the view
 116  
      * @param indexKey - Map of index key parameters, these are the parameters the indexer used to index
 117  
      * the view initially and needs to identify an unique view instance
 118  
      * @return boolean true if view exists, false if not
 119  
      */
 120  
     public boolean viewByTypeExist(ViewType viewTypeName, Map<String, String> indexKey) {
 121  0
         boolean viewExist = false;
 122  
 
 123  0
         String index = buildTypeIndex(indexKey);
 124  0
         ViewTypeDictionaryIndex typeIndex = getTypeIndex(viewTypeName);
 125  
 
 126  0
         String beanName = typeIndex.get(index);
 127  0
         if (StringUtils.isNotBlank(beanName)) {
 128  0
             viewExist = true;
 129  
         }
 130  
 
 131  0
         return viewExist;
 132  
     }
 133  
 
 134  
     /**
 135  
      * Retrieves the configured property values for the view bean definition associated with the given id
 136  
      *
 137  
      * <p>
 138  
      * Since constructing the View object can be expensive, when metadata only is needed this method can be used
 139  
      * to retrieve the configured property values. Note this looks at the merged bean definition
 140  
      * </p>
 141  
      *
 142  
      * @param viewId - id for the view to retrieve
 143  
      * @return PropertyValues configured on the view bean definition, or null if view is not found
 144  
      */
 145  
     public PropertyValues getViewPropertiesById(String viewId) {
 146  0
         String beanName = viewBeanEntriesById.get(viewId);
 147  0
         if (StringUtils.isBlank(beanName)) {
 148  0
             BeanDefinition beanDefinition = ddBeans.getMergedBeanDefinition(beanName);
 149  
 
 150  0
             return beanDefinition.getPropertyValues();
 151  
         }
 152  
 
 153  0
         return null;
 154  
     }
 155  
 
 156  
     /**
 157  
      * Retrieves the configured property values for the view bean definition associated with the given type and
 158  
      * index
 159  
      *
 160  
      * <p>
 161  
      * Since constructing the View object can be expensive, when metadata only is needed this method can be used
 162  
      * to retrieve the configured property values. Note this looks at the merged bean definition
 163  
      * </p>
 164  
      *
 165  
      * @param viewTypeName - type name for the view
 166  
      * @param indexKey - Map of index key parameters, these are the parameters the indexer used to index
 167  
      * the view initially and needs to identify an unique view instance
 168  
      * @return PropertyValues configured on the view bean definition, or null if view is not found
 169  
      */
 170  
     public PropertyValues getViewPropertiesByType(ViewType viewTypeName, Map<String, String> indexKey) {
 171  0
         String index = buildTypeIndex(indexKey);
 172  
 
 173  0
         ViewTypeDictionaryIndex typeIndex = getTypeIndex(viewTypeName);
 174  
 
 175  0
         String beanName = typeIndex.get(index);
 176  0
         if (StringUtils.isNotBlank(beanName)) {
 177  0
             BeanDefinition beanDefinition = ddBeans.getMergedBeanDefinition(beanName);
 178  
 
 179  0
             return beanDefinition.getPropertyValues();
 180  
         }
 181  
 
 182  0
         return null;
 183  
     }
 184  
 
 185  
     /**
 186  
      * Gets all <code>View</code> prototypes configured for the given view type
 187  
      * name
 188  
      *
 189  
      * @param viewTypeName - view type name to retrieve
 190  
      * @return List<View> view prototypes with the given type name, or empty
 191  
      *         list
 192  
      */
 193  
     public List<View> getViewsForType(ViewType viewTypeName) {
 194  0
         List<View> typeViews = new ArrayList<View>();
 195  
 
 196  
         // get view ids for the type
 197  0
         if (viewEntriesByType.containsKey(viewTypeName.name())) {
 198  0
             ViewTypeDictionaryIndex typeIndex = viewEntriesByType.get(viewTypeName.name());
 199  0
             for (Entry<String, String> typeEntry : typeIndex.getViewIndex().entrySet()) {
 200  0
                 View typeView = ddBeans.getBean(typeEntry.getValue(), View.class);
 201  0
                 typeViews.add(typeView);
 202  0
             }
 203  0
         } else {
 204  0
             throw new DataDictionaryException("Unable to find view index for type: " + viewTypeName);
 205  
         }
 206  
 
 207  0
         return typeViews;
 208  
     }
 209  
 
 210  
     /**
 211  
      * Initializes the view index <code>Map</code> then iterates through all the
 212  
      * beans in the factory that implement <code>View</code>, adding them to the
 213  
      * index
 214  
      */
 215  
     protected void buildViewIndicies() {
 216  0
         viewBeanEntriesById = new HashMap<String, String>();
 217  0
         viewEntriesByType = new HashMap<String, ViewTypeDictionaryIndex>();
 218  
 
 219  0
         String[] beanNames = ddBeans.getBeanNamesForType(View.class);
 220  0
         for (int i = 0; i < beanNames.length; i++) {
 221  0
             String beanName = beanNames[i];
 222  0
             BeanDefinition beanDefinition = ddBeans.getMergedBeanDefinition(beanName);
 223  0
             PropertyValues propertyValues = beanDefinition.getPropertyValues();
 224  
 
 225  0
             String id = ViewModelUtils.getStringValFromPVs(propertyValues, "id");
 226  0
             if (StringUtils.isBlank(id)) {
 227  0
                 id = beanName;
 228  
             }
 229  
 
 230  0
             if (viewBeanEntriesById.containsKey(id)) {
 231  0
                 throw new DataDictionaryException("Two views must not share the same id. Found duplicate id: " + id);
 232  
             }
 233  0
             viewBeanEntriesById.put(id, beanName);
 234  
 
 235  0
             indexViewForType(propertyValues, beanName);
 236  
         }
 237  0
     }
 238  
 
 239  
     /**
 240  
      * Performs additional indexing based on the view type associated with the view instance. The
 241  
      * <code>ViewTypeService</code> associated with the view type name on the instance is invoked to retrieve
 242  
      * the parameter key/value pairs from the configured property values, which are then used to build up an index
 243  
      * used to key the entry
 244  
      *
 245  
      * @param propertyValues - property values configured on the view bean definition
 246  
      * @param beanName - name of the view's bean in Spring
 247  
      */
 248  
     protected void indexViewForType(PropertyValues propertyValues, String beanName) {
 249  0
         String viewTypeName = ViewModelUtils.getStringValFromPVs(propertyValues,  "viewTypeName");
 250  0
         if (StringUtils.isBlank(viewTypeName)) {
 251  0
             return;
 252  
         }
 253  
 
 254  0
         UifConstants.ViewType viewType = ViewType.valueOf(viewTypeName);
 255  
 
 256  0
         ViewTypeService typeService = KRADServiceLocatorWeb.getViewService().getViewTypeService(viewType);
 257  0
         if (typeService == null) {
 258  
             // don't do any further indexing
 259  0
             return;
 260  
         }
 261  
 
 262  
         // invoke type service to retrieve it parameter name/value pairs
 263  0
         Map<String, String> typeParameters = typeService.getParametersFromViewConfiguration(propertyValues);
 264  
 
 265  
         // build the index string from the parameters
 266  0
         String index = buildTypeIndex(typeParameters);
 267  
 
 268  
         // get the index for the type and add the view entry
 269  0
         ViewTypeDictionaryIndex typeIndex = getTypeIndex(viewType);
 270  
 
 271  0
         typeIndex.put(index, beanName);
 272  0
     }
 273  
 
 274  
     /**
 275  
      * Retrieves the <code>ViewTypeDictionaryIndex</code> instance for the given
 276  
      * view type name. If one does not exist yet for the given name, a new
 277  
      * instance is created
 278  
      *
 279  
      * @param viewType - name of the view type to retrieve index for
 280  
      * @return ViewTypeDictionaryIndex instance
 281  
      */
 282  
     protected ViewTypeDictionaryIndex getTypeIndex(UifConstants.ViewType viewType) {
 283  0
         ViewTypeDictionaryIndex typeIndex = null;
 284  
 
 285  0
         if (viewEntriesByType.containsKey(viewType.name())) {
 286  0
             typeIndex = viewEntriesByType.get(viewType.name());
 287  
         } else {
 288  0
             typeIndex = new ViewTypeDictionaryIndex();
 289  0
             viewEntriesByType.put(viewType.name(), typeIndex);
 290  
         }
 291  
 
 292  0
         return typeIndex;
 293  
     }
 294  
 
 295  
     /**
 296  
      * Builds up an index string from the given Map of parameters
 297  
      *
 298  
      * @param typeParameters - Map of parameters to use for index
 299  
      * @return String index
 300  
      */
 301  
     protected String buildTypeIndex(Map<String, String> typeParameters) {
 302  0
         String index = "";
 303  
 
 304  0
         for (String parameterName : typeParameters.keySet()) {
 305  0
             if (StringUtils.isNotBlank(index)) {
 306  0
                 index += "|||";
 307  
             }
 308  0
             index += parameterName + "^^" + typeParameters.get(parameterName);
 309  
         }
 310  
 
 311  0
         return index;
 312  
     }
 313  
 
 314  
 }