HHH-8088 - Redesign Scanner contract

This commit is contained in:
Steve Ebersole 2013-03-20 19:26:16 -05:00
parent a1afa0ce35
commit eeca84460e
50 changed files with 2892 additions and 1790 deletions

View File

@ -26,10 +26,12 @@ package org.hibernate.ejb.packaging;
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 );
}

View File

@ -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 {
}

View File

@ -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 @@ public class JarVisitorFactory {
* @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 @@ public class JarVisitorFactory {
"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 @@ public class JarVisitorFactory {
* 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 class JarVisitorFactory {
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 );
int slash = fileName.lastIndexOf( "/" );
if ( slash != -1 ) {
fileName = fileName.substring(
fileName.lastIndexOf( "/" ) + 1,
fileName.length()
);
}
if ( fileName.length() > 4 && fileName.endsWith( "ar" ) && fileName.charAt( fileName.length() - 4 ) == '.' ) {
fileName = fileName.substring( 0, fileName.length() - 4 );
}
return fileName;
}
public static byte[] getBytesFromInputStreamSafely(InputStream inputStream) {
try {
return getBytesFromInputStream( inputStream );
}
catch (IOException e) {
throw new ArchiveException( "Unable to extract bytes from InputStream", e );
}
}
/**
* 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, "" );
}
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 );
}
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 );
}
}
else {
//let's assume the url can return the jar as a zip stream
return new InputStreamZippedJarVisitor( jarUrl, filters, entry );
}
}
// 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;

View File

@ -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 );
}
}
}

View File

@ -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;
}
}

View File

@ -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
);
}
}
}

View File

@ -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 );
}
}

View File

@ -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 );
}
}

View File

@ -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 );
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -0,0 +1,39 @@
/*
* 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.net.URL;
/**
* Contract for building ArchiveDescriptor instances.
*
* @author Steve Ebersole
*/
public interface ArchiveDescriptorFactory {
public ArchiveDescriptor buildArchiveDescriptor(URL url);
public ArchiveDescriptor buildArchiveDescriptor(URL jarUrl, String entry);
public URL getJarURLFromURLEntry(URL url, String entry) throws IllegalArgumentException;
public URL getURLFromPath(String jarPath);
}

View File

@ -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();
Filter[] getFilters();
public String getName();
/**
* Return the matching entries for each filter in the same order the filter where passed
* Get the relative name of the entry within the archive. Typically what we are looking for here is
* the ClassLoader resource lookup name.
*
* @return array of Set of JarVisitor.Entry
* @throws java.io.IOException if something went wrong
* @return
*/
Set[] getMatchingEntries() throws IOException;
public String getNameWithinArchive();
/**
* Get access to the stream for the entry
*
* @return
*/
public InputStreamAccess getStreamAccess();
}

View File

@ -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,13 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.jpa.packaging.internal;
package org.hibernate.jpa.boot.archive.spi;
/**
* Filter use to match a file by its name
* Handler for archive entries, based on the classified type of the entry
*
* @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 );
}
/**
* Return true if the fully qualified file name match
*/
public abstract boolean accept(String name);
}
public interface ArchiveEntryHandler {
public void handleEntry(ArchiveEntry entry, ArchiveContext context);
}

View File

@ -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 );
}
}

View File

@ -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() );
}
}

View File

@ -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;
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;
return true;
ClassDescriptorImpl that = (ClassDescriptorImpl) o;
return name.equals( that.name );
}
@Override
public int hashCode() {
return name.hashCode();
}
}
}

View File

@ -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.Properties;
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.EntityManagerFactoryBuilder;
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.secure.internal.JACCConfiguration;
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 class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 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 class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
}
}
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 class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
@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 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
}
}
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 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
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 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
// 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 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
@SuppressWarnings("unchecked")
private ScanResult scan(BootstrapServiceRegistry bootstrapServiceRegistry) {
Scanner scanner = locateOrBuildScanner( bootstrapServiceRegistry );
ScanningContext scanningContext = new ScanningContext();
final Scanner scanner = locateOrBuildScanner( bootstrapServiceRegistry );
final ScanOptions scanOptions = determineScanOptions();
final ScanResult scanResult = new ScanResult();
if ( persistenceUnit.getMappingFileNames() != null ) {
scanResult.getMappingFiles().addAll( persistenceUnit.getMappingFileNames() );
}
return scanner.scan( persistenceUnit, scanOptions );
}
// 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 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 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
}
}
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 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
//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 class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
}
}
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>();

View File

@ -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() );
}
}

View File

@ -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;
// }
}

View File

@ -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();
}
}

View File

@ -54,8 +54,8 @@ import org.xml.sax.SAXException;
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 class PersistenceXmlParser {
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 @@ public class PersistenceXmlParser {
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 );

View File

@ -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();
}
catch (Exception e) {
throw new HibernateException( "Could not open url stream : " + url.toExternalForm() );
}
}
@Override
public NamedInputStream asNamedInputStream() {
return new NamedInputStream( getStreamName(), accessInputStream() );
}
}

View File

@ -0,0 +1,67 @@
/*
* 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.scan.internal;
import org.hibernate.jpa.boot.scan.spi.ScanOptions;
/**
* @author Steve Ebersole
*/
public class StandardScanOptions implements ScanOptions {
private final boolean detectClassesInRoot;
private final boolean detectClassesInNonRoot;
private final boolean detectHibernateMappingFiles;
public StandardScanOptions() {
this( "hbm,class", false );
}
public StandardScanOptions(String explicitDetectionSetting, boolean persistenceUnitExcludeUnlistedClassesValue) {
if ( explicitDetectionSetting == null ) {
detectHibernateMappingFiles = true;
detectClassesInRoot = ! persistenceUnitExcludeUnlistedClassesValue;
detectClassesInNonRoot = true;
}
else {
detectHibernateMappingFiles = explicitDetectionSetting.contains( "hbm" );
detectClassesInRoot = explicitDetectionSetting.contains( "class" );
detectClassesInNonRoot = detectClassesInRoot;
}
}
@Override
public boolean canDetectUnlistedClassesInRoot() {
return detectClassesInRoot;
}
@Override
public boolean canDetectUnlistedClassesInNonRoot() {
return detectClassesInNonRoot;
}
@Override
public boolean canDetectHibernateMappingFiles() {
return detectHibernateMappingFiles;
}
}

View File

@ -0,0 +1,40 @@
/*
* 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.scan.internal;
import org.hibernate.jpa.boot.archive.internal.StandardArchiveDescriptorFactory;
import org.hibernate.jpa.boot.scan.spi.AbstractScannerImpl;
/**
* Standard implementation of the Scanner contract, supporting typical archive walking support where
* the urls we are processing can be treated using normal file handling.
*
* @author Steve Ebersole
* @author Emmanuel Bernard
*/
public class StandardScanner extends AbstractScannerImpl {
public StandardScanner() {
super( StandardArchiveDescriptorFactory.INSTANCE );
}
}

View File

