You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by ju...@apache.org on 2005/02/21 18:30:50 UTC

svn commit: r154696 - in geronimo/trunk/modules/spring: project.xml src/java/org/apache/geronimo/spring/SpringGBean.java

Author: jules
Date: Mon Feb 21 09:30:48 2005
New Revision: 154696

URL: http://svn.apache.org/viewcvs?view=rev&rev=154696
Log:
now that we have support for cglib's InterfaceMaker, hook Spring generated POJOs directly into Geronimo kernel via a 1.3 proxy generated from such an interface.

Modified:
    geronimo/trunk/modules/spring/project.xml
    geronimo/trunk/modules/spring/src/java/org/apache/geronimo/spring/SpringGBean.java

Modified: geronimo/trunk/modules/spring/project.xml
URL: http://svn.apache.org/viewcvs/geronimo/trunk/modules/spring/project.xml?view=diff&r1=154695&r2=154696
==============================================================================
--- geronimo/trunk/modules/spring/project.xml (original)
+++ geronimo/trunk/modules/spring/project.xml Mon Feb 21 09:30:48 2005
@@ -6,16 +6,16 @@
     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.
 -->
-  
+
 <!-- $Rev$ $Date$ -->
 
 <project>
@@ -88,7 +88,7 @@
         <unitTest>
            <includes>
                 <include>**/*Test.java</include>
-            </includes>                
+            </includes>
         </unitTest>
         <resources>
             <resource>

Modified: geronimo/trunk/modules/spring/src/java/org/apache/geronimo/spring/SpringGBean.java
URL: http://svn.apache.org/viewcvs/geronimo/trunk/modules/spring/src/java/org/apache/geronimo/spring/SpringGBean.java?view=diff&r1=154695&r2=154696
==============================================================================
--- geronimo/trunk/modules/spring/src/java/org/apache/geronimo/spring/SpringGBean.java (original)
+++ geronimo/trunk/modules/spring/src/java/org/apache/geronimo/spring/SpringGBean.java Mon Feb 21 09:30:48 2005
@@ -17,15 +17,19 @@
 
 package org.apache.geronimo.spring;
 
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
 import java.net.URI;
 import java.net.URL;
 import java.net.URLClassLoader;
+import java.util.HashSet;
 import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.Set;
 import javax.management.MalformedObjectNameException;
 import javax.management.ObjectName;
 
+import net.sf.cglib.proxy.InterfaceMaker;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.geronimo.gbean.GBeanData;
@@ -58,6 +62,7 @@
   protected final URL         _configurationBaseUrl;
   protected final URI         _configPath;
 
+  protected ClassLoader                _appClassLoader;
   protected ObjectName                 _jmxName;
   protected DefaultListableBeanFactory _factory;
 
@@ -107,6 +112,12 @@
   // GBeanLifecycle
   //----------------------------------------
 
+  class GeronimoBeanFactory
+    extends DefaultListableBeanFactory
+  {
+    GeronimoBeanFactory(){super();}
+  }
+
   public void
     doStart()
     throws Exception
@@ -125,13 +136,13 @@
       urls[i]=url;
     }
 
-    ClassLoader cl=new URLClassLoader(urls, _classLoader);
+    _appClassLoader=new URLClassLoader(urls, _classLoader);
 
     // delegate work to Spring framework...
-    _factory=new DefaultListableBeanFactory();
+    _factory=new GeronimoBeanFactory();
     XmlBeanDefinitionReader xbdr=new XmlBeanDefinitionReader(_factory);
-    xbdr.setBeanClassLoader(cl);
-    xbdr.loadBeanDefinitions(new ClassPathResource(_configPath.toString(), cl));
+    xbdr.setBeanClassLoader(_appClassLoader);
+    xbdr.loadBeanDefinitions(new ClassPathResource(_configPath.toString(), _appClassLoader));
 
     // install aspects around Spring Bean initialisation...
     _factory.addBeanPostProcessor(new BeanPostProcessor() {
@@ -178,6 +189,7 @@
     tidyUp()
     throws Exception
   {
+    // can we put this as a spring aspect around each POJO ? would be better...
     String pattern=_jmxName.getDomain()+":J2EEApplication="+_jmxName.getKeyProperty("J2EEApplication")+",J2EEServer="+_jmxName.getKeyProperty("J2EEServer")+",SpringModule="+_jmxName.getKeyProperty("name")+",j2eeType=SpringBean,*";
     ObjectName on=new ObjectName(pattern);
 
@@ -186,7 +198,7 @@
     //     props.put("SpringModule" , props.get("name"));
     //     props.put("j2eeType"     , "SpringBean");
     //     props.remove("name");
-    //     props.put("*"           , null);
+    //     props.put("*", "");
     //     ObjectName on=new ObjectName(_jmxName.getDomain(), props);
 
     Set peers=_kernel.listGBeans(on);
@@ -237,8 +249,10 @@
       	_log.warn("No GBean available for name: " + name + " bean: " + bean);
       else
       {
+	_log.info("proxying: "+bean);
 	_log.info("loading: "+gd.getName());
-      	_kernel.loadGBean(gd, _classLoader);
+	//      	_kernel.loadGBeanProxy(bean, gd, _appClassLoader);
+      	_kernel.loadGBean(gd, _appClassLoader);
 	_log.info("starting: "+gd.getName());
 	_kernel.startGBean(gd.getName());
       }
@@ -271,13 +285,75 @@
     return new ObjectName(_jmxName.getDomain(), props);
   }
 
-  protected GBeanData
+  protected int _count=0;	// we should use a Spring generated unique name here - TODO
+
+  public static class InvocationHandler
+    implements java.lang.reflect.InvocationHandler, java.io.Serializable
+  {
+    protected Object _pojo;
+
+    public
+      InvocationHandler(Object pojo) {_pojo=pojo;}
+
+    public Object
+      invoke(Object proxy, Method method, Object[] args)
+      throws Throwable
+    {
+      return _pojo.getClass().getMethod(method.getName(), method.getParameterTypes()).invoke(_pojo, args);
+    }
+  }
+
+  protected synchronized GBeanData
     createPOJOGBeanData(Object bean, String name)
-    throws MalformedObjectNameException
+      throws MalformedObjectNameException
+  {
+    Class c=createProxyClass(bean);
+    GBeanInfoBuilder gbif = new GBeanInfoBuilder(c, "POJO["+(_count++)+"]");
+
+    gbif.addAttribute("invocationHandler", java.lang.reflect.InvocationHandler.class, true);
+    gbif.setConstructor(new String[]{"invocationHandler"});
+    // describe the rest of the POJOs public API
+    Set pm=new HashSet();
+    Method[] methods=c.getMethods();
+    for (int i=0;i<methods.length;i++)
+    {
+      Method m=methods[i];
+      String n=m.getName();
+      Class[] pt=m.getParameterTypes();
+      Class rt=m.getReturnType();
+
+      // ugly way of collecting Bean property names - maybe we can get this from Spring ?
+      if ((n.startsWith("get") && pt.length==0) || (n.startsWith("set") && pt.length==1 && rt==Void.TYPE))
+	pm.add(n.substring(3,4).toLowerCase()+n.substring(4));
+    }
+
+    //    pm.remove("class"); // do we want this available ?
+    gbif.addInterface(c, (String[])pm.toArray(new String[pm.size()]));
+    //gbif.addInterface(c);
+    GBeanData gbd=new GBeanData(createObjectName(name), gbif.getBeanInfo());
+    // ensure the injection of the InvocationHandler into the newly instantiated Proxy
+    gbd.setAttribute("invocationHandler"  , new InvocationHandler(bean));
+
+    return gbd;
+  }
+
+  // We have to create a proxy here because the kernel only accepts
+  // classes from which to instantiate GBeanInstance targets, not
+  // instances, which is what we get from Spring. So we create a proxy
+  // that can be instantiated and injected with an InvocationHandler
+  // which will delegate all calls onto the corresponding method on
+  // the bean that we wanted to pass in in the first place. Complex
+  // syntactic sugar - eh...!
+  protected Class
+    createProxyClass(Object pojo)
   {
-    GBeanData gbeanData=new GBeanData(createObjectName(name), POJOGBean.GBEAN_INFO);
-    gbeanData.setAttribute("peer", bean);
+    InterfaceMaker im=new InterfaceMaker();
+    im.add(pojo.getClass());	// add all class' public methods...
+
+    // if POJO does not implement GBeanLifeCycle should we implement
+    // it and dump/reroute it, to be safe ?
 
-    return gbeanData;
+    Class c=im.create();
+    return Proxy.getProxyClass(c.getClassLoader(), new Class[] {c});
   }
 }