Announcement Announcement Module
Collapse
No announcement yet.
Maintaing State while using HttpInvoker Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Maintaing State while using HttpInvoker

    Hi,
    I am working on a project which is rich client based (Swing) connecting to server side using http protocol. So i am using spring on server side and remoting using HttpInvoker and it is working fine and i feel i dont need EJB right now (great work spring team!). Now i am facing a problem, we want to maintain some state on server side (preferably using web http session) as we donot want to use SFSB ejb's here. I certainly want to pass that state information to my remotely exposed service object, but i donot know how to do that. I am pasting my code here so please can anybody help me?

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http&#58;//www.springframework.org/dtd/spring-beans.dtd">
    
    <!--
      - Application context definition for Petclinic on Hibernate.
    	-->
    <beans>
    	<!-- ========================= RESOURCE DEFINITIONS ========================= -->
    	<!-- JNDI DataSource for J2EE environments -->
    	<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
    		<property name="jndiName"><value>java&#58;/OracleDS</value></property>
    	</bean>
    
    	<!-- Hibernate SessionFactory -->
    	<bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
    		<property name="dataSource"><ref local="dataSource"/></property>
    		<property name="mappingResources">
    			<value>com/sequelsys/common/model/scheduling/HolidaysSchedule.hbm.xml</value>
    		</property>
    		<property name="hibernateProperties">
    			<props>
    				<prop key="hibernate.dialect">net.sf.hibernate.dialect.Oracle9Dialect</prop>
                                    <prop key="hibernate.show_sql">true</prop>
    			</props>
    		</property>
    	</bean>
    
    	<!-- Transaction manager for a single Hibernate SessionFactory &#40;alternative to JTA&#41; -->
    	<bean id="transactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager">
    		<property name="sessionFactory"><ref local="sessionFactory"/></property>
    	</bean>
    
            <bean id="holidayScheduleDAO" class="com.sequelsys.server.scheduling.dao.HolidayScheduleDAO">
              <property name="sessionFactory"><ref local="sessionFactory"/></property>
            </bean>
    
    	<!-- ========================= BUSINESS OBJECT DEFINITIONS ========================= -->
    
    	<!--
    		- A parent bean definition which is a base definition for transaction proxies.
    		- It is markes as abstract, since it is never supposed to be instantiated itself.
    		- We set shared transaction attributes here, following our naming patterns.
    		- The attributes can still be overridden in child bean definitions.
    		-->
    	<bean id="baseTransactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"	abstract="true">
    		<property name="transactionManager"><ref bean="transactionManager"/></property>
    		<property name="transactionAttributes">
    			<props>
    				<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
    				<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
    				<prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>
    				<prop key="create*">PROPAGATION_REQUIRED</prop>
    			</props>
    		</property>
    	</bean>
    
    	<bean id="holidayScheduleService" parent="baseTransactionProxy">
    		<property name="target">
    			<bean class="com.sequelsys.server.scheduling.service.HolidayScheduleService">
                              <property name="holidayScheduleDAO"><ref local="holidayScheduleDAO"/></property>
                            </bean>
                   </property>
    	</bean>
    </beans>
    Code:
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http&#58;//www.springframework.org/dtd/spring-beans.dtd">
    <beans>
      <bean name="/HolidayScheduleService" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
    	<property name="service"><ref bean="holidayScheduleService"/></property>
    	<property name="serviceInterface">
    		<value>com.sequelsys.server.scheduling.service.IHolidayScheduleService</value>
           </property>
      </bean>
    </beans>
    So i want something (prefeably in web layer) taht can maintain state on user behalf and pass it to teh same object that is remotely exposed for swing side.

  • #2
    http://article.gmane.org/gmane.comp....ork.user/3652/

    Comment


    • #3
      Re

      Hi,
      Thanks Ben for u r prompt reply but i am afraid that it is not the solution of my problem. Their are some requirements which need HttpSession atleast , i know spring philosophy is against SFSB but that doest mean that there should be no state at all. And by the way when u r using http for remoting it means u have web servers and all the web structure is already in place so why do not we should benefit to the available infrastructure i think instead of denying a very legitimate problem the people at spring should provide solution. I hope u people will not mind my boldness and i always agree that Spring is the best J2ee framework i have ever seen and i love it and i want to use it whenever possible but this Http sesson is causing problems for my cause of convincing my upper management and also i ma not using acegi security and we have some other things also to store in session.So kindly please help me. Looking forward with great hope from great people who wrote a great framework

      Comment


      • #4
        Shoaib,

        are you absolutely sure that you need to maintain state on the server? If you post your use case perhaps we can suggest an alternative implementation that uses the existing (stateless) remoting support.

        Ollie

        Comment


        • #5
          I think adding Session support would be very useful. What if you need to get through a security product like Siteminder that is setup to use session cookies.

          While there may be reasons not to use it, shouldn't that be the architect's decision, not a limitation of Spring?

          Comment


          • #6
            Shoaib,

            You can use the session in the following way. For your client context, use the commons remote executor to maintain the same session:
            Code:
            	<bean id="httpInvokerProxy" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
            		<property name="serviceUrl">
            			<value>http&#58;//$&#123;serverName&#125;&#58;$&#123;httpPort&#125;$&#123;contextPath&#125;/remoting/RemoteService-httpinvoker</value>
            		</property>
            		<property name="serviceInterface">
            			<value>org.timnolan.springsample.domain.logic.RemoteService</value>
            		</property>
            		<property name="httpInvokerRequestExecutor">
            			<ref bean="httpInvokerExecutor"/>
            		</property>
            	</bean>
            
            	<bean id="httpInvokerExecutor" class="org.springframework.remoting.httpinvoker.CommonsHttpInvokerRequestExecutor"/>
            To use the session, you can attach it to a ThreadLocal in some way (I've done this by subclassing the Dispatcher servlet, and using ThreadLocals inside a custom class, CurrentThread).

            Code:
                    CurrentThread.setSessionHolder&#40;new SessionHolderImpl&#40;request&#41;&#41;;
                    super.doService&#40;request, response&#41;;
                    CurrentThread.cleanUp&#40;&#41;;
            SessionHolderImpl implements SessionHolder interface to hide the Web dependencies.
            Code:
            public class SessionHolderImpl implements SessionHolder &#123;
                private HttpSession session;
            
                public SessionHolderImpl&#40;HttpServletRequest request&#41; &#123;
                    session = request.getSession&#40;&#41;;
                &#125;
            
                public Object getAttribute&#40;String name&#41; &#123;
                    return session.getAttribute&#40;name&#41;;
                &#125;
            
                public void setAttribute&#40;String name, Object value&#41; &#123;
                    session.setAttribute&#40;name, value&#41;;
                &#125;
            
            &#125;
            Your code can then access the Session.
            Code:
                public Employee login&#40;String username, String password&#41; &#123;
                    if &#40;password==null&#41; &#123;
                        return null;
                    &#125;
                    Employee employeeFound = findEmployeeByUsername&#40;username&#41;;
                    if &#40;employeeFound!=null && employeeFound.isActive&#40;&#41; && password.equals&#40;employeeFound.getPassword&#40;&#41;&#41;&#41; &#123;
                        CurrentThread.getSessionHolder&#40;&#41;.setAttribute&#40;Constants.EMPLOYEE, employeeFound&#41;;
                        return employeeFound;
                    &#125;
                    return null;
                &#125;
            Having done I wouldn't recommend spreading this code everywhere. I've used it in one case to verify login which works very well. My Web and Remoting clients now use the same custom authentication.

            Comment


            • #7
              Re

              Hi katentim,
              Thanks for your solution i will try it soon ( can you send me the code for it) . Though i still believe that spring should have this support built in as it is handy in many cases and also not everybody can use the excellent acegi security system (you know the politics). So i rquest to developer of spring of addition of HttpSession .

              Regards,
              Shoaib Akhtar

              Comment


              • #8
                It shouldn't be too much to fill in the gaps from here, but anyway... CurrentThread looks like:
                Code:
                    private static ThreadLocal sessionHolder = new ThreadLocal&#40;&#41;;
                
                    public static void setSessionHolder&#40;SessionHolder session&#41; &#123;
                        CurrentThread.sessionHolder.set&#40;session&#41;;
                    &#125;
                
                    public static SessionHolder getSessionHolder&#40;&#41; &#123;
                        if &#40;sessionHolder.get&#40;&#41;==null&#41; &#123;
                            return null;
                        &#125;
                        return &#40;SessionHolder&#41; sessionHolder.get&#40;&#41;;
                    &#125;
                
                   public static void cleanUp&#40;&#41; &#123;
                       //Clear all thread locals here
                       CurrentThread.sessionHolder.set&#40;null&#41;;
                    &#125;
                And SessionHolder:
                Code:
                public interface SessionHolder &#123;
                    public abstract Object getAttribute&#40;String name&#41;;
                    public abstract void setAttribute&#40;String name, Object value&#41;;
                &#125;
                Good luck.

                Comment


                • #9
                  Tim,

                  do you mind elaborating how you deal with things like session timeout? Also why do you need to store this employee object in the session for remoting requests (you use session holder elsewhere to check it)?

                  In our application we login on every request and place the "user" object into a thread local. This gives us the flexibility to use any kind of remoting protocol not just HTTP. To save out web clients having to login on every requrest we have filter that checks for a validated "user" in the session and if it's present does the login again using the details from the session.

                  Ollie

                  Comment


                  • #10
                    how you deal with things like session timeout
                    Any request after a session timeout will be rejected and the remote application will have to login again (the remote application could automate this).
                    why do you need to store this employee object in the session for remoting requests
                    It contains roles and information for security checking and auditing.
                    ...we login on every request...This gives us the flexibility to use any kind of remoting protocol not just HTTP
                    True. My approach was just useful for my scenario. Browser and remote client use exactly the same authentication and authorisation code.

                    Comment


                    • #11
                      Re: Maintaing State while using HttpInvoker

                      Originally posted by oliverhutchison

                      are you absolutely sure that you need to maintain state on the server? If you post your use case perhaps we can suggest an alternative implementation that uses the existing (stateless) remoting support.
                      Hi Ollie.
                      From my point of view, server-side state is very important when you use Hibernate on the server and you have a remote client.
                      It simplies things when you do typical load - edit - save Business Object (BO) cycle
                      E.g.
                      1) User requested a BO to be shown in "Edit Dialog" (by Id)
                      2) Hibernate loads it and closes the database transaction
                      3) You push loaded instance to the server-side storage
                      4) You serialize instance to remote client.
                      5) User edits it, and then send it back to the server.
                      6) Server looks up the pushed instance in server-side storage and applies deserialized user changes to it
                      7) Server calls some kind of [Hibernate] Session.save(BO)

                      Please note, we can't serialize the whole BO instance on step 4), e.g. because of security reasons (current user is not allowed to see all fields in instance) or maybe because the BO is quite big and expensive to serialize (not all fields must be shown in current "Edit Dialog"). Because of that we can't recreate the edited BO in step 6) from deserialized information without server-side storage or additional SQL query to fetch it again from DB. The second approach (to fetch edited object from DB) has obvious performace penalty and has a side effect - this BO may have been changed since step 1), so user's changes will be mixed with other's changes.
                      IMHO this use case forces us to use some kind of server-side state management, and HttpSession very convenient in a case of HTTP remoting :-)

                      WBR, Dmitry Kirillov

                      Comment


                      • #12
                        The second approach (to fetch edited object from DB) has obvious performace penalty
                        does it? Given that you already loaded the object in step 1 it's extremely likely that it's still in the Hibernate cache (assuming your using a cache). Also how many updates does your application actual handle? Is the small overhead of doing a DB fetch really significant? If it is, my gut feeling would be that the overhead of placing all of the loaded objects into the session would be even greater.

                        and has a side effect - this BO may have been changed since step 1), so user's changes will be mixed with other's changes.
                        If you take advantage of Hibernates optimistic concurrency support this is not an issue. How do you prevent/handle multiple concurrent updates with your statefull approach?

                        I'm know there are some valid situations where maintaining state on the server does make sense (transferring chunked data springs to mind) but most of the time you shouldn't need this feature.

                        Ollie

                        Comment


                        • #13
                          Originally posted by oliverhutchison
                          The second approach (to fetch edited object from DB) has obvious performace penalty
                          does it? Given that you already loaded the object in step 1 it's extremely likely that it's still in the Hibernate cache (assuming your using a cache).
                          Is the small overhead of doing a DB fetch really significant?
                          Do you mean transaction-level (first-level) cache or second level cache? Please note, we've closed the database transaction and discarded hibernate session after step 2) - so we don't have first-level cache. And since edited BOs are actively edited, they are not cached in second-level cache.
                          And the overhead to fetch DB for BO is significant in my system - due to some reasons discussed BOs are quite expensive to load from DB - they are spead accross some SQL tables, so there are several roundtrips to DB when we fetch each object.

                          Originally posted by oliverhutchison
                          and has a side effect - this BO may have been changed since step 1), so user's changes will be mixed with other's changes.
                          If you take advantage of Hibernates optimistic concurrency support this is not an issue.
                          The approach I use in my system is descibed in Section 8.2 of the book "Hibernate in Action". Your particular approach is closest to the section 8.2.2 in this book, named "Doing it the hard way" :-). Let me cite some paragraph from it:
                          "There is one problem with this notion: The user already used the possibly stale data to arrive at the decision to approve! Reloading the Item in the second request is useless, since the reloaded state will not be used for anything —at least, it can’t be used in deciding whether the auction should be approved, which is the important thing."

                          Yes I agree we can still use automatic Hibernate's version checking capability, but "The user already used the possibly stale data to arrive at the decision to approve".
                          And this book advises (Section 8.2.3) using detached object support of Hibernate, which is my preferred approach.

                          WBR, Dmitry.

                          Comment


                          • #14
                            And since edited BOs are actively edited, they are not cached in second-level cache.
                            Can you please explain this? Why are you BO not cached in the second level cache? Given that you've said that they are very expensive to load this sound like a bad idea.

                            The approach I use in my system is descibed in Section 8.2 of the book "Hibernate in Action". Your particular approach is closest to the section 8.2.2 in this book, named "Doing it the hard way"
                            I've don't have a copy of HiA so I can't have a look at sections 8.2 and 8.2.2 but I can certainly say that the approach I suggested is not "the hard way" and is in fact "best practice". Especially when you are working with the detached object support. The following is from the Hibernate manual:

                            We very strongly recommend that you use version/timestamp columns for optimistic locking with Hibernate. This is the optimal strategy with respect to performance and is the only strategy that correctly handles modifications made to detached instances (ie. when Session.update() is used)
                            Ollie

                            Comment


                            • #15
                              Originally posted by oliverhutchison
                              And since edited BOs are actively edited, they are not cached in second-level cache.
                              Can you please explain this? Why are you BO not cached in the second level cache? Given that you've said that they are very expensive to load this sound like a bad idea.
                              May be I shall cache those BOs, but I prefer caching only reference (read-only) data. May be it worths trying caching these BOs, since they are expensive to load, I'll think it over. Although authors of HiA claim: "Bad candidates for second-level caching are: Data that is updated often". Because ot that I don't chache them.

                              Originally posted by oliverhutchison
                              I can certainly say that the approach I suggested is not "the hard way" and is in fact "best practice". Especially when you are working with the detached object support. The following is from the Hibernate manual:
                              Yes I do agree that Hibernate's ability to automate handling versions column is very useful. But the "hard way" also has other upleasant feature - you fetch data which is possible inconsistent that user has seen.
                              And please note words in your quote "strategy that correctly handles modifications made to detached instances" - detached instance means some kind of server-side state in my scenario.

                              WBR, Dmitry

                              Comment

                              Working...
                              X