@Override
  public void setResourceLoader(ResourceLoader resourceLoader) {
    if (Metadata.getCurrent().isWarDeployed()) {
      localResourceLoader = resourceLoader;
    } else {
      // The "settings" may be null in some of the Grails unit tests.
      BuildSettings settings = BuildSettingsHolder.getSettings();

      String location = null;
      if (settings != null) {
        location = settings.getResourcesDir().getPath();
      } else if (Environment.getCurrent().isReloadEnabled()) {
        location = Environment.getCurrent().getReloadLocation();
      }

      if (location != null) {
        localResourceLoader = new DevelopmentResourceLoader(application, location);
      } else {
        localResourceLoader = resourceLoader;
      }
    }
    super.setResourceLoader(localResourceLoader);

    if (resourceResolver == null) {
      resourceResolver = new PathMatchingResourcePatternResolver(localResourceLoader);
    }
  }
  private static ScriptAndArgs processAndReturnArguments(CommandLine commandLine) {
    ScriptAndArgs info = new ScriptAndArgs();
    if (Environment.isSystemSet()) {
      info.env = Environment.getCurrent().getName();
    } else if (commandLine.getEnvironment() != null) {
      info.env = commandLine.getEnvironment();
    }

    info.inputName = commandLine.getCommandName();
    info.name = GrailsNameUtils.getNameFromScript(commandLine.getCommandName());
    return info;
  }
 private static List getBindingIncludeList(final Object object) {
   List includeList = Collections.emptyList();
   try {
     final Class<? extends Object> objectClass = object.getClass();
     if (CLASS_TO_BINDING_INCLUDE_LIST.containsKey(objectClass)) {
       includeList = CLASS_TO_BINDING_INCLUDE_LIST.get(objectClass);
     } else {
       final Field whiteListField =
           objectClass.getDeclaredField(DefaultASTDatabindingHelper.DEFAULT_DATABINDING_WHITELIST);
       if (whiteListField != null) {
         if ((whiteListField.getModifiers() & Modifier.STATIC) != 0) {
           final Object whiteListValue = whiteListField.get(objectClass);
           if (whiteListValue instanceof List) {
             includeList = (List) whiteListValue;
           }
         }
       }
       if (!Environment.getCurrent().isReloadEnabled()) {
         CLASS_TO_BINDING_INCLUDE_LIST.put(objectClass, includeList);
       }
     }
   } catch (Exception e) {
   }
   return includeList;
 }
  public GroovyPageParser(
      String name, String uri, String filename, String gspSource, String expressionCodecName)
      throws IOException {
    Config config = Holders.getConfig();
    if (config != null) {
      setEnableSitemeshPreprocessing(
          config.getProperty(
              GroovyPageParser.CONFIG_PROPERTY_GSP_SITEMESH_PREPROCESS,
              Boolean.class,
              enableSitemeshPreprocessing));
    }

    GrailsPluginInfo pluginInfo = null;
    //        TODO: figure out a way to restore plugin metadata for GSP
    //        if (filename != null && BuildSettingsHolder.getSettings() != null) {
    //            pluginInfo =
    // GrailsPluginUtils.getPluginBuildSettings().getPluginInfoForSource(filename);
    //            if (pluginInfo != null) {
    //                pluginAnnotation = "@GrailsPlugin(name='" + pluginInfo.getName() + "',
    // version='" +
    //                    pluginInfo.getVersion() + "')";
    //            }
    //        }

    OutputEncodingSettings gspConfig = new OutputEncodingSettings(config);

    this.expressionCodecDirectiveValue = expressionCodecName;
    if (expressionCodecDirectiveValue == null) {
      expressionCodecDirectiveValue =
          gspConfig.getCodecSettings(pluginInfo, OutputEncodingSettings.EXPRESSION_CODEC_NAME);
    }
    staticCodecDirectiveValue =
        gspConfig.getCodecSettings(pluginInfo, OutputEncodingSettings.STATIC_CODEC_NAME);
    outCodecDirectiveValue =
        gspConfig.getCodecSettings(pluginInfo, OutputEncodingSettings.OUT_CODEC_NAME);
    taglibCodecDirectiveValue =
        gspConfig.getCodecSettings(pluginInfo, OutputEncodingSettings.TAGLIB_CODEC_NAME);

    Map<String, String> directives = parseDirectives(gspSource);

    if (isSitemeshPreprocessingEnabled(directives.get(SITEMESH_PREPROCESS_DIRECTIVE))) {
      if (LOG.isDebugEnabled()) {
        LOG.debug(
            "Preprocessing "
                + uri
                + " for sitemesh. Replacing head, title, meta and body elements with sitemesh:capture*.");
      }
      // GSP preprocessing for direct sitemesh integration: replace head -> g:captureHead, title ->
      // g:captureTitle, meta -> g:captureMeta, body -> g:captureBody
      gspSource = sitemeshPreprocessor.addGspSitemeshCapturing(gspSource);
      sitemeshPreprocessMode = true;
    }
    scan = new GroovyPageScanner(gspSource, uri);
    pageName = uri;
    environment = Environment.getCurrent();
    makeName(name);
    makeSourceName(filename);
  }
 private Resource getResourceWithinContext(String uri) {
   if (resourceLoader == null)
     throw new IllegalStateException(
         "TemplateEngine not initialised correctly, no [resourceLoader] specified!");
   if (Environment.getCurrent().isReloadEnabled() && Metadata.getCurrent().isWarDeployed()) {
     return resourceLoader.getResource(uri);
   }
   Resource r = servletContextLoader.getResource(uri);
   if (r.exists()) return r;
   return resourceLoader.getResource(uri);
 }
 @Override
 public Resource findResourceForURI(String uri) {
   Resource resource = uriResolveCache.get(uri);
   if (resource == null) {
     resource = super.findResourceForURI(uri);
     if (resource == null && Environment.isWarDeployed()) {
       resource = NULL_RESOURCE;
     }
     if (resource != null) uriResolveCache.put(uri, resource);
   }
   return resource == NULL_RESOURCE ? null : resource;
 }
  public void afterPropertiesSet() throws Exception {
    resourceLoader = GrailsResourceLoaderHolder.getResourceLoader();
    if (resourceLoader != null) {
      return;
    }

    if (Environment.getCurrent().isReloadEnabled()) {
      ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
      try {
        Resource[] resources =
            resolver.getResources(
                "file:" + Environment.getCurrent().getReloadLocation() + "/grails-app/**/*.groovy");
        resourceLoader = new GrailsResourceLoader(resources);
      } catch (IOException e) {
        createDefaultInternal();
      }
    } else {
      createDefaultInternal();
    }
    GrailsResourceLoaderHolder.setResourceLoader(resourceLoader);
  }
 /**
  * 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 StringBuilder(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(Environment.getCurrent().getName())
       .toString();
 }
 /**
  * Returns the absolute path to the provided Grails plugin if it is being used "inline" or {@code
  * null} if the plugin is <b>not</b> being used "inline".
  *
  * @param grailsPlugin The Grails plugin.
  * @return The absolute path to the "inline" plugin or {@code null} if the plugin is not being
  *     used "inline".
  */
 protected String getInlinePluginPath(GrailsPlugin grailsPlugin) {
   if (Environment.isWarDeployed()) return null;
   try {
     final GrailsPluginInfo pluginInfo =
         pluginBuildSettings.getPluginInfoForName(grailsPlugin.getFileSystemShortName());
     if (pluginInfo != null) {
       return new File(
               pluginBuildSettings.getBuildSettings().getResourcesDir(),
               "plugins/" + pluginInfo.getFullName())
           .getCanonicalPath();
     }
   } catch (final IOException e) {
     LOG.debug(
         "Unable to retrieve plugin directory for plugin " + grailsPlugin.getFileSystemShortName(),
         e);
   }
   return null;
 }
 @Override
 public void autowireBeanProperties(Object existingBean, int autowireMode, boolean dependencyCheck)
     throws BeansException {
   if (Environment.isInitializing()) {
     return;
   }
   if (autowireMode == AUTOWIRE_BY_NAME) {
     if (DISABLE_AUTOWIRE_BY_NAME_OPTIMIZATIONS
         || dependencyCheck
         || existingBean instanceof Aware) {
       super.autowireBeanProperties(existingBean, autowireMode, dependencyCheck);
     } else {
       populateBeanInAutowireByName(existingBean);
     }
   } else {
     super.autowireBeanProperties(existingBean, autowireMode, dependencyCheck);
   }
 }
  /** 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);
  }
  @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());
      }
    }
  }
/**
 * Default ResourceLocator implementation that doesn't take into account servlet loading.
 *
 * @author Graeme Rocher
 * @since 2.0
 */
