You are viewing a plain text version of this content. The canonical link for it is here.
Posted to slide-user@jakarta.apache.org by Pete Heist <pe...@compoze.com> on 2001/07/11 16:58:15 UTC
thread-safety issue with webdav client library (and tip on connecting to Exchange 2K)
Hello,
I am using Slide's WebDAV library to connect to Microsoft Exchange Server
2000. First of all, as a side note for those trying it be sure to upgrade to
service pack 1 of Exchange so that valid XML is generated in response to a
PROPFIND for all properties. Otherwise you won't be able to parse the XML
response to this query.
Nextly, there is an issue with thread-safety that appers to be in the Slide
WebDAV client library and is simple to reproduce. At the bottom of this
email is source code written to Slide 1.0.11 that causes the error. It
simply creates N number of threads to do a PROPFIND for all properties.
(This exerciser really doesn't need to connect to Exchange 2K- any WebDAV
server should be fine.) An example command line to run it with five threads
is as follows:
java ExchangeWebdavTest http://server/exchange/Mailbox/Inbox 5
Occasionally all five threads will succeed, but much of the time output will
be like:
-----
Making DAV Connection...
Making DAV Connection...
Making DAV Connection...
Making DAV Connection...
Making DAV Connection...
connect time = 3475
connect time = 4317
java.lang.NullPointerException
at
org.apache.commons.httpclient.HttpMethodBase.generateRequestLine(HttpMethodB
ase.java:519)
at
org.apache.commons.httpclient.HttpClient.sendRequestHeader(HttpClient.java:8
35)
at
org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:422)
at
org.apache.webdav.lib.WebdavResource.propfindMethod(WebdavResource.java:2388
)
at
org.apache.webdav.lib.WebdavResource.propfindMethod(WebdavResource.java:2359
)
at
ExchangeWebdavTest$ExchangeWebdavThread.run(ExchangeWebdavTest.java:110)
at java.lang.Thread.run(Unknown Source)
-----
Looking at the source code for HttpMethodBase, it seems like the "state"
member variable is ending up null. It's almost as if these objects are
getting recycled before we finish using them. I would like to find and fix
this problem myself but it's unclear what revision of commons should be
pulled down to work with Slide 1.0.11 (there are no obvious tags in the
commons tree). Does anyone know what the issue could be? Or know how I can
get a buildable snapshot of the commons tree used as of the 1.0.11 Slide
release?
tx,
Pete
-----
/**
*
* Exchange 2K WebDAV test program. First argument is the URL to connect to
* and second is the number of threads to create.
*
* @author PHeist (07/01)
*/
public class ExchangeWebdavTest
{
/**
* Method description.
*
* @author PHeist (07/01)
*/
public ExchangeWebdavTest
(
)
{
}
/**
* Main.
*
* @author PHeist (07/01)
*/
public static void main
(
String[] args
)
{
for (int i = 0; i < Integer.parseInt (args[1]); i++)
{
ExchangeWebdavTest test = new ExchangeWebdavTest();
Thread thr = new Thread (test.new ExchangeWebdavThread (new String
(args[0])));
thr.start ();
}
}
/**
*
* Exchange WebDAV thread.
*
* @author PHeist (07/01)
*/
public class ExchangeWebdavThread
implements Runnable
{
private String i_sUrl;
/**
* Constructor.
*
* @author PHeist (07/01)
*/
public ExchangeWebdavThread
(
String sUrl
)
{
i_sUrl = sUrl;
}
/**
* Method description.
*
* @author PHeist (07/101)
*/
public void run
(
)
{
WebdavResource resource = null;
try
{
System.out.println ("Making DAV Connection...");
HttpURL url = new HttpURL (i_sUrl);
url.setUserInfo ("CLUSTER\\PHeist", "pheist");
long lStart = System.currentTimeMillis ();
resource = new WebdavResource (url);
Enumeration props = resource.propfindMethod(Integer.MAX_VALUE);
int i = 0;
while (props.hasMoreElements())
{
ResponseEntity entity = (ResponseEntity) props.nextElement();
//System.out.println ((i++) + " (" + entity.getClass() + "): " +
entity);
//System.out.println (i++);
Enumeration responseProperties = entity.getProperties();
while (responseProperties.hasMoreElements())
{
Property responseProp = (Property) responseProperties.nextElement();
//System.out.println (" " + responseProp.getName() + "| " +
// responseProp.getPropertyAsString());
}
}
System.out.println ("connect time = " + (System.currentTimeMillis() -
lStart));
}
catch (Exception e)
{
e.printStackTrace ();
}
finally
{
if (null != resource)
try
{
resource.close ();
}
catch (IOException ioe)
{
}
}
}
} // ExchangeWebdavThread
} // ExchangeWebdavTest
RE: thread-safety issue with webdav client library (and tip on connecting to Exchange 2K)
Posted by Pete Heist <pe...@compoze.com>.
Remy, thanks for the response. Some more information on the issue:
Printing out the value of resource.retrieveSessionInstance() for each of the
threads shows that sometimes the HttpClient objects for more than one
WebdavResource is the same, which I'm not sure is a problem or not (I would
think it would be because HttpClient maintains state about the connection).
There is some logic in WebdavSession.getSessionInstance() that keeps clients
in a HashMap keyed off of httpURL.getAuthority(). Wouldn't that be the same
for connections to the same machine?
Also, I was able to reproduce some other exceptions more easily by slowing
the rate at which new threads are created. These exceptions plus the
exerciser program used to cause them are attached (may have to run it a few
times to reproduce them). Pardon the large message.
thanks,
Pete
output:
-----
Making DAV Connection...
HttpClient: org.apache.commons.httpclient.HttpClient@6102dc
Making DAV Connection...
Making DAV Connection...
Making DAV Connection...
connect time = 3205
java.lang.IllegalArgumentException: port out range:-1
HttpClient: org.apache.commons.httpclient.HttpClient@4741d6
at java.net.Socket.<init>(Unknown Source)
at java.net.Socket.<init>(Unknown Source)
at
org.apache.commons.httpclient.HttpClient.openConnection(HttpClient.java:764)
at
org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:412)
at
org.apache.webdav.lib.WebdavResource.propfindMethod(WebdavResource.java:2452
)
at
org.apache.webdav.lib.WebdavResource.propfindMethod(WebdavResource.java:2421
)
at
org.apache.webdav.lib.WebdavResource.setNamedProp(WebdavResource.java:650)
at
org.apache.webdav.lib.WebdavResource.setBasicProperties(WebdavResource.java:
637)
at
org.apache.webdav.lib.WebdavResource.setProperties(WebdavResource.java:1541)
at
org.apache.webdav.lib.WebdavResource.setHttpURL(WebdavResource.java:988)
at
org.apache.webdav.lib.WebdavResource.setHttpURL(WebdavResource.java:1007)
at
org.apache.webdav.lib.WebdavResource.setHttpURL(WebdavResource.java:1086)
at
org.apache.webdav.lib.WebdavResource.<init>(WebdavResource.java:256)
at
ExchangeWebdavTest$ExchangeWebdavThread.run(ExchangeWebdavTest.java:115)
at java.lang.Thread.run(Unknown Source)
java.lang.IllegalArgumentException: port out range:-1
at java.net.Socket.<init>(Unknown Source)
at java.net.Socket.<init>(Unknown Source)
at
org.apache.commons.httpclient.HttpClient.openConnection(HttpClient.java:764)
at
org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:412)
at
org.apache.webdav.lib.WebdavResource.propfindMethod(WebdavResource.java:2452
)
at
org.apache.webdav.lib.WebdavResource.propfindMethod(WebdavResource.java:2421
)
at
org.apache.webdav.lib.WebdavResource.setNamedProp(WebdavResource.java:650)
at
org.apache.webdav.lib.WebdavResource.setBasicProperties(WebdavResource.java:
637)
at
org.apache.webdav.lib.WebdavResource.setProperties(WebdavResource.java:1541)
at
org.apache.webdav.lib.WebdavResource.setHttpURL(WebdavResource.java:988)
at
org.apache.webdav.lib.WebdavResource.setHttpURL(WebdavResource.java:1007)
at
org.apache.webdav.lib.WebdavResource.setHttpURL(WebdavResource.java:1086)
at
org.apache.webdav.lib.WebdavResource.<init>(WebdavResource.java:256)
at
ExchangeWebdavTest$ExchangeWebdavThread.run(ExchangeWebdavTest.java:115)
at java.lang.Thread.run(Unknown Source)
Making DAV Connection...
connect time = 5007
java.io.IOException: Socket Closed
at java.net.PlainSocketImpl.getOutputStream(Unknown Source)
at java.net.Socket$2.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.Socket.getOutputStream(Unknown Source)
at
org.apache.commons.httpclient.HttpClient.openConnection(HttpClient.java:768)
at
org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:412)
at
org.apache.webdav.lib.WebdavResource.propfindMethod(WebdavResource.java:2452
)
at
org.apache.webdav.lib.WebdavResource.propfindMethod(WebdavResource.java:2421
)
at
org.apache.webdav.lib.WebdavResource.setNamedProp(WebdavResource.java:650)
at
org.apache.webdav.lib.WebdavResource.setBasicProperties(WebdavResource.java:
637)
at
org.apache.webdav.lib.WebdavResource.setProperties(WebdavResource.java:1541)
at
org.apache.webdav.lib.WebdavResource.setHttpURL(WebdavResource.java:988)
at
org.apache.webdav.lib.WebdavResource.setHttpURL(WebdavResource.java:1007)
at
org.apache.webdav.lib.WebdavResource.setHttpURL(WebdavResource.java:1086)
at
org.apache.webdav.lib.WebdavResource.<init>(WebdavResource.java:256)
at
ExchangeWebdavTest$ExchangeWebdavThread.run(ExchangeWebdavTest.java:115)
at java.lang.Thread.run(Unknown Source)
-----
source code to new exerciser to reproduce thread issue:
-----
import java.io.*;
import java.util.*;
import org.apache.util.*;
import org.apache.webdav.lib.*;
import org.apache.webdav.lib.methods.*;
/**
*
* Class description.
*
* @author PHeist (07/01)
*/
public class ExchangeWebdavTest
{
/**
* Method description.
*
* @author PHeist (07/01)
*/
public ExchangeWebdavTest
(
)
{
}
/**
* Main.
*
* @author PHeist (07/01)
*/
public static void main
(
String[] args
)
{
for (int i = 0; i < Integer.parseInt (args[1]); i++)
{
ExchangeWebdavTest test = new ExchangeWebdavTest();
Thread thr = new Thread (test.new ExchangeWebdavThread (new String
(args[0])));
thr.start ();
try
{
Thread.sleep (1000L);
}
catch (InterruptedException ie)
{
}
}
}
/**
*
* Exchange WebDAV thread.
*
* @author PHeist (07/01)
*/
public class ExchangeWebdavThread
implements Runnable
{
private String i_sUrl;
/**
* Constructor.
*
* @author PHeist (07/01)
*/
public ExchangeWebdavThread
(
String sUrl
)
{
i_sUrl = sUrl;
}
/**
* Method description.
*
* @author PHeist (07/01)
*/
public void run
(
)
{
WebdavResource resource = null;
try
{
System.out.println ("Making DAV Connection...");
HttpURL url = new HttpURL (i_sUrl);
url.setUserInfo ("CLUSTER\\PHeist", "pheist");
long lStart = System.currentTimeMillis ();
resource = new WebdavResource (url);
System.out.println ("HttpClient: " + resource.retrieveSessionInstance());
Enumeration props = resource.propfindMethod(Integer.MAX_VALUE);
int i = 0;
while (props.hasMoreElements())
{
ResponseEntity entity = (ResponseEntity) props.nextElement();
Enumeration responseProperties = entity.getProperties();
while (responseProperties.hasMoreElements())
{
Property responseProp = (Property) responseProperties.nextElement();
}
}
System.out.println ("connect time = " + (System.currentTimeMillis() -
lStart));
}
catch (Exception e)
{
e.printStackTrace ();
}
finally
{
if (null != resource)
try
{
resource.close ();
}
catch (IOException ioe)
{
}
}
}
} // ExchangeWebdavThread
} // ExchangeWebdavTest
-----
-----Original Message-----
From: Remy Maucherat [mailto:remm@apache.org]
Sent: Wednesday, July 11, 2001 2:15 PM
To: slide-user@jakarta.apache.org
Subject: Re: thread-safety issue with webdav client library (and tip on
connecting to Exchange 2K)
----- Original Message -----
From: "Pete Heist" <pe...@compoze.com>
To: <sl...@jakarta.apache.org>
Sent: Wednesday, July 11, 2001 7:58 AM
Subject: thread-safety issue with webdav client library (and tip on
connecting to Exchange 2K)
...
> Nextly, there is an issue with thread-safety that appers to be in the
Slide
> WebDAV client library and is simple to reproduce. At the bottom of this
> email is source code written to Slide 1.0.11 that causes the error. It
> simply creates N number of threads to do a PROPFIND for all properties.
> (This exerciser really doesn't need to connect to Exchange 2K- any WebDAV
> server should be fine.) An example command line to run it with five
threads
> is as follows:
>
> java ExchangeWebdavTest http://server/exchange/Mailbox/Inbox 5
>
> Occasionally all five threads will succeed, but much of the time output
will
> be like:
Thanks for the report.
I look at your code, and it's fine, as you have one Webdav client associated
with each thread.
I think the problem is that the WebdavResource uses some static fields,
which need to be removed. Thanks for the code, that will help me fix the
issue.
...
Remy
Re: thread-safety issue with webdav client library (and tip on connecting to Exchange 2K)
Posted by Remy Maucherat <re...@apache.org>.
----- Original Message -----
From: "Pete Heist" <pe...@compoze.com>
To: <sl...@jakarta.apache.org>
Sent: Wednesday, July 11, 2001 7:58 AM
Subject: thread-safety issue with webdav client library (and tip on
connecting to Exchange 2K)
> Hello,
>
> I am using Slide's WebDAV library to connect to Microsoft Exchange Server
> 2000. First of all, as a side note for those trying it be sure to upgrade
to
> service pack 1 of Exchange so that valid XML is generated in response to a
> PROPFIND for all properties. Otherwise you won't be able to parse the XML
> response to this query.
>
> Nextly, there is an issue with thread-safety that appers to be in the
Slide
> WebDAV client library and is simple to reproduce. At the bottom of this
> email is source code written to Slide 1.0.11 that causes the error. It
> simply creates N number of threads to do a PROPFIND for all properties.
> (This exerciser really doesn't need to connect to Exchange 2K- any WebDAV
> server should be fine.) An example command line to run it with five
threads
> is as follows:
>
> java ExchangeWebdavTest http://server/exchange/Mailbox/Inbox 5
>
> Occasionally all five threads will succeed, but much of the time output
will
> be like:
Thanks for the report.
I look at your code, and it's fine, as you have one Webdav client associated
with each thread.
I think the problem is that the WebdavResource uses some static fields,
which need to be removed. Thanks for the code, that will help me fix the
issue.
There's something strange in your traces : the traces in the httpclient
refer to an older version. I must have made a packaging mistake ... (That
means I'll release a fixed 1.0.12 really soon)
Remy