Schema validation fails when Glassfish expands JAR in a directory with spaces in the name

Description

(Imported from Google Code)
Reported by Andrew:

I'm trying to use DDMSence as part of a Web Service (in order to parse
a DDMS document then extract some fields). I'm seeing some strange
behaviour in NetBeans 6.9 and GlassFish 3.0.1 and I was wondering if
anyone had some ideas as to where I'm going wrong.

The steps to reproduce are basically:

1. In NetBeans, create a new Web Application project. Targeting
GlassFish and Java EE 6 Web.

2. Within your new project, create a new Web Service. Define a simple
web service (doesn't matter what its inputs or outputs are).

3. Import the DDMSence libraries:

  • ddmsence-1.4.0.jar

  • serializer-2.7.1.jar

  • xalan-2.7.1.jar

  • xercesImpl-2.9.1.jar

  • xml-apis-1.3.04.jar

  • xom-1.2.4.jar

4. My web service code looks like this:

import buri.ddmsence.ddms.Resource;
import buri.ddmsence.util.DDMSReader;
import java.io.File;
import javax.jws.WebMethod;
import javax.jws.WebService;

@WebService()
public class DDMSservice{
@WebMethod(operationName = "getTitle&quot
public String getTitle()
{
String title = null;
try
{
DDMSReader reader = new DDMSReader();
Resource ddms = reader.getDDMSResource(new File("C:\\testbed\
\ddmsence-bin-1.4.0\\data\\sample
DDMS-
v2_0_EarlierVersion_Example.xml&quot);
title = ddms.getTitles().get(0).toText();
} catch(Exception e)
{
e.printStackTrace();
}
return title;
}
}

5. Deploy the application and call the web service (I'm doing this by
right-clicking on the web service and selecting "Test Web Service"
from the popup). The following exception is raised:

-------------------------------------------------------------------------------------

SEVERE: buri.ddmsence.ddms.InvalidDDMSException:
nu.xom.ValidityException: cvc-elt.1: Cannot find the declaration of
element 'ddms:Resource'. at line 2, column 235 in
file:///C:/testbed/ddmsence-bin-1.4.0/data/sample/DDMS-v2_0_EarlierVersion_Example.xml
at buri.ddmsence.util.DDMSReader.getElement(Unknown Source)
at buri.ddmsence.util.DDMSReader.getDDMSResource(Unknown
Source)
at ddms.test.DDMSservice.getTitle(DDMSservice.java:18)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:
39)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:
25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.glassfish.webservices.InstanceResolverImpl
$1.invoke(InstanceResolverImpl.java:137)
at com.sun.xml.ws.server.InvokerTube$2.invoke(InvokerTube.java:
146)
at
com.sun.xml.ws.server.sei.EndpointMethodHandler.invoke(EndpointMethodHandler.java:
257)
at
com.sun.xml.ws.server.sei.SEIInvokerTube.processRequest(SEIInvokerTube.java:
95)
at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:629)
at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:588)
at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:573)
at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:470)
at
com.sun.xml.ws.api.pipe.helper.AbstractTubeImpl.process(AbstractTubeImpl.java:
112)
at
org.glassfish.webservices.MonitoringPipe.process(MonitoringPipe.java:
138)
at
com.sun.xml.ws.api.pipe.helper.PipeAdapter.processRequest(PipeAdapter.java:
115)
at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:629)
at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:588)
at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:573)
at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:470)
at
com.sun.xml.ws.api.pipe.helper.AbstractTubeImpl.process(AbstractTubeImpl.java:
112)
at
com.sun.enterprise.security.webservices.CommonServerSecurityPipe.processRequest(CommonServerSecurityPipe.java:
195)
at
com.sun.enterprise.security.webservices.CommonServerSecurityPipe.process(CommonServerSecurityPipe.java:
127)
at
com.sun.xml.ws.api.pipe.helper.PipeAdapter.processRequest(PipeAdapter.java:
115)
at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:629)
at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:588)
at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:573)
at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:470)
at com.sun.xml.ws.server.WSEndpointImpl
$2.process(WSEndpointImpl.java:295)
at com.sun.xml.ws.transport.http.HttpAdapter
$HttpToolkit.handle(HttpAdapter.java:519)
at
com.sun.xml.ws.transport.http.HttpAdapter.handle(HttpAdapter.java:288)
at
com.sun.xml.ws.transport.http.servlet.ServletAdapter.handle(ServletAdapter.java:
143)
at
org.glassfish.webservices.JAXWSServlet.doPost(JAXWSServlet.java:149)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:
754)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:
847)
at
org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:
1523)
at
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:
279)
at
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:
188)
at
org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:
641)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:
97)
at
com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:
85)
at
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:
185)
at
org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:
325)
at
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:
226)
at
com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:
165)
at
com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:
791)
at
com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:693)
at
com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:954)
at
com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:
170)
at
com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:
135)
at
com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:
102)
at
com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:
88)
at
com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:
76)
at
com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:
53)
at
com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:
57)
at com.sun.grizzly.ContextTask.run(ContextTask.java:69)
at com.sun.grizzly.util.AbstractThreadPool
$Worker.doWork(AbstractThreadPool.java:330)
at com.sun.grizzly.util.AbstractThreadPool
$Worker.run(AbstractThreadPool.java:309)
at java.lang.Thread.run(Thread.java:619)
Caused by: nu.xom.ValidityException: cvc-elt.1: Cannot find the
declaration of element 'ddms:Resource'. at line 2, column 235 in
file:///C:/testbed/ddmsence-bin-1.4.0/data/sample/DDMS-v2_0_EarlierVersion_Example.xml
at nu.xom.Builder$ValidityRequired.error(Unknown Source)
at org.apache.xerces.util.ErrorHandlerWrapper.error(Unknown
Source)
at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown
Source)
at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown
Source)
at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown
Source)
at
org.apache.xerces.impl.xs.XMLSchemaValidator.handleStartElement(Unknown
Source)
at
org.apache.xerces.impl.xs.XMLSchemaValidator.startElement(Unknown
Source)
at
org.apache.xerces.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown
Source)
at org.apache.xerces.impl.XMLNSDocumentScannerImpl
$NSContentDispatcher.scanRootElementHook(Unknown Source)
at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl
$FragmentContentDispatcher.dispatch(Unknown Source)
at
org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown
Source)
at org.apache.xerces.parsers.XML11Configuration.parse(Unknown
Source)
at org.apache.xerces.parsers.XML11Configuration.parse(Unknown
Source)
at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown
Source)
at nu.xom.Builder.build(Unknown Source)
at nu.xom.Builder.build(Unknown Source)
at nu.xom.Builder.build(Unknown Source)
... 61 more
Caused by: org.xml.sax.SAXParseException: cvc-elt.1: Cannot find the
declaration of element 'ddms:Resource'.
at
org.apache.xerces.util.ErrorHandlerWrapper.createSAXParseException(Unknown
Source)
... 78 more