public class DefaultResourceLocator
    implements ResourceLocator, ResourceLoaderAware, PluginManagerAware {

  public static final String WILDCARD = "*";
  public static final String FILE_SEPARATOR = File.separator;
  public static final String CLOSURE_MARKER = "$";
  public static final String WEB_APP_DIR = "web-app";

  protected static final Resource NULL_RESOURCE = new ByteArrayResource("null".getBytes());

  protected PathMatchingResourcePatternResolver patchMatchingResolver;
  protected List<String> classSearchDirectories = new ArrayList<String>();
  protected List<String> resourceSearchDirectories = new ArrayList<String>();
  protected Map<String, Resource> classNameToResourceCache =
      new ConcurrentHashMap<String, Resource>();
  protected Map<String, Resource> uriToResourceCache = new ConcurrentHashMap<String, Resource>();
  protected ResourceLoader defaultResourceLoader = new FileSystemResourceLoader();
  protected GrailsPluginManager pluginManager;
  protected boolean warDeployed = Environment.isWarDeployed();

  public void setSearchLocation(String searchLocation) {
    ResourceLoader resourceLoader = getDefaultResourceLoader();
    patchMatchingResolver = new CachingPathMatchingResourcePatternResolver(resourceLoader);
    initializeForSearchLocation(searchLocation);
  }

  protected ResourceLoader getDefaultResourceLoader() {
    return defaultResourceLoader;
  }

  public void setSearchLocations(Collection<String> searchLocations) {
    patchMatchingResolver =
        new CachingPathMatchingResourcePatternResolver(getDefaultResourceLoader());
    for (String searchLocation : searchLocations) {
      initializeForSearchLocation(searchLocation);
    }
  }

  private void initializeForSearchLocation(String searchLocation) {
    String searchLocationPlusSlash =
        searchLocation.endsWith("/") ? searchLocation : searchLocation + FILE_SEPARATOR;
    try {
      File[] directories =
          new File(searchLocationPlusSlash + GrailsResourceUtils.GRAILS_APP_DIR)
              .listFiles(
                  new FileFilter() {
                    public boolean accept(File file) {
                      return file.isDirectory() && !file.isHidden();
                    }
                  });
      if (directories != null) {
        for (File directory : directories) {
          classSearchDirectories.add(directory.getCanonicalPath());
        }
      }
    } catch (IOException e) {
      // ignore
    }

    classSearchDirectories.add(searchLocationPlusSlash + "src/main/java");
    classSearchDirectories.add(searchLocationPlusSlash + "src/main/groovy");
    resourceSearchDirectories.add(searchLocationPlusSlash);
  }

  public Resource findResourceForURI(String uri) {
    Resource resource = uriToResourceCache.get(uri);
    if (resource == null) {

      PluginResourceInfo info = inferPluginNameFromURI(uri);
      if (warDeployed) {
        Resource defaultResource = defaultResourceLoader.getResource(uri);
        if (defaultResource != null && defaultResource.exists()) {
          resource = defaultResource;
        }
      } else {
        String uriWebAppRelative = WEB_APP_DIR + uri;

        for (String resourceSearchDirectory : resourceSearchDirectories) {
          Resource res = resolveExceptionSafe(resourceSearchDirectory + uriWebAppRelative);
          if (res.exists()) {
            resource = res;
          } else if (!warDeployed) {
            Resource dir = resolveExceptionSafe(resourceSearchDirectory);
            if (dir.exists() && info != null) {
              try {
                String filename = dir.getFilename();
                if (filename != null && filename.equals(info.pluginName)) {
                  Resource pluginFile = dir.createRelative(WEB_APP_DIR + info.uri);
                  if (pluginFile.exists()) {
                    resource = pluginFile;
                  }
                }
              } catch (IOException e) {
                // ignore
              }
            }
          }
        }
      }

      if (resource == null && info != null) {
        resource = findResourceInBinaryPlugins(info);
      }

      if (resource == null || !resource.exists()) {
        Resource tmp =
            defaultResourceLoader != null ? defaultResourceLoader.getResource(uri) : null;
        if (tmp != null && tmp.exists()) {
          resource = tmp;
        }
      }

      if (resource != null) {
        uriToResourceCache.put(uri, resource);
      } else if (warDeployed) {
        uriToResourceCache.put(uri, NULL_RESOURCE);
      }
    }
    return resource == NULL_RESOURCE ? null : resource;
  }

  protected Resource findResourceInBinaryPlugins(PluginResourceInfo info) {
    if (pluginManager != null) {
      String fullPluginName = info.pluginName;
      for (GrailsPlugin plugin : pluginManager.getAllPlugins()) {
        if (plugin.getFileSystemName().equals(fullPluginName)
            && (plugin instanceof BinaryGrailsPlugin)) {
          return ((BinaryGrailsPlugin) plugin).getResource(info.uri);
        }
      }
    }
    return null;
  }

  private PluginResourceInfo inferPluginNameFromURI(String uri) {
    if (uri.startsWith("/plugins/")) {
      String withoutPluginsPath = uri.substring("/plugins/".length(), uri.length());
      int i = withoutPluginsPath.indexOf('/');
      if (i > -1) {
        PluginResourceInfo info = new PluginResourceInfo();
        info.pluginName = withoutPluginsPath.substring(0, i);
        info.uri = withoutPluginsPath.substring(i, withoutPluginsPath.length());
        return info;
      }
    }
    return null;
  }

  public Resource findResourceForClassName(String className) {

    if (className.contains(CLOSURE_MARKER)) {
      className = className.substring(0, className.indexOf(CLOSURE_MARKER));
    }
    Resource resource = classNameToResourceCache.get(className);
    if (resource == null) {
      String classNameWithPathSeparator = className.replace(".", FILE_SEPARATOR);
      for (String pathPattern :
          getSearchPatternForExtension(classNameWithPathSeparator, ".groovy", ".java")) {
        resource = resolveExceptionSafe(pathPattern);
        if (resource != null && resource.exists()) {
          classNameToResourceCache.put(className, resource);
          break;
        }
      }
    }
    return resource != null && resource.exists() ? resource : null;
  }

  private List<String> getSearchPatternForExtension(
      String classNameWithPathSeparator, String... extensions) {

    List<String> searchPatterns = new ArrayList<String>();
    for (String extension : extensions) {
      String filename = classNameWithPathSeparator + extension;
      for (String classSearchDirectory : classSearchDirectories) {
        searchPatterns.add(classSearchDirectory + FILE_SEPARATOR + filename);
      }
    }

    return searchPatterns;
  }

  private Resource resolveExceptionSafe(String pathPattern) {
    try {
      Resource[] resources = patchMatchingResolver.getResources("file:" + pathPattern);
      if (resources != null && resources.length > 0) {
        return resources[0];
      }
    } catch (IOException e) {
      return null;
    }
    return null;
  }

  public void setResourceLoader(ResourceLoader resourceLoader) {
    defaultResourceLoader = resourceLoader;
  }

  public void setPluginManager(GrailsPluginManager pluginManager) {
    this.pluginManager = pluginManager;
  }

  class PluginResourceInfo {
    String pluginName;
    String uri;
  }
}
  @SuppressWarnings("rawtypes")
  @Override
  public GrailsClass getArtefactForFeature(Object featureId) {
    if (artefactInfo == null) {
      return null;
    }

    String uri;
    String pluginName = null;

    if (featureId instanceof Map) {
      Map featureIdMap = (Map) featureId;
      uri = (String) featureIdMap.get("uri");
      pluginName = (String) featureIdMap.get("pluginName");
    } else {
      uri = featureId.toString();
    }

    GrailsClass controllerClass = uriToControllerClassCache.get(uri);
    if (controllerClass == null) {
      final ApplicationContext mainContext = grailsApplication.getMainContext();
      GrailsPluginManager grailsPluginManager = null;
      if (mainContext.containsBean(GrailsPluginManager.BEAN_NAME)) {
        final Object pluginManagerBean = mainContext.getBean(GrailsPluginManager.BEAN_NAME);
        if (pluginManagerBean instanceof GrailsPluginManager) {
          grailsPluginManager = (GrailsPluginManager) pluginManagerBean;
        }
      }
      final GrailsClass[] controllerClasses = artefactInfo.getGrailsClasses();
      // iterate in reverse in order to pick up application classes first
      for (int i = (controllerClasses.length - 1); i >= 0; i--) {
        GrailsClass c = controllerClasses[i];
        if (((GrailsControllerClass) c).mapsToURI(uri)) {
          boolean foundController = false;
          if (pluginName != null && grailsPluginManager != null) {
            final GrailsPlugin pluginForClass = grailsPluginManager.getPluginForClass(c.getClazz());
            if (pluginForClass != null && pluginName.equals(pluginForClass.getName())) {
              foundController = true;
            }
          } else {
            foundController = true;
          }
          if (foundController) {
            controllerClass = c;
            break;
          }
        }
      }
      if (controllerClass == null) {
        controllerClass = NO_CONTROLLER;
      }

      // don't cache for dev environment
      if (Environment.getCurrent() != Environment.DEVELOPMENT) {
        uriToControllerClassCache.put(uri, controllerClass);
      }
    }

    if (controllerClass == NO_CONTROLLER) {
      controllerClass = null;
    }
    return controllerClass;
  }
 public boolean supportsEnvironment(Environment environment) {
   return supportsValueInIncludeExcludeMap(pluginEnvs, environment.getName());
 }
