Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

first cut of AST transformer for providing dynamic controller behavio…

…r at compile time
  • Loading branch information...
commit b8e8c79aa417fedd43088bddc50eee389708721e 1 parent 43f1b1f
@graemerocher graemerocher authored
Showing with 403 additions and 209 deletions.
  1. +1 −0  .gitignore
  2. +0 −101 grails-core/src/main/groovy/org/codehaus/groovy/grails/compiler/GrailsCompiler.groovy
  3. +52 −14 grails-core/src/main/groovy/org/codehaus/groovy/grails/compiler/Grailsc.java
  4. +129 −0 ...s-core/src/main/groovy/org/codehaus/groovy/grails/compiler/injection/AbstractGrailsArtefactTransformer.java
  5. +34 −0 grails-core/src/main/groovy/org/codehaus/groovy/grails/compiler/injection/AstTransformer.java
  6. +7 −11 grails-core/src/main/groovy/org/codehaus/groovy/grails/compiler/injection/GrailsAwareInjectionOperation.java
  7. +45 −0 grails-plugin-controllers/src/main/groovy/org/codehaus/groovy/grails/compiler/web/ControllerTransformer.java
  8. +25 −35 ...ls-plugin-controllers/src/main/groovy/org/codehaus/groovy/grails/plugins/web/ControllersGrailsPlugin.groovy
  9. +24 −23 grails-plugin-controllers/src/main/groovy/org/codehaus/groovy/grails/plugins/web/api/ControllersApi.java
  10. +0 −7 grails-plugin-controllers/src/main/groovy/org/codehaus/groovy/grails/web/metaclass/ForwardMethod.groovy
  11. +20 −17 grails-plugin-controllers/src/main/groovy/org/codehaus/groovy/grails/web/metaclass/RedirectDynamicMethod.java
  12. +61 −0 ...plugin-controllers/src/test/groovy/org/codehaus/groovy/grails/compiler/web/ControllerTransformerSpec.groovy
  13. +4 −0 grails-plugin-gsp/src/main/groovy/org/codehaus/groovy/grails/plugins/web/api/TagLibraryApi.java
  14. +1 −1  grails-web/src/main/groovy/org/codehaus/groovy/grails/plugins/web/api/CommonWebApi.java
