Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 344111 - IllegalStateException in org.eclipse.osgi.framework.internal.protocol.MultiplexingURLStreamHandler.toExternalForm
Summary: IllegalStateException in org.eclipse.osgi.framework.internal.protocol.Multipl...
Status: RESOLVED FIXED
Alias: None
Product: Equinox
Classification: Eclipse Project
Component: Framework (show other bugs)
Version: unspecified   Edit
Hardware: PC Linux
: P3 minor (vote)
Target Milestone: Kepler M2   Edit
Assignee: Thomas Watson CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks: 388944 388945
  Show dependency tree
 
Reported: 2011-04-28 07:46 EDT by Craig Chaney CLA
Modified: 2012-09-06 09:43 EDT (History)
3 users (show)

See Also:


Attachments
WAS SystemOut.log (246.13 KB, text/plain)
2011-04-28 07:46 EDT, Craig Chaney CLA
no flags Details
patch + tests (16.49 KB, patch)
2011-05-17 16:43 EDT, Thomas Watson CLA
no flags Details | Diff
IllegalStateException (2.39 KB, text/plain)
2011-11-18 10:45 EST, Catalin Tileaga CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Craig Chaney CLA 2011-04-28 07:46:07 EDT
Build Identifier: 3.5.2.R35x_v20100126

Rational Team Concert embeds equinox.  Our application failed to start when running under WebSphere Application Server 7.0.0.13, and the SystemOut.log (attached) contain several stack traces with the title:
[4/27/11 12:28:47:959 EDT] 0000001e webapp        E com.ibm.ws.webcontainer.webapp.WebApp logServletError SRVE0293E: [Servlet Error]-[equinoxbridgeservlet]: java.lang.IllegalStateException

This looks similar to 198578 (which was fixed long ago).  However, this has only been reported once, and there's an easy workaround - restart WAS.

Reproducible: Couldn't Reproduce
Comment 1 Craig Chaney CLA 2011-04-28 07:46:55 EDT
Created attachment 194251 [details]
WAS SystemOut.log
Comment 2 Thomas Watson CLA 2011-04-28 08:52:17 EDT
This could possible be caused by bug200593.  In order for that to occur I would expect the framework would have to have been stopped though.  Another possibility is bug208281 depending on how you construct the URLs that are failing.
Comment 3 Thomas Watson CLA 2011-05-17 16:43:20 EDT
Created attachment 195910 [details]
patch + tests

The only way I can see this happening is if the URL is being constructed with one of the multi-param constructors which does not take a URL context:

URL(String, String, int, String)
URL(String, String, int, String, URLStreamHandler)
URL(String, String, String)

The other constructors all cause the handler.parseURL method to be called which forces the real handler to get set or a MalformedURLException to be thrown if we cannot find the real handler for the protocol: 

URL(String)
URL(URL, String)
URL(URL, String, URLStreamHandler)

What I think must be happening is that some code must be using one of the first constructors.  It does not matter where this code lives, it could be in WAS or in RTC (with embedded equinox).  That URL is then being passed into the RTC context and being used.  Once this happens we could get one of these exceptions to occur.

This patch adds a safeguard to MultiplexingURLStreamHandler to keep a reference of the authorized handler that was found when we constructed the MultiplexingURLStreamHandler.  This handler will get used if we cannot find a handler in the context of the call (i.e. call to URL.toExternalForm()).  I think this is the best we can do.  It still leaves a strange hole where a URL can be constructed in a context where it likely should not.

For example, technically code within RTC (running in an embedded equinox) should not be able to construct URLs with protocols from registered handlers in WAS.  But with this change code will be able to use one of the following constructors and work just fine:

