diff --git a/hibernate-core/src/main/java/org/hibernate/boot/cfgxml/internal/ConfigLoader.java b/hibernate-core/src/main/java/org/hibernate/boot/cfgxml/internal/ConfigLoader.java index c58f0e35ed..ab094f769b 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/cfgxml/internal/ConfigLoader.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/cfgxml/internal/ConfigLoader.java @@ -52,12 +52,23 @@ public class ConfigLoader { if ( stream == null ) { throw new ConfigurationException( "Could not locate cfg.xml resource [" + cfgXmlResourceName + "]" ); } - final JaxbCfgHibernateConfiguration jaxbCfg = jaxbProcessorHolder.getValue().unmarshal( - stream, - new Origin( SourceType.RESOURCE, cfgXmlResourceName ) - ); - return LoadedConfig.consume( jaxbCfg ); + try { + final JaxbCfgHibernateConfiguration jaxbCfg = jaxbProcessorHolder.getValue().unmarshal( + stream, + new Origin( SourceType.RESOURCE, cfgXmlResourceName ) + ); + + return LoadedConfig.consume( jaxbCfg ); + } + finally { + try { + stream.close(); + } + catch (IOException e) { + log.debug( "Unable to close cfg.xml resource stream", e ); + } + } } public LoadedConfig loadConfigXmlFile(File cfgXmlFile) { diff --git a/hibernate-core/src/test/java/org/hibernate/test/boot/cfgXml/CfgXmlResourceNameClosingTest.java b/hibernate-core/src/test/java/org/hibernate/test/boot/cfgXml/CfgXmlResourceNameClosingTest.java new file mode 100644 index 0000000000..0ec3c4bcfd --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/boot/cfgXml/CfgXmlResourceNameClosingTest.java @@ -0,0 +1,112 @@ +/* + * 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 . + */ +package org.hibernate.test.boot.cfgXml; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import org.hibernate.boot.cfgxml.internal.ConfigLoader; +import org.hibernate.boot.registry.BootstrapServiceRegistry; +import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; +import org.hibernate.boot.registry.StandardServiceRegistry; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl; +import org.hibernate.engine.config.spi.ConfigurationService; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseUnitTestCase; + +import org.junit.Test; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +/** + * Test that makes sure the input stream inside {@link ConfigLoader#loadConfigXmlResource(java.lang.String)} + * gets closed. + * + * @author Steve Ebersole + */ +@TestForIssue( jiraKey = "HHH-10120" ) +public class CfgXmlResourceNameClosingTest extends BaseUnitTestCase { + private static class InputStreamWrapper extends InputStream { + private final InputStream wrapped; + private boolean wasClosed = false; + + public InputStreamWrapper(InputStream wrapped) { + this.wrapped = wrapped; + } + + @Override + public int read() throws IOException { + return wrapped.read(); + } + + @Override + public void close() throws IOException { + wrapped.close(); + wasClosed = true; + super.close(); + } + + public boolean wasClosed() { + return wasClosed; + } + } + + private static class LocalClassLoaderServiceImpl extends ClassLoaderServiceImpl { + final List openedStreams = new ArrayList(); + boolean stopped = false; + + @Override + public InputStream locateResourceStream(String name) { + InputStreamWrapper stream = new InputStreamWrapper( super.locateResourceStream( name ) ); + openedStreams.add( stream ); + return stream; + } + + @Override + public void stop() { + for ( InputStreamWrapper openedStream : openedStreams ) { + if ( !openedStream.wasClosed ) { + try { + openedStream.close(); + } + catch (IOException ignore) { + } + } + } + openedStreams.clear(); + stopped = true; + super.stop(); + } + } + + LocalClassLoaderServiceImpl classLoaderService = new LocalClassLoaderServiceImpl(); + + @Test + public void testStreamClosing() { + BootstrapServiceRegistry bsr = new BootstrapServiceRegistryBuilder() + .applyClassLoaderService( classLoaderService ) + .build(); + StandardServiceRegistry ssr = new StandardServiceRegistryBuilder( bsr ) + .configure( "org/hibernate/test/boot/cfgXml/hibernate.cfg.xml" ) + .build(); + try { + for ( InputStreamWrapper openedStream : classLoaderService.openedStreams ) { + assertTrue( openedStream.wasClosed ); + } + } + finally { + StandardServiceRegistryBuilder.destroy( ssr ); + } + + assertTrue( classLoaderService.stopped ); + } +}