-------------------------------------------------------------------------------------

Now, obviously because I'm loading a sample file that comes with
DDMSence it should parse correctly. Due to the fact that the same
code works fine in a non-web application I'm thinking that the
libraries that NetBeans/GlassFish is importing is in some way
conflicting with the parsing of the Resource? Other than that, I'm
totally stumped.

The other libraries that are loaded as part of GlassFish are:

javax.security.jacc.jar
jaxb-api-osgi.jar
bean-validator.jar
javax.jms.jar
jsr311-api.jar
javax.security.auth.message.jar
javax.servlet.jsp.jar
javax.enterprise.deploy.jar
javax.annotation.jar
javax.resource.jar
mail.jar
javax.transaction.jar
jsf-impl.jar
weld-osgi-bundle.jar
jstl-impl.jar
javax.management.j2ee.jar
javax.servlet.jar
jsf-api.jar
webservices-api-osgi.jar
javax.persistence.jar
javax.servlet.jsp.jstl.jar

Environment

None

Activity

Show:
Brian Uri
July 7, 2010, 11:49 AM

Fixed in Rev 245. Basic space replacement with %20.

Brian Uri
July 7, 2010, 11:24 AM

Bug does not occur in these cases:

1) Deploying the DDMSence JAR in a directory structure with spaces in it.

http://metadata.dod.mil/mdr/ns/DDMS/2.0/ jar:file:/D:/dd%20ms/lib/ddmsence-1.5.0.jar!/schemas/2.0/DDMS/2.0/DDMS-v2_0.xsd

2) Unzipping the DDMSence JAR in a directory structure with spaces in it.

http://metadata.dod.mil/mdr/ns/DDMS/2.0/ file:/D:/dd%20ms/spacedfile%20name/schemas/2.0/DDMS/2.0/DDMS-v2_0.xsd

There must be something unique about the way Glassfish unzips the JAR file.

Brian Uri
July 6, 2010, 12:50 PM

Sun's "Will Not Fix" bug related to spaces and file-based URLs:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4466485

A clean, generic conversion of the path from URL to URI may not be possible. The URL returned from ClassLoader.getResource() does no encoding and includes spaces.
1) url.toExternalForm() does no encoding (this is what DDMSence does today)
2) url.getFile() uses %20 for spaces, but drops the file: prefix.
3) url.toURI() fails because a Windows file URL is not a valid URI.
4) URLEncoder(url, "UTF-8") also encodes the forward slashes.

If no elegant strategy can be found, a simple token replacement will cover the most common cases:

url.toExternalForm().replaceAll(" ", "%20");

Brian Uri
July 6, 2010, 11:20 AM

The expected output of the debugging command should have been similar to:

http://metadata.dod.mil/mdr/ns/DDMS/2.0/ jar:file:/C:/testbed/ddmsence-
bin-1.4.0/lib/ddmsence-1.4.0.jar!/schemas/2.0/DDMS/2.0/DDMS-v2_0.xsd [...]

The actual output in the failing instance was:

http://metadata.dod.mil/mdr/ns/DDMS/2.0/ file:/C:/Program Files/
glassfishv3/glassfish/domains/domain1/generated/jsp/DDMStest/
loader_31468488/schemas/2.0/DDMS/2.0/DDMS-v2_0.xsd [...]

When the DDMSReader is initialized, the ClassLoader may return a URL for local schemas with a space embedded. The format of the SAXReader property requires a URI, not a URL, so certain characters, including spaces, must be escaped (i.e. %20). In
the case described with this ticket, the SAXReader expected to find a schema at "file:/C:/Program", and thought that "Files/glassfish..." was the XML namespace for the next schema in the space-delimited list.

This bug was exposed because Glassfish does some sort of expansion/unpacking on the DDMSence JAR file, but it's possible that it could happen any time that the JAR is deployed in a directory structure with spaces in it.

Fixed

Assignee

Brian Uri

Reporter

Brian Uri

Labels

None

Fix versions

Priority

Medium