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