Announcement Announcement Module
Collapse
No announcement yet.
RmiServiceExporter/Prototype bean - Not working Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • RmiServiceExporter/Prototype bean - Not working

    We are trying to do a POC using the RmiServiceExporter with a 'stateful' bean for a distributed application.
    When testing with multiple simultaneous clients, the same exact same bean is getting returned to separate requesters and the stateful data is getting corrupted.

    We have two layers of RMI remote, but I think they may both have the same problem.
    Also, in our servlet, (for now) we are creating a new application context for every request. (bad, I know) but wanted to include that detail.



    Our first layer of RMI:
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    		xmlns:tx="http://www.springframework.org/schema/tx"
    		xsi:schemaLocation="http://www.springframework.org/schema/beans
    							http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
    							http://www.springframework.org/schema/tx
    							http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
    
    
    	<bean id="accountRepository" class="com.theocc.drive.AccountServerBean" scope="prototype" >
    	</bean>
    
    </beans>
    Exposed using: Includes reference to our next layer.
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    		xsi:schemaLocation="http://www.springframework.org/schema/beans
    							http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
    
    	<bean id="accountExporter" class="org.springframework.remoting.rmi.RmiServiceExporter">
    		<property name="service" ref="accountRepository"/>
    		<property name="serviceInterface" value="com.theocc.drive.AccountServerRemote"/>
    		<property name="serviceName" value="accountService"/>
    	</bean>
    	
    	<bean id="riskService1" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
    	<property name="serviceUrl" value="rmi://tappa3:1099/riskService"/>
    	<property name="serviceInterface" value="com.theocc.interfaces.RiskServer"/>
    	</bean>
    	
    	<bean id="riskService2" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
    	<property name="serviceUrl" value="rmi://tappa4:1099/riskService"/>
    	<property name="serviceInterface" value="com.theocc.interfaces.RiskServer"/>
    	</bean>
    		
    </beans>
    Our second layer of RMI:
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    		xsi:schemaLocation="http://www.springframework.org/schema/beans
    							http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
    
    	<bean id="riskExporter" class="org.springframework.remoting.rmi.RmiServiceExporter">
    		<property name="service" ref="riskRepository"/>
    		<property name="serviceInterface" value="com.theocc.interfaces.RiskServer"/>
    		<property name="serviceName" value="riskService"/>
    	</bean>
    	
    	<bean id="riskRepository" class="com.theocc.businessobjects.RiskBO" scope="prototype" >
    	</bean>
    		
    </beans>
    Our lookups are using straight:
    ctx.getBean("accountService")

    Our RMI services are run using a simple main()
    Code:
    		public static void main(String[] args) throws Exception {
    			new ClassPathXmlApplicationContext(
    					new String[] { 
    							"com/theocc/drive/rmi-server-config.xml",
    							"com/theocc/drive/application-config.xml"});
    			
    			System.out.println("RMI Account Server started.");
    			System.in.read();
    		}
    I tried putting a scope="prototype" on the RMIServiceExporter, but then the main() routine just falls through and the application exits.
    Wasn't sure if that would solve our problem anyway.. so haven't tried to fix that yet.

    Anybody know what may be wrong with this setup?

    Thanks, Mike

  • #2
    Simple Example

    I'm not sure if I'm not getting responses to this because I didn't have a simple example code included, so I've worked up a basic bean to show my problem.

    beanif.java
    Code:
    public interface beanif {
            public int myid( );
    }
    mybean.java
    Code:
    public class mybean implements beanif
    {
      public int myid() { return System.identityHashCode(this); }
    }
    beanmain.java -> To provide the RMI service
    Code:
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class beanmain {
            public static void main(String[] args) throws Exception {
                    new ClassPathXmlApplicationContext("bean.xml");
                    System.out.println("RMI Bean Server started.");
                    System.in.read();
            }
    }
    client.java
    Code:
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class client {
            public static void main(String[] args) throws Exception {
    
                ApplicationContext ctx =
                    new ClassPathXmlApplicationContext("client.xml");
    
                beanif b1 = (beanif) ctx.getBean("beanService");
                beanif b2 = (beanif) ctx.getBean("beanService");
    
                int b1id = b1.myid();
                int b2id = b2.myid();
    
                System.out.println("ID1: " + b1id + "   ID2: " + b2id );
            }
    }
    client.xml
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                    xsi:schemaLocation="http://www.springframework.org/schema/beans
                    http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
    
            <bean id="beanService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
            <property name="serviceUrl" value="rmi://localhost:1099/beanService"/>
            <property name="serviceInterface" value="beanif"/>
            </bean>
    </beans>
    When I run the client, I get
    ID1: 7858936 ID2: 7858936

    which means I'm getting the SAME bean for two seperate RMI calls.

    Should the 'prototype' be on the RmiServiceExporter instead of the mybean object?

    I'm using spring version 2.0.2 if that makes a difference.

    -Thanks, Mike

    Comment


    • #3
      I've done a little more searching, and found several others have actually had basically the exact same problem. The only response thus far has been, why would you want a stateful RMI service?

      Anyway, a little more info that makes this a little stranger,

      Adding prototype to my FmiProxyFactorBean didnt' help

      Code:
      <bean id="beanService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean" scope="prototype" >
      AND if I do a

      Code:
         RmiProxyFactoryBean fb = (RmiProxyFactoryBean) ctx.getBean("&beanService");  
      System.out.println("Singleton? " + fb.isSingleton() );
      I get "singleton? true" !!! Is that factory hard-coded to return a singleton object? Shouldn't the server control this reference type?

      I would assume the RmiProxyFactory would also ask the server for a new reference and let the singleton decision get handled on the serverside.


      P.S. Forgot to include my bean.xml
      Code:
      <beans xmlns="http://www.springframework.org/schema/beans"
                      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
              <bean id="beanExporter" class="org.springframework.remoting.rmi.RmiServiceExporter">
                      <property name="service" ref="beanImpl"/>
                      <property name="serviceInterface" value="beanif"/>
                      <property name="serviceName" value="beanService"/>
              </bean>
      
              <bean id="beanImpl" class="mybean" scope="prototype" >
              </bean>
      </beans>

      Comment


      • #4
        Can't get there from here.

        RmiServiceExporter can only produce singletons because named RMI services are inherently singletons. An RMI remote object which is addressable as, e.g.,
        Code:
        rmi://foo:1099/service
        , is a reference to a single remote object, not a factory that produces remote objects.

        To do what you're trying to do you'll need to use RMI directly. As far as I know, Spring won't be able to help much. Start with a service (which you can export with Spring):

        Code:
        public class ServiceImpl implements Service, Remote
        {
            ...
            Session getSession(...params...)
                throws RemoteException
            {
                ... Do Stuff ...
                return new SessionImpl(...params...);
            }
            ...
        }
        where SessionImpl is defined along the lines:

        Code:
        public class SessionImpl implements Session, Remote
        {
            public SessionImpl(...params...) 
                throws RemoteException
            ...
            public int getSomething()
                throws RemoteException
            ...
        
            public void doSomething()
                throws RemoteException
            ...
        }
        Each client then connects to the Service and gets a Session, newed up fresh and clean and as stateful as you want it to be.

        Cheers,
        Britt

        Comment

        Working...
        X