@Override
  protected View loadView(String viewName, Locale locale) throws Exception {
    Assert.notNull(templateEngine, "Property [templateEngine] cannot be null");
    if (viewName.endsWith(GSP_SUFFIX)) {
      viewName = viewName.substring(0, viewName.length() - GSP_SUFFIX.length());
    }

    if (!allowGrailsViewCaching) {
      return createGrailsView(viewName);
    }

    String viewCacheKey = groovyPageLocator.resolveViewFormat(viewName);

    String currentControllerKeyPrefix = resolveCurrentControllerKeyPrefixes();
    if (currentControllerKeyPrefix != null) {
      viewCacheKey = currentControllerKeyPrefix + ':' + viewCacheKey;
    }

    CacheEntry<View> entry = viewCache.get(viewCacheKey);

    final String lookupViewName = viewName;
    Callable<View> updater =
        new Callable<View>() {
          public View call() throws Exception {
            try {
              return createGrailsView(lookupViewName);
            } catch (Exception e) {
              throw new WrappedInitializationException(e);
            }
          }
        };

    View view = null;
    if (entry == null) {
      try {
        return CacheEntry.getValue(viewCache, viewCacheKey, cacheTimeout, updater);
      } catch (CacheEntry.UpdateException e) {
        e.rethrowCause();
        // make compiler happy
        return null;
      }
    }

    try {
      view = entry.getValue(cacheTimeout, updater, true, null);
    } catch (WrappedInitializationException e) {
      e.rethrowCause();
    }

    return view;
  }
 /**
  * Get a PropertiesHolder that contains the actually visible properties for a Locale, after
  * merging all specified resource bundles. Either fetches the holder from the cache or freshly
  * loads it.
  *
  * <p>Only used when caching resource bundle contents forever, i.e. with cacheSeconds < 0.
  * Therefore, merged properties are always cached forever.
  */
 protected PropertiesHolder getMergedPluginProperties(final Locale locale) {
   return CacheEntry.getValue(
       cachedMergedPluginProperties,
       locale,
       cacheMillis,
       new Callable<PropertiesHolder>() {
         @Override
         public PropertiesHolder call() throws Exception {
           Properties mergedProps = new Properties();
           PropertiesHolder mergedHolder = new PropertiesHolder(mergedProps);
           mergeBinaryPluginProperties(locale, mergedProps);
           for (String basename : pluginBaseNames) {
             List<Pair<String, Resource>> filenamesAndResources =
                 calculateAllFilenames(basename, locale);
             for (int j = filenamesAndResources.size() - 1; j >= 0; j--) {
               Pair<String, Resource> filenameAndResource = filenamesAndResources.get(j);
               if (filenameAndResource.getbValue() != null) {
                 PropertiesHolder propHolder =
                     getProperties(
                         filenameAndResource.getaValue(), filenameAndResource.getbValue());
                 mergedProps.putAll(propHolder.getProperties());
               }
             }
           }
           return mergedHolder;
         }
       });
 }
 protected PropertiesHolder getMergedBinaryPluginProperties(final Locale locale) {
   return CacheEntry.getValue(
       cachedMergedBinaryPluginProperties,
       locale,
       cacheMillis,
       new Callable<PropertiesHolder>() {
         @Override
         public PropertiesHolder call() throws Exception {
           Properties mergedProps = new Properties();
           PropertiesHolder mergedHolder = new PropertiesHolder(mergedProps);
           mergeBinaryPluginProperties(locale, mergedProps);
           return mergedHolder;
         }
       });
 }