You are viewing a plain text version of this content. The canonical link for it is here.
Posted to java-dev@axis.apache.org by gd...@apache.org on 2002/10/16 19:11:04 UTC

cvs commit: xml-axis/java/src/org/apache/axis/transport/http AxisHttpSession.java

gdaniels    2002/10/16 10:11:04

  Modified:    java/src/org/apache/axis/providers/java JavaProvider.java
               java/src/org/apache/axis/session Session.java
                        SimpleSession.java
               java/src/org/apache/axis/transport/http AxisHttpSession.java
  Log:
  Improve synchronization/locking when getting and making new
  session-based service objects.  This should deal with Doug's problem
  of constructors calling back into the engine.
  
  Revision  Changes    Path
  1.88      +78 -22    xml-axis/java/src/org/apache/axis/providers/java/JavaProvider.java
  
  Index: JavaProvider.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/providers/java/JavaProvider.java,v
  retrieving revision 1.87
  retrieving revision 1.88
  diff -u -r1.87 -r1.88
  --- JavaProvider.java	10 Oct 2002 17:22:54 -0000	1.87
  +++ JavaProvider.java	16 Oct 2002 17:11:04 -0000	1.88
  @@ -65,8 +65,6 @@
   import org.apache.axis.description.ServiceDesc;
   import org.apache.axis.encoding.TypeMapping;
   import org.apache.axis.enum.Scope;
  -import org.apache.axis.enum.Style;
  -import org.apache.axis.enum.Use;
   import org.apache.axis.handlers.soap.SOAPService;
   import org.apache.axis.message.SOAPEnvelope;
   import org.apache.axis.providers.BasicProvider;
  @@ -149,16 +147,8 @@
               // look in incoming session
               Session session = msgContext.getSession();
               if (session != null) {
  -                // This part isn't thread safe...
  -                synchronized (session) {
  -                    // store service objects in session, indexed by class name
  -                    Object obj = session.get(serviceName);
  -                    if (obj == null) {
  -                        obj = getNewServiceObject(msgContext, clsName);
  -                        session.set(serviceName, obj);
  -                    }
  -                    return obj;
  -                }
  +                return getSessionServiceObject(session, serviceName,
  +                                               msgContext, clsName);
               } else {
                   // was no incoming session, sigh, treat as request scope
                   scopeHolder.value = Scope.DEFAULT.getValue();
  @@ -169,16 +159,8 @@
               AxisEngine engine = msgContext.getAxisEngine();
               Session appSession = engine.getApplicationSession();
               if (appSession != null) {
  -                // This part isn't thread safe
  -                synchronized (appSession) {
  -                    // store service objects in session, indexed by class name
  -                    Object obj = appSession.get(serviceName);
  -                    if (obj == null) {
  -                        obj = getNewServiceObject(msgContext, clsName);
  -                        appSession.set(serviceName, obj);
  -                    }
  -                    return obj;
  -                }
  +                return getSessionServiceObject(appSession, serviceName, 
  +                                               msgContext, clsName);
               } else {
                   // was no application session, sigh, treat as request scope
                   // FIXME : Should we bomb in this case?
  @@ -189,6 +171,80 @@
               // NOTREACHED
               return null;
           }
  +    }
  +    
  +    /**
  +     * Simple utility class for dealing with synchronization issues.
  +     */ 
  +    class LockObject {
  +        private boolean completed = false;
  +        
  +        synchronized void waitUntilComplete() throws InterruptedException {
  +            while (!completed) {
  +                wait();
  +            }
  +        }
  +        
  +        synchronized void complete() {
  +            completed = true;
  +            notifyAll();
  +        }
  +    }
  +
  +    /**
  +     * Get a service object from a session.  Handles threading / locking
  +     * issues when multiple threads might be accessing the same session
  +     * object, and ensures only one thread gets to create the service
  +     * object if there isn't one already.
  +     */ 
  +    private Object getSessionServiceObject(Session session,
  +                                           String serviceName,
  +                                           MessageContext msgContext,
  +                                           String clsName) throws Exception {
  +        Object obj = null;
  +        boolean makeNewObject = false;
  +                
  +        // This is a little tricky.  
  +        synchronized (session.getLockObject()) {
  +            // store service objects in session, indexed by class name
  +            obj = session.get(serviceName);
  +            
  +            // If nothing there, put in a placeholder object so
  +            // other threads wait for us to create the real
  +            // service object.
  +            if (obj == null) {
  +                obj = new LockObject();
  +                makeNewObject = true;
  +                session.set(serviceName, obj);
  +            }            
  +        }
  +        
  +        // OK, we DEFINITELY have something in obj at this point.  Either
  +        // it's the service object or it's a LockObject (ours or someone
  +        // else's).
  +        
  +        if (LockObject.class == obj.getClass()) {
  +            LockObject lock = (LockObject)obj;
  +            
  +            // If we were the lucky thread who got to install the
  +            // placeholder, create a new service object and install it
  +            // instead, then notify anyone waiting on the LockObject.
  +            if (makeNewObject) {
  +                obj = getNewServiceObject(msgContext, clsName);
  +                session.set(serviceName, obj);
  +                lock.complete();
  +            } else {
  +                // It's someone else's LockObject, so wait around until
  +                // it's completed.
  +                lock.waitUntilComplete();
  +                
  +                // Now we are guaranteed there is a service object in the
  +                // session, so this next part doesn't need syncing
  +                obj = session.get(serviceName);
  +            }
  +        }
  +        
  +        return obj;
       }
   
       /**
  
  
  
  1.7       +10 -0     xml-axis/java/src/org/apache/axis/session/Session.java
  
  Index: Session.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/session/Session.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- Session.java	6 May 2002 19:41:46 -0000	1.6
  +++ Session.java	16 Oct 2002 17:11:04 -0000	1.7
  @@ -109,4 +109,14 @@
        * "Touch" the session (mark it recently used)
        */ 
       public void touch();
  +    
  +    /**
  +     * Get an Object suitable for synchronizing the session.  This method
  +     * exists because different session implementations might provide
  +     * different ways of getting at shared data.  For a simple hashtable-
  +     * based session, this would just be the hashtable, but for sessions
  +     * which use database connections, etc. it might be an object wrapping
  +     * a table ID or somesuch.
  +     */ 
  +    public Object getLockObject();
   }
  
  
  
  1.7       +15 -0     xml-axis/java/src/org/apache/axis/session/SimpleSession.java
  
  Index: SimpleSession.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/session/SimpleSession.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- SimpleSession.java	6 May 2002 19:41:46 -0000	1.6
  +++ SimpleSession.java	16 Oct 2002 17:11:04 -0000	1.7
  @@ -153,4 +153,19 @@
       {
           return lastTouched;
       }
  +
  +    /**
  +     * Get an Object suitable for synchronizing the session.  This method
  +     * exists because different session implementations might provide
  +     * different ways of getting at shared data.  For a simple hashtable-
  +     * based session, this would just be the hashtable, but for sessions
  +     * which use database connections, etc. it might be an object wrapping
  +     * a table ID or somesuch.
  +     */
  +    public Object getLockObject() {
  +        if (rep == null) {
  +            rep = new Hashtable();
  +        }
  +        return rep;
  +    }
   }
  
  
  
  1.11      +13 -0     xml-axis/java/src/org/apache/axis/transport/http/AxisHttpSession.java
  
  Index: AxisHttpSession.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/transport/http/AxisHttpSession.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- AxisHttpSession.java	13 Aug 2002 00:38:46 -0000	1.10
  +++ AxisHttpSession.java	16 Oct 2002 17:11:04 -0000	1.11
  @@ -171,4 +171,17 @@
                 rep = req.getSession();
           }
       }
  +
  +    /**
  +     * Get an Object suitable for synchronizing the session.  This method
  +     * exists because different session implementations might provide
  +     * different ways of getting at shared data.  For a simple hashtable-
  +     * based session, this would just be the hashtable, but for sessions
  +     * which use database connections, etc. it might be an object wrapping
  +     * a table ID or somesuch.
  +     */
  +    public Object getLockObject() {
  +        ensureSession();
  +        return rep;
  +    }
   }