URL(String, String, int, String)
URL(String, String, int, String, URLStreamHandler)
URL(String, String, String)
Comment 4 Thomas Watson CLA 2011-05-17 16:45:46 EDT
The other thing to mention is that the version of equinox used by WAS must have this patch applied in order to see it work.  Patching the equinox version embedded in RTC does no good.  The Equinox version which is launched first must contain this fix since it is the one constructing the MultiplexingURLStreamHandler objects.
Comment 5 Randy Hudson CLA 2011-05-19 09:57:03 EDT
(In reply to comment #3)
> The only way I can see this happening is if the URL is being constructed with
> one of the multi-param constructors which does not take a URL context:

The code causing the problem is:
String url = new URL(
    request.getScheme(),
    request.getLocalAddr(),
    request.getLocalPort(),
    request.getContextPath() + Constants.PATH_ROOT_SERVICES).toString();

> What I think must be happening is that some code must be using one of the first
> constructors.  It does not matter where this code lives, it could be in WAS or
> in RTC (with embedded equinox).  That URL is then being passed into the RTC
> context and being used.  Once this happens we could get one of these exceptions
> to occur.

As you can see, the URL is constructed and immedately we call toString() on it.  There is no passing the URL around, and it doesn't involve multiple threads.

> For example, technically code within RTC (running in an embedded equinox)
> should not be able to construct URLs with protocols from registered handlers in
> WAS.

The protocol here is https.
Comment 6 Randy Hudson CLA 2011-05-19 09:59:01 EDT
BTW, this problem is reproducible, but it doesn't always happen.  Supposedly, one workaround is to delete the app's temp folder, but that doesn't really make any sense unless it just changes the timing.
Comment 7 Thomas Watson CLA 2011-05-19 11:10:44 EDT
(In reply to comment #6)
> BTW, this problem is reproducible, but it doesn't always happen.  Supposedly,
> one workaround is to delete the app's temp folder, but that doesn't really make
> any sense unless it just changes the timing.

I can see how the code in comment 5 would always fail, but I cannot see how it would ever succeed.  It has nothing to do with timing or threading etc.  The stream factory will detect that the context is RTC and attempt to find a handler service registered in RTC and fail to find it.  The only way I can imagine it ever succeeding is if RTC has a bundle that also registers an https protocol handler service.

(In reply to comment #5)
> 
> The code causing the problem is:
> String url = new URL(
>     request.getScheme(),
>     request.getLocalAddr(),
>     request.getLocalPort(),
>     request.getContextPath() + Constants.PATH_ROOT_SERVICES).toString();
> 

I think there is a better, more reliable way to create a url String.  1) concatenate the parts yourself or 2) use the URI class instead.  There is no need to go through the URL class and all of its gorp to simply get a url String.  Now, I have no idea what you are doing with this url string.  If you are simply going to call new URL(url) with it then that will also fail because we will again not find a protocol handler service in the context of RTC to handle it.

If the framework is expected to solve issues like this then we have an option.  But it is not ideal or pretty.  Basically we need to treat the "primordial" framework StreamHandlerFactory as a "parent" factory.  The idea is that this primordial framework (in this case the framework used by WAS) would be used as a last resort for finding protocol handler services if we could not find one in the context where the URL is being constructed/used.

There are two options to implementing this solution:

1) Have the primordial framework StreamHandlerFactory handle this.

This would involve a change to the primordial framework (used in WAS) to have the MultiplexingURLStreamHandler always fall back to asking the primordial framework for a handler if one could not be found in the authorized context (RTC).

2) Have the "child" framework StreamHandlerFactory handle this.

This would involve a change to the child or embedded framework (used in RTC) to have the StreamHandlerFactory detect the existing multiplexing capable factory with which it is registered with and to always fall back to delegating to that factory for a handler if one could not be found in the authorized context (RTC).


Option 2) would be nice because it would only require a change to RTC and allow it to be run on existing WAS servers.  But it has a disadvantage when/if the primordial framework is shutdown.  When that happens the primordial StreamHandlerFactory will have to designate a successor and will no longer be valid.  But we will have every other StreamHandlerFactory objects thinking that it is still the primordial factory.  Another variation of 2) is fall back to the factory registered with the VM each time if we cannot find the factory in the authorized context.  This would involve using reflection like we do in the Framework class when we jettison the existing factory and replace it with a multiplexing capable one.

Option 1) is a bit more simple but has drawbacks that it requires the primordial framework to be fixed.
Comment 8 Catalin Tileaga CLA 2011-11-18 10:45:15 EST
Created attachment 207225 [details]
IllegalStateException
Comment 9 Catalin Tileaga CLA 2011-11-18 10:48:25 EST
In our application we have a problem that looks similar with this one (see the attached Exception). We added a ThreadPoolExecutor and we receive always this exception. We are running WebSphere Application Server 7.0.0.19 (but we are also testes under 8.0.0.1).

Is there a JAR available for your patch? And how I can patch it?
Comment 10 Thomas Watson CLA 2012-09-06 09:41:32 EDT
I released the fix to Kepler in commit:

http://git.eclipse.org/c/equinox/rt.equinox.framework.git/commit/?id=1d5e88b1dcfca7ff764ce0e9741b1e432b320617