Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

HHH-8088 - Redesign Scanner contract

  • Loading branch information...
commit eeca84460ef36f93339f98fed3ab4b7047625da2 1 parent a1afa0c
Steve Ebersole sebersole authored
Showing with 2,884 additions and 1,782 deletions.
  1. +4 −2 hibernate-entitymanager/src/main/java/org/hibernate/ejb/packaging/NamedInputStream.java
  2. +2 −2 hibernate-entitymanager/src/main/java/org/hibernate/ejb/packaging/Scanner.java
  3. +35 −68 ...g/hibernate/jpa/{packaging/internal/JarVisitorFactory.java → boot/archive/internal/ArchiveHelper.java}
  4. +212 −0 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/internal/ExplodedArchiveDescriptor.java
  5. +193 −0 ...nate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/internal/JarFileBasedArchiveDescriptor.java
  6. +168 −0 ...titymanager/src/main/java/org/hibernate/jpa/boot/archive/internal/JarInputStreamBasedArchiveDescriptor.java
  7. +71 −0 ...rnate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/internal/JarProtocolArchiveDescriptor.java
  8. +105 −0 ...e-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/internal/StandardArchiveDescriptorFactory.java
  9. +92 −0 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/spi/AbstractArchiveDescriptor.java
  10. +37 −0 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/spi/ArchiveContext.java
  11. +9 −15 ...main/java/org/hibernate/jpa/{packaging/internal/Filter.java → boot/archive/spi/ArchiveDescriptor.java}
  12. +14 −18 ...rg/hibernate/jpa/{packaging/internal/FileFilter.java → boot/archive/spi/ArchiveDescriptorFactory.java}
  13. +24 −15 .../main/java/org/hibernate/jpa/{packaging/internal/JarVisitor.java → boot/archive/spi/ArchiveEntry.java}
  14. +33 −0 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/spi/ArchiveEntryHandler.java
  15. +15 −14 .../java/org/hibernate/jpa/{packaging/internal/ClassFilter.java → boot/archive/spi/ArchiveException.java}
  16. +60 −0 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/ByteArrayInputStreamAccess.java
  17. +29 −23 ...c/main/java/org/hibernate/jpa/{packaging/internal/Entry.java → boot/internal/ClassDescriptorImpl.java}
  18. +206 −234 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java
  19. +77 −0 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/FileInputStreamAccess.java
  20. +73 −0 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/MappingFileDescriptorImpl.java
  21. +68 −0 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/PackageDescriptorImpl.java
  22. +3 −3 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/PersistenceXmlParser.java
  23. +62 −0 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/UrlInputStreamAccess.java
  24. +67 −0 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/internal/StandardScanOptions.java
  25. +40 −0 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/internal/StandardScanner.java
  26. +302 −0 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/spi/AbstractScannerImpl.java
  27. +132 −0 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/spi/ClassFileArchiveEntryHandler.java
  28. +82 −0 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/spi/NonClassFileArchiveEntryHandler.java
  29. +71 −0 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/spi/PackageInfoArchiveEntryHandler.java
  30. +12 −16 ...c/main/java/org/hibernate/jpa/{packaging/internal/PackageFilter.java → boot/scan/spi/ScanOptions.java}
  31. +41 −0 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/spi/ScanResult.java
  32. +46 −0 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/scan/spi/Scanner.java
  33. +34 −0 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/ClassDescriptor.java
  34. +52 −0 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/InputStreamAccess.java
  35. +32 −0 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/MappingFileDescriptor.java
  36. +11 −12 hibernate-entitymanager/src/main/java/org/hibernate/jpa/{packaging → boot}/spi/NamedInputStream.java
  37. +34 −0 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/spi/PackageDescriptor.java
  38. +0 −262 hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/AbstractJarVisitor.java
  39. +0 −138 hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/ExplodedJarVisitor.java
  40. +0 −133 hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/FileZippedJarVisitor.java
  41. +0 −121 hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/InputStreamZippedJarVisitor.java
  42. +0 −73 hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/JarProtocolVisitor.java
  43. +0 −52 hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/JavaElementFilter.java
  44. +0 −248 hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/internal/NativeScanner.java
  45. +0 −67 hibernate-entitymanager/src/main/java/org/hibernate/jpa/packaging/spi/Scanner.java
  46. +67 −0 hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/TestHelper.java
  47. +9 −30 hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/packaging/CustomScanner.java
  48. +208 −199 hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/packaging/JarVisitorTest.java
  49. +9 −2 hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/packaging/PackagingTestCase.java
  50. +43 −35 hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/packaging/ScannerTest.java
