protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent)
      throws BeansException {
    WebApplicationContext wac =
        WebApplicationContextUtils.getWebApplicationContext(getServletContext());
    WebApplicationContext webContext;
    // construct the SpringConfig for the container managed application
    Assert.notNull(
        parent,
        "Grails requires a parent ApplicationContext, is the /WEB-INF/applicationContext.xml file missing?");
    this.application =
        (GrailsApplication)
            parent.getBean(GrailsApplication.APPLICATION_ID, GrailsApplication.class);

    if (wac instanceof GrailsApplicationContext) {
      webContext = wac;
    } else {
      webContext = GrailsConfigUtils.configureWebApplicationContext(getServletContext(), parent);
      try {
        GrailsConfigUtils.executeGrailsBootstraps(application, webContext, getServletContext());
      } catch (Exception e) {
        GrailsUtil.deepSanitize(e);
        if (e instanceof BeansException) throw (BeansException) e;
        else {
          throw new BootstrapException("Error executing bootstraps", e);
        }
      }
    }

    initMainController(webContext);
    this.interceptors = establishInterceptors(webContext);

    return webContext;
  }
  public void rebuild() {
    initialised = false;
    loadedClasses.clear();
    initArtefactHandlers();

    if (GrailsUtil.isDevelopmentEnv()) {
      initialise();
    } else {
      throw new IllegalStateException(
          "Cannot rebuild GrailsApplication when not in development mode!");
    }
  }
