Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 412627

Summary: DirectoryInsideJarURLArchive.getEntryAsURL returns incorrect URL for a valid war file persistence root
Product: z_Archived Reporter: Albert Lee <allee8285>
Component: EclipselinkAssignee: Nobody - feel free to take it <nobody>
Status: CLOSED FIXED QA Contact:
Severity: major    
Priority: P2 CC: allee8285, eclipselink.orm-inbox, tom.ware
Version: unspecified   
Target Milestone: ---   
Hardware: PC   
OS: Windows 7   
Whiteboard: submitted_patch
Attachments:
Description Flags
proposed fix - 2.5.1 none

Description Albert Lee CLA 2013-07-09 17:24:10 EDT
DirectoryInsideJarURLArchive.getEntryAsURL returns incorrect URL for a valid root of a persistence root.

If ArchiveBase.rootURL is set to a valid root of a persistence unit in the form of:

jar:file:/....../appl.war!/WEB-INF/classes/

getEntryAsURL(entryPath) returns

jar:jar:file:/c:/....../appl.war!/WEB-INF/classes/!/WEB-INF/classes/${entryPath}

It works after I change it to :

    public URL getEntryAsURL(String entryPath) throws IOException {
    	String urlString = rootURL.toString();
    	urlString = urlString.startsWith("jar:") ? urlString : "jar:"+rootURL+"!/"+ relativeRootPath;  
        URL result = entries.contains(entryPath) ?
            new URL(    // "jar:"+rootURL+"!/"+ relativeRootPath
            		urlString
            		+ entryPath) : null; // NOI18N
        return result;
    }
Comment 1 Albert Lee CLA 2013-07-31 12:43:03 EDT
Any chance someone takes a look at the problem? Thanks.
Comment 2 Tom Ware CLA 2013-08-15 08:19:26 EDT
Setting target and priority.  See the following page for the meanings of these fields:

http://wiki.eclipse.org/EclipseLink/Development/Bugs/Guidelines

Community: Please vote for this bug if it is important to you.  Votes are one of the main criteria we use to determine which bugs to fix next.
Comment 3 Tom Ware CLA 2013-08-16 15:17:10 EDT
how does ArchiveBase.rootURL get set to: jar:file:/....../appl.war!/WEB-INF/classes/

We are likely expecting that to be something like jar:file:/../../../appl.war!/WEB-INF/classes/

What environment are you deploying in?  What container?  What OS?
Comment 4 Tom Ware CLA 2013-08-16 15:38:00 EDT
I am not correct about what we are expecting, but the questions above are still important.
Comment 5 Albert Lee CLA 2013-08-19 09:39:15 EDT
I am using EclipseLink 2.4.1 runs in the IBM WebSphere Liberty profile container in Windows 7.

The test case is an web app with JPA artifacts in the war file's WEB-INF/classes/META-INF folder, which is one of the five supported location of the root of the persistence xml (8.2).