6 hibernate-entitymanager/src/main/java/org/hibernate/ejb/packaging/NamedInputStream.java
View
@@ -26,10 +26,12 @@
import java.io.InputStream;
/**
- * @deprecated Use {@link org.hibernate.jpa.packaging.spi.NamedInputStream} instead
+ * @deprecated Doubly deprecated actually :) Moved to {@link org.hibernate.jpa.boot.spi.NamedInputStream}
+ * due to package renaming (org.hibernate.ejb -> org.hibernate.jpa). But also, the role fulfilled by this class
+ * was moved to the new {@link org.hibernate.jpa.boot.spi.InputStreamAccess} contract.
*/
@Deprecated
-public class NamedInputStream extends org.hibernate.jpa.packaging.spi.NamedInputStream {
+public class NamedInputStream extends org.hibernate.jpa.boot.spi.NamedInputStream {
public NamedInputStream(String name, InputStream stream) {
super( name, stream );
}
4 hibernate-entitymanager/src/main/java/org/hibernate/ejb/packaging/Scanner.java
View
@@ -24,8 +24,8 @@
package org.hibernate.ejb.packaging;
/**
- * @deprecated Use {@link org.hibernate.jpa.packaging.spi.Scanner} instead
+ * @deprecated Use {@link org.hibernate.jpa.boot.scan.spi.Scanner} instead
*/
@Deprecated
-public interface Scanner extends org.hibernate.jpa.packaging.spi.Scanner {
+public interface Scanner extends org.hibernate.jpa.boot.scan.spi.Scanner {
}
103 ...ate/jpa/packaging/internal/JarVisitorFactory.java → ...nate/jpa/boot/archive/internal/ArchiveHelper.java
View
@@ -1,8 +1,10 @@
/*
- * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
- * distributed under license by Red Hat Middleware LLC.
+ * distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@@ -19,29 +21,26 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
-package org.hibernate.jpa.packaging.internal;
+package org.hibernate.jpa.boot.archive.internal;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
-import java.net.URISyntaxException;
import java.net.URL;
import java.util.LinkedList;
import java.util.List;
-import org.hibernate.internal.util.StringHelper;
-import org.hibernate.jpa.internal.EntityManagerMessageLogger;
import org.jboss.logging.Logger;
+import org.hibernate.jpa.boot.archive.spi.ArchiveException;
+
/**
* @author Emmanuel Bernard
- * @author Brett Meyer
+ * @author Steve Ebersole
*/
-public class JarVisitorFactory {
-
- private static final EntityManagerMessageLogger LOG = Logger.getMessageLogger(EntityManagerMessageLogger.class,
- JarVisitorFactory.class.getName());
+public class ArchiveHelper {
+ private static final Logger log = Logger.getLogger( ArchiveHelper.class );
/**
* Get the JAR URL of the JAR containing the given entry
@@ -51,7 +50,6 @@
* @param entry file known to be in the JAR
* @return the JAR URL
* @throws IllegalArgumentException if none URL is found
- * TODO move to a ScannerHelper service?
*/
public static URL getJarURLFromURLEntry(URL url, String entry) throws IllegalArgumentException {
URL jarUrl;
@@ -106,7 +104,7 @@ else if ( "zip".equals( protocol ) //Weblogic has it's own way
"Unable to determine JAR Url from " + url + ". Cause: " + e.getMessage()
);
}
- LOG.trace("JAR URL from URL Entry: " + url + " >> " + jarUrl);
+ log.trace("JAR URL from URL Entry: " + url + " >> " + jarUrl);
return jarUrl;
}
@@ -114,7 +112,6 @@ else if ( "zip".equals( protocol ) //Weblogic has it's own way
* get the URL from a given path string
*
* @throws IllegalArgumentException is something goes wrong
- * TODO move to a ScannerHelper service?
*/
public static URL getURLFromPath(String jarPath) {
URL jarUrl;
@@ -134,70 +131,40 @@ public static URL getURLFromPath(String jarPath) {
return jarUrl;
}
- /**
- * Get a JarVisitor to the jar <code>jarPath</code> applying the given filters
- *
- * Method used in a non-managed environment
- *
- * @throws IllegalArgumentException if the jarPath is incorrect
- */
- public static JarVisitor getVisitor(String jarPath, Filter[] filters) throws IllegalArgumentException {
- File file = new File( jarPath );
- if ( file.isFile() ) {
- return new InputStreamZippedJarVisitor( jarPath, filters );
+ public static String unqualifiedJarFileName(URL jarUrl) {
+ // todo : weak algorithm subject to AOOBE
+ String fileName = jarUrl.getFile();
+ int exclamation = fileName.lastIndexOf( "!" );
+ if (exclamation != -1) {
+ fileName = fileName.substring( 0, exclamation );
}
- else {
- return new ExplodedJarVisitor( jarPath, filters );
- }
- }
- /**
- * Build a JarVisitor on the given JAR URL applying the given filters
- *
- * @throws IllegalArgumentException if the URL is malformed
- */
- public static JarVisitor getVisitor(URL jarUrl, Filter[] filters) throws IllegalArgumentException {
- return getVisitor( jarUrl, filters, "" );
- }
+ int slash = fileName.lastIndexOf( "/" );
+ if ( slash != -1 ) {
+ fileName = fileName.substring(
+ fileName.lastIndexOf( "/" ) + 1,
+ fileName.length()
+ );
+ }
- public static JarVisitor getVisitor(URL jarUrl, Filter[] filters, String entry) throws IllegalArgumentException {
- String protocol = jarUrl.getProtocol();
- if ( "jar".equals( protocol ) ) {
- return new JarProtocolVisitor( jarUrl, filters, entry );
+ if ( fileName.length() > 4 && fileName.endsWith( "ar" ) && fileName.charAt( fileName.length() - 4 ) == '.' ) {
+ fileName = fileName.substring( 0, fileName.length() - 4 );
}
- else if ( StringHelper.isEmpty( protocol ) || "file".equals( protocol ) || "vfszip".equals( protocol ) || "vfsfile".equals( protocol ) ) {
- File file;
- try {
- final String filePart = jarUrl.getFile();
- if ( filePart != null && filePart.indexOf( ' ' ) != -1 ) {
- //unescaped (from the container), keep as is
- file = new File( jarUrl.getFile() );
- }
- else {
- file = new File( jarUrl.toURI().getSchemeSpecificPart() );
- }
- }
- catch (URISyntaxException e) {
- throw new IllegalArgumentException(
- "Unable to visit JAR " + jarUrl + ". Cause: " + e.getMessage(), e
- );
- }
- if ( file.isDirectory() ) {
- return new ExplodedJarVisitor( jarUrl, filters, entry );
- }
- else {
- return new FileZippedJarVisitor( jarUrl, filters, entry );
- }
+ return fileName;
+ }
+
+ public static byte[] getBytesFromInputStreamSafely(InputStream inputStream) {
+ try {
+ return getBytesFromInputStream( inputStream );
}
- else {
- //let's assume the url can return the jar as a zip stream
- return new InputStreamZippedJarVisitor( jarUrl, filters, entry );
+ catch (IOException e) {
+ throw new ArchiveException( "Unable to extract bytes from InputStream", e );
}
}
- // Optimized by HHH-7835
public static byte[] getBytesFromInputStream(InputStream inputStream) throws IOException {
+ // Optimized by HHH-7835
int size;
List<byte[]> data = new LinkedList<byte[]>();
int bufferSize = 4096;
212 ...rnate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/internal/ExplodedArchiveDescriptor.java
View
@@ -0,0 +1,212 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.jpa.boot.archive.internal;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.jar.JarFile;
+import java.util.zip.ZipEntry;
+
+import org.jboss.logging.Logger;
+
+import org.hibernate.jpa.boot.archive.spi.AbstractArchiveDescriptor;
+import org.hibernate.jpa.boot.archive.spi.ArchiveContext;
+import org.hibernate.jpa.boot.archive.spi.ArchiveDescriptorFactory;
+import org.hibernate.jpa.boot.archive.spi.ArchiveEntry;
+import org.hibernate.jpa.boot.archive.spi.ArchiveException;
+import org.hibernate.jpa.boot.internal.FileInputStreamAccess;
+import org.hibernate.jpa.boot.spi.InputStreamAccess;
+import org.hibernate.jpa.internal.EntityManagerMessageLogger;
+
+/**
+ * @author Steve Ebersole
+ */
+public class ExplodedArchiveDescriptor extends AbstractArchiveDescriptor {
+ private static final EntityManagerMessageLogger LOG = Logger.getMessageLogger(
+ EntityManagerMessageLogger.class,
+ ExplodedArchiveDescriptor.class.getName()
+ );
+
+ public ExplodedArchiveDescriptor(
+ ArchiveDescriptorFactory archiveDescriptorFactory,
+ URL archiveUrl,
+ String entryBasePrefix) {
+ super( archiveDescriptorFactory, archiveUrl, entryBasePrefix );
+ }
+
+ @Override
+ public void visitArchive(ArchiveContext context) {
+ final File rootDirectory = resolveRootDirectory();
+ if ( rootDirectory == null ) {
+ return;
+ }
+
+ if ( rootDirectory.isDirectory() ) {
+ processDirectory( rootDirectory, null, context );
+ }
+ else {
+ //assume zipped file
+ processZippedRoot( rootDirectory, context );
+ }
+ }
+
+ private File resolveRootDirectory() {
+ final File archiveUrlDirectory;
+ try {
+ final String filePart = getArchiveUrl().getFile();
+ if ( filePart != null && filePart.indexOf( ' ' ) != -1 ) {
+ //unescaped (from the container), keep as is
+ archiveUrlDirectory = new File( filePart );
+ }
+ else {
+ archiveUrlDirectory = new File( getArchiveUrl().toURI().getSchemeSpecificPart() );
+ }
+ }
+ catch (URISyntaxException e) {
+ LOG.malformedUrl( getArchiveUrl(), e );
+ return null;
+ }
+
+ if ( !archiveUrlDirectory.exists() ) {
+ LOG.explodedJarDoesNotExist( getArchiveUrl() );
+ return null;
+ }
+ if ( !archiveUrlDirectory.isDirectory() ) {
+ LOG.explodedJarNotDirectory( getArchiveUrl() );
+ return null;
+ }
+
+ final String entryBase = getEntryBasePrefix();
+ if ( entryBase != null && entryBase.length() > 0 && ! "/".equals( entryBase ) ) {
+ return new File( archiveUrlDirectory, entryBase );
+ }
+ else {
+ return archiveUrlDirectory;
+ }
+ }
+
+ private void processDirectory(
+ File directory,
+ String path,
+ ArchiveContext context) {
+ if ( directory == null ) {
+ return;
+ }
+
+ final File[] files = directory.listFiles();
+ if ( files == null ) {
+ return;
+ }
+
+ path = path == null ? "" : path + "/";
+ for ( final File localFile : files ) {
+ if ( !localFile.exists() ) {
+ // should never happen conceptually, but...
+ continue;
+ }
+
+ if ( localFile.isDirectory() ) {
+ processDirectory( localFile, path + localFile.getName(), context );
+ continue;
+ }
+
+ final String name = localFile.getAbsolutePath();
+ final String relativeName = path + localFile.getName();
+ final InputStreamAccess inputStreamAccess = new FileInputStreamAccess( name, localFile );
+
+ final ArchiveEntry entry = new ArchiveEntry() {
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getNameWithinArchive() {
+ return relativeName;
+ }
+
+ @Override
+ public InputStreamAccess getStreamAccess() {
+ return inputStreamAccess;
+ }
+ };
+
+ context.obtainArchiveEntryHandler( entry ).handleEntry( entry, context );
+ }
+ }
+
+ private void processZippedRoot(File rootFile, ArchiveContext context) {
+ try {
+ final JarFile jarFile = new JarFile(rootFile);
+ final Enumeration<? extends ZipEntry> entries = jarFile.entries();
+ while ( entries.hasMoreElements() ) {
+ final ZipEntry zipEntry = entries.nextElement();
+ if ( zipEntry.isDirectory() ) {
+ continue;
+ }
+
+ final String name = extractName( zipEntry );
+ final String relativeName = extractRelativeName( zipEntry );
+ final InputStreamAccess inputStreamAccess;
+ try {
+ inputStreamAccess = buildByteBasedInputStreamAccess( name, jarFile.getInputStream( zipEntry ) );
+ }
+ catch (IOException e) {
+ throw new ArchiveException(
+ String.format(
+ "Unable to access stream from jar file [%s] for entry [%s]",
+ jarFile.getName(),
+ zipEntry.getName()
+ )
+ );
+ }
+
+ final ArchiveEntry entry = new ArchiveEntry() {
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getNameWithinArchive() {
+ return relativeName;
+ }
+
+ @Override
+ public InputStreamAccess getStreamAccess() {
+ return inputStreamAccess;
+ }
+ };
+ context.obtainArchiveEntryHandler( entry ).handleEntry( entry, context );
+ }
+ }
+ catch (IOException e) {
+ throw new ArchiveException( "Error accessing jar file [" + rootFile.getAbsolutePath() + "]", e );
+ }
+ }
+
+}
193 ...e-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/internal/JarFileBasedArchiveDescriptor.java
View
@@ -0,0 +1,193 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.jpa.boot.archive.internal;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.jar.JarFile;
+import java.util.jar.JarInputStream;
+import java.util.zip.ZipEntry;
+
+import org.jboss.logging.Logger;
+
+import org.hibernate.jpa.boot.archive.spi.AbstractArchiveDescriptor;
+import org.hibernate.jpa.boot.archive.spi.ArchiveContext;
+import org.hibernate.jpa.boot.archive.spi.ArchiveDescriptorFactory;
+import org.hibernate.jpa.boot.archive.spi.ArchiveEntry;
+import org.hibernate.jpa.boot.archive.spi.ArchiveEntryHandler;
+import org.hibernate.jpa.boot.archive.spi.ArchiveException;
+import org.hibernate.jpa.internal.EntityManagerMessageLogger;
+import org.hibernate.jpa.boot.spi.InputStreamAccess;
+
+/**
+ * An ArchiveDescriptor implementation leveraging the {@link JarFile} API for processing.
+ *
+ * @author Steve Ebersole
+ */
+public class JarFileBasedArchiveDescriptor extends AbstractArchiveDescriptor {
+ private static final EntityManagerMessageLogger LOG = Logger.getMessageLogger(
+ EntityManagerMessageLogger.class,
+ JarFileBasedArchiveDescriptor.class.getName()
+ );
+
+ public JarFileBasedArchiveDescriptor(
+ ArchiveDescriptorFactory archiveDescriptorFactory,
+ URL archiveUrl,
+ String entry) {
+ super( archiveDescriptorFactory, archiveUrl, entry );
+ }
+
+ @Override
+ public void visitArchive(ArchiveContext context) {
+ final JarFile jarFile = resolveJarFileReference();
+ if ( jarFile == null ) {
+ return;
+ }
+
+ final Enumeration<? extends ZipEntry> zipEntries = jarFile.entries();
+ while ( zipEntries.hasMoreElements() ) {
+ final ZipEntry zipEntry = zipEntries.nextElement();
+ final String entryName = extractName( zipEntry );
+
+ if ( getEntryBasePrefix() != null && ! entryName.startsWith( getEntryBasePrefix() ) ) {
+ continue;
+ }
+ if ( zipEntry.isDirectory() ) {
+ continue;
+ }
+
+ if ( entryName.equals( getEntryBasePrefix() ) ) {
+ // exact match, might be a nested jar entry (ie from jar:file:..../foo.ear!/bar.jar)
+ //
+ // This algorithm assumes that the zipped file is only the URL root (including entry), not
+ // just any random entry
+ try {
+ InputStream is = new BufferedInputStream( jarFile.getInputStream( zipEntry ) );
+ try {
+ final JarInputStream jarInputStream = new JarInputStream( is );
+ ZipEntry subZipEntry = jarInputStream.getNextEntry();
+ while ( subZipEntry != null ) {
+ if ( ! subZipEntry.isDirectory() ) {
+
+ final String name = extractName( subZipEntry );
+ final String relativeName = extractRelativeName( subZipEntry );
+ final InputStreamAccess inputStreamAccess
+ = buildByteBasedInputStreamAccess( name, jarInputStream );
+
+ final ArchiveEntry entry = new ArchiveEntry() {
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getNameWithinArchive() {
+ return relativeName;
+ }
+
+ @Override
+ public InputStreamAccess getStreamAccess() {
+ return inputStreamAccess;
+ }
+ };
+
+ final ArchiveEntryHandler entryHandler = context.obtainArchiveEntryHandler( entry );
+ entryHandler.handleEntry( entry, context );
+ }
+
+ subZipEntry = jarInputStream.getNextEntry();
+ }
+ }
+ finally {
+ is.close();
+ }
+ }
+ catch (Exception e) {
+ throw new ArchiveException( "Error accessing JarFile entry [" + zipEntry.getName() + "]", e );
+ }
+ }
+ else {
+ final String name = extractName( zipEntry );
+ final String relativeName = extractRelativeName( zipEntry );
+ final InputStreamAccess inputStreamAccess;
+ try {
+ inputStreamAccess = buildByteBasedInputStreamAccess( name, jarFile.getInputStream( zipEntry ) );
+ }
+ catch (IOException e) {
+ throw new ArchiveException(
+ String.format(
+ "Unable to access stream from jar file [%s] for entry [%s]",
+ jarFile.getName(),
+ zipEntry.getName()
+ )
+ );
+ }
+
+ final ArchiveEntry entry = new ArchiveEntry() {
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getNameWithinArchive() {
+ return relativeName;
+ }
+
+ @Override
+ public InputStreamAccess getStreamAccess() {
+ return inputStreamAccess;
+ }
+ };
+
+ final ArchiveEntryHandler entryHandler = context.obtainArchiveEntryHandler( entry );
+ entryHandler.handleEntry( entry, context );
+ }
+ }
+ }
+
+ private JarFile resolveJarFileReference() {
+ try {
+ String filePart = getArchiveUrl().getFile();
+ if ( filePart != null && filePart.indexOf( ' ' ) != -1 ) {
+ // unescaped (from the container), keep as is
+ return new JarFile( getArchiveUrl().getFile() );
+ }
+ else {
+ return new JarFile( getArchiveUrl().toURI().getSchemeSpecificPart() );
+ }
+ }
+ catch (IOException e) {
+ LOG.unableToFindFile( getArchiveUrl(), e );
+ }
+ catch (URISyntaxException e) {
+ LOG.malformedUrlWarning( getArchiveUrl(), e );
+ }
+ return null;
+ }
+}
168 ...ymanager/src/main/java/org/hibernate/jpa/boot/archive/internal/JarInputStreamBasedArchiveDescriptor.java
View
@@ -0,0 +1,168 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.jpa.boot.archive.internal;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+import java.util.zip.ZipEntry;
+
+import org.jboss.logging.Logger;
+
+import org.hibernate.jpa.boot.archive.spi.AbstractArchiveDescriptor;
+import org.hibernate.jpa.boot.archive.spi.ArchiveContext;
+import org.hibernate.jpa.boot.archive.spi.ArchiveDescriptorFactory;
+import org.hibernate.jpa.boot.archive.spi.ArchiveEntry;
+import org.hibernate.jpa.boot.archive.spi.ArchiveException;
+import org.hibernate.jpa.boot.spi.InputStreamAccess;
+import org.hibernate.jpa.internal.EntityManagerMessageLogger;
+
+/**
+ * An ArchiveDescriptor implementation that works on archives accessible through a {@link java.util.jar.JarInputStream}.
+ * NOTE : This is less efficient implementation than {@link JarFileBasedArchiveDescriptor}
+ *
+ * @author Emmanuel Bernard
+ * @author Steve Ebersole
+ */
+public class JarInputStreamBasedArchiveDescriptor extends AbstractArchiveDescriptor {
+ private static final EntityManagerMessageLogger LOG = Logger.getMessageLogger(
+ EntityManagerMessageLogger.class,
+ JarInputStreamBasedArchiveDescriptor.class.getName()
+ );
+
+ public JarInputStreamBasedArchiveDescriptor(
+ ArchiveDescriptorFactory archiveDescriptorFactory,
+ URL url,
+ String entry) {
+ super( archiveDescriptorFactory, url, entry );
+ }
+
+ @Override
+ public void visitArchive(ArchiveContext context) {
+ final JarInputStream jarInputStream;
+ try {
+ jarInputStream = new JarInputStream( getArchiveUrl().openStream() );
+ }
+ catch (Exception e) {
+ //really should catch IOException but Eclipse is buggy and raise NPE...
+ LOG.unableToFindFile( getArchiveUrl(), e );
+ return;
+ }
+
+ try {
+ JarEntry jarEntry;
+ while ( ( jarEntry = jarInputStream.getNextJarEntry() ) != null ) {
+ String jarEntryName = jarEntry.getName();
+ if ( getEntryBasePrefix() != null && ! jarEntryName.startsWith( getEntryBasePrefix() ) ) {
+ continue;
+ }
+
+ if ( jarEntry.isDirectory() ) {
+ continue;
+ }
+
+ if ( jarEntryName.equals( getEntryBasePrefix() ) ) {
+ // exact match, might be a nested jar entry (ie from jar:file:..../foo.ear!/bar.jar)
+ //
+ // This algorithm assumes that the zipped file is only the URL root (including entry), not
+ // just any random entry
+ try {
+ final JarInputStream subJarInputStream = new JarInputStream( jarInputStream );
+ try {
+ ZipEntry subZipEntry = jarInputStream.getNextEntry();
+ while (subZipEntry != null) {
+ if ( ! subZipEntry.isDirectory() ) {
+ final String subName = extractName( subZipEntry );
+ final InputStreamAccess inputStreamAccess
+ = buildByteBasedInputStreamAccess( subName, subJarInputStream );
+
+ final ArchiveEntry entry = new ArchiveEntry() {
+ @Override
+ public String getName() {
+ return subName;
+ }
+
+ @Override
+ public String getNameWithinArchive() {
+ return subName;
+ }
+
+ @Override
+ public InputStreamAccess getStreamAccess() {
+ return inputStreamAccess;
+ }
+ };
+
+ context.obtainArchiveEntryHandler( entry ).handleEntry( entry, context );
+ }
+ subZipEntry = jarInputStream.getNextJarEntry();
+ }
+ }
+ finally {
+ subJarInputStream.close();
+ }
+ }
+ catch (Exception e) {
+ throw new ArchiveException( "Error accessing nested jar", e );
+ }
+ }
+ else {
+ final String entryName = extractName( jarEntry );
+ final InputStreamAccess inputStreamAccess
+ = buildByteBasedInputStreamAccess( entryName, jarInputStream );
+
+ final String relativeName = extractRelativeName( jarEntry );
+
+ final ArchiveEntry entry = new ArchiveEntry() {
+ @Override
+ public String getName() {
+ return entryName;
+ }
+
+ @Override
+ public String getNameWithinArchive() {
+ return relativeName;
+ }
+
+ @Override
+ public InputStreamAccess getStreamAccess() {
+ return inputStreamAccess;
+ }
+ };
+
+ context.obtainArchiveEntryHandler( entry ).handleEntry( entry, context );
+ }
+ }
+
+ jarInputStream.close();
+ }
+ catch (IOException ioe) {
+ throw new ArchiveException(
+ String.format( "Error accessing JarInputStream [%s]", getArchiveUrl() ),
+ ioe
+ );
+ }
+ }
+}
71 ...te-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/internal/JarProtocolArchiveDescriptor.java
View
@@ -0,0 +1,71 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.jpa.boot.archive.internal;
+
+import java.net.URL;
+
+import org.hibernate.annotations.common.AssertionFailure;
+import org.hibernate.jpa.boot.archive.spi.ArchiveContext;
+import org.hibernate.jpa.boot.archive.spi.ArchiveDescriptor;
+import org.hibernate.jpa.boot.archive.spi.ArchiveDescriptorFactory;
+
+/**
+ * An ArchiveDescriptor implementation for handling archives whose url reported a JAR protocol (i.e., jar://).
+ *
+ * @author Steve Ebersole
+ */
+public class JarProtocolArchiveDescriptor implements ArchiveDescriptor {
+ private final ArchiveDescriptor delegateDescriptor;
+
+ public JarProtocolArchiveDescriptor(
+ ArchiveDescriptorFactory archiveDescriptorFactory,
+ URL url,
+ String incomingEntry) {
+ if ( incomingEntry != null && incomingEntry.length() > 0 ) {
+ throw new IllegalArgumentException( "jar:jar: not supported: " + url );
+ }
+
+ final String urlFile = url.getFile();
+ final int subEntryIndex = urlFile.lastIndexOf( "!" );
+ if ( subEntryIndex == -1 ) {
+ throw new AssertionFailure( "JAR URL does not contain '!/' :" + url );
+ }
+
+ final String subEntry;
+ if ( subEntryIndex + 1 >= urlFile.length() ) {
+ subEntry = "";
+ }
+ else {
+ subEntry = urlFile.substring( subEntryIndex + 1 );
+ }
+
+ URL fileUrl = archiveDescriptorFactory.getJarURLFromURLEntry( url, subEntry );
+ delegateDescriptor = archiveDescriptorFactory.buildArchiveDescriptor( fileUrl, subEntry );
+ }
+
+ @Override
+ public void visitArchive(ArchiveContext context) {
+ delegateDescriptor.visitArchive( context );
+ }
+}
105 ...ntitymanager/src/main/java/org/hibernate/jpa/boot/archive/internal/StandardArchiveDescriptorFactory.java
View
@@ -0,0 +1,105 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.jpa.boot.archive.internal;
+
+import java.io.File;
+import java.net.URISyntaxException;
+import java.net.URL;
+
+import org.hibernate.internal.util.StringHelper;
+import org.hibernate.jpa.boot.archive.spi.ArchiveDescriptor;
+import org.hibernate.jpa.boot.archive.spi.ArchiveDescriptorFactory;
+
+/**
+ * @author Emmanuel Bernard
+ * @author Steve Ebersole
+ */
+public class StandardArchiveDescriptorFactory implements ArchiveDescriptorFactory {
+ public static final StandardArchiveDescriptorFactory INSTANCE = new StandardArchiveDescriptorFactory();
+
+ @Override
+ public ArchiveDescriptor buildArchiveDescriptor(URL url) {
+ return buildArchiveDescriptor( url, "" );
+ }
+
+ @Override
+ public ArchiveDescriptor buildArchiveDescriptor(URL url, String entry) {
+ final String protocol = url.getProtocol();
+ if ( "jar".equals( protocol ) ) {
+ return new JarProtocolArchiveDescriptor( this, url, entry );
+ }
+ else if ( StringHelper.isEmpty( protocol )
+ || "file".equals( protocol )
+ || "vfszip".equals( protocol )
+ || "vfsfile".equals( protocol ) ) {
+ final File file;
+ try {
+ final String filePart = url.getFile();
+ if ( filePart != null && filePart.indexOf( ' ' ) != -1 ) {
+ //unescaped (from the container), keep as is
+ file = new File( url.getFile() );
+ }
+ else {
+ file = new File( url.toURI().getSchemeSpecificPart() );
+ }
+
+ if ( ! file.exists() ) {
+ throw new IllegalArgumentException(
+ String.format(
+ "File [%s] referenced by given URL [%s] does not exist",
+ filePart,
+ url.toExternalForm()
+ )
+ );
+ }
+ }
+ catch (URISyntaxException e) {
+ throw new IllegalArgumentException(
+ "Unable to visit JAR " + url + ". Cause: " + e.getMessage(), e
+ );
+ }
+
+ if ( file.isDirectory() ) {
+ return new ExplodedArchiveDescriptor( this, url, entry );
+ }
+ else {
+ return new JarFileBasedArchiveDescriptor( this, url, entry );
+ }
+ }
+ else {
+ //let's assume the url can return the jar as a zip stream
+ return new JarInputStreamBasedArchiveDescriptor( this, url, entry );
+ }
+ }
+
+ @Override
+ public URL getJarURLFromURLEntry(URL url, String entry) throws IllegalArgumentException {
+ return ArchiveHelper.getJarURLFromURLEntry( url, entry );
+ }
+
+ @Override
+ public URL getURLFromPath(String jarPath) {
+ return ArchiveHelper.getURLFromPath( jarPath );
+ }
+}
92 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/spi/AbstractArchiveDescriptor.java
View
@@ -0,0 +1,92 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.jpa.boot.archive.spi;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.util.zip.ZipEntry;
+
+import org.hibernate.internal.util.StringHelper;
+import org.hibernate.jpa.boot.internal.ByteArrayInputStreamAccess;
+import org.hibernate.jpa.boot.archive.internal.ArchiveHelper;
+import org.hibernate.jpa.boot.spi.InputStreamAccess;
+
+/**
+ * @author Steve Ebersole
+ */
+public abstract class AbstractArchiveDescriptor implements ArchiveDescriptor {
+ private final ArchiveDescriptorFactory archiveDescriptorFactory;
+ private final URL archiveUrl;
+ private final String entryBasePrefix;
+
+ protected AbstractArchiveDescriptor(
+ ArchiveDescriptorFactory archiveDescriptorFactory,
+ URL archiveUrl,
+ String entryBasePrefix) {
+ this.archiveDescriptorFactory = archiveDescriptorFactory;
+ this.archiveUrl = archiveUrl;
+ this.entryBasePrefix = normalizeEntryBasePrefix( entryBasePrefix );
+ }
+
+ private static String normalizeEntryBasePrefix(String entryBasePrefix) {
+ if ( StringHelper.isEmpty( entryBasePrefix ) || entryBasePrefix.length() == 1 ) {
+ return null;
+ }
+
+ return entryBasePrefix.startsWith( "/" ) ? entryBasePrefix.substring( 1 ) : entryBasePrefix;
+ }
+
+ protected ArchiveDescriptorFactory getArchiveDescriptorFactory() {
+ return archiveDescriptorFactory;
+ }
+
+ protected URL getArchiveUrl() {
+ return archiveUrl;
+ }
+
+ protected String getEntryBasePrefix() {
+ return entryBasePrefix;
+ }
+
+ protected String extractRelativeName(ZipEntry zipEntry) {
+ final String entryName = extractName( zipEntry );
+ return entryBasePrefix == null ? entryName : entryName.substring( entryBasePrefix.length() );
+ }
+
+ protected String extractName(ZipEntry zipEntry) {
+ return normalizePathName( zipEntry.getName() );
+ }
+
+ protected String normalizePathName(String pathName) {
+ return pathName.startsWith( "/" ) ? pathName.substring( 1 ) : pathName;
+ }
+
+ protected InputStreamAccess buildByteBasedInputStreamAccess(final String name, InputStream inputStream) {
+ // because of how jar InputStreams work we need to extract the bytes immediately. However, we
+ // do delay the creation of the ByteArrayInputStreams until needed
+ final byte[] bytes = ArchiveHelper.getBytesFromInputStreamSafely( inputStream );
+ return new ByteArrayInputStreamAccess( name, bytes );
+ }
+
+}
37 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/spi/ArchiveContext.java
View
@@ -0,0 +1,37 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.jpa.boot.archive.spi;
+
+import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor;
+
+/**
+* @author Steve Ebersole
+*/
+public interface ArchiveContext {
+ public PersistenceUnitDescriptor getPersistenceUnitDescriptor();
+
+ public boolean isRootUrl();
+
+ public ArchiveEntryHandler obtainArchiveEntryHandler(ArchiveEntry entry);
+}
24 .../org/hibernate/jpa/packaging/internal/Filter.java → ...rnate/jpa/boot/archive/spi/ArchiveDescriptor.java
View
@@ -1,8 +1,10 @@
/*
- * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
- * distributed under license by Red Hat Middleware LLC.
+ * distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@@ -19,22 +21,14 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
-package org.hibernate.jpa.packaging.internal;
-
+package org.hibernate.jpa.boot.archive.spi;
/**
- * Filter used when searching elements in a JAR
+ * Contract for visiting an archive, which might be a jar, a zip, an exploded directory, etc.
*
+ * @author Steve Ebersole
* @author Emmanuel Bernard
*/
-public abstract class Filter {
- private boolean retrieveStream;
-
- protected Filter(boolean retrieveStream) {
- this.retrieveStream = retrieveStream;
- }
-
- public boolean getStream() {
- return retrieveStream;
- }
+public interface ArchiveDescriptor {
+ public void visitArchive(ArchiveContext archiveContext);
}
32 .../hibernate/jpa/packaging/internal/FileFilter.java → ...pa/boot/archive/spi/ArchiveDescriptorFactory.java
View
@@ -1,8 +1,10 @@
/*
- * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
- * distributed under license by Red Hat Middleware LLC.
+ * distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@@ -19,25 +21,19 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
-package org.hibernate.jpa.packaging.internal;
+package org.hibernate.jpa.boot.archive.spi;
+import java.net.URL;
/**
- * Filter use to match a file by its name
+ * Contract for building ArchiveDescriptor instances.
*
- * @author Emmanuel Bernard
+ * @author Steve Ebersole
*/
-public abstract class FileFilter extends Filter {
-
- /**
- * @param retrieveStream Give back an open stream to the matching element or not
- */
- public FileFilter(boolean retrieveStream) {
- super( retrieveStream );
- }
+public interface ArchiveDescriptorFactory {
+ public ArchiveDescriptor buildArchiveDescriptor(URL url);
+ public ArchiveDescriptor buildArchiveDescriptor(URL jarUrl, String entry);
- /**
- * Return true if the fully qualified file name match
- */
- public abstract boolean accept(String name);
- }
+ public URL getJarURLFromURLEntry(URL url, String entry) throws IllegalArgumentException;
+ public URL getURLFromPath(String jarPath);
+}
39 .../hibernate/jpa/packaging/internal/JarVisitor.java → .../hibernate/jpa/boot/archive/spi/ArchiveEntry.java
View
@@ -1,8 +1,10 @@
/*
- * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
- * distributed under license by Red Hat Middleware LLC.
+ * distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@@ -19,28 +21,35 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
-package org.hibernate.jpa.packaging.internal;
-import java.io.IOException;
-import java.util.Set;
+package org.hibernate.jpa.boot.archive.spi;
+
+import org.hibernate.jpa.boot.spi.InputStreamAccess;
/**
- * @author Emmanuel Bernard
+ * Represent an entry in the archive.
+ *
+ * @author Steve Ebersole
*/
-public interface JarVisitor {
+public interface ArchiveEntry {
/**
- * Get the unqualified Jar name (ie wo path and wo extension)
+ * Get the entry's name
*
- * @return the unqualified jar name.
+ * @return
*/
- String getUnqualifiedJarName();
+ public String getName();
- Filter[] getFilters();
+ /**
+ * Get the relative name of the entry within the archive. Typically what we are looking for here is
+ * the ClassLoader resource lookup name.
+ *
+ * @return
+ */
+ public String getNameWithinArchive();
/**
- * Return the matching entries for each filter in the same order the filter where passed
+ * Get access to the stream for the entry
*
- * @return array of Set of JarVisitor.Entry
- * @throws java.io.IOException if something went wrong
+ * @return
*/
- Set[] getMatchingEntries() throws IOException;
+ public InputStreamAccess getStreamAccess();
}
33 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/archive/spi/ArchiveEntryHandler.java
View
@@ -0,0 +1,33 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.jpa.boot.archive.spi;
+
+/**
+ * Handler for archive entries, based on the classified type of the entry
+ *
+ * @author Steve Ebersole
+ */
+public interface ArchiveEntryHandler {
+ public void handleEntry(ArchiveEntry entry, ArchiveContext context);
+}
29 ...hibernate/jpa/packaging/internal/ClassFilter.java → ...ernate/jpa/boot/archive/spi/ArchiveException.java
View
@@ -1,8 +1,10 @@
/*
- * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
- * distributed under license by Red Hat Middleware LLC.
+ * distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@@ -19,20 +21,19 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
-package org.hibernate.jpa.packaging.internal;
+package org.hibernate.jpa.boot.archive.spi;
+import org.hibernate.HibernateException;
/**
- * Filter on class elements
- *
- * @author Emmanuel Bernard
- * @see JavaElementFilter
+ * @author Steve Ebersole
*/
-public abstract class ClassFilter extends JavaElementFilter {
- /**
- * @see JavaElementFilter#JavaElementFilter(boolean, Class[])
- */
- protected ClassFilter(boolean retrieveStream, Class[] annotations) {
- super( retrieveStream, annotations );
+public class ArchiveException extends HibernateException {
+ public ArchiveException(String message) {
+ super( message );
+ }
+
+ public ArchiveException(String message, Throwable root) {
+ super( message, root );
}
-}
+}
60 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/ByteArrayInputStreamAccess.java
View
@@ -0,0 +1,60 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.jpa.boot.internal;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+import org.hibernate.jpa.boot.spi.InputStreamAccess;
+import org.hibernate.jpa.boot.spi.NamedInputStream;
+
+/**
+ * An InputStreamAccess implementation based on a byte array
+ *
+ * @author Steve Ebersole
+ */
+public class ByteArrayInputStreamAccess implements InputStreamAccess {
+ private final String name;
+ private final byte[] bytes;
+
+ public ByteArrayInputStreamAccess(String name, byte[] bytes) {
+ this.name = name;
+ this.bytes = bytes;
+ }
+
+ @Override
+ public String getStreamName() {
+ return name;
+ }
+
+ @Override
+ public InputStream accessInputStream() {
+ return new ByteArrayInputStream( bytes );
+ }
+
+ @Override
+ public NamedInputStream asNamedInputStream() {
+ return new NamedInputStream( getStreamName(), accessInputStream() );
+ }
+}
52 ...a/org/hibernate/jpa/packaging/internal/Entry.java → ...ernate/jpa/boot/internal/ClassDescriptorImpl.java
View
@@ -1,8 +1,10 @@
/*
- * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
- * distributed under license by Red Hat Middleware LLC.
+ * distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@@ -19,44 +21,48 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
-package org.hibernate.jpa.packaging.internal;
-import java.io.InputStream;
+package org.hibernate.jpa.boot.internal;
+
+import org.hibernate.jpa.boot.spi.ClassDescriptor;
+import org.hibernate.jpa.boot.spi.InputStreamAccess;
/**
- * Represent a JAR entry
- * Contains a name and an optional Input stream to the entry
- *
- * @author Emmanuel Bernard
+ * @author Steve Ebersole
*/
-public class Entry {
- private String name;
- private InputStream is;
+public class ClassDescriptorImpl implements ClassDescriptor {
+ private final String name;
+ private final InputStreamAccess streamAccess;
- public Entry(String name, InputStream is) {
+ public ClassDescriptorImpl(String name, InputStreamAccess streamAccess) {
this.name = name;
- this.is = is;
+ this.streamAccess = streamAccess;
}
+ @Override
public String getName() {
return name;
}
- public InputStream getInputStream() {
- return is;
+ @Override
+ public InputStreamAccess getStreamAccess() {
+ return streamAccess;
}
+ @Override
public boolean equals(Object o) {
- if ( this == o ) return true;
- if ( o == null || getClass() != o.getClass() ) return false;
-
- final Entry entry = (Entry) o;
-
- if ( !name.equals( entry.name ) ) return false;
+ if ( this == o ) {
+ return true;
+ }
+ if ( o == null || getClass() != o.getClass() ) {
+ return false;
+ }
- return true;
+ ClassDescriptorImpl that = (ClassDescriptorImpl) o;
+ return name.equals( that.name );
}
+ @Override
public int hashCode() {
return name.hashCode();
}
-}
+}
440 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java
View
@@ -23,12 +23,17 @@
*/
package org.hibernate.jpa.boot.internal;
+import javax.persistence.AttributeConverter;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.EntityNotFoundException;
+import javax.persistence.PersistenceException;
+import javax.persistence.spi.PersistenceUnitTransactionType;
+import javax.sql.DataSource;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
-import java.lang.annotation.Annotation;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
@@ -42,18 +47,17 @@
import java.util.Set;
import java.util.StringTokenizer;
-import javax.persistence.AttributeConverter;
-import javax.persistence.Converter;
-import javax.persistence.Embeddable;
-import javax.persistence.Entity;
-import javax.persistence.EntityManagerFactory;
-import javax.persistence.EntityNotFoundException;
-import javax.persistence.MappedSuperclass;
-import javax.persistence.PersistenceException;
-import javax.persistence.spi.PersistenceUnitTransactionType;
-import javax.sql.DataSource;
+import org.jboss.jandex.AnnotationInstance;
+import org.jboss.jandex.ClassInfo;
+import org.jboss.jandex.DotName;
+import org.jboss.jandex.Index;
+import org.jboss.jandex.IndexView;
+import org.jboss.jandex.Indexer;
+
+import org.jboss.logging.Logger;
import org.hibernate.Interceptor;
+import org.hibernate.InvalidMappingException;
import org.hibernate.MappingException;
import org.hibernate.MappingNotFoundException;
import org.hibernate.SessionFactory;
@@ -81,14 +85,21 @@
import org.hibernate.jpa.boot.spi.IntegratorProvider;
import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor;
import org.hibernate.jpa.event.spi.JpaIntegrator;
-import org.hibernate.jpa.internal.schemagen.JpaSchemaGenerator;
import org.hibernate.jpa.internal.EntityManagerFactoryImpl;
import org.hibernate.jpa.internal.EntityManagerMessageLogger;
+import org.hibernate.jpa.internal.schemagen.JpaSchemaGenerator;
import org.hibernate.jpa.internal.util.LogHelper;
import org.hibernate.jpa.internal.util.PersistenceUnitTransactionTypeHelper;
-import org.hibernate.jpa.packaging.internal.NativeScanner;
-import org.hibernate.jpa.packaging.spi.NamedInputStream;
-import org.hibernate.jpa.packaging.spi.Scanner;
+import org.hibernate.jpa.boot.scan.internal.StandardScanOptions;
+import org.hibernate.jpa.boot.scan.internal.StandardScanner;
+import org.hibernate.jpa.boot.spi.ClassDescriptor;
+import org.hibernate.jpa.boot.spi.InputStreamAccess;
+import org.hibernate.jpa.boot.spi.MappingFileDescriptor;
+import org.hibernate.jpa.boot.spi.NamedInputStream;
+import org.hibernate.jpa.boot.spi.PackageDescriptor;
+import org.hibernate.jpa.boot.scan.spi.ScanOptions;
+import org.hibernate.jpa.boot.scan.spi.ScanResult;
+import org.hibernate.jpa.boot.scan.spi.Scanner;
import org.hibernate.jpa.spi.IdentifierGeneratorStrategyProvider;
import org.hibernate.metamodel.source.annotations.JPADotNames;
import org.hibernate.metamodel.source.annotations.JandexHelper;
@@ -97,14 +108,6 @@
import org.hibernate.service.ConfigLoader;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.spi.ServiceRegistryImplementor;
-import org.jboss.jandex.AnnotationInstance;
-import org.jboss.jandex.ClassInfo;
-import org.jboss.jandex.CompositeIndex;
-import org.jboss.jandex.DotName;
-import org.jboss.jandex.Index;
-import org.jboss.jandex.IndexView;
-import org.jboss.jandex.Indexer;
-import org.jboss.logging.Logger;
/**
* @author Steve Ebersole
@@ -199,13 +202,14 @@ public EntityManagerFactoryBuilderImpl(
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Next we do a preliminary pass at metadata processing, which involves:
// 1) scanning
- ScanResult scanResult = scan( bootstrapServiceRegistry );
+ final ScanResult scanResult = scan( bootstrapServiceRegistry );
+ final DeploymentResources deploymentResources = buildDeploymentResources( scanResult, bootstrapServiceRegistry );
// 2) building a Jandex index
- Set<String> collectedManagedClassNames = collectManagedClassNames( scanResult );
- IndexView jandexIndex = locateOrBuildJandexIndex( collectedManagedClassNames, scanResult.getPackageNames(), bootstrapServiceRegistry );
+ final IndexView jandexIndex = locateOrBuildJandexIndex( deploymentResources );
// 3) building "metadata sources" to keep for later to use in building the SessionFactory
- metadataSources = prepareMetadataSources( jandexIndex, collectedManagedClassNames, scanResult, bootstrapServiceRegistry );
+ metadataSources = prepareMetadataSources( jandexIndex, deploymentResources, bootstrapServiceRegistry );
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
withValidatorFactory( configurationValues.get( AvailableSettings.VALIDATION_FACTORY ) );
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -217,6 +221,122 @@ public EntityManagerFactoryBuilderImpl(
}
}
+ private static interface DeploymentResources {
+ public Iterable<ClassDescriptor> getClassDescriptors();
+ public Iterable<PackageDescriptor> getPackageDescriptors();
+ public Iterable<MappingFileDescriptor> getMappingFileDescriptors();
+ }
+
+ private DeploymentResources buildDeploymentResources(
+ ScanResult scanResult,
+ BootstrapServiceRegistry bootstrapServiceRegistry) {
+
+ // mapping files ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ final ArrayList<MappingFileDescriptor> mappingFileDescriptors = new ArrayList<MappingFileDescriptor>();
+
+ final Set<String> nonLocatedMappingFileNames = new HashSet<String>();
+ final List<String> explicitMappingFileNames = persistenceUnit.getMappingFileNames();
+ if ( explicitMappingFileNames != null ) {
+ nonLocatedMappingFileNames.addAll( explicitMappingFileNames );
+ }
+
+ for ( MappingFileDescriptor mappingFileDescriptor : scanResult.getLocatedMappingFiles() ) {
+ mappingFileDescriptors.add( mappingFileDescriptor );
+ nonLocatedMappingFileNames.remove( mappingFileDescriptor.getName() );
+ }
+
+ for ( String name : nonLocatedMappingFileNames ) {
+ MappingFileDescriptor descriptor = buildMappingFileDescriptor( name, bootstrapServiceRegistry );
+ mappingFileDescriptors.add( descriptor );
+ }
+
+
+ // classes and packages ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ final HashMap<String, ClassDescriptor> classDescriptorMap = new HashMap<String, ClassDescriptor>();
+ final HashMap<String, PackageDescriptor> packageDescriptorMap = new HashMap<String, PackageDescriptor>();
+
+ for ( ClassDescriptor classDescriptor : scanResult.getLocatedClasses() ) {
+ classDescriptorMap.put( classDescriptor.getName(), classDescriptor );
+ }
+
+ for ( PackageDescriptor packageDescriptor : scanResult.getLocatedPackages() ) {
+ packageDescriptorMap.put( packageDescriptor.getName(), packageDescriptor );
+ }
+
+ final List<String> explicitClassNames = persistenceUnit.getManagedClassNames();
+ if ( explicitClassNames != null ) {
+ for ( String explicitClassName : explicitClassNames ) {
+ // IMPL NOTE : explicitClassNames can contain class or package names!!!
+ if ( classDescriptorMap.containsKey( explicitClassName ) ) {
+ continue;
+ }
+ if ( packageDescriptorMap.containsKey( explicitClassName ) ) {
+ continue;
+ }
+
+ // try it as a class name first...
+ final String classFileName = explicitClassName.replace( '.', '/' ) + ".class";
+ final URL classFileUrl = bootstrapServiceRegistry.getService( ClassLoaderService.class )
+ .locateResource( classFileName );
+ if ( classFileUrl != null ) {
+ classDescriptorMap.put(
+ explicitClassName,
+ new ClassDescriptorImpl( explicitClassName, new UrlInputStreamAccess( classFileUrl ) )
+ );
+ continue;
+ }
+
+ // otherwise, try it as a package name
+ final String packageInfoFileName = explicitClassName.replace( '.', '/' ) + "/package-info.class";
+ final URL packageInfoFileUrl = bootstrapServiceRegistry.getService( ClassLoaderService.class )
+ .locateResource( packageInfoFileName );
+ if ( packageInfoFileUrl != null ) {
+ packageDescriptorMap.put(
+ explicitClassName,
+ new PackageDescriptorImpl( explicitClassName, new UrlInputStreamAccess( packageInfoFileUrl ) )
+ );
+ continue;
+ }
+
+ LOG.debugf(
+ "Unable to resolve class [%s] named in persistence unit [%s]",
+ explicitClassName,
+ persistenceUnit.getName()
+ );
+ }
+ }
+
+ return new DeploymentResources() {
+ @Override
+ public Iterable<ClassDescriptor> getClassDescriptors() {
+ return classDescriptorMap.values();
+ }
+
+ @Override
+ public Iterable<PackageDescriptor> getPackageDescriptors() {
+ return packageDescriptorMap.values();
+ }
+
+ @Override
+ public Iterable<MappingFileDescriptor> getMappingFileDescriptors() {
+ return mappingFileDescriptors;
+ }
+ };
+ }
+
+ private MappingFileDescriptor buildMappingFileDescriptor(
+ String name,
+ BootstrapServiceRegistry bootstrapServiceRegistry) {
+ final URL url = bootstrapServiceRegistry.getService( ClassLoaderService.class ).locateResource( name );
+ if ( url == null ) {
+ throw persistenceException( "Unable to resolve named mapping-file [" + name + "]" );
+ }
+
+ return new MappingFileDescriptorImpl( name, new UrlInputStreamAccess( url ) );
+ }
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// temporary!
@SuppressWarnings("unchecked")
@@ -233,13 +353,13 @@ public Configuration getHibernateConfiguration() {
@SuppressWarnings("unchecked")
private MetadataSources prepareMetadataSources(
IndexView jandexIndex,
- Set<String> collectedManagedClassNames,
- ScanResult scanResult,
+ DeploymentResources deploymentResources,
BootstrapServiceRegistry bootstrapServiceRegistry) {
// todo : this needs to tie into the metamodel branch...
MetadataSources metadataSources = new MetadataSources();
- for ( String className : collectedManagedClassNames ) {
+ for ( ClassDescriptor classDescriptor : deploymentResources.getClassDescriptors() ) {
+ final String className = classDescriptor.getName();
final ClassInfo classInfo = jandexIndex.getClassByName( DotName.createSimple( className ) );
if ( classInfo == null ) {
// Not really sure what this means. Most likely it is explicitly listed in the persistence unit,
@@ -266,15 +386,19 @@ private MetadataSources prepareMetadataSources(
}
}
- metadataSources.packageNames.addAll( scanResult.getPackageNames() );
+ for ( PackageDescriptor packageDescriptor : deploymentResources.getPackageDescriptors() ) {
+ metadataSources.packageNames.add( packageDescriptor.getName() );
+ }
- metadataSources.namedMappingFileInputStreams.addAll( scanResult.getHbmFiles() );
+ for ( MappingFileDescriptor mappingFileDescriptor : deploymentResources.getMappingFileDescriptors() ) {
+ metadataSources.namedMappingFileInputStreams.add( mappingFileDescriptor.getStreamAccess().asNamedInputStream() );
+ }
- metadataSources.mappingFileResources.addAll( scanResult.getMappingFiles() );
final String explicitHbmXmls = (String) configurationValues.remove( AvailableSettings.HBXML_FILES );
if ( explicitHbmXmls != null ) {
metadataSources.mappingFileResources.addAll( Arrays.asList( StringHelper.split( ", ", explicitHbmXmls ) ) );
}
+
final List<String> explicitOrmXml = (List<String>) configurationValues.remove( AvailableSettings.XML_FILE_NAMES );
if ( explicitOrmXml != null ) {
metadataSources.mappingFileResources.addAll( explicitOrmXml );
@@ -283,41 +407,26 @@ private MetadataSources prepareMetadataSources(
return metadataSources;
}
- private Set<String> collectManagedClassNames(ScanResult scanResult) {
- Set<String> collectedNames = new HashSet<String>();
- if ( persistenceUnit.getManagedClassNames() != null ) {
- collectedNames.addAll( persistenceUnit.getManagedClassNames() );
- }
- collectedNames.addAll( scanResult.getManagedClassNames() );
- return collectedNames;
- }
-
- private IndexView locateOrBuildJandexIndex(
- Set<String> collectedManagedClassNames,
- List<String> packageNames,
- BootstrapServiceRegistry bootstrapServiceRegistry) {
+ private IndexView locateOrBuildJandexIndex(DeploymentResources deploymentResources) {
// for now create a whole new Index to work with, eventually we need to:
// 1) accept an Index as an incoming config value
// 2) pass that Index along to the metamodel code...
- //
- // (1) is mocked up here, but JBoss AS does not currently pass in any Index to use...
IndexView jandexIndex = (IndexView) configurationValues.get( JANDEX_INDEX );
if ( jandexIndex == null ) {
- jandexIndex = buildJandexIndex( collectedManagedClassNames, packageNames, bootstrapServiceRegistry );
+ jandexIndex = buildJandexIndex( deploymentResources );
}
return jandexIndex;
}
- private IndexView buildJandexIndex(Set<String> classNamesSource, List<String> packageNames, BootstrapServiceRegistry bootstrapServiceRegistry) {
+ private IndexView buildJandexIndex(DeploymentResources deploymentResources) {
Indexer indexer = new Indexer();
- for ( String className : classNamesSource ) {
- indexResource( className.replace( '.', '/' ) + ".class", indexer, bootstrapServiceRegistry );
+ for ( ClassDescriptor classDescriptor : deploymentResources.getClassDescriptors() ) {
+ indexStream( indexer, classDescriptor.getStreamAccess() );
}
- // add package-info from the configured packages
- for ( String packageName : packageNames ) {
- indexResource( packageName.replace( '.', '/' ) + "/package-info.class", indexer, bootstrapServiceRegistry );
+ for ( PackageDescriptor packageDescriptor : deploymentResources.getPackageDescriptors() ) {
+ indexStream( indexer, packageDescriptor.getStreamAccess() );
}
// for now we just skip entities defined in (1) orm.xml files and (2) hbm.xml files. this part really needs
@@ -325,16 +434,25 @@ private IndexView buildJandexIndex(Set<String> classNamesSource, List<String> pa
// for now, we also need to wrap this in a CompositeIndex until Jandex is updated to use a common interface
// between the 2...
- return CompositeIndex.create( indexer.complete() );
+ return indexer.complete();
}
- private void indexResource(String resourceName, Indexer indexer, BootstrapServiceRegistry bootstrapServiceRegistry) {
- InputStream stream = bootstrapServiceRegistry.getService( ClassLoaderService.class ).locateResourceStream( resourceName );
+ private void indexStream(Indexer indexer, InputStreamAccess streamAccess) {
try {
- indexer.index( stream );
+ InputStream stream = streamAccess.accessInputStream();
+ try {
+ indexer.index( stream );
+ }
+ finally {
+ try {
+ stream.close();
+ }
+ catch (Exception ignore) {
+ }
+ }
}
catch ( IOException e ) {
- throw persistenceException( "Unable to open input stream for resource " + resourceName, e );
+ throw persistenceException( "Unable to index from stream " + streamAccess.getStreamName(), e );
}
}
@@ -586,37 +704,24 @@ private void addCacheRegionDefinition(String role, String value, CacheRegionDefi
@SuppressWarnings("unchecked")
private ScanResult scan(BootstrapServiceRegistry bootstrapServiceRegistry) {
- Scanner scanner = locateOrBuildScanner( bootstrapServiceRegistry );
- ScanningContext scanningContext = new ScanningContext();
-
- final ScanResult scanResult = new ScanResult();
- if ( persistenceUnit.getMappingFileNames() != null ) {
- scanResult.getMappingFiles().addAll( persistenceUnit.getMappingFileNames() );
- }
+ final Scanner scanner = locateOrBuildScanner( bootstrapServiceRegistry );
+ final ScanOptions scanOptions = determineScanOptions();
- // dunno, but the old code did it...
- scanningContext.setSearchOrm( ! scanResult.getMappingFiles().contains( META_INF_ORM_XML ) );
-
- if ( persistenceUnit.getJarFileUrls() != null ) {
- prepareAutoDetectionSettings( scanningContext, false );
- for ( URL jar : persistenceUnit.getJarFileUrls() ) {
- scanningContext.setUrl( jar );
- scanInContext( scanner, scanningContext, scanResult );
- }
- }
-
- prepareAutoDetectionSettings( scanningContext, persistenceUnit.isExcludeUnlistedClasses() );
- scanningContext.setUrl( persistenceUnit.getPersistenceUnitRootUrl() );
- scanInContext( scanner, scanningContext, scanResult );
+ return scanner.scan( persistenceUnit, scanOptions );
+ }
- return scanResult;
+ private ScanOptions determineScanOptions() {
+ return new StandardScanOptions(
+ (String) configurationValues.get( AvailableSettings.AUTODETECTION ),
+ persistenceUnit.isExcludeUnlistedClasses()
+ );
}
@SuppressWarnings("unchecked")
private Scanner locateOrBuildScanner(BootstrapServiceRegistry bootstrapServiceRegistry) {
final Object value = configurationValues.remove( AvailableSettings.SCANNER );
if ( value == null ) {
- return new NativeScanner();
+ return new StandardScanner();
}
if ( Scanner.class.isInstance( value ) ) {
@@ -650,91 +755,6 @@ private Scanner locateOrBuildScanner(BootstrapServiceRegistry bootstrapServiceRe
}
}
- private void prepareAutoDetectionSettings(ScanningContext context, boolean excludeUnlistedClasses) {
- final String detectionSetting = (String) configurationValues.get( AvailableSettings.AUTODETECTION );
-
- if ( detectionSetting == null ) {
- if ( excludeUnlistedClasses ) {
- context.setDetectClasses( false );
- context.setDetectHbmFiles( false );
- }
- else {
- context.setDetectClasses( true );
- context.setDetectHbmFiles( true );
- }
- }
- else {
- for ( String token : StringHelper.split( ", ", detectionSetting ) ) {
- if ( "class".equalsIgnoreCase( token ) ) {
- context.setDetectClasses( true );
- }
- if ( "hbm".equalsIgnoreCase( token ) ) {
- context.setDetectClasses( true );
- }
- }
- }
- }
-
- private void scanInContext(
- Scanner scanner,
- ScanningContext scanningContext,
- ScanResult scanResult) {
- if ( scanningContext.getUrl() == null ) {
- // not sure i like just ignoring this being null, but this is exactly what the old code does...
- LOG.containerProvidingNullPersistenceUnitRootUrl();
- return;
- }
- if ( scanningContext.getUrl().getProtocol().equalsIgnoreCase( "bundle" ) ) {
- // TODO: Is there a way to scan the root bundle URL in OSGi containers?
- // Although the URL provides a stream handler that works for finding
- // resources in a specific Bundle, the root one does not work.
- return;
- }
-
- try {
- if ( scanningContext.isDetectClasses() ) {
- Set<Package> matchingPackages = scanner.getPackagesInJar( scanningContext.url, new HashSet<Class<? extends Annotation>>(0) );
- for ( Package pkg : matchingPackages ) {
- scanResult.getPackageNames().add( pkg.getName() );
- }
-
- Set<Class<? extends Annotation>> annotationsToLookFor = new HashSet<Class<? extends Annotation>>();
- annotationsToLookFor.add( Entity.class );
- annotationsToLookFor.add( MappedSuperclass.class );
- annotationsToLookFor.add( Embeddable.class );
- annotationsToLookFor.add( Converter.class );
- Set<Class<?>> matchingClasses = scanner.getClassesInJar( scanningContext.url, annotationsToLookFor );
- for ( Class<?> clazz : matchingClasses ) {
- scanResult.getManagedClassNames().add( clazz.getName() );
- }
- }
-
- Set<String> patterns = new HashSet<String>();
- if ( scanningContext.isSearchOrm() ) {
- patterns.add( META_INF_ORM_XML );
- }
- if ( scanningContext.isDetectHbmFiles() ) {
- patterns.add( "**/*.hbm.xml" );
- }
- if ( ! scanResult.getMappingFiles().isEmpty() ) {
- patterns.addAll( scanResult.getMappingFiles() );
- }
- if ( patterns.size() != 0 ) {
- Set<NamedInputStream> files = scanner.getFilesInJar( scanningContext.getUrl(), patterns );
- for ( NamedInputStream file : files ) {
- scanResult.getHbmFiles().add( file );
- scanResult.getMappingFiles().remove( file.getName() );
- }
- }
- }
- catch (PersistenceException e ) {
- throw e;
- }
- catch ( RuntimeException e ) {
- throw persistenceException( "error trying to scan url: " + scanningContext.getUrl().toString(), e );
- }
- }
-
@Override
public EntityManagerFactoryBuilder withValidatorFactory(Object validatorFactory) {
this.validatorFactory = validatorFactory;
@@ -1094,14 +1114,28 @@ else if (Boolean.FALSE.equals(useMetaInf)) {
//addInputStream has the responsibility to close the stream
cfg.addInputStream( new BufferedInputStream( namedInputStream.getStream() ) );
}
- catch (MappingException me) {
- //try our best to give the file name
- if ( StringHelper.isEmpty( namedInputStream.getName() ) ) {
- throw me;
+ catch ( InvalidMappingException e ) {
+ // try our best to give the file name
+ if ( StringHelper.isNotEmpty( namedInputStream.getName() ) ) {
+ throw new InvalidMappingException(
+ "Error while parsing file: " + namedInputStream.getName(),
+ e.getType(),
+ e.getPath(),
+ e
+ );
}
else {
+ throw e;
+ }
+ }
+ catch (MappingException me) {
+ // try our best to give the file name
+ if ( StringHelper.isNotEmpty( namedInputStream.getName() ) ) {
throw new MappingException("Error while parsing file: " + namedInputStream.getName(), me );
}
+ else {
+ throw me;
+ }
}
}
for ( String packageName : metadataSources.packageNames ) {
@@ -1176,68 +1210,6 @@ public JaccDefinition(String contextId, String role, String clazz, String action
}
}
- public static class ScanningContext {
- private URL url;
- private boolean detectClasses;
- private boolean detectHbmFiles;
- private boolean searchOrm;
-
- public URL getUrl() {
- return url;
- }
-
- public void setUrl(URL url) {
- this.url = url;
- }
-
- public boolean isDetectClasses() {
- return detectClasses;
- }
-
- public void setDetectClasses(boolean detectClasses) {
- this.detectClasses = detectClasses;
- }
-
- public boolean isDetectHbmFiles() {
- return detectHbmFiles;
- }
-
- public void setDetectHbmFiles(boolean detectHbmFiles) {
- this.detectHbmFiles = detectHbmFiles;
- }
-
- public boolean isSearchOrm() {
- return searchOrm;
- }
-
- public void setSearchOrm(boolean searchOrm) {
- this.searchOrm = searchOrm;
- }
- }
-
- private static class ScanResult {
- private final List<String> managedClassNames = new ArrayList<String>();
- private final List<String> packageNames = new ArrayList<String>();
- private final List<NamedInputStream> hbmFiles = new ArrayList<NamedInputStream>();
- private final List<String> mappingFiles = new ArrayList<String>();
-
- public List<String> getManagedClassNames() {
- return managedClassNames;
- }
-
- public List<String> getPackageNames() {
- return packageNames;
- }
-
- public List<NamedInputStream> getHbmFiles() {
- return hbmFiles;
- }
-
- public List<String> getMappingFiles() {
- return mappingFiles;
- }
- }
-
public static class MetadataSources {
private final List<String> annotatedMappingClassNames = new ArrayList<String>();
private final List<ConverterDescriptor> converterDescriptors = new ArrayList<ConverterDescriptor>();
77 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/FileInputStreamAccess.java
View
@@ -0,0 +1,77 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.jpa.boot.internal;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+
+import org.hibernate.HibernateException;
+import org.hibernate.jpa.boot.archive.spi.ArchiveException;
+import org.hibernate.jpa.boot.spi.InputStreamAccess;
+import org.hibernate.jpa.boot.spi.NamedInputStream;
+
+/**
+ * An InputStreamAccess implementation based on a File reference
+ *
+ * @author Steve Ebersole
+ */
+public class FileInputStreamAccess implements InputStreamAccess {
+ private final String name;
+ private final File file;
+
+ public FileInputStreamAccess(String name, File file) {
+ this.name = name;
+ this.file = file;
+ if ( ! file.exists() ) {
+ throw new HibernateException( "File must exist : " + file.getAbsolutePath() );
+ }
+ }
+
+ @Override
+ public String getStreamName() {
+ return name;
+ }
+
+ @Override
+ public InputStream accessInputStream() {
+ try {
+ return new BufferedInputStream( new FileInputStream( file ) );
+ }
+ catch (FileNotFoundException e) {
+ // should never ever ever happen, but...
+ throw new ArchiveException(
+ "File believed to exist based on File.exists threw error when passed to FileInputStream ctor",
+ e
+ );
+ }
+ }
+
+ @Override
+ public NamedInputStream asNamedInputStream() {
+ return new NamedInputStream( getStreamName(), accessInputStream() );
+ }
+}
73 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/MappingFileDescriptorImpl.java
View
@@ -0,0 +1,73 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.jpa.boot.internal;
+
+import org.hibernate.jpa.boot.spi.InputStreamAccess;
+import org.hibernate.jpa.boot.spi.MappingFileDescriptor;
+
+/**
+ * @author Steve Ebersole
+ */
+public class MappingFileDescriptorImpl implements MappingFileDescriptor {
+ private final String name;
+ private final InputStreamAccess streamAccess;
+
+ public MappingFileDescriptorImpl(String name, InputStreamAccess streamAccess) {
+ this.name = name;
+ this.streamAccess = streamAccess;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public InputStreamAccess getStreamAccess() {
+ return streamAccess;
+ }
+
+// @Override
+// public boolean equals(Object o) {
+// if ( this == o ) {
+// return true;
+// }
+// if ( o == null || getClass() != o.getClass() ) {
+// return false;
+// }
+//
+// MappingFileDescriptorImpl that = (MappingFileDescriptorImpl) o;
+//
+// return name.equals( that.name )
+// && streamAccess.getStreamName().equals( that.streamAccess.getStreamName() );
+//
+// }
+//
+// @Override
+// public int hashCode() {
+// int result = name.hashCode();
+// result = 31 * result + streamAccess.getStreamName().hashCode();
+// return result;
+// }
+}
68 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/PackageDescriptorImpl.java
View
@@ -0,0 +1,68 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.jpa.boot.internal;
+
+import org.hibernate.jpa.boot.spi.InputStreamAccess;
+import org.hibernate.jpa.boot.spi.PackageDescriptor;
+
+/**
+ * @author Steve Ebersole
+ */
+public class PackageDescriptorImpl implements PackageDescriptor {
+ private final String name;
+ private final InputStreamAccess streamAccess;
+
+ public PackageDescriptorImpl(String name, InputStreamAccess streamAccess) {
+ this.name = name;
+ this.streamAccess = streamAccess;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public InputStreamAccess getStreamAccess() {
+ return streamAccess;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if ( this == o ) {
+ return true;
+ }
+ if ( o == null || getClass() != o.getClass() ) {
+ return false;
+ }
+
+ PackageDescriptorImpl that = (PackageDescriptorImpl) o;
+ return name.equals( that.name );
+ }
+
+ @Override
+ public int hashCode() {
+ return name.hashCode();
+ }
+}
6 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/PersistenceXmlParser.java
View
@@ -54,8 +54,8 @@
import org.xml.sax.SAXParseException;
import org.hibernate.jpa.AvailableSettings;
+import org.hibernate.jpa.boot.archive.internal.ArchiveHelper;
import org.hibernate.jpa.internal.EntityManagerMessageLogger;
-import org.hibernate.jpa.packaging.internal.JarVisitorFactory;
import org.hibernate.jpa.internal.util.ConfigurationHelper;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.source.XsdException;
@@ -121,7 +121,7 @@ public PersistenceXmlParser(ClassLoaderService classLoaderService, PersistenceUn
final Element element = (Element) children.item( i );
final String tag = element.getTagName();
if ( tag.equals( "persistence-unit" ) ) {
- final URL puRootUrl = JarVisitorFactory.getJarURLFromURLEntry( xmlUrl, "/META-INF/persistence.xml" );
+ final URL puRootUrl = ArchiveHelper.getJarURLFromURLEntry( xmlUrl, "/META-INF/persistence.xml" );
ParsedPersistenceXmlDescriptor persistenceUnit = new ParsedPersistenceXmlDescriptor( puRootUrl );
bindPersistenceUnit( persistenceUnit, element );
@@ -214,7 +214,7 @@ else if ( tag.equals( "mapping-file" ) ) {
persistenceUnit.addMappingFiles( extractContent( element ) );
}
else if ( tag.equals( "jar-file" ) ) {
- persistenceUnit.addJarFileUrl( JarVisitorFactory.getURLFromPath( extractContent( element ) ) );
+ persistenceUnit.addJarFileUrl( ArchiveHelper.getURLFromPath( extractContent( element ) ) );
}
else if ( tag.equals( "exclude-unlisted-classes" ) ) {
persistenceUnit.setExcludeUnlistedClasses( true );
62 hibernate-entitymanager/src/main/java/org/hibernate/jpa/boot/internal/UrlInputStreamAccess.java
View
@@ -0,0 +1,62 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2013, Red Hat Inc. or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.jpa.boot.internal;
+
+import java.io.InputStream;
+import java.net.URL;
+
+import org.hibernate.HibernateException;
+import org.hibernate.jpa.boot.spi.InputStreamAccess;
+import org.hibernate.jpa.boot.spi.NamedInputStream;
+
+/**
+ * @author Steve Ebersole
+ */
+public class UrlInputStreamAccess implements InputStreamAccess {
+ private final URL url;
+
+ public UrlInputStreamAccess(URL url) {
+ this.url = url;
+ }
+
+ @Override
+ public String getStreamName() {
+ return url.toExternalForm();
+ }
+
+ @Override
+ public InputStream accessInputStream() {
+ try {
+ return url.openStream();
+ }