示例#3
0
 /**
  * Get the default Compass connection (ie, Lucene index dir)
  *
  * @param grailsApplication the GrailsApplication - may be null
  * @return {user.home}/.grails/projects/{project-name}/searchable-index/{grails.env}
  */
 public static String getDefaultConnection(GrailsApplication grailsApplication) {
   String appName = SearchableUtils.getAppName(grailsApplication);
   return new StringBuffer(System.getProperty("user.home"))
       .append(File.separator)
       .append(".grails")
       .append(File.separator)
       .append("projects")
       .append(File.separator)
       .append(appName)
       .append(File.separator)
       .append("searchable-index")
       .append(File.separator)
       .append(GrailsUtil.getEnvironment())
       .toString();
 }
 /* (non-Javadoc)
  * @see org.codehaus.groovy.grails.plugins.AbstractGrailsPlugin#refresh()
  */
 @Override
 public void refresh() {
   // do nothing
   Resource descriptor = getDescriptor();
   if (application != null && descriptor != null) {
     ClassLoader parent = application.getClassLoader();
     GroovyClassLoader gcl = new GroovyClassLoader(parent);
     try {
       Class pluginClass = gcl.parseClass(descriptor.getFile());
       initialisePlugin(pluginClass);
     } catch (Exception e) {
       GrailsUtil.deepSanitize(e);
       LOG.error("Error refreshing plugin: " + e.getMessage(), e);
     }
   }
 }
  /**
   * Creates a GroovyPageMetaInfo instance from the given Parse object, and initialises it with the
   * the specified last modifed date and InputStream
   *
   * @param parse The Parse object
   * @param lastModified The last modified date
   * @param in The InputStream instance
   * @return A GroovyPageMetaInfo instance
   */
  private GroovyPageMetaInfo createPageMetaInfo(
      GroovyPageParser parse, long lastModified, InputStream in) {
    GroovyPageMetaInfo pageMeta = new GroovyPageMetaInfo();
    pageMeta.setJspTagLibraryResolver(jspTagLibraryResolver);
    pageMeta.setTagLibraryLookup(tagLibraryLookup);
    pageMeta.setContentType(parse.getContentType());
    pageMeta.setLineNumbers(parse.getLineNumberMatrix());
    pageMeta.setLastModified(lastModified);
    pageMeta.setJspTags(parse.getJspTags());
    pageMeta.setCodecName(parse.getDefaultCodecDirectiveValue());
    pageMeta.initCodec();
    // just return groovy and don't compile if asked
    if (isReloadEnabled() || GrailsUtil.isDevelopmentEnv()) {
      pageMeta.setGroovySource(in);
    }

    return pageMeta;
  }
  @Override
  protected View loadView(String viewName, Locale locale) throws Exception {
    Assert.notNull(templateEngine, "Property [templateEngine] cannot be null");

    if (GrailsUtil.isDevelopmentEnv()) {
      return createGrailsView(viewName);
    }

    View view = VIEW_CACHE.get(viewName);
    if (view == null
        || (templateEngine.isReloadEnabled()
            && view instanceof GroovyPageView
            && ((GroovyPageView) view).isExpired())) {
      view = createGrailsView(viewName);
    }
    VIEW_CACHE.put(viewName, view);
    return view;
  }
  @Override
  protected View loadView(String viewName, Locale locale) throws Exception {
    final View resolvedView = super.loadView(viewName, locale);
    if (templateGenerator == null || resolvedView instanceof GroovyPageView) {
      return resolvedView;
    }

    GrailsWebRequest webRequest = WebUtils.retrieveGrailsWebRequest();
    List<String> controllerActions = scaffoldedActionMap.get(webRequest.getControllerName());
    if (controllerActions != null && controllerActions.contains(webRequest.getActionName())) {
      GrailsDomainClass domainClass = scaffoldedDomains.get(webRequest.getControllerName());
      if (domainClass != null) {
        String viewFileName;
        final int i = viewName.lastIndexOf('/');
        if (i > -1) {
          viewFileName = viewName.substring(i, viewName.length());
        } else {
          viewFileName = viewName;
        }
        final ViewKey viewKey = new ViewKey(webRequest.getControllerName(), viewFileName);
        View v = scaffoldedViews.get(viewKey);
        if (v == null) {
          String viewCode = null;
          try {
            viewCode = generateViewSource(webRequest, domainClass);
          } catch (Exception e) {
            GrailsUtil.deepSanitize(e);
            LOG.error("Error generating scaffolded view [" + viewName + "]: " + e.getMessage(), e);
            return resolvedView;
          }
          v = createScaffoldedView(viewName, viewCode);
          scaffoldedViews.put(viewKey, v);
        }
        if (v != null) {
          return v;
        }
      }
    }
    return resolvedView;
  }
  /** Default constructor. */
  public ReloadAwareAutowireCapableBeanFactory() {
    reloadEnabled = GrailsUtil.isDevelopmentEnv() || Environment.getCurrent().isReloadEnabled();
    if (reloadEnabled) {

      // Implementation note: The default Spring InstantiationStrategy caches constructors.
      // This is no good at development time because if the class reloads then Spring
      // continues to use the old class. We deal with this here by disabling the caching
      // for development time only
      setInstantiationStrategy(
          new CglibSubclassingInstantiationStrategy() {
            @Override
            public Object instantiate(
                RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) {
              // Don't override the class with CGLIB if no overrides.
              if (beanDefinition.getMethodOverrides().isEmpty()) {
                Constructor<?> constructorToUse;
                Class<?> clazz = beanDefinition.getBeanClass();
                if (clazz.isInterface()) {
                  throw new BeanInstantiationException(clazz, "Specified class is an interface");
                }
                try {
                  constructorToUse = clazz.getDeclaredConstructor((Class[]) null);
                } catch (Exception ex) {
                  throw new BeanInstantiationException(clazz, "No default constructor found", ex);
                }

                return BeanUtils.instantiateClass(constructorToUse);
              }
              // Must generate CGLIB subclass.
              return instantiateWithMethodInjection(beanDefinition, beanName, owner);
            }
          });
    }

    setParameterNameDiscoverer(new LocalVariableTableParameterNameDiscoverer());
    setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
    ignoreDependencyType(Closure.class);
  }
  /**
   * Trigger afterCompletion callbacks on the mapped HandlerInterceptors. Will just invoke
   * afterCompletion for all interceptors whose preHandle invocation has successfully completed and
   * returned true.
   *
   * @param mappedHandler the mapped HandlerExecutionChain
   * @param interceptorIndex index of last interceptor that successfully completed
   * @param ex Exception thrown on handler execution, or <code>null</code> if none
   * @see HandlerInterceptor#afterCompletion
   */
  protected void triggerAfterCompletion(
      HandlerExecutionChain mappedHandler,
      int interceptorIndex,
      HttpServletRequest request,
      HttpServletResponse response,
      Exception ex)
      throws Exception {

    // Apply afterCompletion methods of registered interceptors.
    if (mappedHandler != null) {
      if (mappedHandler.getInterceptors() != null) {
        for (int i = interceptorIndex; i >= 0; i--) {
          HandlerInterceptor interceptor = mappedHandler.getInterceptors()[i];
          try {
            interceptor.afterCompletion(request, response, mappedHandler.getHandler(), ex);
          } catch (Throwable ex2) {
            GrailsUtil.deepSanitize(ex2);
            logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
          }
        }
      }
    }
  }
  /**
   * Overrides the default behaviour to establish the handler from the GrailsApplication instance
   *
   * @param request The request
   * @param cache Whether to cache the Handler in the request
   * @return The HandlerExecutionChain
   * @throws Exception
   */
  protected HandlerExecutionChain getHandler(HttpServletRequest request, boolean cache)
      throws Exception {
    String uri = urlHelper.getPathWithinApplication(request);
    if (logger.isDebugEnabled()) {
      logger.debug("Looking up Grails controller for URI [" + uri + "]");
    }
    GrailsControllerClass controllerClass =
        (GrailsControllerClass)
            application.getArtefactForFeature(ControllerArtefactHandler.TYPE, uri);
    final String actionName =
        (String) request.getAttribute(GrailsApplicationAttributes.ACTION_NAME_ATTRIBUTE);

    if (controllerClass != null) {
      HandlerInterceptor[] interceptors;
      // if we're in a development environment we want to re-establish interceptors just in case
      // they
      // have changed at runtime

      if (GrailsUtil.isDevelopmentEnv()) {
        interceptors = establishInterceptors(getWebApplicationContext());
      } else {
        interceptors = this.interceptors;
      }
      if (controllerClass.isFlowAction(actionName)) {
        FlowHandler flowHandler =
            new AbstractFlowHandler() {
              public String getFlowId() {
                return actionName;
              }
            };
        return new HandlerExecutionChain(flowHandler, interceptors);
      } else {
        return new HandlerExecutionChain(mainController, interceptors);
      }
    }
    return null;
  }
  @SuppressWarnings("unchecked")
  private void evaluateOnChangeListener() {
    if (pluginBean.isReadableProperty(ON_SHUTDOWN)) {
      onShutdownListener =
          (Closure) GrailsClassUtils.getPropertyOrStaticPropertyOrFieldValue(plugin, ON_SHUTDOWN);
    }
    if (pluginBean.isReadableProperty(ON_CONFIG_CHANGE)) {
      onConfigChangeListener =
          (Closure)
              GrailsClassUtils.getPropertyOrStaticPropertyOrFieldValue(plugin, ON_CONFIG_CHANGE);
    }
    if (pluginBean.isReadableProperty(ON_CHANGE)) {
      onChangeListener =
          (Closure) GrailsClassUtils.getPropertyOrStaticPropertyOrFieldValue(plugin, ON_CHANGE);
    }

    final boolean warDeployed = Metadata.getCurrent().isWarDeployed();
    final boolean reloadEnabled = Environment.getCurrent().isReloadEnabled();

    if (!((reloadEnabled || !warDeployed) && onChangeListener != null)) {
      return;
    }

    Object referencedResources =
        GrailsClassUtils.getPropertyOrStaticPropertyOrFieldValue(plugin, WATCHED_RESOURCES);

    try {
      List resourceList = null;
      if (referencedResources instanceof String) {
        if (LOG.isDebugEnabled()) {
          LOG.debug(
              "Configuring plugin "
                  + this
                  + " to watch resources with pattern: "
                  + referencedResources);
        }
        resourceList = new ArrayList();
        resourceList.add(referencedResources.toString());
      } else if (referencedResources instanceof List) {
        resourceList = (List) referencedResources;
      }

      if (resourceList != null) {
        List<String> resourceListTmp = new ArrayList<String>();
        PluginBuildSettings pluginBuildSettings = GrailsPluginUtils.getPluginBuildSettings();

        if (pluginBuildSettings != null) {

          final Resource[] pluginDirs = pluginBuildSettings.getPluginDirectories();
          final Environment env = Environment.getCurrent();
          final String baseLocation = env.getReloadLocation();

          for (Object ref : resourceList) {
            String stringRef = ref.toString();
            if (!warDeployed) {
              for (Resource pluginDir : pluginDirs) {
                if (pluginDir != null) {
                  String pluginResources =
                      getResourcePatternForBaseLocation(
                          pluginDir.getFile().getCanonicalPath(), stringRef);
                  resourceListTmp.add(pluginResources);
                }
              }
              addBaseLocationPattern(resourceListTmp, baseLocation, stringRef);
            } else {
              addBaseLocationPattern(resourceListTmp, baseLocation, stringRef);
            }
          }

          watchedResourcePatternReferences = new String[resourceListTmp.size()];
          for (int i = 0; i < watchedResourcePatternReferences.length; i++) {
            String resRef = resourceListTmp.get(i);
            watchedResourcePatternReferences[i] = resRef;
          }

          watchedResourcePatterns =
              new WatchPatternParser()
                  .getWatchPatterns(Arrays.asList(watchedResourcePatternReferences));
        }
      }
    } catch (IllegalArgumentException e) {
      if (GrailsUtil.isDevelopmentEnv()) {
        LOG.debug(
            "Cannot load plug-in resource watch list from ["
                + ArrayUtils.toString(watchedResourcePatternReferences)
                + "]. This means that the plugin "
                + this
                + ", will not be able to auto-reload changes effectively. Try runnng grails upgrade.: "
                + e.getMessage());
      }
    } catch (IOException e) {
      if (GrailsUtil.isDevelopmentEnv()) {
        LOG.debug(
            "Cannot load plug-in resource watch list from ["
                + ArrayUtils.toString(watchedResourcePatternReferences)
                + "]. This means that the plugin "
                + this
                + ", will not be able to auto-reload changes effectively. Try runnng grails upgrade.: "
                + e.getMessage());
      }
    }
  }
  /* (non-Javadoc)
   * @see org.springframework.web.servlet.DispatcherServlet#doDispatch(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
   */
  protected void doDispatch(final HttpServletRequest request, HttpServletResponse response)
      throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    int interceptorIndex = -1;
    final LocaleResolver localeResolver =
        (LocaleResolver) request.getAttribute(LOCALE_RESOLVER_ATTRIBUTE);

    // Expose current LocaleResolver and request as LocaleContext.
    LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
    LocaleContextHolder.setLocaleContext(
        new LocaleContext() {
          public Locale getLocale() {

            return localeResolver.resolveLocale(request);
          }
        });

    // If the request is an include we need to try to use the original wrapped sitemesh
    // response, otherwise layouts won't work properly
    if (WebUtils.isIncludeRequest(request)) {
      response = useWrappedOrOriginalResponse(response);
    }

    GrailsWebRequest requestAttributes = null;
    GrailsWebRequest previousRequestAttributes = null;
    Exception handlerException = null;
    try {
      ModelAndView mv = null;
      try {
        Object exceptionAttribute = request.getAttribute(EXCEPTION_ATTRIBUTE);
        // only process multipart requests if an exception hasn't occured
        if (exceptionAttribute == null) processedRequest = checkMultipart(request);
        // Expose current RequestAttributes to current thread.
        previousRequestAttributes =
            (GrailsWebRequest) RequestContextHolder.currentRequestAttributes();
        requestAttributes = new GrailsWebRequest(processedRequest, response, getServletContext());
        copyParamsFromPreviousRequest(previousRequestAttributes, requestAttributes);

        // Update the current web request.
        WebUtils.storeGrailsWebRequest(requestAttributes);

        if (logger.isDebugEnabled()) {
          logger.debug("Bound request context to thread: " + request);
          logger.debug("Using response object: " + response.getClass());
        }

        // Determine handler for the current request.
        mappedHandler = getHandler(processedRequest, false);
        if (mappedHandler == null || mappedHandler.getHandler() == null) {
          noHandlerFound(processedRequest, response);
          return;
        }

        // Apply preHandle methods of registered interceptors.
        if (mappedHandler.getInterceptors() != null) {
          for (int i = 0; i < mappedHandler.getInterceptors().length; i++) {
            HandlerInterceptor interceptor = mappedHandler.getInterceptors()[i];
            if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {
              triggerAfterCompletion(
                  mappedHandler, interceptorIndex, processedRequest, response, null);
              return;
            }
            interceptorIndex = i;
          }
        }

        // Actually invoke the handler.
        HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
        mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

        // Apply postHandle methods of registered interceptors.
        if (mappedHandler.getInterceptors() != null) {
          for (int i = mappedHandler.getInterceptors().length - 1; i >= 0; i--) {
            HandlerInterceptor interceptor = mappedHandler.getInterceptors()[i];
            interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);
          }
        }
      } catch (ModelAndViewDefiningException ex) {
        GrailsUtil.deepSanitize(ex);
        handlerException = ex;
        if (logger.isDebugEnabled()) logger.debug("ModelAndViewDefiningException encountered", ex);
        mv = ex.getModelAndView();
      } catch (Exception ex) {
        GrailsUtil.deepSanitize(ex);
        handlerException = ex;
        Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
        mv = processHandlerException(request, response, handler, ex);
      }

      // Did the handler return a view to render?
      if (mv != null && !mv.wasCleared()) {
        // If an exception occurs in here, like a bad closing tag,
        // we have nothing to render.

        try {
          render(mv, processedRequest, response);
        } catch (Exception e) {
          mv = super.processHandlerException(processedRequest, response, mappedHandler, e);
          handlerException = e;
          render(mv, processedRequest, response);
        }
      } else {
        if (logger.isDebugEnabled()) {
          logger.debug(
              "Null ModelAndView returned to DispatcherServlet with name '"
                  + getServletName()
                  + "': assuming HandlerAdapter completed request handling");
        }
      }

      // Trigger after-completion for successful outcome.
      triggerAfterCompletion(
          mappedHandler, interceptorIndex, processedRequest, response, handlerException);
    } catch (Exception ex) {
      // Trigger after-completion for thrown exception.
      triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
      throw ex;
    } catch (Error err) {
      ServletException ex = new NestedServletException("Handler processing failed", err);
      // Trigger after-completion for thrown exception.
      triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
      throw ex;
    } finally {
      // Clean up any resources used by a multipart request.
      if (processedRequest instanceof MultipartHttpServletRequest && processedRequest != request) {
        if (multipartResolver != null)
          this.multipartResolver.cleanupMultipart((MultipartHttpServletRequest) processedRequest);
      }
      request.removeAttribute(MultipartHttpServletRequest.class.getName());

      // Reset thread-bound holders
      if (requestAttributes != null) {
        requestAttributes.requestCompleted();
        WebUtils.storeGrailsWebRequest(previousRequestAttributes);
      }

      LocaleContextHolder.setLocaleContext(previousLocaleContext);

      if (logger.isDebugEnabled()) {
        logger.debug("Cleared thread-bound request context: " + request);
      }
    }
  }
  @SuppressWarnings("unchecked")
  @Override
  protected Object createNode(Object name, Map attributes) {
    // we do this so that missing property exception is throw if it doesn't exist

    try {
      String property = (String) name;
      ConstrainedProperty cp;
      if (constrainedProperties.containsKey(property)) {
        cp = constrainedProperties.get(property);
      } else {
        cp =
            new ConstrainedProperty(
                targetClass, property, classPropertyFetcher.getPropertyType(property));
        cp.setOrder(order++);
        constrainedProperties.put(property, cp);
      }

      if (cp.getPropertyType() == null) {
        GrailsUtil.warn(
            "Property ["
                + cp.getPropertyName()
                + "] not found in domain class "
                + targetClass.getName()
                + "; cannot apply constraints: "
                + attributes);
        return cp;
      }

      for (Object o : attributes.keySet()) {
        String constraintName = (String) o;
        final Object value = attributes.get(constraintName);
        if (SHARED_CONSTRAINT.equals(constraintName)) {
          if (value != null) {
            sharedConstraints.put(property, value.toString());
          }
          continue;
        }
        if (cp.supportsContraint(constraintName)) {
          cp.applyConstraint(constraintName, value);
        } else {
          if (ConstrainedProperty.hasRegisteredConstraint(constraintName)) {
            // constraint is registered but doesn't support this property's type
            GrailsUtil.warn(
                "Property ["
                    + cp.getPropertyName()
                    + "] of domain class "
                    + targetClass.getName()
                    + " has type ["
                    + cp.getPropertyType().getName()
                    + "] and doesn't support constraint ["
                    + constraintName
                    + "]. This constraint will not be checked during validation.");
          } else {
            // in the case where the constraint is not supported we still retain meta data
            // about the constraint in case its needed for other things
            cp.addMetaConstraint(constraintName, value);
          }
        }
      }
      return cp;
    } catch (InvalidPropertyException ipe) {
      throw new MissingMethodException((String) name, targetClass, new Object[] {attributes});
    }
  }