@ -0,0 +1,302 @@
/*
* 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.scan.spi;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.hibernate.jpa.boot.archive.spi.ArchiveContext;
import org.hibernate.jpa.boot.archive.spi.ArchiveDescriptor;
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.internal.ClassDescriptorImpl;
import org.hibernate.jpa.boot.internal.MappingFileDescriptorImpl;
import org.hibernate.jpa.boot.internal.PackageDescriptorImpl;
import org.hibernate.jpa.boot.spi.ClassDescriptor;
import org.hibernate.jpa.boot.spi.MappingFileDescriptor;
import org.hibernate.jpa.boot.spi.PackageDescriptor;
import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor;
/**
* @author Steve Ebersole
*/
public abstract class AbstractScannerImpl implements Scanner {
private final ArchiveDescriptorFactory archiveDescriptorFactory;
private final Map<URL, ArchiveDescriptorInfo> archiveDescriptorCache = new HashMap<URL, ArchiveDescriptorInfo>();
protected AbstractScannerImpl(ArchiveDescriptorFactory archiveDescriptorFactory) {
this.archiveDescriptorFactory = archiveDescriptorFactory;
}
@Override
public ScanResult scan(PersistenceUnitDescriptor persistenceUnit, ScanOptions scanOptions) {
final ResultCollector resultCollector = new ResultCollector( scanOptions );
if ( persistenceUnit.getJarFileUrls() != null ) {
for ( URL url : persistenceUnit.getJarFileUrls() ) {
final ArchiveDescriptor descriptor = buildArchiveDescriptor( url, false, scanOptions );
final ArchiveContext context = buildArchiveContext( persistenceUnit, false, resultCollector );
descriptor.visitArchive( context );
}
}
if ( persistenceUnit.getPersistenceUnitRootUrl() != null ) {
final ArchiveDescriptor descriptor = buildArchiveDescriptor( persistenceUnit.getPersistenceUnitRootUrl(), true, scanOptions );
final ArchiveContext context = buildArchiveContext( persistenceUnit, false, resultCollector );
descriptor.visitArchive( context );
}
return ScanResultImpl.from( resultCollector );
}
private ArchiveContext buildArchiveContext(
PersistenceUnitDescriptor persistenceUnit,
boolean isRoot,
ArchiveEntryHandlers entryHandlers) {
return new ArchiveContextImpl( persistenceUnit, isRoot, entryHandlers );
}
protected static interface ArchiveEntryHandlers {
public ArchiveEntryHandler getClassFileHandler();
public ArchiveEntryHandler getPackageInfoHandler();
public ArchiveEntryHandler getFileHandler();
}
private ArchiveDescriptor buildArchiveDescriptor(URL url, boolean isRootUrl, ScanOptions scanOptions) {
final ArchiveDescriptor descriptor;
final ArchiveDescriptorInfo descriptorInfo = archiveDescriptorCache.get( url );
if ( descriptorInfo == null ) {
descriptor = archiveDescriptorFactory.buildArchiveDescriptor( url );
archiveDescriptorCache.put(
url,
new ArchiveDescriptorInfo( descriptor, isRootUrl, scanOptions )
);
}
else {
validateReuse( descriptorInfo, isRootUrl, scanOptions );
descriptor = descriptorInfo.archiveDescriptor;
}
return descriptor;
}
public static class ResultCollector
implements ArchiveEntryHandlers,
PackageInfoArchiveEntryHandler.Callback,
ClassFileArchiveEntryHandler.Callback,
NonClassFileArchiveEntryHandler.Callback {
private final ClassFileArchiveEntryHandler classFileHandler;
private final PackageInfoArchiveEntryHandler packageInfoHandler;
private final NonClassFileArchiveEntryHandler fileHandler;
private final Set<PackageDescriptor> packageDescriptorSet = new HashSet<PackageDescriptor>();
private final Set<ClassDescriptor> classDescriptorSet = new HashSet<ClassDescriptor>();
private final Set<MappingFileDescriptor> mappingFileSet = new HashSet<MappingFileDescriptor>();
public ResultCollector(ScanOptions scanOptions) {
this.classFileHandler = new ClassFileArchiveEntryHandler( scanOptions, this );
this.packageInfoHandler = new PackageInfoArchiveEntryHandler( scanOptions, this );
this.fileHandler = new NonClassFileArchiveEntryHandler( scanOptions, this );
}
@Override
public ArchiveEntryHandler getClassFileHandler() {
return classFileHandler;
}
@Override
public ArchiveEntryHandler getPackageInfoHandler() {
return packageInfoHandler;
}
@Override
public ArchiveEntryHandler getFileHandler() {
return fileHandler;
}
@Override
public void locatedPackage(PackageDescriptor packageDescriptor) {
if ( PackageDescriptorImpl.class.isInstance( packageDescriptor ) ) {
packageDescriptorSet.add( packageDescriptor );
}
else {
// to make sure we have proper equals/hashcode
packageDescriptorSet.add(
new PackageDescriptorImpl(
packageDescriptor.getName(),
packageDescriptor.getStreamAccess()
)
);
}
}
@Override
public void locatedClass(ClassDescriptor classDescriptor) {
if ( ClassDescriptorImpl.class.isInstance( classDescriptor ) ) {
classDescriptorSet.add( classDescriptor );
}
else {
// to make sure we have proper equals/hashcode
classDescriptorSet.add(
new ClassDescriptorImpl(
classDescriptor.getName(),
classDescriptor.getStreamAccess()
)
);
}
}
@Override
public void locatedMappingFile(MappingFileDescriptor mappingFileDescriptor) {
if ( MappingFileDescriptorImpl.class.isInstance( mappingFileDescriptor ) ) {
mappingFileSet.add( mappingFileDescriptor );
}
else {
// to make sure we have proper equals/hashcode
mappingFileSet.add(
new MappingFileDescriptorImpl(
mappingFileDescriptor.getName(),
mappingFileDescriptor.getStreamAccess()
)
);
}
}
public Set<PackageDescriptor> getPackageDescriptorSet() {
return packageDescriptorSet;
}
public Set<ClassDescriptor> getClassDescriptorSet() {
return classDescriptorSet;
}
public Set<MappingFileDescriptor> getMappingFileSet() {
return mappingFileSet;
}
}
private static class ArchiveDescriptorInfo {
private final ArchiveDescriptor archiveDescriptor;
private final boolean isRoot;
private final ScanOptions scanOptions;
private ArchiveDescriptorInfo(
ArchiveDescriptor archiveDescriptor,
boolean isRoot,
ScanOptions scanOptions) {
this.archiveDescriptor = archiveDescriptor;
this.isRoot = isRoot;
this.scanOptions = scanOptions;
}
}
protected void validateReuse(ArchiveDescriptorInfo descriptor, boolean root, ScanOptions options) {
// is it really reasonable that a single url be processed multiple times?
// for now, throw an exception, mainly because I am interested in situations where this might happen
throw new IllegalStateException( "ArchiveDescriptor reused; can URLs be processed multiple times?" );
}
public static class ArchiveContextImpl implements ArchiveContext {
private final PersistenceUnitDescriptor persistenceUnitDescriptor;
private final boolean isRootUrl;
private final ArchiveEntryHandlers entryHandlers;
public ArchiveContextImpl(
PersistenceUnitDescriptor persistenceUnitDescriptor,
boolean isRootUrl,
ArchiveEntryHandlers entryHandlers) {
this.persistenceUnitDescriptor = persistenceUnitDescriptor;
this.isRootUrl = isRootUrl;
this.entryHandlers = entryHandlers;
}
@Override
public PersistenceUnitDescriptor getPersistenceUnitDescriptor() {
return persistenceUnitDescriptor;
}
@Override
public boolean isRootUrl() {
return isRootUrl;
}
@Override
public ArchiveEntryHandler obtainArchiveEntryHandler(ArchiveEntry entry) {
final String nameWithinArchive = entry.getNameWithinArchive();
if ( nameWithinArchive.endsWith( "package-info.class" ) ) {
return entryHandlers.getPackageInfoHandler();
}
else if ( nameWithinArchive.endsWith( ".class" ) ) {
return entryHandlers.getClassFileHandler();
}
else {
return entryHandlers.getFileHandler();
}
}
}
private static class ScanResultImpl implements ScanResult {
private final Set<PackageDescriptor> packageDescriptorSet;
private final Set<ClassDescriptor> classDescriptorSet;
private final Set<MappingFileDescriptor> mappingFileSet;
private ScanResultImpl(
Set<PackageDescriptor> packageDescriptorSet,
Set<ClassDescriptor> classDescriptorSet,
Set<MappingFileDescriptor> mappingFileSet) {
this.packageDescriptorSet = packageDescriptorSet;
this.classDescriptorSet = classDescriptorSet;
this.mappingFileSet = mappingFileSet;
}
private static ScanResult from(ResultCollector resultCollector) {
return new ScanResultImpl(
Collections.unmodifiableSet( resultCollector.packageDescriptorSet ),
Collections.unmodifiableSet( resultCollector.classDescriptorSet ),
Collections.unmodifiableSet( resultCollector.mappingFileSet )
);
}
@Override
public Set<PackageDescriptor> getLocatedPackages() {
return packageDescriptorSet;
}
@Override
public Set<ClassDescriptor> getLocatedClasses() {
return classDescriptorSet;
}
@Override
public Set<MappingFileDescriptor> getLocatedMappingFiles() {
return mappingFileSet;
}
}
}

View File

@ -0,0 +1,132 @@
/*
* 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.scan.spi;
import javax.persistence.Converter;
import javax.persistence.Embeddable;
import javax.persistence.Entity;
import javax.persistence.MappedSuperclass;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import javassist.bytecode.AnnotationsAttribute;
import javassist.bytecode.ClassFile;
import org.hibernate.jpa.boot.archive.spi.ArchiveContext;
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.boot.internal.ClassDescriptorImpl;
import org.hibernate.jpa.boot.scan.spi.ScanOptions;
import org.hibernate.jpa.boot.spi.ClassDescriptor;
/**
* @author Steve Ebersole
*/
public class ClassFileArchiveEntryHandler implements ArchiveEntryHandler {
private final ScanOptions scanOptions;
private final Callback callback;
public static interface Callback {
public void locatedClass(ClassDescriptor classDescriptor);
}
public ClassFileArchiveEntryHandler(ScanOptions scanOptions, Callback callback) {
this.scanOptions = scanOptions;
this.callback = callback;
}
@Override
public void handleEntry(ArchiveEntry entry, ArchiveContext context) {
final ClassFile classFile = toClassFile( entry );
final ClassDescriptor classDescriptor = toClassDescriptor( classFile, entry );
if ( ! context.getPersistenceUnitDescriptor().getManagedClassNames().contains( classDescriptor.getName() ) ) {
if ( context.isRootUrl() ) {
if ( ! scanOptions.canDetectUnlistedClassesInRoot() ) {
return;
}
}
else {
if ( ! scanOptions.canDetectUnlistedClassesInNonRoot() ) {
return;
}
}
}
// we are only interested in classes with certain annotations, so see if the ClassDescriptor
// represents a class which contains any of those annotations
if ( ! containsClassAnnotationsOfInterest( classFile ) ) {
return;
}
notifyMatchedClass( classDescriptor );
}
private ClassFile toClassFile(ArchiveEntry entry) {
final InputStream inputStream = entry.getStreamAccess().accessInputStream();
final DataInputStream dataInputStream = new DataInputStream( inputStream );
try {
return new ClassFile( dataInputStream );
}
catch (IOException e) {
throw new ArchiveException( "Could not build ClassFile" );
}
finally {
try {
dataInputStream.close();
}
catch (Exception ignore) {
}
try {
inputStream.close();
}
catch (IOException ignore) {
}
}
}
@SuppressWarnings("SimplifiableIfStatement")
private boolean containsClassAnnotationsOfInterest(ClassFile cf) {
final AnnotationsAttribute visibleAnnotations = (AnnotationsAttribute) cf.getAttribute( AnnotationsAttribute.visibleTag );
if ( visibleAnnotations == null ) {
return false;
}
return visibleAnnotations.getAnnotation( Entity.class.getName() ) != null
|| visibleAnnotations.getAnnotation( MappedSuperclass.class.getName() ) != null
|| visibleAnnotations.getAnnotation( Embeddable.class.getName() ) != null
|| visibleAnnotations.getAnnotation( Converter.class.getName() ) != null;
}
protected ClassDescriptor toClassDescriptor(ClassFile classFile, ArchiveEntry entry) {
return new ClassDescriptorImpl( classFile.getName(), entry.getStreamAccess() );
}
protected final void notifyMatchedClass(ClassDescriptor classDescriptor) {
callback.locatedClass( classDescriptor );
}
}

View File

@ -0,0 +1,82 @@
/*
* 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.scan.spi;
import org.hibernate.jpa.boot.archive.spi.ArchiveContext;
import org.hibernate.jpa.boot.archive.spi.ArchiveEntry;
import org.hibernate.jpa.boot.archive.spi.ArchiveEntryHandler;
import org.hibernate.jpa.boot.internal.MappingFileDescriptorImpl;
import org.hibernate.jpa.boot.spi.MappingFileDescriptor;
/**
* @author Steve Ebersole
*/
public class NonClassFileArchiveEntryHandler implements ArchiveEntryHandler {
private final ScanOptions scanOptions;
private final Callback callback;
public static interface Callback {
public void locatedMappingFile(MappingFileDescriptor mappingFileDescriptor);
}
public NonClassFileArchiveEntryHandler(ScanOptions scanOptions, Callback callback) {
this.scanOptions = scanOptions;
this.callback = callback;
}
@Override
public void handleEntry(ArchiveEntry entry, ArchiveContext context) {
if ( acceptAsMappingFile( entry, context) ) {
notifyMatchedMappingFile( entry );
}
}
@SuppressWarnings("SimplifiableIfStatement")
private boolean acceptAsMappingFile(ArchiveEntry entry, ArchiveContext context) {
if ( entry.getName().endsWith( "hbm.xml" ) ) {
return scanOptions.canDetectHibernateMappingFiles();
}
// todo : should really do this case-insensitively
if ( entry.getName().endsWith( "META-INF/orm.xml" ) ) {
if ( context.getPersistenceUnitDescriptor().getMappingFileNames().contains( "META-INF/orm.xml" ) ) {
// if the user explicitly listed META-INF/orm.xml, only except the root one
//
// not sure why exactly, but this is what the old code does
return context.isRootUrl();
}
return true;
}
return context.getPersistenceUnitDescriptor().getMappingFileNames().contains( entry.getNameWithinArchive() );
}
protected final void notifyMatchedMappingFile(ArchiveEntry entry) {
callback.locatedMappingFile( toMappingFileDescriptor( entry ) );
}
protected MappingFileDescriptor toMappingFileDescriptor(ArchiveEntry entry) {
return new MappingFileDescriptorImpl( entry.getNameWithinArchive(), entry.getStreamAccess() );
}
}