/**
 * Enhances controller classes with a method missing implementation for tags at compile time.
 *
 * @author Graeme Rocher
 * @since 2.0
 */
public class ControllerTagLibraryApi extends CommonWebApi {

  private static final long serialVersionUID = 1;

  private transient TagLibraryLookup tagLibraryLookup;
  private boolean developmentMode = Environment.isDevelopmentMode();

  public ControllerTagLibraryApi(GrailsPluginManager pluginManager) {
    super(pluginManager);
  }

  public ControllerTagLibraryApi() {
    super(null);
  }

  @Autowired
  public void setTagLibraryLookup(TagLibraryLookup lookup) {
    tagLibraryLookup = lookup;
  }

  @Autowired
  public void setGspTagLibraryLookup(TagLibraryLookup lookup) {
    tagLibraryLookup = lookup;
  }

  /**
   * Method missing implementation that handles tag invocation by method name
   *
   * @param instance The instance
   * @param methodName The method name
   * @param argsObject The arguments
   * @return The result
   */
  public Object methodMissing(Object instance, String methodName, Object argsObject) {
    Object[] args =
        argsObject instanceof Object[] ? (Object[]) argsObject : new Object[] {argsObject};
    TagLibraryLookup lookup = getTagLibraryLookup();
    if (lookup != null) {
      GroovyObject tagLibrary = lookup.lookupTagLibrary(GroovyPage.DEFAULT_NAMESPACE, methodName);
      if (tagLibrary != null) {
        if (!developmentMode) {
          MetaClass controllerMc = GrailsMetaClassUtils.getMetaClass(instance);
          WebMetaUtils.registerMethodMissingForTags(
              controllerMc, lookup, GroovyPage.DEFAULT_NAMESPACE, methodName);
        }
        List<MetaMethod> respondsTo =
            tagLibrary.getMetaClass().respondsTo(tagLibrary, methodName, args);
        if (respondsTo.size() > 0) {
          return respondsTo.get(0).invoke(tagLibrary, args);
        }
      }
    }

    throw new MissingMethodException(methodName, instance.getClass(), args);
  }

