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