View
1  .gitignore
@@ -1,3 +1,4 @@
+/out
/bin
/conf
*.ipr
View
101 grails-core/src/main/groovy/org/codehaus/groovy/grails/compiler/GrailsCompiler.groovy
@@ -1,101 +0,0 @@
-/*
- * Copyright 2003-2007 Graeme Rocher.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.compiler
-
-import org.codehaus.groovy.ant.Groovyc
-
-import org.codehaus.groovy.grails.compiler.support.GrailsResourceLoader
-import org.codehaus.groovy.grails.compiler.support.GrailsResourceLoaderHolder
-import org.codehaus.groovy.grails.plugins.GrailsPluginUtils
-
-import org.springframework.core.io.Resource
-import org.springframework.core.io.support.PathMatchingResourcePatternResolver
-
-/**
- * An extended version of the Groovy compiler that sets up the Grails ResourceLoader upon compilation.
- *
- * @author Graeme Rocher
- * @deprecated Use {@link Grailsc} instead
- *
- * @since 0.6
- */
-class GrailsCompiler extends Groovyc {
-
- String projectName
- def resolver = new PathMatchingResourcePatternResolver()
-
- private destList = []
-
- @Override
- void scanDir(File srcDir, File destDir, String[] files) {
- def srcList = []
- def srcPath = srcDir.absolutePath
- def destPath = destDir.absolutePath
- for (f in files) {
- def sf = new File("${srcPath}/$f")
- def df = null
- if (f.endsWith(".groovy") ) {
- df = new File("${destPath}/${f[0..-7] + 'class'}")
- def i = f.lastIndexOf('/')
- if (!df.exists() && i > -1) {
- // check root package
- def tmp = new File("${destPath}/${f[i..-7] + 'class'}")
- if (tmp.exists()) {
- df = tmp
- }
- }
- }
- else if (f.endsWith(".java")) {
- df = new File("${destPath}/${f[0..-5] + 'class'}")
- }
- else {
- continue
- }
-
- if (sf.lastModified() > df.lastModified()) {
- srcList << sf
- destList << df
- }
- }
- addToCompileList(srcList as File[])
- }
-
- void compile() {
-
- configureResourceLoader()
-
- if (compileList) {
- long now = System.currentTimeMillis()
- try {
- super.compile()
- getDestdir().setLastModified(now)
- }
- finally {
- // set the destination files as modified so recompile doesn't happen continuously
- for(f in destList) {
- f.setLastModified(now)
- }
- }
- }
- }
-
- private configureResourceLoader() {
- def basedir = System.getProperty("base.dir") ?: "."
- Resource[] resources = GrailsPluginUtils.getArtefactResources(basedir)
- def resourceLoader = new GrailsResourceLoader(resources)
- GrailsResourceLoaderHolder.resourceLoader = resourceLoader
- }
-}
View
66 grails-core/src/main/groovy/org/codehaus/groovy/grails/compiler/Grailsc.java
@@ -15,21 +15,60 @@
*/
package org.codehaus.groovy.grails.compiler;
-import grails.util.PluginBuildSettings;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-
+import groovy.lang.GroovyResourceLoader;
import org.codehaus.groovy.ant.Groovyc;
+import org.codehaus.groovy.control.CompilationUnit;
+import org.codehaus.groovy.control.Phases;
+import org.codehaus.groovy.grails.compiler.injection.AstTransformer;
+import org.codehaus.groovy.grails.compiler.injection.ClassInjector;
+import org.codehaus.groovy.grails.compiler.injection.GrailsAwareInjectionOperation;
import org.codehaus.groovy.grails.compiler.support.GrailsResourceLoader;
import org.codehaus.groovy.grails.compiler.support.GrailsResourceLoaderHolder;
+import org.codehaus.groovy.grails.plugins.GrailsPluginUtils;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.beans.factory.support.SimpleBeanDefinitionRegistry;
+import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
+import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
+import org.springframework.core.type.filter.AnnotationTypeFilter;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
public class Grailsc extends Groovyc {
private List<File> destList = new ArrayList<File>();
- private PluginBuildSettings pluginBuildSettings;
+
+
+ @Override protected CompilationUnit makeCompileUnit() {
+ BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
+ ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry);
+ scanner.setResourceLoader(new DefaultResourceLoader(Thread.currentThread().getContextClassLoader()));
+ scanner.addIncludeFilter(new AnnotationTypeFilter(AstTransformer.class));
+ scanner.scan("org.codehaus.groovy.grails.compiler");
+
+ CompilationUnit unit = super.makeCompileUnit();
+
+ List<ClassInjector> classInjectors = new ArrayList<ClassInjector>();
+ ClassLoader classLoader = getClass().getClassLoader();
+ for(String beanName : registry.getBeanDefinitionNames()) {
+ try {
+ Class<?> injectorClass = classLoader.loadClass(registry.getBeanDefinition(beanName).getBeanClassName());
+ if(ClassInjector.class.isAssignableFrom(injectorClass))
+ classInjectors.add((ClassInjector) injectorClass.newInstance());
+ } catch (ClassNotFoundException e) {
+ // ignore
+ } catch (InstantiationException e) {
+ // ignore
+ } catch (IllegalAccessException e) {
+ // ignore
+ }
+ }
+ unit.addPhaseOperation(new GrailsAwareInjectionOperation(configureResourceLoader(), classInjectors.toArray(new ClassInjector[classInjectors.size()])), Phases.CANONICALIZATION);
+ return unit;
+ }
+
@Override
protected void scanDir(File srcDir, File destDir, String[] files) {
@@ -67,7 +106,7 @@ else if (f.endsWith(".java")) {
@Override
protected void compile() {
- configureResourceLoader();
+
if (compileList.length > 0) {
long now = System.currentTimeMillis();
@@ -84,11 +123,10 @@ protected void compile() {
}
}
- private void configureResourceLoader() {
- if (pluginBuildSettings != null) {
- Resource[] resources = pluginBuildSettings.getArtefactResources();
- GrailsResourceLoader resourceLoader = new GrailsResourceLoader(resources);
- GrailsResourceLoaderHolder.setResourceLoader(resourceLoader);
- }
+ private GroovyResourceLoader configureResourceLoader() {
+ Resource[] resources = GrailsPluginUtils.getPluginBuildSettings().getArtefactResources();
+ GrailsResourceLoader resourceLoader = new GrailsResourceLoader(resources);
+ GrailsResourceLoaderHolder.setResourceLoader(resourceLoader);
+ return resourceLoader;
}
}
View
129 ...ore/src/main/groovy/org/codehaus/groovy/grails/compiler/injection/AbstractGrailsArtefactTransformer.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2011 SpringSource
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.groovy.grails.compiler.injection;
+
+import grails.util.GrailsNameUtils;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.PropertyNode;
+import org.codehaus.groovy.ast.expr.*;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.ast.stmt.ExpressionStatement;
+import org.codehaus.groovy.classgen.GeneratorContext;
+import org.codehaus.groovy.control.SourceUnit;
+import org.springframework.util.Assert;
+
+import java.lang.reflect.Modifier;
+import java.util.List;
+
+/**
+ * Abstract transformer that takes an implementation class and creates methods in a target ClassNode that delegate to that
+ * implementation class. Subclasses should override to provide the implementation class details
+ *
+ * @since 1.4
+ * @author Graeme Rocher
+ */
+public abstract class AbstractGrailsArtefactTransformer implements ClassInjector{
+
+ private static final Parameter[] ZERO_PARAMETERS = new Parameter[0];
+ private static final ClassNode OBJECT_CLASS = new ClassNode(Object.class);
+ private static final ClassNode[] EMPTY_CLASS_ARRAY = new ClassNode[0];
+ private static final VariableExpression THIS_EXPRESSION = new VariableExpression("this");
+ private static final ArgumentListExpression ZERO_ARGS = new ArgumentListExpression();
+
+ @Override
+ public void performInjection(SourceUnit source, GeneratorContext context, ClassNode classNode) {
+ Class implementation = getInstanceImplementation();
+
+ Assert.notNull(implementation, "No implementation found for AST transform: " + getClass());
+
+ ClassNode implementationNode = new ClassNode(implementation);
+
+ String apiInstanceProperty = GrailsNameUtils.getPropertyNameRepresentation(implementation);
+ VariableExpression apiInstance = new VariableExpression(apiInstanceProperty);
+
+
+ classNode.addProperty(new PropertyNode(apiInstanceProperty, Modifier.PUBLIC, implementationNode, classNode, new ConstructorCallExpression(implementationNode, ZERO_ARGS), null, null));
+
+
+
+ while(!implementationNode.equals(OBJECT_CLASS)) {
+ List<MethodNode> declaredMethods = implementationNode.getMethods();
+ for (MethodNode declaredMethod : declaredMethods) {
+
+ if(isCandidateInstanceMethod(declaredMethod)) {
+
+ Parameter[] parameterTypes = getParameterTypes(declaredMethod.getParameters());
+ if(!classNode.hasMethod(declaredMethod.getName(), parameterTypes)) {
+ BlockStatement methodBody = new BlockStatement();
+ ArgumentListExpression arguments = new ArgumentListExpression();
+ arguments.addExpression(THIS_EXPRESSION);
+ for (Parameter parameterType : parameterTypes) {
+ arguments.addExpression(new VariableExpression(parameterType.getName()));
+ }
+ methodBody.addStatement(new ExpressionStatement( new MethodCallExpression(apiInstance, declaredMethod.getName(), arguments)));
+ MethodNode methodNode = new MethodNode(declaredMethod.getName(),
+ Modifier.PUBLIC,
+ declaredMethod.getReturnType(),
+ parameterTypes,
+ EMPTY_CLASS_ARRAY,
+ methodBody
+ );
+ classNode.addMethod(methodNode);
+ }
+
+ }
+ }
+ implementationNode = implementationNode.getSuperClass();
+ }
+
+ }
+
+ private Parameter[] getParameterTypes(Parameter[] parameters) {
+ if(parameters.length>1) {
+ Parameter[] newParameters = new Parameter[parameters.length-1];
+ System.arraycopy(parameters, 1, newParameters, 0, parameters.length - 1);
+ return newParameters;
+ }
+ return ZERO_PARAMETERS;
+ }
+
+
+ private boolean isCandidateInstanceMethod(MethodNode declaredMethod) {
+ Parameter[] parameterTypes = declaredMethod.getParameters();
+ return isCandidateMethod(declaredMethod) && parameterTypes != null && parameterTypes.length > 0 && parameterTypes[0].getType().equals(OBJECT_CLASS);
+ }
+
+ private boolean isCandidateMethod(MethodNode declaredMethod) {
+ return !declaredMethod.isSynthetic()
+ && Modifier.isPublic(declaredMethod.getModifiers()) && !Modifier.isAbstract(declaredMethod.getModifiers());
+ }
+
+ /**
+ * The class that provides the implementation of all instance methods and properties
+ *
+ * @return A class whose methods contain a first argument of type object that is the instance
+ */
+ public abstract Class getInstanceImplementation();
+
+ @Override
+ public void performInjection(SourceUnit source, ClassNode classNode) {
+ performInjection(source, null, classNode);
+ }
+
+
+}
View
34 grails-core/src/main/groovy/org/codehaus/groovy/grails/compiler/injection/AstTransformer.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2011 SpringSource
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.codehaus.groovy.grails.compiler.injection;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ *
+ * Marker annotation that for classes that transform Grails classes at the AST level
+ *
+ * @since 1.4
+ * @author Graeme Rocher
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+public @interface AstTransformer {
+}
View
18 ...ls-core/src/main/groovy/org/codehaus/groovy/grails/compiler/injection/GrailsAwareInjectionOperation.java
@@ -15,10 +15,6 @@
package org.codehaus.groovy.grails.compiler.injection;
import groovy.lang.GroovyResourceLoader;
-
-import java.net.MalformedURLException;
-import java.net.URL;
-
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.groovy.ast.ClassNode;
@@ -30,6 +26,9 @@
import org.codehaus.groovy.grails.commons.GrailsResourceUtils;
import org.springframework.util.Assert;
+import java.net.MalformedURLException;
+import java.net.URL;
+
/**
* A Groovy compiler injection operation that uses a specified array of ClassInjector instances to
* attempt AST injection.
@@ -54,24 +53,21 @@ public GrailsAwareInjectionOperation(GroovyResourceLoader resourceLoader, ClassI
@Override
public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException {
- for (int i = 0; i < classInjectors.length; i++) {
- ClassInjector classInjector = classInjectors[i];
+ for (ClassInjector classInjector : classInjectors) {
try {
URL url;
if (GrailsResourceUtils.isGrailsPath(source.getName())) {
url = grailsResourceLoader.loadGroovySource(GrailsResourceUtils.getClassName(source.getName()));
- }
- else {
+ } else {
url = grailsResourceLoader.loadGroovySource(source.getName());
}
if (classInjector.shouldInject(url)) {
classInjector.performInjection(source, context, classNode);
}
- }
- catch (MalformedURLException e) {
+ } catch (MalformedURLException e) {
LOG.error("Error loading URL during addition of compile time properties: " + e.getMessage(), e);
- throw new CompilationFailedException(Phases.CONVERSION,source, e);
+ throw new CompilationFailedException(Phases.CONVERSION, source, e);
}
}
}
View
45 ...ls-plugin-controllers/src/main/groovy/org/codehaus/groovy/grails/compiler/web/ControllerTransformer.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2011 SpringSource
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.groovy.grails.compiler.web;
+
+import org.codehaus.groovy.grails.commons.GrailsResourceUtils;
+import org.codehaus.groovy.grails.compiler.injection.AbstractGrailsArtefactTransformer;
+import org.codehaus.groovy.grails.compiler.injection.AstTransformer;
+import org.codehaus.groovy.grails.plugins.web.api.ControllersApi;
+
+import java.net.URL;
+import java.util.regex.Pattern;
+
+/**
+ * Enhances controller classes with the appropriate API at compile time
+ *
+ * @author Graeme Rocher
+ * @since 1.4
+ */
+@AstTransformer
+public class ControllerTransformer extends AbstractGrailsArtefactTransformer{
+ public static Pattern CONTROLLER_PATTERN = Pattern.compile(".+/"+ GrailsResourceUtils.GRAILS_APP_DIR+"/controllers/(.+)\\.groovy");
+ @Override
+ public Class getInstanceImplementation() {
+ return ControllersApi.class;
+ }
+
+ @Override
+ public boolean shouldInject(URL url) {
+ return url != null && CONTROLLER_PATTERN.matcher(url.getFile()).find();
+
+ }
+}
View
60 ...plugin-controllers/src/main/groovy/org/codehaus/groovy/grails/plugins/web/ControllersGrailsPlugin.groovy
@@ -17,43 +17,31 @@ package org.codehaus.groovy.grails.plugins.web
import grails.util.Environment
import grails.util.GrailsUtil
-
-import java.lang.reflect.Modifier
-
-import org.codehaus.groovy.grails.commons.*
-import org.codehaus.groovy.grails.commons.metaclass.MetaClassEnhancer;
+import org.codehaus.groovy.grails.commons.ControllerArtefactHandler
+import org.codehaus.groovy.grails.commons.GrailsClass
+import org.codehaus.groovy.grails.commons.GrailsDomainClass
import org.codehaus.groovy.grails.plugins.GrailsPluginManager
-import org.codehaus.groovy.grails.plugins.web.api.ControllersApi;
+import org.codehaus.groovy.grails.plugins.web.api.ControllersApi
import org.codehaus.groovy.grails.web.binding.DataBindingLazyMetaPropertyMap
import org.codehaus.groovy.grails.web.binding.DataBindingUtils
import org.codehaus.groovy.grails.web.errors.GrailsExceptionResolver
import org.codehaus.groovy.grails.web.filters.HiddenHttpMethodFilter
-import org.codehaus.groovy.grails.web.metaclass.BindDynamicMethod
-import org.codehaus.groovy.grails.web.metaclass.ChainMethod
-import org.codehaus.groovy.grails.web.metaclass.ForwardMethod
import org.codehaus.groovy.grails.web.metaclass.RedirectDynamicMethod
-import org.codehaus.groovy.grails.web.metaclass.RenderDynamicMethod
-import org.codehaus.groovy.grails.web.metaclass.WithFormMethod
import org.codehaus.groovy.grails.web.multipart.ContentLengthAwareCommonsMultipartResolver
-import org.codehaus.groovy.grails.web.plugins.support.WebMetaUtils
-import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes
import org.codehaus.groovy.grails.web.servlet.GrailsControllerHandlerMapping
import org.codehaus.groovy.grails.web.servlet.filter.GrailsReloadServletFilter
import org.codehaus.groovy.grails.web.servlet.mvc.CommandObjectEnablingPostProcessor
import org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequestFilter
+import org.codehaus.groovy.grails.web.servlet.mvc.RedirectEventListener
import org.codehaus.groovy.grails.web.servlet.mvc.SimpleGrailsController
-
import org.springframework.beans.BeanUtils
import org.springframework.context.ApplicationContext
-import org.springframework.validation.Errors
-import org.springframework.web.context.request.RequestContextHolder as RCH
-import org.springframework.web.servlet.ModelAndView
import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter
-import org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
+import org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
import org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
-/**
+ /**
* Handles the configuration of controllers for Grails.
*
* @author Graeme Rocher
@@ -97,12 +85,15 @@ class ControllersGrailsPlugin {
stripLeadingSlash = false
}
+ controllersApi(ControllersApi, ref("pluginManager"))
+
for (controller in application.controllerClasses) {
log.debug "Configuring controller $controller.fullName"
if (controller.available) {
"${controller.fullName}"(controller.clazz) { bean ->
bean.scope = "prototype"
bean.autowire = "byName"
+ controllersApi = ref("controllersApi")
}
}
}
@@ -212,25 +203,26 @@ class ControllersGrailsPlugin {
}
}
- def controllerApi = new ControllersApi(application, pluginManager, ctx)
+ ControllersApi controllerApi = ctx.getBean("controllersApi")
+ Object gspEnc = application.getFlatConfig().get("grails.views.gsp.encoding");
+
+ if ((gspEnc != null) && (gspEnc.toString().trim().length() > 0)) {
+ controllerApi.setGspEncoding( gspEnc.toString() )
+ }
+
+ def redirectListeners = ctx.getBeansOfType(RedirectEventListener.class)
+ controllerApi.setRedirectListeners(redirectListeners.values())
+
+ Object o = application.getFlatConfig().get(RedirectDynamicMethod.GRAILS_VIEWS_ENABLE_JSESSIONID);
+ if (o instanceof Boolean) {
+ controllerApi.setUseJessionId(o)
+ }
- def enhancer = new MetaClassEnhancer()
- enhancer.addApi controllerApi
// add commons objects and dynamic methods like render and redirect to controllers
for (GrailsClass controller in application.controllerClasses) {
MetaClass mc = controller.metaClass
-
Class controllerClass = controller.clazz
- Class superClass = controller.clazz.superclass
- enhancer.enhance mc
- // deal with abstract super classes
- while (superClass != Object) {
- if (Modifier.isAbstract(superClass.getModifiers())) {
- enhancer.enhance superClass.metaClass
- }
- superClass = superClass.superclass
- }
mc.constructor = { ->
ctx.getBean(controllerClass.name)
@@ -254,15 +246,13 @@ class ControllersGrailsPlugin {
"${controllerClass.fullName}"(controllerClass.clazz) { bean ->
bean.scope = "prototype"
bean.autowire = true
+ controllersApi = ref("controllersApi")
}
}
// now that we have a BeanBuilder calling registerBeans and passing the app ctx will
// register the necessary beans with the given app ctx
beanDefinitions.registerBeans(event.ctx)
- // Add the dynamic methods back to the class (since it's
- // effectively a completely new class).
- event.manager?.getGrailsPlugin("controllers")?.doWithDynamicMethods(event.ctx)
}
}
}
View
47 grails-plugin-controllers/src/main/groovy/org/codehaus/groovy/grails/plugins/web/api/ControllersApi.java
@@ -16,28 +16,21 @@
package org.codehaus.groovy.grails.plugins.web.api;
import groovy.lang.Closure;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
import org.codehaus.groovy.grails.plugins.GrailsPluginManager;
-import org.codehaus.groovy.grails.web.mapping.UrlMappingsHolder;
-import org.codehaus.groovy.grails.web.metaclass.BindDynamicMethod;
-import org.codehaus.groovy.grails.web.metaclass.ChainMethod;
-import org.codehaus.groovy.grails.web.metaclass.ForwardMethod;
-import org.codehaus.groovy.grails.web.metaclass.RedirectDynamicMethod;
-import org.codehaus.groovy.grails.web.metaclass.RenderDynamicMethod;
-import org.codehaus.groovy.grails.web.metaclass.WithFormMethod;
+import org.codehaus.groovy.grails.web.metaclass.*;
import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes;
import org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequest;
+import org.codehaus.groovy.grails.web.servlet.mvc.RedirectEventListener;
import org.codehaus.groovy.runtime.DefaultGroovyMethods;
-import org.springframework.context.ApplicationContext;
import org.springframework.validation.Errors;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.servlet.ModelAndView;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
/**
* API for each controller in a Grails application
*
@@ -56,22 +49,30 @@
private WithFormMethod withFormMethod = new WithFormMethod();
private ForwardMethod forwardMethod;
- public ControllersApi(GrailsApplication application, GrailsPluginManager pluginManager, ApplicationContext applicationContext) {
+ public ControllersApi() {
+ super(null);
+ }
+
+ public ControllersApi(GrailsPluginManager pluginManager) {
super(pluginManager);
- this.redirect = new RedirectDynamicMethod(applicationContext);
- if(application != null) {
- Object gspEnc = application.getConfig().get("grails.views.gsp.encoding");
+ this.redirect = new RedirectDynamicMethod();
+ this.forwardMethod= new ForwardMethod();
+ }
- if ((gspEnc != null) && (gspEnc.toString().trim().length() > 0)) {
- render.setGspEncoding( gspEnc.toString() );
- }
+ public void setGspEncoding(String gspEncoding) {
+ render.setGspEncoding( gspEncoding );
+ }
- }
+ public void setRedirectListeners(Collection<RedirectEventListener> redirectListeners) {
+ redirect.setRedirectListeners(redirectListeners);
+ }
- this.forwardMethod= new ForwardMethod((UrlMappingsHolder) applicationContext.getBean("grailsUrlMappingsHolder"));
+ public void setUseJessionId(boolean useJessionId) {
+ redirect.setUseJessionId(useJessionId);
}
+
/**
* Returns the URI of the currently executing action
*
View
7 grails-plugin-controllers/src/main/groovy/org/codehaus/groovy/grails/web/metaclass/ForwardMethod.groovy
@@ -36,13 +36,6 @@ class ForwardMethod {
public static final String CALLED = "org.codehaus.groovy.grails.FORWARD_CALLED"
- UrlMappingsHolder holder
-
- ForwardMethod(UrlMappingsHolder urlMappingsHolder) {
- Assert.notNull(urlMappingsHolder, "Argument [urlMappingsHolder] is required")
- holder = urlMappingsHolder
- }
-
String forward(HttpServletRequest request, HttpServletResponse response, Map params) {
def urlInfo = new ForwardUrlMappingInfo()
View
37 ...s-plugin-controllers/src/main/groovy/org/codehaus/groovy/grails/web/metaclass/RedirectDynamicMethod.java
@@ -21,6 +21,7 @@
import groovy.lang.MissingMethodException;
import java.io.IOException;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@@ -70,27 +71,27 @@
public static final String ARGUMENT_ERRORS = "errors";
private static final Log LOG = LogFactory.getLog(RedirectDynamicMethod.class);
- private UrlMappingsHolder urlMappingsHolder;
private boolean useJessionId = false;
- private ApplicationContext applicationContext;
+ private Collection<RedirectEventListener> redirectListeners;
/**
- * Constructor.
- * @param applicationContext
*/
- public RedirectDynamicMethod(ApplicationContext applicationContext) {
+ public RedirectDynamicMethod(Collection<RedirectEventListener> redirectListeners) {
super(METHOD_PATTERN);
- if (applicationContext.containsBean(UrlMappingsHolder.BEAN_ID)) {
- urlMappingsHolder = (UrlMappingsHolder)applicationContext.getBean(UrlMappingsHolder.BEAN_ID);
- }
+ this.redirectListeners = redirectListeners;
+ }
- GrailsApplication application = (GrailsApplication)applicationContext.getBean(GrailsApplication.APPLICATION_ID);
- Object o = application.getFlatConfig().get(GRAILS_VIEWS_ENABLE_JSESSIONID);
- if (o instanceof Boolean) {
- useJessionId = (Boolean) o;
- }
- this.applicationContext = applicationContext;
+ public RedirectDynamicMethod() {
+ super(METHOD_PATTERN);
+ }
+
+ public void setRedirectListeners(Collection<RedirectEventListener> redirectListeners) {
+ this.redirectListeners = redirectListeners;
+ }
+
+ public void setUseJessionId(boolean useJessionId) {
+ this.useJessionId = useJessionId;
}
@SuppressWarnings({"unchecked","rawtypes"})
@@ -106,6 +107,7 @@ public Object invoke(Object target, String methodName, Object[] arguments) {
}
GrailsWebRequest webRequest = (GrailsWebRequest)RequestContextHolder.currentRequestAttributes();
+ UrlMappingsHolder urlMappingsHolder = webRequest.getApplicationContext().getBean(UrlMappingsHolder.BEAN_ID, UrlMappingsHolder.class);
HttpServletRequest request = webRequest.getCurrentRequest();
if (request.getAttribute(GRAILS_REDIRECT_ISSUED) != null) {
@@ -205,9 +207,10 @@ private Object redirectResponse(String actualUri, HttpServletRequest request, Ht
String redirectUrl = useJessionId ? response.encodeRedirectURL(actualUri) : actualUri;
response.sendRedirect(redirectUrl);
- Map<String, RedirectEventListener> redirectListeners = applicationContext.getBeansOfType(RedirectEventListener.class);
- for (RedirectEventListener redirectEventListener : redirectListeners.values()) {
- redirectEventListener.responseRedirected(redirectUrl);
+ if(redirectListeners != null) {
+ for (RedirectEventListener redirectEventListener : redirectListeners) {
+ redirectEventListener.responseRedirected(redirectUrl);
+ }
}
request.setAttribute(GRAILS_REDIRECT_ISSUED, true);
View
61 ...gin-controllers/src/test/groovy/org/codehaus/groovy/grails/compiler/web/ControllerTransformerSpec.groovy
@@ -0,0 +1,61 @@
+package org.codehaus.groovy.grails.compiler.web
+
+import org.codehaus.groovy.grails.compiler.injection.GrailsAwareClassLoader
+import spock.lang.Specification
+import org.codehaus.groovy.grails.compiler.injection.ClassInjector
+import grails.util.GrailsWebUtil
+import org.springframework.web.context.request.RequestContextHolder
+import javax.servlet.http.HttpServletRequest
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: graemerocher
+ * Date: 07/03/2011
+ * Time: 16:56
+ * To change this template use File | Settings | File Templates.
+ */
+class ControllerTransformerSpec extends Specification{
+
+ void "Test that the API is injected via AST"() {
+
+ given:
+ def gcl = new GrailsAwareClassLoader()
+ gcl.classInjectors = [new ControllerTransformer() {
+ @Override
+ boolean shouldInject(URL url) {
+ return true;
+ }
+
+ }] as ClassInjector[]
+
+
+ when:
+ def cls = gcl.parseClass('''
+class TestTransformedController {}
+''')
+ def controller = cls.newInstance()
+
+ then:
+ controller != null
+ controller.controllersApi != null
+
+ when:
+ GrailsWebUtil.bindMockWebRequest()
+
+ then:
+ controller.getRequest() instanceof HttpServletRequest
+ controller.request instanceof HttpServletRequest
+
+
+ when:
+ controller.render(view:"foo")
+
+ then:
+ controller.modelAndView != null
+
+ }
+
+ def cleanup() {
+ RequestContextHolder.setRequestAttributes(null)
+ }
+}
View
4 grails-plugin-gsp/src/main/groovy/org/codehaus/groovy/grails/plugins/web/api/TagLibraryApi.java
@@ -33,6 +33,10 @@
*/
public class TagLibraryApi extends CommonWebApi {
+ public TagLibraryApi() {
+ super(null);
+ }
+
public TagLibraryApi(GrailsPluginManager pluginManager) {
super(pluginManager);
}
View
2  grails-web/src/main/groovy/org/codehaus/groovy/grails/plugins/web/api/CommonWebApi.java
@@ -165,7 +165,7 @@ public GrailsWebRequest getWebRequest(@SuppressWarnings("unused") Object instanc
* @return The plugin context path
*/
public String getPluginContextPath(Object delegate) {
- final String pluginPath = pluginManager.getPluginPathForInstance(delegate);
+ final String pluginPath = pluginManager != null ? pluginManager.getPluginPathForInstance(delegate) : null;
return pluginPath !=null ? pluginPath : "";
}
}
Please sign in to comment.
Something went wrong with that request. Please try again.