/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.jpa.test.packaging;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;
import java.util.Collections;
import java.util.List;
import org.hibernate.boot.archive.internal.ArchiveHelper;
import org.hibernate.boot.archive.internal.ExplodedArchiveDescriptor;
import org.hibernate.boot.archive.internal.JarFileBasedArchiveDescriptor;
import org.hibernate.boot.archive.internal.JarProtocolArchiveDescriptor;
import org.hibernate.boot.archive.internal.StandardArchiveDescriptorFactory;
import org.hibernate.boot.archive.scan.internal.ClassDescriptorImpl;
import org.hibernate.boot.archive.scan.internal.ScanResultCollector;
import org.hibernate.boot.archive.scan.internal.StandardScanOptions;
import org.hibernate.boot.archive.scan.internal.StandardScanParameters;
import org.hibernate.boot.archive.scan.internal.StandardScanner;
import org.hibernate.boot.archive.scan.spi.AbstractScannerImpl;
import org.hibernate.boot.archive.scan.spi.ClassDescriptor;
import org.hibernate.boot.archive.scan.spi.MappingFileDescriptor;
import org.hibernate.boot.archive.scan.spi.ScanEnvironment;
import org.hibernate.boot.archive.scan.spi.ScanResult;
import org.hibernate.boot.archive.spi.ArchiveDescriptor;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.jpa.test.pack.defaultpar.Version;
import org.hibernate.jpa.test.pack.explodedpar.Carpet;
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;
/**
* @author Emmanuel Bernard
* @author Hardy Ferentschik
* @author Brett Meyer
*/
@RequiresDialect( H2Dialect.class ) // Nothing dialect-specific -- no need to run in matrix.
@SuppressWarnings("unchecked")
public class JarVisitorTest extends PackagingTestCase {
@Test
public void testHttp() throws Exception {
final URL url = ArchiveHelper.getJarURLFromURLEntry(
new URL(
"jar:http://www.ibiblio.org/maven/hibernate/jars/hibernate-annotations-3.0beta1.jar!/META-INF/persistence.xml"
),
"/META-INF/persistence.xml"
);
try {
URLConnection urlConnection = url.openConnection();
urlConnection.connect();
}
catch ( IOException ie ) {
//fail silently
return;
}
ScanResult result = standardScan( url );
assertEquals( 0, result.getLocatedClasses().size() );
assertEquals( 0, result.getLocatedPackages().size() );
assertEquals( 0, result.getLocatedMappingFiles().size() );
}
private ScanResult standardScan(URL url) {
ScanEnvironment env = new ScanEnvironmentImpl( url );
return new StandardScanner().scan(
env,
new StandardScanOptions(),
StandardScanParameters.INSTANCE
);
}
private static class ScanEnvironmentImpl implements ScanEnvironment {
private final URL rootUrl;
private ScanEnvironmentImpl(URL rootUrl) {
this.rootUrl = rootUrl;
}
@Override
public URL getRootUrl() {
return rootUrl;
}
@Override
public List<URL> getNonRootUrls() {
return Collections.emptyList();
}
@Override
public List<String> getExplicitlyListedClassNames() {
return Collections.emptyList();
}
@Override
public List<String> getExplicitlyListedMappingFiles() {
return Collections.emptyList();
}
}
@Test
public void testInputStreamZippedJar() throws Exception {
File defaultPar = buildDefaultPar();
addPackageToClasspath( defaultPar );
ScanResult result = standardScan( defaultPar.toURL() );
validateResults( result, org.hibernate.jpa.test.pack.defaultpar.ApplicationServer.class, Version.class );
}
private void validateResults(ScanResult scanResult, Class... expectedClasses) throws IOException {
assertEquals( 3, scanResult.getLocatedClasses().size() );
for ( Class expectedClass : expectedClasses ) {
assertTrue(
scanResult.getLocatedClasses().contains(
new ClassDescriptorImpl( expectedClass.getName(), ClassDescriptor.Categorization.MODEL, null )
)
);
}
assertEquals( 2, scanResult.getLocatedMappingFiles().size() );
for ( MappingFileDescriptor mappingFileDescriptor : scanResult.getLocatedMappingFiles() ) {
assertNotNull( mappingFileDescriptor.getStreamAccess() );
final InputStream stream = mappingFileDescriptor.getStreamAccess().accessInputStream();
assertNotNull( stream );
stream.close();
}
}
@Test
public void testNestedJarProtocol() throws Exception {
File defaultPar = buildDefaultPar();
File nestedEar = buildNestedEar( defaultPar );
File nestedEarDir = buildNestedEarDir( defaultPar );
addPackageToClasspath( nestedEar );
String jarFileName = nestedEar.toURL().toExternalForm() + "!/defaultpar.par";
URL rootUrl = new URL( jarFileName );
JarProtocolArchiveDescriptor archiveDescriptor = new JarProtocolArchiveDescriptor(
StandardArchiveDescriptorFactory.INSTANCE,
rootUrl,
""
);
ScanEnvironment environment = new ScanEnvironmentImpl( rootUrl );
ScanResultCollector collector = new ScanResultCollector(
environment,
new StandardScanOptions(),
StandardScanParameters.INSTANCE
);
archiveDescriptor.visitArchive(
new AbstractScannerImpl.ArchiveContextImpl( true, collector )
);
validateResults(
collector.toScanResult(),
org.hibernate.jpa.test.pack.defaultpar.ApplicationServer.class,
Version.class
);
jarFileName = nestedEarDir.toURL().toExternalForm() + "!/defaultpar.par";
rootUrl = new URL( jarFileName );
archiveDescriptor = new JarProtocolArchiveDescriptor(
StandardArchiveDescriptorFactory.INSTANCE,
rootUrl,
""
);
environment = new ScanEnvironmentImpl( rootUrl );
collector = new ScanResultCollector(
environment,
new StandardScanOptions(),
StandardScanParameters.INSTANCE
);
archiveDescriptor.visitArchive(
new AbstractScannerImpl.ArchiveContextImpl( true, collector )
);
validateResults(
collector.toScanResult(),
org.hibernate.jpa.test.pack.defaultpar.ApplicationServer.class,
Version.class
);
}
@Test
public void testJarProtocol() throws Exception {
File war = buildWar();
addPackageToClasspath( war );
String jarFileName = war.toURL().toExternalForm() + "!/WEB-INF/classes";
URL rootUrl = new URL( jarFileName );
JarProtocolArchiveDescriptor archiveDescriptor = new JarProtocolArchiveDescriptor(
StandardArchiveDescriptorFactory.INSTANCE,
rootUrl,
""
);
final ScanEnvironment environment = new ScanEnvironmentImpl( rootUrl );
final ScanResultCollector collector = new ScanResultCollector(
environment,
new StandardScanOptions(),
StandardScanParameters.INSTANCE
);
archiveDescriptor.visitArchive(
new AbstractScannerImpl.ArchiveContextImpl( true, collector )
);
validateResults(
collector.toScanResult(),
org.hibernate.jpa.test.pack.war.ApplicationServer.class,
org.hibernate.jpa.test.pack.war.Version.class
);
}
@Test
public void testZippedJar() throws Exception {
File defaultPar = buildDefaultPar();
addPackageToClasspath( defaultPar );
ScanResult result = standardScan( defaultPar.toURL() );
validateResults(
result,
org.hibernate.jpa.test.pack.defaultpar.ApplicationServer.class,
Version.class
);
}
@Test
public void testExplodedJar() throws Exception {
File explodedPar = buildExplodedPar();
addPackageToClasspath( explodedPar );
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 );
}
ScanResult result = standardScan( ArchiveHelper.getURLFromPath( dirPath ) );
assertEquals( 1, result.getLocatedClasses().size() );
assertEquals( 1, result.getLocatedPackages().size() );
assertEquals( 1, result.getLocatedMappingFiles().size() );
assertTrue(
result.getLocatedClasses().contains(
new ClassDescriptorImpl( Carpet.class.getName(), ClassDescriptor.Categorization.MODEL, null )
)
);
for ( MappingFileDescriptor mappingFileDescriptor : result.getLocatedMappingFiles() ) {
assertNotNull( mappingFileDescriptor.getStreamAccess() );
final InputStream stream = mappingFileDescriptor.getStreamAccess().accessInputStream();
assertNotNull( stream );
stream.close();
}
}
@Test
@TestForIssue(jiraKey = "HHH-6806")
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() {
public URLStreamHandler createURLStreamHandler(String protocol) {
if("vfszip".equals(protocol) || "vfsfile".equals(protocol) )
return new URLStreamHandler() {
protected URLConnection openConnection(URL u)
throws IOException {
return null;
}
};
return null;
}
});
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
@TestForIssue( jiraKey = "EJB-230" )
public void testDuplicateFilterExplodedJarExpected() throws Exception {
// File explodedPar = buildExplodedPar();
// addPackageToClasspath( explodedPar );
//
// Filter[] filters = getFilters();
// Filter[] dupeFilters = new Filter[filters.length * 2];
// int index = 0;
// for ( Filter filter : filters ) {
// dupeFilters[index++] = filter;
// }
// filters = getFilters();
// for ( Filter filter : filters ) {
// dupeFilters[index++] = filter;
// }
// 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, dupeFilters );
// assertEquals( "explodedpar", jarVisitor.getUnqualifiedJarName() );
// Set[] entries = jarVisitor.getMatchingEntries();
// assertEquals( 1, entries[1].size() );
// assertEquals( 1, entries[0].size() );
// assertEquals( 1, entries[2].size() );
// for ( Entry entry : ( Set<Entry> ) entries[2] ) {
// InputStream is = entry.getInputStream();
// if ( is != null ) {
// assertTrue( 0 < is.available() );
// is.close();
// }
// }
// for ( Entry entry : ( Set<Entry> ) entries[5] ) {
// InputStream is = entry.getInputStream();
// if ( is != null ) {
// assertTrue( 0 < is.available() );
// is.close();
// }
// }
//
// Entry entry = new Entry( Carpet.class.getName(), null );
// assertTrue( entries[1].contains( entry ) );
}
@Test
@TestForIssue(jiraKey = "HHH-7835")
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;
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 );
}
// 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 {
int size;
byte[] entryBytes = new byte[0];
for ( ;; ) {
byte[] tmpByte = new byte[4096];
size = inputStream.read( tmpByte );
if ( size == -1 )
break;
byte[] current = new byte[entryBytes.length + size];
System.arraycopy( entryBytes, 0, current, 0, entryBytes.length );
System.arraycopy( tmpByte, 0, current, entryBytes.length, size );
entryBytes = current;
}
return entryBytes;
}
@Test
@TestForIssue(jiraKey = "HHH-7835")
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!" );
}
InputStream emptyStream = new BufferedInputStream( emptyTxtUrl.openStream() );
int length = ArchiveHelper.getBytesFromInputStream( emptyStream ).length;
assertEquals( length, 0 );
emptyStream.close();
}
}