  /**
   * Looks up namespaces on missing property
   *
   * @param instance The instance
   * @param propertyName The property name
   * @return The namespace or a MissingPropertyException
   */
  public Object propertyMissing(Object instance, String propertyName) {
    TagLibraryLookup lookup = getTagLibraryLookup();
    NamespacedTagDispatcher namespacedTagDispatcher =
        lookup.lookupNamespaceDispatcher(propertyName);
    if (namespacedTagDispatcher != null) {
      if (!developmentMode) {
        WebMetaUtils.registerPropertyMissingForTag(
            GrailsMetaClassUtils.getMetaClass(instance), propertyName, namespacedTagDispatcher);
      }
      return namespacedTagDispatcher;
    }

    throw new MissingPropertyException(propertyName, instance.getClass());
  }

  public TagLibraryLookup getTagLibraryLookup() {
    if (tagLibraryLookup == null) {
      ApplicationContext applicationContext = getApplicationContext(null);
      if (applicationContext != null) {
        try {
          tagLibraryLookup = applicationContext.getBean(TagLibraryLookup.class);
        } catch (BeansException e) {
          return null;
        }
      }
    }
    return tagLibraryLookup;
  }

  public Object withCodec(Object instance, Object codecInfo, Closure body) {
    return WithCodecHelper.withCodec(getGrailsApplication(null), codecInfo, body);
  }
}
 public boolean supportsCurrentScopeAndEnvironment() {
   BuildScope bs = BuildScope.getCurrent();
   Environment e = Environment.getCurrent();
   return supportsEnvironment(e) && supportsScope(bs);
 }
