From 62d5f5be466cc9735dba8c06b2c3f80b16df54a4 Mon Sep 17 00:00:00 2001
From: Lari Hotari <lari.hotari@sagire.fi>
Date: Wed, 27 May 2009 10:46:54 +0300
Subject: [PATCH] request scope for TagLib beans (GRAILS-4594)

---
 .../plugins/web/GroovyPagesGrailsPlugin.groovy     |   17 ++++++++----
 .../grails/web/plugins/support/WebMetaUtils.groovy |   16 ++++++++----
 .../web/taglib/NamespacedTagDispatcher.groovy      |   15 +++++------
 .../groovy/grails/web/pages/TagLibraryLookup.java  |   25 ++++++++++++++++----
 4 files changed, 49 insertions(+), 24 deletions(-)

diff --git a/grails/src/groovy/org/codehaus/groovy/grails/plugins/web/GroovyPagesGrailsPlugin.groovy b/grails/src/groovy/org/codehaus/groovy/grails/plugins/web/GroovyPagesGrailsPlugin.groovy
index 5aa7bd4..ef94570 100644
--- a/grails/src/groovy/org/codehaus/groovy/grails/plugins/web/GroovyPagesGrailsPlugin.groovy
+++ b/grails/src/groovy/org/codehaus/groovy/grails/plugins/web/GroovyPagesGrailsPlugin.groovy
@@ -158,6 +158,7 @@ public class GroovyPagesGrailsPlugin {
         for(taglib in application.tagLibClasses) {
             "${taglib.fullName}"(taglib.clazz) { bean ->
                    bean.autowire = true
+				   bean.scope = 'request'
             }
         }
 
@@ -225,8 +226,7 @@ public class GroovyPagesGrailsPlugin {
             WebMetaUtils.registerCommonWebProperties(mc, application)
 
             for(tag in taglib.tagNames) {
-                def tagLibrary = gspTagLibraryLookup.lookupTagLibrary(namespace, tag)
-                WebMetaUtils.registerMethodMissingForTags(mc, tagLibrary, tag)
+                WebMetaUtils.registerMethodMissingForTags(mc, gspTagLibraryLookup, namespace, tag)
             }
 
             mc.throwTagError = {String message ->
@@ -274,10 +274,15 @@ public class GroovyPagesGrailsPlugin {
 
             }
             mc.methodMissing = {String name, args ->
+            	def usednamespace = namespace
                 def tagLibrary = gspTagLibraryLookup.lookupTagLibrary(namespace, name)
-                if(!tagLibrary) tagLibrary = gspTagLibraryLookup.lookupTagLibrary(GroovyPage.DEFAULT_NAMESPACE, name)
+                if(!tagLibrary) {
+                	tagLibrary = gspTagLibraryLookup.lookupTagLibrary(GroovyPage.DEFAULT_NAMESPACE, name)
+					usednamespace = GroovyPage.DEFAULT_NAMESPACE
+                }
                 if(tagLibrary) {
-                    WebMetaUtils.registerMethodMissingForTags(mc, tagLibrary, name)
+                	WebMetaUtils.registerMethodMissingForTags(mc, gspTagLibraryLookup, usednamespace, name)
+                    //WebMetaUtils.registerMethodMissingForTags(mc, tagLibrary, name)
                 }
                 if (mc.respondsTo(delegate, name, args)) {
                     return mc.invokeMethod(delegate, name, args)
@@ -286,7 +291,6 @@ public class GroovyPagesGrailsPlugin {
                     throw new MissingMethodException(name, delegate.class, args)
                 }
             }
-            ctx.getBean(taglib.fullName).metaClass = mc
         }
 
     }
@@ -300,7 +304,7 @@ public class GroovyPagesGrailsPlugin {
             def tagLibrary = lookup.lookupTagLibrary(GroovyPage.DEFAULT_NAMESPACE, name)
             if (tagLibrary) {
                 MetaClass controllerMc = delegate.class.metaClass
-                WebMetaUtils.registerMethodMissingForTags(controllerMc,tagLibrary, name)
+                WebMetaUtils.registerMethodMissingForTags(controllerMc, lookup, GroovyPage.DEFAULT_NAMESPACE, name)
                 if(controllerMc.respondsTo(delegate, name, args)) {
                   return controllerMc.invokeMethod(delegate, name, args)
                 }
@@ -325,6 +329,7 @@ public class GroovyPagesGrailsPlugin {
                 def beans = beans {
                     "$beanName"(taglibClass.getClazz()) {bean ->
                         bean.autowire = true
+						bean.scope = 'request'
                     }
                 }
                 beans.registerBeans(event.ctx)
diff --git a/grails/src/groovy/org/codehaus/groovy/grails/web/plugins/support/WebMetaUtils.groovy b/grails/src/groovy/org/codehaus/groovy/grails/web/plugins/support/WebMetaUtils.groovy
index 7ab5775..d40247f 100644
--- a/grails/src/groovy/org/codehaus/groovy/grails/web/plugins/support/WebMetaUtils.groovy
+++ b/grails/src/groovy/org/codehaus/groovy/grails/web/plugins/support/WebMetaUtils.groovy
@@ -21,7 +21,7 @@ import org.springframework.beans.BeanWrapperImpl
 import org.codehaus.groovy.grails.web.pages.GroovyPage
 import org.springframework.web.context.request.RequestContextHolder as RCH
 import org.codehaus.groovy.grails.commons.GrailsApplication
-
+import org.codehaus.groovy.grails.web.pages.TagLibraryLookup
 /**
  * Provides utility methods used to support meta-programming. In particular commons methods to
  * register tag library method invokations as new methods an a given MetaClass
@@ -91,13 +91,13 @@ class WebMetaUtils {
     }
 
 
-    static registerMethodMissingForTags(MetaClass mc, GroovyObject tagLibrary, String name) {
+    static registerMethodMissingForTags(MetaClass mc, TagLibraryLookup gspTagLibraryLookup, String namespace, String name) {
         mc."$name" = {Map attrs, Closure body ->
             def webRequest = RCH.currentRequestAttributes()
             def originalOut = webRequest.out
             def capturedOutput
             try {
-                capturedOutput = GroovyPage.captureTagOutput(tagLibrary, name, attrs, body, webRequest)
+                capturedOutput = GroovyPage.captureTagOutput(gspTagLibraryLookup.lookupTagLibrary(namespace, name), name, attrs, body, webRequest)
             } finally {
                 webRequest.out = originalOut
             }
@@ -110,6 +110,7 @@ class WebMetaUtils {
             def capturedOutput
             try {
                 Closure bodyClosure = {out << body}
+                def tagLibrary=gspTagLibraryLookup.lookupTagLibrary(namespace, name)
                 bodyClosure.delegate = tagLibrary
                 bodyClosure.resolveStrategy = Closure.DELEGATE_ONLY
                 capturedOutput = GroovyPage.captureTagOutput(tagLibrary, name, attrs, bodyClosure, webRequest)
@@ -125,6 +126,7 @@ class WebMetaUtils {
             def originalOut = webRequest.out
             def capturedOutput
             try {
+            	def tagLibrary=gspTagLibraryLookup.lookupTagLibrary(namespace, name)
                 capturedOutput = GroovyPage.captureTagOutput(tagLibrary, name, attrs, null, webRequest)
             } finally {
                 webRequest.out = originalOut
@@ -137,6 +139,7 @@ class WebMetaUtils {
             def originalOut = webRequest.out
             def capturedOutput
             try {
+            	def tagLibrary=gspTagLibraryLookup.lookupTagLibrary(namespace, name)
                 capturedOutput = GroovyPage.captureTagOutput(tagLibrary, name, [:], body, webRequest)
             } finally {
                 webRequest.out = originalOut
@@ -150,6 +153,7 @@ class WebMetaUtils {
             def originalOut = webRequest.out
             def capturedOutput
             try {
+            	def tagLibrary=gspTagLibraryLookup.lookupTagLibrary(namespace, name)
                 capturedOutput = GroovyPage.captureTagOutput(tagLibrary, name, [:], null, webRequest)
             } finally {
                 webRequest.out = originalOut
@@ -159,8 +163,10 @@ class WebMetaUtils {
     }
 
     static registerMethodMissingForTags(MetaClass mc, ApplicationContext ctx, GrailsTagLibClass tagLibraryClass, String name) {
-        def tagLibrary = ctx.getBean(tagLibraryClass.fullName)
-        registerMethodMissingForTags(mc,tagLibrary,name)
+        //def tagLibrary = ctx.getBean(tagLibraryClass.fullName)
+		TagLibraryLookup gspTagLibraryLookup = ctx.getBean("gspTagLibraryLookup")
+		String namespace = tagLibraryClass.namespace ?: GroovyPage.DEFAULT_NAMESPACE
+        registerMethodMissingForTags(mc,gspTagLibraryLookup,namespace,name)
     }
 
 
diff --git a/grails/src/groovy/org/codehaus/groovy/grails/web/taglib/NamespacedTagDispatcher.groovy b/grails/src/groovy/org/codehaus/groovy/grails/web/taglib/NamespacedTagDispatcher.groovy
index b477adf..b6be784 100644
--- a/grails/src/groovy/org/codehaus/groovy/grails/web/taglib/NamespacedTagDispatcher.groovy
+++ b/grails/src/groovy/org/codehaus/groovy/grails/web/taglib/NamespacedTagDispatcher.groovy
@@ -16,8 +16,8 @@
 package org.codehaus.groovy.grails.web.taglib
 
 import org.codehaus.groovy.grails.commons.GrailsApplication
-import org.springframework.context.ApplicationContext
 import org.codehaus.groovy.grails.commons.TagLibArtefactHandler
+import org.codehaus.groovy.grails.web.pages.TagLibraryLookup
 
 /**
 * <p>This class allows dispatching to namespaced tag libraries and is used within controllers and tag libraries
@@ -33,20 +33,19 @@ import org.codehaus.groovy.grails.commons.TagLibArtefactHandler
 class NamespacedTagDispatcher extends GroovyObjectSupport {
    String namespace
    GrailsApplication application
-   ApplicationContext applicationContext
    Class type
+   TagLibraryLookup lookup
 
-   NamespacedTagDispatcher(String ns, Class callingType, GrailsApplication application, ApplicationContext applicationContext) {
+   NamespacedTagDispatcher(String ns, Class callingType, GrailsApplication application, TagLibraryLookup lookup) {
         this.namespace = ns
         this.application = application
-        this.applicationContext = applicationContext
+        this.lookup = lookup
         this.type = callingType
    }
+
    def invokeMethod(String name, args) {
-        def tag = "$namespace:$name"
-        def tagLibClass = application.getArtefactForFeature(TagLibArtefactHandler.TYPE, tag.toString())
-        if(tagLibClass) {
-            def tagBean = applicationContext.getBean(tagLibClass.fullName)
+        def tagBean = lookup.lookupTagLibrary(namespace, name)
+        if(tagBean) {
             Object result = tagBean.invokeMethod(name, args)
             return result
         }
diff --git a/grails/src/web/org/codehaus/groovy/grails/web/pages/TagLibraryLookup.java b/grails/src/web/org/codehaus/groovy/grails/web/pages/TagLibraryLookup.java
index 9ec2d79..0145a3f 100644
--- a/grails/src/web/org/codehaus/groovy/grails/web/pages/TagLibraryLookup.java
+++ b/grails/src/web/org/codehaus/groovy/grails/web/pages/TagLibraryLookup.java
@@ -20,11 +20,14 @@ import org.codehaus.groovy.grails.commons.GrailsClass;
 import org.codehaus.groovy.grails.commons.GrailsTagLibClass;
 import org.codehaus.groovy.grails.commons.TagLibArtefactHandler;
 import org.codehaus.groovy.grails.plugins.support.aware.GrailsApplicationAware;
+import org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequest;
 import org.codehaus.groovy.grails.web.taglib.NamespacedTagDispatcher;
 import org.springframework.beans.BeansException;
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationContextAware;
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.RequestContextHolder;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -41,7 +44,7 @@ import java.util.Set;
 public class TagLibraryLookup implements ApplicationContextAware, GrailsApplicationAware, InitializingBean{
     private ApplicationContext applicationContext;
     private GrailsApplication grailsApplication;
-    private Map<String, GroovyObject> tagLibraries = new HashMap<String, GroovyObject>();
+    private Map<String, String> tagLibraries = new HashMap<String, String>();
     private Map<String, NamespacedTagDispatcher> namespaceDispatchers = new HashMap<String, NamespacedTagDispatcher>();
 
     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
@@ -58,7 +61,7 @@ public class TagLibraryLookup implements ApplicationContextAware, GrailsApplicat
             for (GrailsClass grailsClass : taglibs) {
                 registerTagLib((GrailsTagLibClass)grailsClass);
             }
-            namespaceDispatchers.put(GroovyPage.TEMPLATE_NAMESPACE, new NamespacedTagDispatcher(GroovyPage.DEFAULT_NAMESPACE, GroovyPage.class, grailsApplication, applicationContext) {
+            namespaceDispatchers.put(GroovyPage.TEMPLATE_NAMESPACE, new NamespacedTagDispatcher(GroovyPage.DEFAULT_NAMESPACE, GroovyPage.class, grailsApplication, this) {
                 @Override
                 public Object invokeMethod(final String name, Object args) {
 
@@ -90,9 +93,9 @@ public class TagLibraryLookup implements ApplicationContextAware, GrailsApplicat
      */
     public void registerTagLib(GrailsTagLibClass taglib) {
         String namespace = taglib.getNamespace();
-        namespaceDispatchers.put(namespace, new NamespacedTagDispatcher(namespace, GroovyPage.class, grailsApplication, applicationContext));
+        namespaceDispatchers.put(namespace, new NamespacedTagDispatcher(namespace, GroovyPage.class, grailsApplication, this));
         for(String tagName : taglib.getTagNames()) {
-            tagLibraries.put(namespace+':'+tagName, (GroovyObject) applicationContext.getBean(taglib.getFullName()));
+            tagLibraries.put(namespace+':'+tagName, taglib.getFullName());
         }
     }
 
@@ -104,7 +107,19 @@ public class TagLibraryLookup implements ApplicationContextAware, GrailsApplicat
      * @return The tag library or null if it wasn't found
      */
     public GroovyObject lookupTagLibrary(String namespace, String tagName) {
-        return tagLibraries.get(namespace+':'+tagName);
+    	String fullName = tagLibraries.get(namespace+':'+tagName);
+    	if(fullName != null) {
+    		// fast lookup of taglib in same request
+    		String attrName = "GRAILS_TAGLIB_" + fullName;
+    		GroovyObject tagBean=(GroovyObject)RequestContextHolder.currentRequestAttributes().getAttribute(attrName, RequestAttributes.SCOPE_REQUEST);
+    		if(tagBean==null) {
+    			tagBean=(GroovyObject) applicationContext.getBean(fullName);
+    			RequestContextHolder.currentRequestAttributes().setAttribute(attrName, tagBean, RequestAttributes.SCOPE_REQUEST);
+    		}
+    		return tagBean; 
+    	} else {
+    		return null;
+    	}
     }
 
     /**
-- 
1.6.1.3