/**
 * Evaluates the existance of a view for different extensions choosing which one to delegate to.
 *
 * @author Graeme Rocher
 * @since 0.1
 */
public class GroovyPageViewResolver extends InternalResourceViewResolver
    implements GrailsViewResolver {
  private static final Log LOG = LogFactory.getLog(GroovyPageViewResolver.class);

  public static final String GSP_SUFFIX = ".gsp";
  public static final String JSP_SUFFIX = ".jsp";

  protected GroovyPagesTemplateEngine templateEngine;
  protected GrailsConventionGroovyPageLocator groovyPageLocator;

  private ConcurrentMap<String, CacheEntry<View>> viewCache =
      new ConcurrentHashMap<String, CacheEntry<View>>();
  private boolean allowGrailsViewCaching = !GrailsUtil.isDevelopmentEnv();
  private long cacheTimeout = -1;

  /** Constructor. */
  public GroovyPageViewResolver() {
    setCache(false);
    setOrder(Ordered.LOWEST_PRECEDENCE - 20);
  }

  public GroovyPageViewResolver(
      GroovyPagesTemplateEngine templateEngine,
      GrailsConventionGroovyPageLocator groovyPageLocator) {
    this();
    this.templateEngine = templateEngine;
    this.groovyPageLocator = groovyPageLocator;
  }

  public void setGroovyPageLocator(GrailsConventionGroovyPageLocator groovyPageLocator) {
    this.groovyPageLocator = groovyPageLocator;
  }

  @Override
  public View resolveViewName(String viewName, Locale locale) throws Exception {
    return super.resolveViewName(WebUtils.addViewPrefix(viewName), locale);
  }

  @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;
  }

  /**
   * @return prefix for cache key that contains current controller's context (currently plugin and
   *     namespace)
   */
  protected String resolveCurrentControllerKeyPrefixes() {
    String pluginContextPath = null;
    String namespace = null;
    GrailsWebRequest webRequest = GrailsWebRequest.lookup();
    if (webRequest != null) {
      namespace = webRequest.getControllerNamespace();
      pluginContextPath =
          (webRequest.getAttributes() != null && webRequest.getCurrentRequest() != null)
              ? webRequest.getAttributes().getPluginContextPath(webRequest.getCurrentRequest())
              : null;
      return (pluginContextPath != null ? pluginContextPath : "-")
          + ","
          + (namespace != null ? namespace : "-");
    } else {
      return null;
    }
  }

  private static class WrappedInitializationException extends RuntimeException {
    private static final long serialVersionUID = 1L;

    public WrappedInitializationException(Throwable cause) {
      super(cause);
    }

    public void rethrowCause() throws Exception {
      if (getCause() instanceof Exception) {
        throw (Exception) getCause();
      }

      throw this;
    }
  }

  protected View createGrailsView(String viewName) throws Exception {
    // try GSP if res is null

    GroovyObject controller = null;

    GrailsWebRequest webRequest = GrailsWebRequest.lookup();
    if (webRequest != null) {
      HttpServletRequest request = webRequest.getCurrentRequest();
      controller = webRequest.getAttributes().getController(request);
    }

    GroovyPageScriptSource scriptSource;
    if (controller == null) {
      scriptSource = groovyPageLocator.findViewByPath(viewName);
    } else {
      scriptSource = groovyPageLocator.findView(controller, viewName);
    }
    if (scriptSource != null) {
      return createGroovyPageView(scriptSource.getURI(), scriptSource);
    }

    return createFallbackView(viewName);
  }

  private View createGroovyPageView(String gspView, ScriptSource scriptSource) {
    if (LOG.isDebugEnabled()) {
      LOG.debug("Resolved GSP view at URI [" + gspView + "]");
    }
    GroovyPageView gspSpringView = new GroovyPageView();
    gspSpringView.setServletContext(getServletContext());
    gspSpringView.setUrl(gspView);
    gspSpringView.setApplicationContext(getApplicationContext());
    gspSpringView.setTemplateEngine(templateEngine);
    gspSpringView.setScriptSource(scriptSource);
    try {
      gspSpringView.afterPropertiesSet();
    } catch (Exception e) {
      throw new RuntimeException("Error initializing GroovyPageView", e);
    }
    return gspSpringView;
  }

  protected View createFallbackView(String viewName) throws Exception {
    return createJstlView(viewName);
  }

  protected View createJstlView(String viewName) throws Exception {
    AbstractUrlBasedView view = buildView(viewName);
    view.setApplicationContext(getApplicationContext());
    view.afterPropertiesSet();
    return view;
  }

  @Autowired(required = true)
  @Qualifier(GroovyPagesTemplateEngine.BEAN_ID)
  public void setTemplateEngine(GroovyPagesTemplateEngine templateEngine) {
    this.templateEngine = templateEngine;
  }

  public long getCacheTimeout() {
    return cacheTimeout;
  }

  public void setCacheTimeout(long cacheTimeout) {
    this.cacheTimeout = cacheTimeout;
  }

  @Override
  public void clearCache() {
    super.clearCache();
    viewCache.clear();
  }

  public boolean isAllowGrailsViewCaching() {
    return allowGrailsViewCaching;
  }

  public void setAllowGrailsViewCaching(boolean allowGrailsViewCaching) {
    this.allowGrailsViewCaching = allowGrailsViewCaching;
  }
}