/**
 * An immutable ConverterConfiguration which chains the lookup calls for ObjectMarshallers for
 * performance reasons.
 *
 * @author Siegfried Puchbauer
 * @author Graeme Rocher
 * @since 1.1
 */
@SuppressWarnings("rawtypes")
public class ChainedConverterConfiguration<C extends Converter>
    implements ConverterConfiguration<C> {

  private List<ObjectMarshaller<C>> marshallerList;
  private ChainedObjectMarshaller<C> root;
  private final String encoding;
  private final Converter.CircularReferenceBehaviour circularReferenceBehaviour;
  private final boolean prettyPrint;
  private ProxyHandler proxyHandler;
  private final boolean cacheObjectMarshallerByClass;
  private Map<Integer, ObjectMarshaller<C>> objectMarshallerForClassCache;
  private final boolean developmentMode = Environment.isDevelopmentMode();
  private final ObjectMarshaller<C> NULL_HOLDER =
      new ObjectMarshaller<C>() {
        public boolean supports(Object object) {
          return false;
        }

        public void marshalObject(Object object, C converter) throws ConverterException {}
      };

  public ChainedConverterConfiguration(ConverterConfiguration<C> cfg) {
    this(cfg, new DefaultProxyHandler());
  }

  public ChainedConverterConfiguration(ConverterConfiguration<C> cfg, ProxyHandler proxyHandler) {
    marshallerList = cfg.getOrderedObjectMarshallers();
    this.proxyHandler = proxyHandler;

    encoding = cfg.getEncoding();
    prettyPrint = cfg.isPrettyPrint();
    cacheObjectMarshallerByClass = cfg.isCacheObjectMarshallerByClass();
    if (cacheObjectMarshallerByClass) {
      objectMarshallerForClassCache = new ConcurrentHashMap<Integer, ObjectMarshaller<C>>();
    }
    circularReferenceBehaviour = cfg.getCircularReferenceBehaviour();

    List<ObjectMarshaller<C>> oms = new ArrayList<ObjectMarshaller<C>>(marshallerList);
    Collections.reverse(oms);
    ChainedObjectMarshaller<C> prev = null;
    for (ObjectMarshaller<C> om : oms) {
      prev = new ChainedObjectMarshaller<C>(om, prev);
    }
    root = prev;
  }

  public ObjectMarshaller<C> getMarshaller(Object o) {
    ObjectMarshaller<C> marshaller = null;

    Integer cacheKey = null;
    if (!developmentMode && cacheObjectMarshallerByClass && o != null) {
      cacheKey = System.identityHashCode(o.getClass());
      marshaller = objectMarshallerForClassCache.get(cacheKey);
      if (marshaller != NULL_HOLDER && marshaller != null && !marshaller.supports(o)) {
        marshaller = null;
      }
    }
    if (marshaller == null) {
      marshaller = root.findMarhallerFor(o);
      if (cacheKey != null) {
        objectMarshallerForClassCache.put(cacheKey, marshaller != null ? marshaller : NULL_HOLDER);
      }
    }
    return marshaller != NULL_HOLDER ? marshaller : null;
  }

  public String getEncoding() {
    return encoding;
  }

  public Converter.CircularReferenceBehaviour getCircularReferenceBehaviour() {
    return circularReferenceBehaviour;
  }

  public boolean isPrettyPrint() {
    return prettyPrint;
  }

  public List<ObjectMarshaller<C>> getOrderedObjectMarshallers() {
    return marshallerList;
  }

  @SuppressWarnings("hiding")
  public class ChainedObjectMarshaller<C extends Converter> implements ObjectMarshaller<C> {

    private ObjectMarshaller<C> om;
    private ChainedObjectMarshaller<C> next;

    public ChainedObjectMarshaller(ObjectMarshaller<C> om, ChainedObjectMarshaller<C> next) {
      this.om = om;
      this.next = next;
    }

    public ObjectMarshaller<C> findMarhallerFor(Object o) {
      if (supports(o)) {
        return om;
      }

      return next != null ? next.findMarhallerFor(o) : null;
    }

    public boolean supports(Object object) {
      return om.supports(object);
    }

    public void marshalObject(Object object, C converter) throws ConverterException {
      om.marshalObject(object, converter);
    }
  }

  public ProxyHandler getProxyHandler() {
    return proxyHandler;
  }

  public boolean isCacheObjectMarshallerByClass() {
    return cacheObjectMarshallerByClass;
  }
}