| Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
| UifDictionaryIndex | 
 | 
 | 2.7777777777777777;2.778 | 
| 1 |  /* | |
| 2 |   * Copyright 2007 The Kuali Foundation | |
| 3 |   * | |
| 4 |   * Licensed under the Educational Community License, Version 1.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/ecl1.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.container.View; | |
| 23 |  import org.kuali.rice.krad.uif.core.Component; | |
| 24 |  import org.kuali.rice.krad.uif.service.ViewTypeService; | |
| 25 |  import org.springframework.beans.factory.support.DefaultListableBeanFactory; | |
| 26 | ||
| 27 |  import java.util.ArrayList; | |
| 28 |  import java.util.HashMap; | |
| 29 |  import java.util.List; | |
| 30 |  import java.util.Map; | |
| 31 |  import java.util.Map.Entry; | |
| 32 | ||
| 33 |  /** | |
| 34 |   * Indexes <code>View</code> bean entries for retrieval | |
| 35 |   *  | |
| 36 |   * <p> | |
| 37 |   * This is used to retrieve a <code>View</code> instance by its unique id. | |
| 38 |   * Furthermore, view of certain types (that have a <code>ViewTypeService</code> | |
| 39 |   * are indexed by their type to support retrieval of views based on parameters. | |
| 40 |   * </p> | |
| 41 |   *  | |
| 42 |   * @author Kuali Rice Team (rice.collab@kuali.org) | |
| 43 |   */ | |
| 44 | public class UifDictionaryIndex implements Runnable { | |
| 45 | 0 |          private static final Log LOG = LogFactory.getLog(UifDictionaryIndex.class); | 
| 46 | ||
| 47 |          private DefaultListableBeanFactory ddBeans; | |
| 48 | ||
| 49 |          // view entries keyed by view id with value the spring bean name | |
| 50 |          private Map<String, String> viewBeanEntriesById; | |
| 51 | ||
| 52 |          // view entries keyed by bean name with value the view prototype | |
| 53 |          private Map<String, View> viewEntriesByBean; | |
| 54 | ||
| 55 |          // view entries indexed by type | |
| 56 |          private Map<String, ViewTypeDictionaryIndex> viewEntriesByType; | |
| 57 | ||
| 58 | 0 |          public UifDictionaryIndex(DefaultListableBeanFactory ddBeans) { | 
| 59 | 0 |                  this.ddBeans = ddBeans; | 
| 60 | 0 |          } | 
| 61 | ||
| 62 | public void run() { | |
| 63 | 0 |                  LOG.info("Starting View Index Building"); | 
| 64 | 0 |                  buildViewIndicies(); | 
| 65 | 0 |                  LOG.info("Completed View Index Building"); | 
| 66 | 0 |          } | 
| 67 | ||
| 68 |          /** | |
| 69 |           * Retrieves the View instance with the given id from the bean factory. | |
| 70 |           * Since View instances are stateful, we need to get a new instance from | |
| 71 |           * Spring each time. | |
| 72 |           *  | |
| 73 |           * @param viewId | |
| 74 |           *            - the unique id for the view | |
| 75 |           * @return <code>View</code> instance | |
| 76 |           */ | |
| 77 |          public View getViewById(String viewId) { | |
| 78 | 0 |                  String beanName = viewBeanEntriesById.get(viewId); | 
| 79 | 0 |                  if (StringUtils.isBlank(beanName)) { | 
| 80 | 0 |                          throw new DataDictionaryException("Unable to find View with id: " + viewId); | 
| 81 | } | |
| 82 | ||
| 83 | 0 |                  return ddBeans.getBean(beanName, View.class); | 
| 84 | } | |
| 85 | ||
| 86 |          /** | |
| 87 |           * Retrieves a <code>View</code> instance that is of the given type based on | |
| 88 |           * the index key | |
| 89 |           *  | |
| 90 |           * @param viewTypeName | |
| 91 |           *            - type name for the view | |
| 92 |           * @param indexKey | |
| 93 |           *            - 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(String 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.isBlank(beanName)) { | 
| 106 | 0 |                          throw new DataDictionaryException("Unable to find View with index: " + index); | 
| 107 | } | |
| 108 | ||
| 109 | 0 |                  return ddBeans.getBean(beanName, View.class); | 
| 110 | } | |
| 111 | ||
| 112 |          /** | |
| 113 |           * Gets all <code>View</code> prototypes configured for the given view type | |
| 114 |           * name | |
| 115 |           *  | |
| 116 |           * @param viewTypeName | |
| 117 |           *            - view type name to retrieve | |
| 118 |           * @return List<View> view prototypes with the given type name, or empty | |
| 119 |           *         list | |
| 120 |           */ | |
| 121 |          public List<View> getViewsForType(String viewTypeName) { | |
| 122 | 0 |                  List<View> typeViews = new ArrayList<View>(); | 
| 123 | ||
| 124 |                  // get view ids for the type | |
| 125 | 0 |                  if (viewEntriesByType.containsKey(viewTypeName)) { | 
| 126 | 0 |                          ViewTypeDictionaryIndex typeIndex = viewEntriesByType.get(viewTypeName); | 
| 127 | 0 |                          for (Entry<String, String> typeEntry : typeIndex.getViewIndex().entrySet()) { | 
| 128 |                                  // get the view prototype by bean name | |
| 129 | 0 |                                  if (viewEntriesByBean.containsKey(typeEntry.getValue())) { | 
| 130 | 0 |                                          View typeView = viewEntriesByBean.get(typeEntry.getValue()); | 
| 131 | 0 |                                          typeViews.add(typeView); | 
| 132 | 0 |                                  } | 
| 133 | } | |
| 134 | 0 |                  } | 
| 135 |                  else { | |
| 136 | 0 |                          throw new DataDictionaryException("Unable to find view index for type: " + viewTypeName); | 
| 137 | } | |
| 138 | ||
| 139 | 0 |                  return typeViews; | 
| 140 | } | |
| 141 | ||
| 142 |          /** | |
| 143 |           * Initializes the view index <code>Map</code> then iterates through all the | |
| 144 |           * beans in the factory that implement <code>View</code>, adding them to the | |
| 145 |           * index | |
| 146 |           */ | |
| 147 | protected void buildViewIndicies() { | |
| 148 | 0 |                  viewBeanEntriesById = new HashMap<String, String>(); | 
| 149 | 0 |                  viewEntriesByBean = new HashMap<String, View>(); | 
| 150 | 0 |                  viewEntriesByType = new HashMap<String, ViewTypeDictionaryIndex>(); | 
| 151 | ||
| 152 | 0 |                  Map<String, View> viewBeans = ddBeans.getBeansOfType(View.class); | 
| 153 | 0 |                  for (String beanName : viewBeans.keySet()) { | 
| 154 | 0 |                          View view = viewBeans.get(beanName); | 
| 155 | 0 |                          if (viewBeanEntriesById.containsKey(view.getId())) { | 
| 156 | 0 |                                  throw new DataDictionaryException("Two views must not share the same id. Found duplicate id: " | 
| 157 | + view.getId()); | |
| 158 | } | |
| 159 | ||
| 160 | 0 |                          viewBeanEntriesById.put(view.getId(), beanName); | 
| 161 | 0 |                          viewEntriesByBean.put(beanName, view); | 
| 162 | ||
| 163 | 0 |                          indexViewForType(view, beanName); | 
| 164 | 0 |                  } | 
| 165 | ||
| 166 |          // trigger a load of all component so they will get indexed in the component factory | |
| 167 | 0 |          Map<String, Component> componentBeans = ddBeans.getBeansOfType(Component.class); | 
| 168 | 0 |          } | 
| 169 | ||
| 170 |          /** | |
| 171 |           * Performs additional indexing based on the view type associated with the | |
| 172 |           * view instance. The <code>ViewTypeService</code> associated with the view | |
| 173 |           * type name on the instance is invoked to retrieve the parameter key/value | |
| 174 |           * pairs from the view instance, which are then used to build up an index | |
| 175 |           * which will key the entry | |
| 176 |           *  | |
| 177 |           * @param view | |
| 178 |           *            - view instance to index | |
| 179 |           * @param beanName | |
| 180 |           *            - name of the view's bean in Spring | |
| 181 |           */ | |
| 182 | protected void indexViewForType(View view, String beanName) { | |
| 183 | 0 |                  String viewType = view.getViewTypeName(); | 
| 184 | ||
| 185 | 0 |                  ViewTypeService typeService = KRADServiceLocatorWeb.getViewService().getViewTypeService(viewType); | 
| 186 | 0 |                  if (typeService == null) { | 
| 187 |                          // don't do any further indexing | |
| 188 | 0 |                          return; | 
| 189 | } | |
| 190 | ||
| 191 |                  // invoke type service to retrieve it parameter name/value pairs from | |
| 192 |                  // the view | |
| 193 | 0 |                  Map<String, String> typeParameters = typeService.getParametersFromView(view); | 
| 194 | ||
| 195 |                  // build the index string from the parameters | |
| 196 | 0 |                  String index = buildTypeIndex(typeParameters); | 
| 197 | ||
| 198 |                  // get the index for the type and add the view entry | |
| 199 | 0 |                  ViewTypeDictionaryIndex typeIndex = getTypeIndex(viewType); | 
| 200 | ||
| 201 | 0 |                  typeIndex.put(index, beanName); | 
| 202 | 0 |          } | 
| 203 | ||
| 204 |          /** | |
| 205 |           * Retrieves the <code>ViewTypeDictionaryIndex</code> instance for the given | |
| 206 |           * view type name. If one does not exist yet for the given name, a new | |
| 207 |           * instance is created | |
| 208 |           *  | |
| 209 |           * @param viewType | |
| 210 |           *            - name of the view type to retrieve index for | |
| 211 |           * @return ViewTypeDictionaryIndex instance | |
| 212 |           */ | |
| 213 |          protected ViewTypeDictionaryIndex getTypeIndex(String viewType) { | |
| 214 | 0 |                  ViewTypeDictionaryIndex typeIndex = null; | 
| 215 | ||
| 216 | 0 |                  if (viewEntriesByType.containsKey(viewType)) { | 
| 217 | 0 |                          typeIndex = viewEntriesByType.get(viewType); | 
| 218 | } | |
| 219 |                  else { | |
| 220 | 0 |                          typeIndex = new ViewTypeDictionaryIndex(); | 
| 221 | 0 |                          viewEntriesByType.put(viewType, typeIndex); | 
| 222 | } | |
| 223 | ||
| 224 | 0 |                  return typeIndex; | 
| 225 | } | |
| 226 | ||
| 227 |          /** | |
| 228 |           * Builds up an index string from the given Map of parameters | |
| 229 |           *  | |
| 230 |           * @param typeParameters | |
| 231 |           *            - Map of parameters to use for index | |
| 232 |           * @return String index | |
| 233 |           */ | |
| 234 |          protected String buildTypeIndex(Map<String, String> typeParameters) { | |
| 235 | 0 |                  String index = ""; | 
| 236 | ||
| 237 | 0 |                  for (String parameterName : typeParameters.keySet()) { | 
| 238 | 0 |                          if (StringUtils.isNotBlank(index)) { | 
| 239 | 0 |                                  index += "|||"; | 
| 240 | } | |
| 241 | 0 |                          index += parameterName + "^^" + typeParameters.get(parameterName); | 
| 242 | } | |
| 243 | ||
| 244 | 0 |                  return index; | 
| 245 | } | |
| 246 | ||
| 247 | } |