View File

@ -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.scan.spi;
import org.hibernate.jpa.boot.archive.spi.ArchiveContext;
import org.hibernate.jpa.boot.archive.spi.ArchiveEntry;
import org.hibernate.jpa.boot.archive.spi.ArchiveEntryHandler;
import org.hibernate.jpa.boot.internal.PackageDescriptorImpl;
import org.hibernate.jpa.boot.spi.PackageDescriptor;
import static java.io.File.separatorChar;
/**
* @author Steve Ebersole
*/
public class PackageInfoArchiveEntryHandler implements ArchiveEntryHandler {
@SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
private final ScanOptions scanOptions;
private final Callback callback;
public static interface Callback {
public void locatedPackage(PackageDescriptor packageDescriptor);
}
public PackageInfoArchiveEntryHandler(ScanOptions scanOptions, Callback callback) {
this.scanOptions = scanOptions;
this.callback = callback;
}
@Override
public void handleEntry(ArchiveEntry entry, ArchiveContext context) {
if ( entry.getNameWithinArchive().equals( "package-info.class" ) ) {
// the old code skipped package-info in the root package/dir...
return;
}
notifyMatchedPackage( toPackageDescriptor( entry ) );
}
protected PackageDescriptor toPackageDescriptor(ArchiveEntry entry) {
final String packageInfoFilePath = entry.getNameWithinArchive();
final String packageName = packageInfoFilePath.substring( 0, packageInfoFilePath.lastIndexOf( '/' ) )
.replace( separatorChar, '.' );
return new PackageDescriptorImpl( packageName, entry.getStreamAccess() );
}
protected final void notifyMatchedPackage(PackageDescriptor packageDescriptor) {
callback.locatedPackage( packageDescriptor );
}
}

View File

@ -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,14 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.jpa.packaging.internal;
package org.hibernate.jpa.boot.scan.spi;
/**
* Filter on pachage element
*
* @author Emmanuel Bernard
* @see JavaElementFilter
* @author Steve Ebersole
*/
public abstract class PackageFilter extends JavaElementFilter {
/**
* @see JavaElementFilter#JavaElementFilter(boolean, Class[])
*/
protected PackageFilter(boolean retrieveStream, Class[] annotations) {
super( retrieveStream, annotations );
}
}
public interface ScanOptions {
public boolean canDetectUnlistedClassesInRoot();
public boolean canDetectUnlistedClassesInNonRoot();
public boolean canDetectHibernateMappingFiles();
}

View File

@ -0,0 +1,41 @@
/*
* 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.scan.spi;
import java.util.Set;
import org.hibernate.jpa.boot.spi.ClassDescriptor;
import org.hibernate.jpa.boot.spi.MappingFileDescriptor;
import org.hibernate.jpa.boot.spi.PackageDescriptor;
/**
* Defines the result of scanning
*
* @author Steve Ebersole
*/
public interface ScanResult {
public Set<PackageDescriptor> getLocatedPackages();
public Set<ClassDescriptor> getLocatedClasses();
public Set<MappingFileDescriptor> getLocatedMappingFiles();
}

View File

@ -0,0 +1,46 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, 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.scan.spi;
import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor;
/**
* Defines the contract for Hibernate to be able to scan for classes, packages and resources inside a
* persistence unit.
*
* @author Emmanuel Bernard
* @author Steve Ebersole
*/
public interface Scanner {
/**
* Perform the scanning against the described persistence unit using the defined options, and return the scan
* results.
*
* @param persistenceUnit THe description of the persistence unit.
* @param options The scan options
*
* @return The scan results.
*/
public ScanResult scan(PersistenceUnitDescriptor persistenceUnit, ScanOptions options);
}

View File

@ -0,0 +1,34 @@
/*
* 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.spi;
/**
* Defines the result of scanning a persistence unit for classes.
*
* @author Steve Ebersole
*/
public interface ClassDescriptor {
public String getName();
public InputStreamAccess getStreamAccess();
}

View File

@ -0,0 +1,52 @@
/*
* 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.spi;
import java.io.InputStream;
/**
* Contract for building InputStreams, especially in on-demand situations
*
* @author Steve Ebersole
*/
public interface InputStreamAccess {
/**
* Get the name of the resource backing the stream
*
* @return The backing resource name
*/
public String getStreamName();
/**
* Get access to the stream. Can be called multiple times, a different stream instance should be returned each time.
*
* @return The stream
*/
public InputStream accessInputStream();
/**
* @deprecated Needed until we can remove NamedInputStream
*/
public NamedInputStream asNamedInputStream();
}

View File

@ -0,0 +1,32 @@
/*
* 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.spi;
/**
* @author Steve Ebersole
*/
public interface MappingFileDescriptor {
public String getName();
public InputStreamAccess getStreamAccess();
}

View File

