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;
+ }
}