Once I make the suggested changes, my test runs without further problem.
Comment 6 Tom Ware CLA 2013-08-19 11:50:20 EDT
Is it possible to provide the stack where you see the problem?  (i.e. I want to know if this is in our initial jar exploration, if we are looking at a particular jar entry, or if we are looking up a file in the jar that is specified by <jar-file> or <mapping-file>
Comment 7 Albert Lee CLA 2013-08-19 14:49:31 EDT
I set a break point at DirectoryInsideJarURLArchive.getEntryAsURL and here is the call stack at the point of call:

DirectoryInsideJarURLArchive.getEntryAsURL(String) line: 103	
MetadataProcessor.loadStandardMappingFiles(String) line: 419	
MetadataProcessor.loadMappingFiles(boolean) line: 344	
PersistenceUnitProcessor.processORMetadata(MetadataProcessor, boolean, PersistenceUnitProcessor$Mode) line: 540	
EntityManagerSetupImpl.predeploy(PersistenceUnitInfo, Map) line: 1469	
PersistenceProvider.createContainerEntityManagerFactory(PersistenceUnitInfo, Map) line: 235	
JPAPUnitInfo.createEMFactory(PersistenceUnitInfo) line: 1363	
JPAPUnitInfo.createEntityManagerFactory() line: 1201	
JPAPxmlInfo.extractPersistenceUnits(JPAPXml, ApplicationInfo) line: 236	
JPAScopeInfo.processPersistenceUnit(JPAPXml, ApplicationInfo) line: 111	
JPAApplInfo.addPersistenceUnits(JPAPXml) line: 132	
JPAComponentImpl.processWebModulePersistenceXml(JPAApplInfo, WebModuleInfo) line: 770	
JPAComponentImpl.moduleStarting(ModuleInfo) line: 624	


If I let it free run, the server failed to start the application with the following stack:

Internal Exception: java.lang.RuntimeException: java.net.MalformedURLException: no !/ in spec
	at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.createPredeployFailedPersistenceException(EntityManagerSetupImpl.java:1541)
	at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.predeploy(EntityManagerSetupImpl.java:1532)
	at org.eclipse.persistence.jpa.PersistenceProvider.createContainerEntityManagerFactory(PersistenceProvider.java:235)
	at com.ibm.ws.jpa.management.JPAPUnitInfo.createEMFactory(JPAPUnitInfo.java:1363)
	at com.ibm.ws.jpa.management.JPAPUnitInfo.createEntityManagerFactory(JPAPUnitInfo.java:1201)
	at com.ibm.ws.jpa.management.JPAPxmlInfo.extractPersistenceUnits(JPAPxmlInfo.java:236)
	at com.ibm.ws.jpa.management.JPAScopeInfo.processPersistenceUnit(JPAScopeInfo.java:111)
	at com.ibm.ws.jpa.management.JPAApplInfo.addPersistenceUnits(JPAApplInfo.java:132)
	at com.ibm.ws.jpa.management.JPAComponentImpl.processWebModulePersistenceXml(JPAComponentImpl.java:770)
	at com.ibm.ws.jpa.management.JPAComponentImpl.moduleStarting(JPAComponentImpl.java:624)

Caused by: Exception [EclipseLink-28018] (Eclipse Persistence Services - 2.4.1.v20121003-ad44345): org.eclipse.persistence.exceptions.EntityManagerSetupException
Exception Description: Predeployment of PersistenceUnit [jpasamplepersistenceunit] failed.
Internal Exception: java.lang.RuntimeException: java.net.MalformedURLException: no !/ in spec
	at org.eclipse.persistence.exceptions.EntityManagerSetupException.predeployFailed(EntityManagerSetupException.java:221)
	... 73 more
Caused by: java.lang.RuntimeException: java.net.MalformedURLException: no !/ in spec
	at org.eclipse.persistence.internal.jpa.metadata.MetadataProcessor.loadStandardMappingFiles(MetadataProcessor.java:431)
	at org.eclipse.persistence.internal.jpa.metadata.MetadataProcessor.loadMappingFiles(MetadataProcessor.java:344)
	at org.eclipse.persistence.internal.jpa.deployment.PersistenceUnitProcessor.processORMetadata(PersistenceUnitProcessor.java:540)
	at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.predeploy(EntityManagerSetupImpl.java:1469)
	... 71 more
Caused by: java.net.MalformedURLException: no !/ in spec
	at java.net.URL.<init>(URL.java:613)
	at java.net.URL.<init>(URL.java:476)
	at java.net.URL.<init>(URL.java:425)
	at java.net.JarURLConnection.parseSpecs(JarURLConnection.java:172)
	at java.net.JarURLConnection.<init>(JarURLConnection.java:155)
	at sun.net.www.protocol.jar.JarURLConnection.<init>(JarURLConnection.java:78)
	at sun.net.www.protocol.jar.Handler.openConnection(Handler.java:36)
	at java.net.URL.openConnection(URL.java:957)
	at org.eclipse.persistence.internal.jpa.metadata.xml.XMLEntityMappingsReader.getInputStreamReader(XMLEntityMappingsReader.java:154)
	at org.eclipse.persistence.internal.jpa.metadata.xml.XMLEntityMappingsReader.read(XMLEntityMappingsReader.java:180)
	at org.eclipse.persistence.internal.jpa.metadata.MetadataProcessor.loadStandardMappingFiles(MetadataProcessor.java:425)
	... 74 more

Replace the additional suggested changes and the app server starts up with no problem.
Comment 8 Tom Ware CLA 2013-08-20 09:12:40 EDT
Can increase the loggging level to FINER or FINEST and post the log of deployment. (persistence unit property - eclipselink.logging.level=FINEST)

I am looking a sequence of logs that contains this string just before the failure:

"Searching for default mapping file in"
Comment 9 Tom Ware CLA 2013-08-20 09:37:26 EDT
BTW: You will likely be able to workaround this issue by not using a default orm.xml.  i.e. you likely have a file called META-INF/orm.xml that is picked up by default.  If you rename it to anything except orm.xml and list it as a <mapping-file> in your persistence.xml that will likely help you workaround the issue.
Comment 10 Albert Lee CLA 2013-08-20 09:58:34 EDT
 [EL Finest]: 2013-08-19 13:40:24.155--ServerSession(832778659)--Thread(Thread[Scheduled Executor-thread-1,5,Scheduled Executor Thread Group])--property=eclipselink.logging.thread; value=false
 [EL Finest]: 2013-08-19 13:40:24.179--ServerSession(832778659)--property=eclipselink.logging.parameters; value=true
 [EL Finest]: 2013-08-19 13:40:24.183--ServerSession(832778659)--Begin predeploying Persistence Unit jpasamplepersistenceunit; session jar:file:/c:/Users/leealber/concord.eclipselink/build.image/wlp/usr/servers/com.ibm.ws.jpa.eclipselink.feature.fat.server/dropins/JPASample.war!/WEB-INF/classes/_jpasamplepersistenceunit; state Initial; factoryCount 0
 [EL Finest]: 2013-08-19 13:40:24.187--ServerSession(832778659)--property=eclipselink.orm.throw.exceptions; default value=true
 [EL Finest]: 2013-08-19 13:40:24.189--ServerSession(832778659)--property=eclipselink.weaving.changetracking; default value=true
 [EL Finest]: 2013-08-19 13:40:24.19--ServerSession(832778659)--property=eclipselink.weaving.lazy; default value=true
 [EL Finest]: 2013-08-19 13:40:24.191--ServerSession(832778659)--property=eclipselink.weaving.eager; default value=false
 [EL Finest]: 2013-08-19 13:40:24.192--ServerSession(832778659)--property=eclipselink.weaving.fetchgroups; default value=true
 [EL Finest]: 2013-08-19 13:40:24.193--ServerSession(832778659)--property=eclipselink.weaving.internal; default value=true
 [EL Finest]: 2013-08-19 13:40:24.195--ServerSession(832778659)--property=eclipselink.multitenant.tenants-share-emf; default value=true
 [EL Finest]: 2013-08-19 13:40:24.197--ServerSession(832778659)--property=eclipselink.multitenant.tenants-share-cache; default value=false
 [EL Finer]: 2013-08-19 13:40:24.229--ServerSession(832778659)--Searching for default mapping file in jar:file:/c:/Users/leealber/concord.eclipselink/build.image/wlp/usr/servers/com.ibm.ws.jpa.eclipselink.feature.fat.server/dropins/JPASample.war!/WEB-INF/classes/ (There is no English translation for this message.)
Comment 11 Tom Ware CLA 2013-08-20 10:21:56 EDT
I think your suggested change can be simplified to something like this:

    public URL getEntryAsURL(String entryPath) throws IOException {
        rootURL = rootURL.toString().startsWith("jar:") ? rootURL : new URL("jar:"+rootURL);
        URL result = entries.contains(entryPath) ?
            new URL(rootURL + entryPath) : null; // NOI18N
        return result;
    }

Basically, the main bug here is that relativeRootPath will always already be part of the rootURL.  We get it by creating a connection on that URL and asking for the entryName.  There is no way that it won't already be on the rootURL.
Comment 12 Tom Ware CLA 2013-08-20 10:23:29 EDT
I do not have a recreation.  Does the code above work for you?
Comment 13 Albert Lee CLA 2013-08-20 11:57:54 EDT
Applied your recommended fix to my workspace and the tests passed successfully.
Comment 14 Tom Ware CLA 2013-08-20 15:16:14 EDT
Created attachment 234589 [details]
proposed fix - 2.5.1

The attached proposed fix does 2 things:

1. Avoid prepending "jar:" to a rootUrl that already starts with that

2. No longer adds relativeRootPath to the URL.  If you look at the constructor for DirectoryInsideJarURLArchive, you can see that relativeRootPath is derived from the rootURL, but rootURL is never altered to remove it.  Since we use rootURL directly, adding the relativeRootPath result in duplication as noted in the URL in the first comment in this bug.
Comment 15 Tom Ware CLA 2013-08-21 08:30:09 EDT
Fix described above checked into 2.5.1 and main

Reviewed by Chris Delahunt

Tested by filer -> I do not have a license for the offending application server

Ran JPA LRG tests
Comment 16 Eclipse Webmaster CLA 2022-06-09 10:16:17 EDT
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink
Comment 17 Eclipse Webmaster CLA 2022-06-09 10:29:05 EDT
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink