/**
   * Performs additional indexing based on the view type associated with the view instance. The
   * {@code ViewTypeService} associated with the view type name on the instance is invoked to
   * retrieve the parameter key/value pairs from the configured property values, which are then used
   * to build up an index used to key the entry
   *
   * @param propertyValues - property values configured on the view bean definition
   * @param id - id (or bean name if id was not set) for the view
   */
  protected void indexViewForType(PropertyValues propertyValues, String id) {
    String viewTypeName = ViewModelUtils.getStringValFromPVs(propertyValues, "viewTypeName");
    if (StringUtils.isBlank(viewTypeName)) {
      return;
    }

    UifConstants.ViewType viewType = ViewType.valueOf(viewTypeName);

    ViewTypeService typeService =
        KRADServiceLocatorWeb.getViewService().getViewTypeService(viewType);
    if (typeService == null) {
      // don't do any further indexing
      return;
    }

    // invoke type service to retrieve it parameter name/value pairs
    Map<String, String> typeParameters =
        typeService.getParametersFromViewConfiguration(propertyValues);

    // build the index string from the parameters
    String index = buildTypeIndex(typeParameters);

    // get the index for the type and add the view entry
    ViewTypeDictionaryIndex typeIndex = getTypeIndex(viewType);

    typeIndex.put(index, id);
  }
  /**
   * Initializes the view index {@code Map} then iterates through all the beans in the factory that
   * implement {@code View}, adding them to the index
   */
  protected void buildViewIndicies() {
    LOG.info("Starting View Index Building");

    viewBeanEntriesById = new HashMap<String, String>();
    viewEntriesByType = new HashMap<String, ViewTypeDictionaryIndex>();
    viewPools = new HashMap<String, UifViewPool>();

    boolean inDevMode =
        Boolean.parseBoolean(
            ConfigContext.getCurrentContextConfig()
                .getProperty(KRADConstants.ConfigParameters.KRAD_DEV_MODE));

    ExecutorService executor = Executors.newFixedThreadPool(threadPoolSize);

    String[] beanNames = ddBeans.getBeanNamesForType(View.class);
    for (final String beanName : beanNames) {
      BeanDefinition beanDefinition = ddBeans.getMergedBeanDefinition(beanName);
      PropertyValues propertyValues = beanDefinition.getPropertyValues();

      String id = ViewModelUtils.getStringValFromPVs(propertyValues, "id");
      if (StringUtils.isBlank(id)) {
        id = beanName;
      }

      if (viewBeanEntriesById.containsKey(id)) {
        throw new DataDictionaryException(
            "Two views must not share the same id. Found duplicate id: " + id);
      }

      viewBeanEntriesById.put(id, beanName);

      indexViewForType(propertyValues, id);

      // pre-load views if necessary
      if (!inDevMode) {
        String poolSizeStr = ViewModelUtils.getStringValFromPVs(propertyValues, "preloadPoolSize");
        if (StringUtils.isNotBlank(poolSizeStr)) {
          int poolSize = Integer.parseInt(poolSizeStr);
          if (poolSize < 1) {
            continue;
          }

          final View view = (View) ddBeans.getBean(beanName);
          final UifViewPool viewPool = new UifViewPool();
          viewPool.setMaxSize(poolSize);
          for (int j = 0; j < poolSize; j++) {
            Runnable createView =
                new Runnable() {
                  @Override
                  public void run() {
                    viewPool.addViewInstance((View) CopyUtils.copy(view));
                  }
                };

            executor.execute(createView);
          }
          viewPools.put(id, viewPool);
        }
      }
    }

    executor.shutdown();

    LOG.info("Completed View Index Building");
  }