@ -21,34 +21,33 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.jpa.packaging.spi;
package org.hibernate.jpa.boot.spi;
import java.io.InputStream;
/**
* Bundles together a stream and the name that was used to locate it. The name is often useful for logging.
*
* @deprecated Use {@link org.hibernate.jpa.boot.spi.InputStreamAccess} instead.
*
* @author Emmanuel Bernard
* @author Steve Ebersole
*/
@Deprecated
public class NamedInputStream {
private final String name;
private final InputStream stream;
public NamedInputStream(String name, InputStream stream) {
this.name = name;
this.stream = stream;
}
private String name;
private InputStream stream;
public InputStream getStream() {
return stream;
}
public void setStream(InputStream stream) {
this.stream = stream;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@ -0,0 +1,34 @@
/*
* 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.spi;
/**
* Defines the result of scanning a persistence unit for packages.
*
* @author Steve Ebersole
*/
public interface PackageDescriptor {
public String getName();
public InputStreamAccess getStreamAccess();
}

View File

@ -1,262 +0,0 @@
/*
* Copyright (c) 2009, Red Hat Middleware LLC 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.
*
* 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.packaging.internal;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javassist.bytecode.AnnotationsAttribute;
import javassist.bytecode.ClassFile;
import org.jboss.logging.Logger;
import org.hibernate.jpa.internal.EntityManagerMessageLogger;
/**
* Parse a JAR of any form (zip file, exploded directory, ...)
* apply a set of filters (File filter, Class filter, Package filter)
* and return the appropriate matching sets of elements
*
* @author Emmanuel Bernard
*/
public abstract class AbstractJarVisitor implements JarVisitor {
//TODO shortcut when filters are null or empty
private static final EntityManagerMessageLogger LOG = Logger.getMessageLogger(EntityManagerMessageLogger.class,
AbstractJarVisitor.class.getName());
protected String unqualifiedJarName;
protected URL jarUrl;
protected boolean done = false;
private List<Filter> filters = new ArrayList<Filter>();
private Set<FileFilter> fileFilters = new HashSet<FileFilter>();
private Set<JavaElementFilter> classFilters = new HashSet<JavaElementFilter>();
private Set<JavaElementFilter> packageFilters = new HashSet<JavaElementFilter>();
private Set[] entries;
/**
* Build a jar visitor from its jar string path
*/
private AbstractJarVisitor(String jarPath) {
this.jarUrl = JarVisitorFactory.getURLFromPath( jarPath );
unqualify();
}
protected AbstractJarVisitor(String fileName, Filter[] filters) {
this( fileName );
initFilters( filters );
}
private void initFilters(Filter[] filters) {
for ( Filter filter : filters ) {
if ( filter instanceof FileFilter ) {
fileFilters.add( (FileFilter) filter );
}
else if ( filter instanceof ClassFilter ) {
classFilters.add( (ClassFilter) filter );
}
else if ( filter instanceof PackageFilter ) {
packageFilters.add( (PackageFilter) filter );
}
else {
throw new AssertionError( "Unknown filter type: " + filter.getClass().getName() );
}
this.filters.add( filter );
}
int size = this.filters.size();
this.entries = new Set[ size ];
for ( int index = 0; index < size ; index++ ) {
this.entries[index] = new HashSet<Entry>();
}
}
protected AbstractJarVisitor(URL url, Filter[] filters) {
this( url );
initFilters( filters );
}
private AbstractJarVisitor(URL url) {
jarUrl = url;
unqualify();
}
protected void unqualify() {
//FIXME weak algorithm subject to AOOBE
String fileName = jarUrl.getFile();
int exclamation = fileName.lastIndexOf( "!" );
if (exclamation != -1) fileName = fileName.substring( 0, exclamation );
int slash = fileName.lastIndexOf( "/" );
if ( slash != -1 ) {
fileName = fileName.substring(
fileName.lastIndexOf( "/" ) + 1,
fileName.length()
);
}
if ( fileName.length() > 4 && fileName.endsWith( "ar" ) && fileName.charAt( fileName.length() - 4 ) == '.' ) {
fileName = fileName.substring( 0, fileName.length() - 4 );
}
unqualifiedJarName = fileName;
LOG.debugf("Searching mapped entities in jar/par: %s", jarUrl);
}
/**
* Get the unqualified Jar name (ie wo path and wo extension)
*/
public String getUnqualifiedJarName() {
return unqualifiedJarName;
}
public Filter[] getFilters() {
return filters.toArray( new Filter[ filters.size() ] );
}
/**
* Return the matching entries for each filter in the same order the filter where passed
*
* @return array of Set of JarVisitor.Entry
* @throws IOException if something went wrong
*/
public Set[] getMatchingEntries() throws IOException {
if ( !done ) {
//avoid url access and so on
if ( filters.size() > 0 ) doProcessElements();
done = true;
}
return entries;
}
protected abstract void doProcessElements() throws IOException;
//TODO avoid 2 input stream when not needed
protected final void addElement(String entryName, InputStream is, InputStream secondIs) throws IOException {
int entryNameLength = entryName.length();
if ( entryName.endsWith( "package-info.class" ) ) {
String name;
if ( entryNameLength == "package-info.class".length() ) {
name = "";
}
else {
name = entryName.substring( 0, entryNameLength - ".package-info.class".length() ).replace( '/', '.' );
}
executeJavaElementFilter( name, packageFilters, is, secondIs );
}
else if ( entryName.endsWith( ".class" ) ) {
String name = entryName.substring( 0, entryNameLength - ".class".length() ).replace( '/', '.' );
LOG.debugf("Filtering: %s", name);
executeJavaElementFilter( name, classFilters, is, secondIs );
}
else {
String name = entryName;
boolean accepted = false;
for ( FileFilter filter : fileFilters ) {
if ( filter.accept( name ) ) {
accepted = true;
InputStream localIs;
if ( filter.getStream() ) {
localIs = secondIs;
}
else {
localIs = null;
secondIs.close();
}
is.close();
LOG.debugf("File Filter matched for %s", name);
Entry entry = new Entry( name, localIs );
int index = this.filters.indexOf( filter );
this.entries[index].add( entry );
}
}
if (!accepted) {
//not accepted free resources
is.close();
secondIs.close();
}
}
}
private void executeJavaElementFilter(
String name, Set<JavaElementFilter> filters, InputStream is, InputStream secondIs
) throws IOException {
boolean accepted = false;
for ( JavaElementFilter filter : filters ) {
if ( filter.accept( name ) ) {
//FIXME cannot currently have a class filtered twice but matching once
// need to copy the is
boolean match = checkAnnotationMatching( is, filter );
if ( match ) {
accepted = true;
InputStream localIs;
if ( filter.getStream() ) {
localIs = secondIs;
}
else {
localIs = null;
secondIs.close();
}
LOG.debugf("Java element filter matched for %s", name);
Entry entry = new Entry( name, localIs );
int index = this.filters.indexOf( filter );
this.entries[index].add( entry );
break; //we matched
}
}
}
if (!accepted) {
is.close();
secondIs.close();
}
}
private boolean checkAnnotationMatching(InputStream is, JavaElementFilter filter) throws IOException {
if ( filter.getAnnotations().length == 0 ) {
is.close();
return true;
}
DataInputStream dstream = new DataInputStream( is );
ClassFile cf = null;
try {
cf = new ClassFile( dstream );
}
finally {
dstream.close();
is.close();
}
boolean match = false;
AnnotationsAttribute visible = (AnnotationsAttribute) cf.getAttribute( AnnotationsAttribute.visibleTag );
if ( visible != null ) {
for ( Class annotation : filter.getAnnotations() ) {
match = visible.getAnnotation( annotation.getName() ) != null;
if ( match ) break;
}
}
return match;
}
}

View File

@ -1,138 +0,0 @@
/*
* Copyright (c) 2009, Red Hat Middleware LLC 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.
*
* 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.packaging.internal;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
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.internal.EntityManagerMessageLogger;
/**
* @author Emmanuel Bernard
*/
public class ExplodedJarVisitor extends AbstractJarVisitor {
private static final EntityManagerMessageLogger LOG = Logger.getMessageLogger(EntityManagerMessageLogger.class,
ExplodedJarVisitor.class.getName());
private String entry;
public ExplodedJarVisitor(URL url, Filter[] filters, String entry) {
super( url, filters );
this.entry = entry;
}
public ExplodedJarVisitor(String fileName, Filter[] filters) {
super( fileName, filters );
}
@Override
protected void doProcessElements() throws IOException {
File jarFile;
try {
String filePart = jarUrl.getFile();
if ( filePart != null && filePart.indexOf( ' ' ) != -1 ) {
//unescaped (from the container), keep as is
jarFile = new File( jarUrl.getFile() );
}
else {
jarFile = new File( jarUrl.toURI().getSchemeSpecificPart() );
}
}
catch (URISyntaxException e) {
LOG.malformedUrl(jarUrl, e);
return;
}
if ( !jarFile.exists() ) {
LOG.explodedJarDoesNotExist(jarUrl);
return;
}
if ( !jarFile.isDirectory() ) {
LOG.explodedJarNotDirectory(jarUrl);
return;
}
File rootFile;
if (entry != null && entry.length() > 0 && ! "/".equals( entry ) ) {
rootFile = new File(jarFile, entry);
}
else {
rootFile = jarFile;
}
if ( rootFile.isDirectory() ) {
getClassNamesInTree( rootFile, null );
}
else {
//assume zipped file
processZippedRoot(rootFile);
}
}
//FIXME shameful copy of FileZippedJarVisitor.doProcess()
//TODO long term fix is to introduce a process interface (closure like) to addElements and then share the code
private void processZippedRoot(File rootFile) throws IOException {
JarFile jarFile = new JarFile(rootFile);
Enumeration<? extends ZipEntry> entries = jarFile.entries();
while ( entries.hasMoreElements() ) {
ZipEntry zipEntry = entries.nextElement();
String name = zipEntry.getName();
if ( !zipEntry.isDirectory() ) {
//build relative name
if ( name.startsWith( "/" ) ) name = name.substring( 1 );
addElement(
name,
new BufferedInputStream( jarFile.getInputStream( zipEntry ) ),
new BufferedInputStream( jarFile.getInputStream( zipEntry ) )
);
}
}
}
private void getClassNamesInTree(File jarFile, String header) throws IOException {
File[] files = jarFile.listFiles();
header = header == null ? "" : header + "/";
for ( File localFile : files ) {
if ( !localFile.isDirectory() ) {
String entryName = localFile.getName();
addElement(
header + entryName,
new BufferedInputStream( new FileInputStream( localFile ) ),
new BufferedInputStream( new FileInputStream( localFile ) )
);
}
else {
getClassNamesInTree( localFile, header + localFile.getName() );
}
}
}
}

View File

@ -1,133 +0,0 @@
/*
* Copyright (c) 2009, Red Hat Middleware LLC 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.
*
* 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.packaging.internal;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
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.internal.EntityManagerMessageLogger;
/**
* Work on a JAR that can be accessed through a File
*
* @author Emmanuel Bernard
*/
public class FileZippedJarVisitor extends AbstractJarVisitor {
private static final EntityManagerMessageLogger LOG = Logger.getMessageLogger(EntityManagerMessageLogger.class,
FileZippedJarVisitor.class.getName());
private String entry;
public FileZippedJarVisitor(String fileName, Filter[] filters) {
super( fileName, filters );
}
public FileZippedJarVisitor(URL url, Filter[] filters, String entry) {
super( url, filters );
this.entry = entry;
}
@Override
protected void doProcessElements() throws IOException {
JarFile jarFile;
try {
String filePart = jarUrl.getFile();
if ( filePart != null && filePart.indexOf( ' ' ) != -1 ) {
//unescaped (from the container), keep as is
jarFile = new JarFile( jarUrl.getFile() );
}
else {
jarFile = new JarFile( jarUrl.toURI().getSchemeSpecificPart() );
}
}
catch (IOException ze) {
LOG.unableToFindFile(jarUrl, ze);
return;
}
catch (URISyntaxException e) {
LOG.malformedUrlWarning(jarUrl, e);
return;
}
if ( entry != null && entry.length() == 1 ) entry = null; //no entry
if ( entry != null && entry.startsWith( "/" ) ) entry = entry.substring( 1 ); //remove '/' header
Enumeration<? extends ZipEntry> entries = jarFile.entries();
while ( entries.hasMoreElements() ) {
ZipEntry zipEntry = entries.nextElement();
String name = zipEntry.getName();
if ( entry != null && ! name.startsWith( entry ) ) continue; //filter it out
if ( !zipEntry.isDirectory() ) {
if ( name.equals( entry ) ) {
//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
*/
InputStream is = null;
try {
is = new BufferedInputStream( jarFile.getInputStream( zipEntry ) );
JarInputStream jis = new JarInputStream( is );
ZipEntry subZipEntry = jis.getNextEntry();
while (subZipEntry != null) {
if ( ! subZipEntry.isDirectory() ) {
//FIXME copy sucks
byte[] entryBytes = JarVisitorFactory.getBytesFromInputStream( jis );
String subname = subZipEntry.getName();
if ( subname.startsWith( "/" ) ) subname = subname.substring( 1 );
addElement(
subname,
new ByteArrayInputStream(entryBytes),
new ByteArrayInputStream(entryBytes)
);
}
subZipEntry = jis.getNextEntry();
}
}
finally {
if ( is != null) is.close();
}
}
else {
//build relative name
if (entry != null) name = name.substring( entry.length() );
if ( name.startsWith( "/" ) ) name = name.substring( 1 );
addElement(
name,
new BufferedInputStream( jarFile.getInputStream( zipEntry ) ),
new BufferedInputStream( jarFile.getInputStream( zipEntry ) )
);
}
}
}
}
}

View File

@ -1,121 +0,0 @@
/*
* Copyright (c) 2009, Red Hat Middleware LLC 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.
*
* 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.packaging.internal;
import java.io.ByteArrayInputStream;
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.internal.EntityManagerMessageLogger;
/**
* Work on a JAR that can only be accessed through a inputstream
* This is less efficient than the {@link FileZippedJarVisitor}
*
* @author Emmanuel Bernard
*/
public class InputStreamZippedJarVisitor extends AbstractJarVisitor {
private static final EntityManagerMessageLogger LOG = Logger.getMessageLogger(EntityManagerMessageLogger.class,
InputStreamZippedJarVisitor.class.getName());
private String entry;
public InputStreamZippedJarVisitor(URL url, Filter[] filters, String entry) {
super( url, filters );
this.entry = entry;
}
public InputStreamZippedJarVisitor(String fileName, Filter[] filters) {
super( fileName, filters );
}
@Override
protected void doProcessElements() throws IOException {
JarInputStream jis;
try {
jis = new JarInputStream( jarUrl.openStream() );
}
catch (Exception ze) {
//really should catch IOException but Eclipse is buggy and raise NPE...
LOG.unableToFindFile(jarUrl, ze);
return;
}
if ( entry != null && entry.length() == 1 ) entry = null; //no entry
if ( entry != null && entry.startsWith( "/" ) ) entry = entry.substring( 1 ); //remove '/' header
JarEntry jarEntry;
while ( ( jarEntry = jis.getNextJarEntry() ) != null ) {
String name = jarEntry.getName();
if ( entry != null && ! name.startsWith( entry ) ) continue; //filter it out
if ( !jarEntry.isDirectory() ) {
if ( name.equals( entry ) ) {
//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
*/
JarInputStream subJis = null;
try {
subJis = new JarInputStream( jis );
ZipEntry subZipEntry = jis.getNextEntry();
while (subZipEntry != null) {
if ( ! subZipEntry.isDirectory() ) {
//FIXME copy sucks
byte[] entryBytes = JarVisitorFactory.getBytesFromInputStream( jis );
String subname = subZipEntry.getName();
if ( subname.startsWith( "/" ) ) subname = subname.substring( 1 );
addElement(
subname,
new ByteArrayInputStream(entryBytes),
new ByteArrayInputStream(entryBytes)
);
}
subZipEntry = jis.getNextJarEntry();
}
}
finally {
if (subJis != null) subJis.close();
}
}
else {
byte[] entryBytes = JarVisitorFactory.getBytesFromInputStream( jis );
//build relative name
if (entry != null) name = name.substring( entry.length() );
if ( name.startsWith( "/" ) ) name = name.substring( 1 );
//this is bad cause we actually read everything instead of walking it lazily
addElement(
name,
new ByteArrayInputStream( entryBytes ),
new ByteArrayInputStream( entryBytes )
);
}
}
}
jis.close();
}
}

View File

@ -1,73 +0,0 @@
/*
* Copyright (c) 2009, Red Hat Middleware LLC 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.
*
* 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.packaging.internal;
import java.io.IOException;
import java.net.URL;
import java.util.Set;
import org.hibernate.annotations.common.AssertionFailure;
/**
* @author Emmanuel Bernard
*/
public class JarProtocolVisitor implements JarVisitor {
private JarVisitor delegate;
private URL jarUrl;
private Filter[] filters;
public JarProtocolVisitor(URL url, Filter[] filters, String entry) {
this.jarUrl = url;
this.filters = filters;
if (entry != null && entry.length() > 0) throw new IllegalArgumentException( "jar:jar: not supported: " + jarUrl );
init();
}
private void init() {
String file = jarUrl.getFile();
String entry;
int subEntryIndex = file.lastIndexOf( "!" );
if (subEntryIndex == -1) throw new AssertionFailure("JAR URL does not contain '!/' :" + jarUrl);
if ( subEntryIndex + 1 >= file.length() ) {
entry = "";
}
else {
entry = file.substring( subEntryIndex + 1 );
}
URL fileUrl = JarVisitorFactory.getJarURLFromURLEntry( jarUrl, entry );
delegate = JarVisitorFactory.getVisitor( fileUrl, filters, entry );
}
public String getUnqualifiedJarName() {
return delegate.getUnqualifiedJarName();
}
public Filter[] getFilters() {
return delegate.getFilters();
}
public Set[] getMatchingEntries() throws IOException {
return delegate.getMatchingEntries();
}
}

View File

@ -1,52 +0,0 @@
/*
* Copyright (c) 2009, Red Hat Middleware LLC 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.
*
* 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.packaging.internal;
/**
* Filter a Java element (class or package per fully qualified name and annotation existence)
* At least 1 annotation has to annotate the element and the accept method must match
* If none annotations are passed, only the accept method must pass.
*
* @author Emmanuel Bernard
*/
public abstract class JavaElementFilter extends Filter {
private Class[] annotations;
/**
* @param retrieveStream Give back an open stream to the matching element or not
* @param annotations Array of annotations that must be present to match (1 of them should annotate the element
*/
protected JavaElementFilter(boolean retrieveStream, Class[] annotations) {
super( retrieveStream );
this.annotations = annotations == null ? new Class[]{} : annotations;
}
public Class[] getAnnotations() {
return annotations;
}
/**
* Return true if the fully qualified name match
*/
public abstract boolean accept(String javaElementName);
}

View File

@ -1,248 +0,0 @@
/*
* Copyright (c) 2009, Red Hat Middleware LLC 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.
*
* 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.packaging.internal;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.persistence.Converter;
import javax.persistence.Embeddable;
import javax.persistence.Entity;
import javax.persistence.MappedSuperclass;
import org.hibernate.AssertionFailure;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.jpa.packaging.spi.NamedInputStream;
import org.hibernate.jpa.packaging.spi.Scanner;
/**
* @author Emmanuel Bernard
*/
public class NativeScanner implements Scanner {
private static final String META_INF_ORM_XML = "META-INF/orm.xml";
private Map<URL, StateJarVisitor> visitors = new HashMap<URL, StateJarVisitor>();
private static final int PACKAGE_FILTER_INDEX = 0;
private static final int CLASS_FILTER_INDEX = 1;
private static final int FILE_FILTER_INDEX = 2;
/**
* This implementation does not honor the list of annotations and return everything.
* Must strictly be used by HEM
*/
public Set<Package> getPackagesInJar(URL jarToScan, Set<Class<? extends Annotation>> annotationsToLookFor) {
if ( annotationsToLookFor.size() > 0 ) {
throw new AssertionFailure( "Improper use of NativeScanner: must not filter packages" );
}
JarVisitor jarVisitor = getVisitor( jarToScan );
final Set<Entry> packageEntries;
try {
packageEntries = ( Set<Entry> ) jarVisitor.getMatchingEntries()[PACKAGE_FILTER_INDEX];
}
catch ( IOException e ) {
throw new RuntimeException( "Error while reading " + jarToScan.toString(), e );
}
Set<Package> packages = new HashSet<Package>( packageEntries.size() );
for ( Entry entry : packageEntries ) {
try {
packages.add( ReflectHelper.classForName( entry.getName() + ".package-info" ).getPackage() );
}
catch ( ClassNotFoundException e ) {
//should never happen, if it happens, simply ignore the flawed package
}
}
return packages;
}
/**
* Build a JarVisitor with some assumptions wrt the scanning
* This helps do one scan instead of several
*/
private JarVisitor getVisitor(URL jar) {
StateJarVisitor stateJarVisitor = visitors.get( jar );
if ( stateJarVisitor == null ) {
Filter[] filters = new Filter[3];
filters[PACKAGE_FILTER_INDEX] = new PackageFilter( false, null ) {
public boolean accept(String javaElementName) {
return true;
}
};
filters[CLASS_FILTER_INDEX] = new ClassFilter(
false, new Class[] {
Entity.class,
MappedSuperclass.class,
Embeddable.class
}
) {
public boolean accept(String javaElementName) {
return true;
}
};
filters[FILE_FILTER_INDEX] = new FileFilter( true ) {
public boolean accept(String javaElementName) {
return javaElementName.endsWith( "hbm.xml" )
|| javaElementName.endsWith( META_INF_ORM_XML );
}
};
stateJarVisitor = new StateJarVisitor( JarVisitorFactory.getVisitor( jar, filters ) );
visitors.put( jar, stateJarVisitor );
}
return stateJarVisitor.visitor;
}
public Set<Class<?>> getClassesInJar(URL jarToScan, Set<Class<? extends Annotation>> annotationsToLookFor) {
if ( isValidForClasses( annotationsToLookFor ) ) {
throw new AssertionFailure(
"Improper use of NativeScanner: "
+ "must not filter classes by other annotations than Entity, MappedSuperclass, embeddable"
);
}
JarVisitor jarVisitor = getVisitor( jarToScan );
final Set<Entry> classesEntry;
try {
classesEntry = ( Set<Entry> ) jarVisitor.getMatchingEntries()[CLASS_FILTER_INDEX];
}
catch ( IOException e ) {
throw new RuntimeException( "Error while reading " + jarToScan.toString(), e );
}
Set<Class<?>> classes = new HashSet<Class<?>>( classesEntry.size() );
for ( Entry entry : classesEntry ) {
try {
classes.add( ReflectHelper.classForName( entry.getName() ) );
}
catch ( ClassNotFoundException e ) {
//should never happen, if it happens, simply ignore the flawed package
}
}
return classes;
}
private boolean isValidForClasses(Set<Class<? extends Annotation>> annotationsToLookFor) {
return annotationsToLookFor.size() != 4
|| !annotationsToLookFor.contains( Entity.class )
|| !annotationsToLookFor.contains( MappedSuperclass.class )
|| !annotationsToLookFor.contains( Embeddable.class )
|| !annotationsToLookFor.contains( Converter.class );
}
/**
* support for patterns is primitive:
* - **\/*.hbm.xml
* Other patterns will not be found
*/
public Set<NamedInputStream> getFilesInJar(URL jarToScan, Set<String> filePatterns) {
StringBuilder sb = new StringBuilder("URL: ").append( jarToScan )
.append( "\n" );
for (String pattern : filePatterns) {
sb.append( " " ).append( pattern ).append( "\n" );
}
JarVisitor jarVisitor = getVisitor( jarToScan );
//state visitor available
final StateJarVisitor stateVisitor = visitors.get( jarToScan );
if ( stateVisitor.hasReadFiles ) {
throw new AssertionFailure( "Cannot read files twice on NativeScanner" );
}
stateVisitor.hasReadFiles = true;
Set<String> endWiths = new HashSet<String>();
Set<String> exacts = new HashSet<String>();
for ( String pattern : filePatterns ) {
if ( pattern.startsWith( "**/*" ) ) {
final String patternTail = pattern.substring( 4, pattern.length() );
if ( !patternTail.equals( ".hbm.xml" ) ) {
throw new AssertionFailure(
"Improper use of NativeScanner: "
+ "must not filter files via pattern other than .hbm.xml"
);
}
endWiths.add( patternTail );
}
else {
exacts.add( pattern );
}
}
final Set<Entry> fileEntries;
try {
fileEntries = ( Set<Entry> ) jarVisitor.getMatchingEntries()[FILE_FILTER_INDEX];
}
catch ( IOException e ) {
throw new RuntimeException( "Error while reading " + jarToScan.toString(), e );
}
Set<NamedInputStream> files = new HashSet<NamedInputStream>( fileEntries.size() );
Set<Entry> leftOver = new HashSet<Entry>( fileEntries );
for ( Entry entry : fileEntries ) {
boolean done = false;
for ( String exact : exacts ) {
if ( entry.getName().equals( exact ) ) {
files.add( new NamedInputStream( entry.getName(), entry.getInputStream() ) );
leftOver.remove( entry );
done = true;
}
}
if (done) continue;
for ( String endWithPattern : endWiths ) {
if ( entry.getName().endsWith( endWithPattern ) ) {
files.add( new NamedInputStream( entry.getName(), entry.getInputStream() ) );
leftOver.remove( entry );
}
}
}
for ( Entry entry : leftOver ) {
try {
entry.getInputStream().close();
}
catch ( IOException e ) {
//swallow as we don't care about these files
}
}
return files;
}
public Set<NamedInputStream> getFilesInClasspath(Set<String> filePatterns) {
throw new AssertionFailure( "Not implemented" );
}
public String getUnqualifiedJarName(URL jarToScan) {
JarVisitor jarVisitor = getVisitor( jarToScan );
return jarVisitor.getUnqualifiedJarName();
}
private static class StateJarVisitor {
StateJarVisitor(JarVisitor visitor) {
this.visitor = visitor;
}
JarVisitor visitor;
boolean hasReadFiles = false;
}
}

View File

@ -1,67 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, 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.packaging.spi;
import java.lang.annotation.Annotation;
import java.net.URL;
import java.util.Set;
/**
* @author Emmanuel Bernard
*/
public interface Scanner {
/**
* return all packages in the jar matching one of these annotations
* if annotationsToLookFor is empty, return all packages
*/
Set<Package> getPackagesInJar(URL jartoScan, Set<Class<? extends Annotation>> annotationsToLookFor);
/**
* return all classes in the jar matching one of these annotations
* if annotationsToLookFor is empty, return all classes
*/
Set<Class<?>> getClassesInJar(URL jartoScan, Set<Class<? extends Annotation>> annotationsToLookFor);
/**
* return all files in the jar matching one of these file names
* if filePatterns is empty, return all files
* eg **\/*.hbm.xml, META-INF/orm.xml
*/
Set<NamedInputStream> getFilesInJar(URL jartoScan, Set<String> filePatterns);
/**
* Return all files in the classpath (ie PU visibility) matching one of these file names
* if filePatterns is empty, return all files
* the use case is really exact file name.
*
* NOT USED by HEM at the moment. We use exact file search via getResourceAsStream for now.
*/
Set<NamedInputStream> getFilesInClasspath(Set<String> filePatterns);
/**
* return the unqualified JAR name ie customer-model.jar or store.war
*/
String getUnqualifiedJarName(URL jarUrl);
}

View File

@ -0,0 +1,67 @@
package org.hibernate.jpa.test;
/*
* 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
*/
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import static java.io.File.separatorChar;
/**
* @author Steve Ebersole
*/
public class TestHelper {
private static URL RESOLVED_TEST_ROOT_URL;
public static URL determineTestRootUrl() {
if ( RESOLVED_TEST_ROOT_URL == null ) {
RESOLVED_TEST_ROOT_URL = resolveRootUrl( TestHelper.class );
}
return RESOLVED_TEST_ROOT_URL;
}
public static URL resolveRootUrl(Class knownClass) {
final String knownClassFileName = '/' + knownClass.getName().replace( '.', separatorChar ) + ".class";
final URL knownClassFileUrl = TestHelper.class.getResource( knownClassFileName );
final String knownClassFileUrlString = knownClassFileUrl.toExternalForm();
// to start, strip off the class file name
String rootUrlString = knownClassFileUrlString.substring( 0, knownClassFileUrlString.lastIndexOf( separatorChar ) );
// then strip off each package dir
final String packageName = knownClass.getPackage().getName();
for ( String packageNamePart : packageName.split( "\\." ) ) {
rootUrlString = rootUrlString.substring( 0, rootUrlString.lastIndexOf( separatorChar ) );
}
try {
return new URL( rootUrlString );
}
catch (MalformedURLException e) {
throw new RuntimeException( "Could not convert class base url as string to URL ref", e );
}
}
}

View File

@ -1,19 +1,17 @@
package org.hibernate.jpa.test.packaging;
import java.lang.annotation.Annotation;
import java.net.URL;
import java.util.Set;
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.spi.PersistenceUnitDescriptor;
import org.hibernate.jpa.boot.scan.internal.StandardScanner;
import org.hibernate.jpa.boot.scan.spi.ScanOptions;
import org.hibernate.jpa.boot.scan.spi.ScanResult;
import org.hibernate.jpa.boot.scan.spi.Scanner;
/**
* @author Emmanuel Bernard
*/
public class CustomScanner implements Scanner {
public static boolean isUsed = false;
private Scanner scanner = new NativeScanner();
private Scanner delegate = new StandardScanner();
public static boolean isUsed() {
return isUsed;
@ -23,28 +21,9 @@ public class CustomScanner implements Scanner {
isUsed = false;
}
public Set<Package> getPackagesInJar(URL jartoScan, Set<Class<? extends Annotation>> annotationsToLookFor) {
@Override
public ScanResult scan(PersistenceUnitDescriptor persistenceUnit, ScanOptions options) {
isUsed = true;
return scanner.getPackagesInJar( jartoScan, annotationsToLookFor );
}
public Set<Class<?>> getClassesInJar(URL jartoScan, Set<Class<? extends Annotation>> annotationsToLookFor) {
isUsed = true;
return scanner.getClassesInJar( jartoScan, annotationsToLookFor );
}
public Set<NamedInputStream> getFilesInJar(URL jartoScan, Set<String> filePatterns) {
isUsed = true;
return scanner.getFilesInJar( jartoScan, filePatterns );
}
public Set<NamedInputStream> getFilesInClasspath(Set<String> filePatterns) {
isUsed = true;
return scanner.getFilesInClasspath( filePatterns );
}
public String getUnqualifiedJarName(URL jarUrl) {
isUsed = true;
return scanner.getUnqualifiedJarName( jarUrl );
return delegate.scan( persistenceUnit, options );
}
}

View File

@ -23,12 +23,6 @@
*/
package org.hibernate.jpa.test.packaging;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
@ -38,29 +32,32 @@ import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;
import java.util.Set;
import javax.persistence.Embeddable;
import javax.persistence.Entity;
import javax.persistence.MappedSuperclass;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.jpa.packaging.internal.ClassFilter;
import org.hibernate.jpa.packaging.internal.Entry;
import org.hibernate.jpa.packaging.internal.ExplodedJarVisitor;
import org.hibernate.jpa.packaging.internal.FileFilter;
import org.hibernate.jpa.packaging.internal.FileZippedJarVisitor;
import org.hibernate.jpa.packaging.internal.Filter;
import org.hibernate.jpa.packaging.internal.InputStreamZippedJarVisitor;
import org.hibernate.jpa.packaging.internal.JarProtocolVisitor;
import org.hibernate.jpa.packaging.internal.JarVisitor;
import org.hibernate.jpa.packaging.internal.JarVisitorFactory;
import org.hibernate.jpa.packaging.internal.PackageFilter;
import org.hibernate.jpa.boot.archive.internal.ArchiveHelper;
import org.hibernate.jpa.boot.archive.internal.ExplodedArchiveDescriptor;
import org.hibernate.jpa.boot.archive.internal.JarFileBasedArchiveDescriptor;
import org.hibernate.jpa.boot.archive.internal.JarInputStreamBasedArchiveDescriptor;
import org.hibernate.jpa.boot.archive.internal.JarProtocolArchiveDescriptor;
import org.hibernate.jpa.boot.archive.internal.StandardArchiveDescriptorFactory;
import org.hibernate.jpa.boot.archive.spi.ArchiveDescriptor;
import org.hibernate.jpa.boot.internal.ClassDescriptorImpl;
import org.hibernate.jpa.boot.scan.internal.StandardScanOptions;
import org.hibernate.jpa.boot.scan.spi.AbstractScannerImpl;
import org.hibernate.jpa.boot.spi.MappingFileDescriptor;
import org.hibernate.jpa.test.PersistenceUnitDescriptorAdapter;
import org.hibernate.jpa.test.pack.defaultpar.Version;
import org.hibernate.jpa.test.pack.explodedpar.Carpet;
import org.junit.Test;
import org.hibernate.testing.RequiresDialect;
import org.hibernate.testing.TestForIssue;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* @author Emmanuel Bernard
@ -72,7 +69,7 @@ import org.junit.Test;
public class JarVisitorTest extends PackagingTestCase {
@Test
public void testHttp() throws Exception {
URL url = JarVisitorFactory.getJarURLFromURLEntry(
URL url = ArchiveHelper.getJarURLFromURLEntry(
new URL(
"jar:http://www.ibiblio.org/maven/hibernate/jars/hibernate-annotations-3.0beta1.jar!/META-INF/persistence.xml"
),
@ -86,10 +83,18 @@ public class JarVisitorTest extends PackagingTestCase {
//fail silently
return;
}
JarVisitor visitor = JarVisitorFactory.getVisitor( url, getFilters() );
assertEquals( 0, visitor.getMatchingEntries()[0].size() );
assertEquals( 0, visitor.getMatchingEntries()[1].size() );
assertEquals( 0, visitor.getMatchingEntries()[2].size() );
ArchiveDescriptor archiveDescriptor = StandardArchiveDescriptorFactory.INSTANCE.buildArchiveDescriptor( url );
AbstractScannerImpl.ResultCollector resultCollector = new AbstractScannerImpl.ResultCollector( new StandardScanOptions() );
archiveDescriptor.visitArchive(
new AbstractScannerImpl.ArchiveContextImpl(
new PersistenceUnitDescriptorAdapter(),
true,
resultCollector
)
);
assertEquals( 0, resultCollector.getClassDescriptorSet().size() );
assertEquals( 0, resultCollector.getPackageDescriptorSet().size() );
assertEquals( 0, resultCollector.getMappingFileSet().size() );
}
@Test
@ -97,20 +102,40 @@ public class JarVisitorTest extends PackagingTestCase {
File defaultPar = buildDefaultPar();
addPackageToClasspath( defaultPar );
Filter[] filters = getFilters();
JarVisitor jarVisitor = new InputStreamZippedJarVisitor( defaultPar.toURL(), filters, "" );
assertEquals( "defaultpar", jarVisitor.getUnqualifiedJarName() );
Set entries = jarVisitor.getMatchingEntries()[1];
assertEquals( 3, entries.size() );
Entry entry = new Entry( org.hibernate.jpa.test.pack.defaultpar.ApplicationServer.class.getName(), null );
assertTrue( entries.contains( entry ) );
entry = new Entry( Version.class.getName(), null );
assertTrue( entries.contains( entry ) );
assertNull( ( ( Entry ) entries.iterator().next() ).getInputStream() );
assertEquals( 2, jarVisitor.getMatchingEntries()[2].size() );
for ( Entry localEntry : ( Set<Entry> ) jarVisitor.getMatchingEntries()[2] ) {
assertNotNull( localEntry.getInputStream() );
localEntry.getInputStream().close();
ArchiveDescriptor archiveDescriptor = new JarInputStreamBasedArchiveDescriptor(
StandardArchiveDescriptorFactory.INSTANCE,
defaultPar.toURL(),
""
);
AbstractScannerImpl.ResultCollector resultCollector = new AbstractScannerImpl.ResultCollector( new StandardScanOptions() );
archiveDescriptor.visitArchive(
new AbstractScannerImpl.ArchiveContextImpl(
new PersistenceUnitDescriptorAdapter(),
true,
resultCollector
)
);
validateResults( resultCollector, org.hibernate.jpa.test.pack.defaultpar.ApplicationServer.class, Version.class );
}
private void validateResults(AbstractScannerImpl.ResultCollector resultCollector, Class... expectedClasses) throws IOException {
assertEquals( 3, resultCollector.getClassDescriptorSet().size() );
for ( Class expectedClass : expectedClasses ) {
assertTrue(
resultCollector.getClassDescriptorSet().contains(
new ClassDescriptorImpl( expectedClass.getName(), null )
)
);
}
assertEquals( 2, resultCollector.getMappingFileSet().size() );
for ( MappingFileDescriptor mappingFileDescriptor : resultCollector.getMappingFileSet() ) {
assertNotNull( mappingFileDescriptor.getStreamAccess() );
final InputStream stream = mappingFileDescriptor.getStreamAccess().accessInputStream();
assertNotNull( stream );
stream.close();
}
}
@ -122,41 +147,39 @@ public class JarVisitorTest extends PackagingTestCase {
addPackageToClasspath( nestedEar );
String jarFileName = nestedEar.toURL().toExternalForm() + "!/defaultpar.par";
Filter[] filters = getFilters();
JarVisitor jarVisitor = new JarProtocolVisitor( new URL( jarFileName ), filters, "" );
//TODO should we fix the name here to reach defaultpar rather than nestedjar ??
//assertEquals( "defaultpar", jarVisitor.getUnqualifiedJarName() );
Set entries = jarVisitor.getMatchingEntries()[1];
assertEquals( 3, entries.size() );
Entry entry = new Entry( org.hibernate.jpa.test.pack.defaultpar.ApplicationServer.class.getName(), null );
assertTrue( entries.contains( entry ) );
entry = new Entry( Version.class.getName(), null );
assertTrue( entries.contains( entry ) );
assertNull( ( ( Entry ) entries.iterator().next() ).getInputStream() );
assertEquals( 2, jarVisitor.getMatchingEntries()[2].size() );
for ( Entry localEntry : ( Set<Entry> ) jarVisitor.getMatchingEntries()[2] ) {
assertNotNull( localEntry.getInputStream() );
localEntry.getInputStream().close();
}
JarProtocolArchiveDescriptor archiveDescriptor = new JarProtocolArchiveDescriptor(
StandardArchiveDescriptorFactory.INSTANCE,
new URL( jarFileName ),
""
);
AbstractScannerImpl.ResultCollector resultCollector = new AbstractScannerImpl.ResultCollector( new StandardScanOptions() );
archiveDescriptor.visitArchive(
new AbstractScannerImpl.ArchiveContextImpl(
new PersistenceUnitDescriptorAdapter(),
true,
resultCollector
)
);
validateResults( resultCollector, org.hibernate.jpa.test.pack.defaultpar.ApplicationServer.class, Version.class );
jarFileName = nestedEarDir.toURL().toExternalForm() + "!/defaultpar.par";
//JarVisitor jarVisitor = new ZippedJarVisitor( jarFileName, true, true );
filters = getFilters();
jarVisitor = new JarProtocolVisitor( new URL( jarFileName ), filters, "" );
//TODO should we fix the name here to reach defaultpar rather than nestedjar ??
//assertEquals( "defaultpar", jarVisitor.getUnqualifiedJarName() );
entries = jarVisitor.getMatchingEntries()[1];
assertEquals( 3, entries.size() );
entry = new Entry( org.hibernate.jpa.test.pack.defaultpar.ApplicationServer.class.getName(), null );
assertTrue( entries.contains( entry ) );
entry = new Entry( Version.class.getName(), null );
assertTrue( entries.contains( entry ) );
assertNull( ( ( Entry ) entries.iterator().next() ).getInputStream() );
assertEquals( 2, jarVisitor.getMatchingEntries()[2].size() );
for ( Entry localEntry : ( Set<Entry> ) jarVisitor.getMatchingEntries()[2] ) {
assertNotNull( localEntry.getInputStream() );
localEntry.getInputStream().close();
}
archiveDescriptor = new JarProtocolArchiveDescriptor(
StandardArchiveDescriptorFactory.INSTANCE,
new URL( jarFileName ),
""
);
resultCollector = new AbstractScannerImpl.ResultCollector( new StandardScanOptions() );
archiveDescriptor.visitArchive(
new AbstractScannerImpl.ArchiveContextImpl(
new PersistenceUnitDescriptorAdapter(),
true,
resultCollector
)
);
validateResults( resultCollector, org.hibernate.jpa.test.pack.defaultpar.ApplicationServer.class, Version.class );
}
@Test
@ -165,21 +188,26 @@ public class JarVisitorTest extends PackagingTestCase {
addPackageToClasspath( war );
String jarFileName = war.toURL().toExternalForm() + "!/WEB-INF/classes";
Filter[] filters = getFilters();
JarVisitor jarVisitor = new JarProtocolVisitor( new URL( jarFileName ), filters, "" );
assertEquals( "war", jarVisitor.getUnqualifiedJarName() );
Set entries = jarVisitor.getMatchingEntries()[1];
assertEquals( 3, entries.size() );
Entry entry = new Entry( org.hibernate.jpa.test.pack.war.ApplicationServer.class.getName(), null );
assertTrue( entries.contains( entry ) );
entry = new Entry( org.hibernate.jpa.test.pack.war.Version.class.getName(), null );
assertTrue( entries.contains( entry ) );
assertNull( ( ( Entry ) entries.iterator().next() ).getInputStream() );
assertEquals( 2, jarVisitor.getMatchingEntries()[2].size() );
for ( Entry localEntry : ( Set<Entry> ) jarVisitor.getMatchingEntries()[2] ) {
assertNotNull( localEntry.getInputStream() );
localEntry.getInputStream().close();
}
JarProtocolArchiveDescriptor archiveDescriptor = new JarProtocolArchiveDescriptor(
StandardArchiveDescriptorFactory.INSTANCE,
new URL( jarFileName ),
""
);
AbstractScannerImpl.ResultCollector resultCollector = new AbstractScannerImpl.ResultCollector( new StandardScanOptions() );
archiveDescriptor.visitArchive(
new AbstractScannerImpl.ArchiveContextImpl(
new PersistenceUnitDescriptorAdapter(),
true,
resultCollector
)
);
validateResults(
resultCollector,
org.hibernate.jpa.test.pack.war.ApplicationServer.class,
org.hibernate.jpa.test.pack.war.Version.class
);
}
@Test
@ -187,21 +215,21 @@ public class JarVisitorTest extends PackagingTestCase {
File defaultPar = buildDefaultPar();
addPackageToClasspath( defaultPar );
Filter[] filters = getFilters();
JarVisitor jarVisitor = new FileZippedJarVisitor( defaultPar.toURL(), filters, "" );
assertEquals( "defaultpar", jarVisitor.getUnqualifiedJarName() );
Set entries = jarVisitor.getMatchingEntries()[1];
assertEquals( 3, entries.size() );
Entry entry = new Entry( org.hibernate.jpa.test.pack.defaultpar.ApplicationServer.class.getName(), null );
assertTrue( entries.contains( entry ) );
entry = new Entry( Version.class.getName(), null );
assertTrue( entries.contains( entry ) );
assertNull( ( ( Entry ) entries.iterator().next() ).getInputStream() );
assertEquals( 2, jarVisitor.getMatchingEntries()[2].size() );
for ( Entry localEntry : ( Set<Entry> ) jarVisitor.getMatchingEntries()[2] ) {
assertNotNull( localEntry.getInputStream() );
localEntry.getInputStream().close();
}
JarFileBasedArchiveDescriptor archiveDescriptor = new JarFileBasedArchiveDescriptor(
StandardArchiveDescriptorFactory.INSTANCE,
defaultPar.toURL(),
""
);
AbstractScannerImpl.ResultCollector resultCollector = new AbstractScannerImpl.ResultCollector( new StandardScanOptions() );
archiveDescriptor.visitArchive(
new AbstractScannerImpl.ArchiveContextImpl(
new PersistenceUnitDescriptorAdapter(),
true,
resultCollector
)
);
validateResults( resultCollector, org.hibernate.jpa.test.pack.defaultpar.ApplicationServer.class, Version.class );
}
@Test
@ -209,32 +237,50 @@ public class JarVisitorTest extends PackagingTestCase {
File explodedPar = buildExplodedPar();
addPackageToClasspath( explodedPar );
Filter[] filters = getFilters();
String dirPath = explodedPar.toURL().toExternalForm();
// TODO - shouldn't ExplodedJarVisitor take care of a trailing slash?
if ( dirPath.endsWith( "/" ) ) {
dirPath = dirPath.substring( 0, dirPath.length() - 1 );
}
JarVisitor jarVisitor = new ExplodedJarVisitor( dirPath, filters );
assertEquals( "explodedpar", jarVisitor.getUnqualifiedJarName() );
Set[] entries = jarVisitor.getMatchingEntries();
assertEquals( 1, entries[1].size() );
assertEquals( 1, entries[0].size() );
assertEquals( 1, entries[2].size() );
Entry entry = new Entry( Carpet.class.getName(), null );
assertTrue( entries[1].contains( entry ) );
for ( Entry localEntry : ( Set<Entry> ) jarVisitor.getMatchingEntries()[2] ) {
assertNotNull( localEntry.getInputStream() );
localEntry.getInputStream().close();
ExplodedArchiveDescriptor archiveDescriptor = new ExplodedArchiveDescriptor(
StandardArchiveDescriptorFactory.INSTANCE,
ArchiveHelper.getURLFromPath( dirPath ),
""
);
AbstractScannerImpl.ResultCollector resultCollector = new AbstractScannerImpl.ResultCollector( new StandardScanOptions() );
archiveDescriptor.visitArchive(
new AbstractScannerImpl.ArchiveContextImpl(
new PersistenceUnitDescriptorAdapter(),
true,
resultCollector
)
);
assertEquals( 1, resultCollector.getClassDescriptorSet().size() );
assertEquals( 1, resultCollector.getPackageDescriptorSet().size() );
assertEquals( 1, resultCollector.getMappingFileSet().size() );
assertTrue(
resultCollector.getClassDescriptorSet().contains(
new ClassDescriptorImpl( Carpet.class.getName(), null )
)
);
for ( MappingFileDescriptor mappingFileDescriptor : resultCollector.getMappingFileSet() ) {
assertNotNull( mappingFileDescriptor.getStreamAccess() );
final InputStream stream = mappingFileDescriptor.getStreamAccess().accessInputStream();
assertNotNull( stream );
stream.close();
}
}
@Test
@TestForIssue(jiraKey = "HHH-6806")
public void testJarVisitorFactory() throws Exception{
addPackageToClasspath( buildExplodedPar(), buildDefaultPar() );
public void testJarVisitorFactory() throws Exception {
final File explodedPar = buildExplodedPar();
final File defaultPar = buildDefaultPar();
addPackageToClasspath( explodedPar, defaultPar );
//setting URL to accept vfs based protocol
URL.setURLStreamHandlerFactory(new URLStreamHandlerFactory() {
@ -250,21 +296,21 @@ public class JarVisitorTest extends PackagingTestCase {
}
});
URL jarUrl = new URL ("file:./target/packages/defaultpar.par");
JarVisitor jarVisitor = JarVisitorFactory.getVisitor(jarUrl, getFilters(), null);
assertEquals(FileZippedJarVisitor.class.getName(), jarVisitor.getClass().getName());
jarUrl = new URL ("file:./target/packages/explodedpar");
jarVisitor = JarVisitorFactory.getVisitor(jarUrl, getFilters(), null);
assertEquals(ExplodedJarVisitor.class.getName(), jarVisitor.getClass().getName());
jarUrl = new URL ("vfszip:./target/packages/defaultpar.par");
jarVisitor = JarVisitorFactory.getVisitor(jarUrl, getFilters(), null);
assertEquals(FileZippedJarVisitor.class.getName(), jarVisitor.getClass().getName());
jarUrl = new URL ("vfsfile:./target/packages/explodedpar");
jarVisitor = JarVisitorFactory.getVisitor(jarUrl, getFilters(), null);
assertEquals(ExplodedJarVisitor.class.getName(), jarVisitor.getClass().getName());
URL jarUrl = defaultPar.toURL();
ArchiveDescriptor descriptor = StandardArchiveDescriptorFactory.INSTANCE.buildArchiveDescriptor( jarUrl );
assertEquals( JarFileBasedArchiveDescriptor.class.getName(), descriptor.getClass().getName() );
jarUrl = explodedPar.toURL();
descriptor = StandardArchiveDescriptorFactory.INSTANCE.buildArchiveDescriptor( jarUrl );
assertEquals( ExplodedArchiveDescriptor.class.getName(), descriptor.getClass().getName() );
jarUrl = new URL( defaultPar.toURL().toExternalForm().replace( "file:", "vfszip:" ) );
descriptor = StandardArchiveDescriptorFactory.INSTANCE.buildArchiveDescriptor( jarUrl );
assertEquals( JarFileBasedArchiveDescriptor.class.getName(), descriptor.getClass().getName());
jarUrl = new URL( explodedPar.toURL().toExternalForm().replace( "file:", "vfsfile:" ) );
descriptor = StandardArchiveDescriptorFactory.INSTANCE.buildArchiveDescriptor( jarUrl );
assertEquals( ExplodedArchiveDescriptor.class.getName(), descriptor.getClass().getName() );
}
@Test
@ -315,36 +361,29 @@ public class JarVisitorTest extends PackagingTestCase {
@Test
@TestForIssue(jiraKey = "HHH-7835")
public void testGetBytesFromInputStream() {
try {
File file = buildLargeJar();
public void testGetBytesFromInputStream() throws Exception {
File file = buildLargeJar();
long start = System.currentTimeMillis();
InputStream stream = new BufferedInputStream(
new FileInputStream( file ) );
int oldLength = getBytesFromInputStream( stream ).length;
stream.close();
long oldTime = System.currentTimeMillis() - start;
long start = System.currentTimeMillis();
InputStream stream = new BufferedInputStream(
new FileInputStream( file ) );
int oldLength = getBytesFromInputStream( stream ).length;
stream.close();
long oldTime = System.currentTimeMillis() - start;
start = System.currentTimeMillis();
stream = new BufferedInputStream( new FileInputStream( file ) );
int newLength = JarVisitorFactory.getBytesFromInputStream(
stream ).length;
stream.close();
long newTime = System.currentTimeMillis() - start;
start = System.currentTimeMillis();
stream = new BufferedInputStream( new FileInputStream( file ) );
int newLength = ArchiveHelper.getBytesFromInputStream( stream ).length;
stream.close();
long newTime = System.currentTimeMillis() - start;
assertEquals( oldLength, newLength );
assertTrue( oldTime > newTime );
}
catch ( Exception e ) {
fail( e.getMessage() );
}
assertEquals( oldLength, newLength );
assertTrue( oldTime > newTime );
}
// This is the old getBytesFromInputStream from JarVisitorFactory before
// it was changed by HHH-7835. Use it as a regression test.
private byte[] getBytesFromInputStream(
InputStream inputStream) throws IOException {
private byte[] getBytesFromInputStream(InputStream inputStream) throws IOException {
int size;
byte[] entryBytes = new byte[0];
@ -363,46 +402,16 @@ public class JarVisitorTest extends PackagingTestCase {
@Test
@TestForIssue(jiraKey = "HHH-7835")
public void testGetBytesFromZeroInputStream() {
try {
// Ensure that JarVisitorFactory#getBytesFromInputStream
// can handle 0 length streams gracefully.
InputStream emptyStream = new BufferedInputStream(
new FileInputStream( new File(
"src/test/resources/org/hibernate/jpa/test/packaging/empty.txt" ) ) );
int length = JarVisitorFactory.getBytesFromInputStream(
emptyStream ).length;
assertEquals( length, 0 );
emptyStream.close();
public void testGetBytesFromZeroInputStream() throws Exception {
// Ensure that JarVisitorFactory#getBytesFromInputStream
// can handle 0 length streams gracefully.
URL emptyTxtUrl = getClass().getResource( "/org/hibernate/jpa/test/packaging/empty.txt" );
if ( emptyTxtUrl == null ) {
throw new RuntimeException( "Bah!" );
}
catch ( Exception e ) {
fail( e.getMessage() );
}
}
private Filter[] getFilters() {
return new Filter[] {
new PackageFilter( false, null ) {
public boolean accept(String javaElementName) {
return true;
}
},
new ClassFilter(
false, new Class[] {
Entity.class,
MappedSuperclass.class,
Embeddable.class
}
) {
public boolean accept(String javaElementName) {
return true;
}
},
new FileFilter( true ) {
public boolean accept(String javaElementName) {
return javaElementName.endsWith( "hbm.xml" ) || javaElementName.endsWith( "META-INF/orm.xml" );
}
}
};
InputStream emptyStream = new BufferedInputStream( emptyTxtUrl.openStream() );
int length = ArchiveHelper.getBytesFromInputStream( emptyStream ).length;
assertEquals( length, 0 );
emptyStream.close();
}
}

View File

@ -45,6 +45,7 @@ import org.hibernate.jpa.test.Cat;
import org.hibernate.jpa.test.Distributor;
import org.hibernate.jpa.test.Item;
import org.hibernate.jpa.test.Kitten;
import org.hibernate.jpa.test.TestHelper;
import org.hibernate.jpa.test.pack.cfgxmlpar.Morito;
import org.hibernate.jpa.test.pack.defaultpar.ApplicationServer;
import org.hibernate.jpa.test.pack.defaultpar.IncrementListener;
@ -204,6 +205,10 @@ public abstract class PackagingTestCase extends BaseCoreFunctionalTestCase {
}
protected File buildExplicitPar() {
// explicitpar/persistence.xml references externaljar.jar so build that from here.
// this is the reason for tests failing after clean at least on my (Steve) local system
buildExternalJar();
String fileName = "explicitpar.par";
JavaArchive archive = ShrinkWrap.create( JavaArchive.class, fileName );
archive.addClasses(
@ -342,8 +347,10 @@ public abstract class PackagingTestCase extends BaseCoreFunctionalTestCase {
// Build a large jar by adding a lorem ipsum file repeatedly.
for ( int i = 0; i < 100; i++ ) {
ArchivePath path = ArchivePaths.create( "META-INF/file" + i );
archive.addAsResource( new File( "src/test/resources/org/hibernate/jpa/test/packaging/loremipsum.txt" ),
path );
archive.addAsResource(
"org/hibernate/jpa/test/packaging/loremipsum.txt",
path
);
}
File testPackage = new File( packageTargetDir, fileName );

View File

@ -23,31 +23,32 @@
*/
package org.hibernate.jpa.test.packaging;
import java.io.File;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Converter;
import javax.persistence.Embeddable;
import javax.persistence.Entity;
import javax.persistence.EntityManagerFactory;
import javax.persistence.MappedSuperclass;
import javax.persistence.Persistence;
import org.junit.Test;
import java.io.File;
import java.io.InputStream;
import java.util.HashMap;
import org.hibernate.jpa.AvailableSettings;
import org.hibernate.jpa.packaging.internal.NativeScanner;
import org.hibernate.jpa.boot.internal.ParsedPersistenceXmlDescriptor;
import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor;
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.MappingFileDescriptor;
import org.hibernate.jpa.boot.spi.NamedInputStream;
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.test.pack.defaultpar.ApplicationServer;
import org.hibernate.jpa.packaging.spi.NamedInputStream;
import org.hibernate.jpa.packaging.spi.Scanner;
import org.hibernate.jpa.test.pack.defaultpar.Version;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* @author Emmanuel Bernard
@ -59,32 +60,39 @@ public class ScannerTest extends PackagingTestCase {
File defaultPar = buildDefaultPar();
addPackageToClasspath( defaultPar );
Scanner scanner = new NativeScanner();
assertEquals( "defaultpar", scanner.getUnqualifiedJarName( defaultPar.toURL() ) );
PersistenceUnitDescriptor descriptor = new ParsedPersistenceXmlDescriptor( defaultPar.toURL() );
ScanOptions options = new StandardScanOptions( "hbm,class", descriptor.isExcludeUnlistedClasses() );
Scanner scanner = new StandardScanner();
ScanResult scanResult = scanner.scan( descriptor, options );
Set<Class<? extends Annotation>> annotationsToLookFor = new HashSet<Class<? extends Annotation>>( 3 );
annotationsToLookFor.add( Entity.class );
annotationsToLookFor.add( MappedSuperclass.class );
annotationsToLookFor.add( Embeddable.class );
annotationsToLookFor.add( Converter.class );
final Set<Class<?>> classes = scanner.getClassesInJar( defaultPar.toURL(), annotationsToLookFor );
assertEquals( 3, scanResult.getLocatedClasses().size() );
assertClassesContained( scanResult, ApplicationServer.class );
assertClassesContained( scanResult, Version.class );
assertEquals( 3, classes.size() );
assertTrue( classes.contains( ApplicationServer.class ) );
assertTrue( classes.contains( Version.class ) );
Set<String> filePatterns = new HashSet<String>( 2 );
filePatterns.add( "**/*.hbm.xml" );
filePatterns.add( "META-INF/orm.xml" );
final Set<NamedInputStream> files = scanner.getFilesInJar( defaultPar.toURL(), filePatterns );
assertEquals( 2, files.size() );
for ( NamedInputStream file : files ) {
assertNotNull( file.getStream() );
file.getStream().close();
assertEquals( 2, scanResult.getLocatedMappingFiles().size() );
for ( MappingFileDescriptor mappingFileDescriptor : scanResult.getLocatedMappingFiles() ) {
assertNotNull( mappingFileDescriptor.getName() );
assertNotNull( mappingFileDescriptor.getStreamAccess() );
InputStream stream = mappingFileDescriptor.getStreamAccess().accessInputStream();
assertNotNull( stream );
stream.close();
NamedInputStream namedInputStream = mappingFileDescriptor.getStreamAccess().asNamedInputStream();
assertNotNull( namedInputStream );
stream = namedInputStream.getStream();
assertNotNull( stream );
stream.close();
}
}
private void assertClassesContained(ScanResult scanResult, Class classToCheckFor) {
for ( ClassDescriptor classDescriptor : scanResult.getLocatedClasses() ) {
if ( classDescriptor.getName().equals( classToCheckFor.getName() ) ) {
return;
}
}
fail( "ScanResult did not contain expected Class : " + classToCheckFor.getName() );
}
@Test
public void testCustomScanner() throws Exception {
File defaultPar = buildDefaultPar();