All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hibernate.boot.archive.internal.JarFileBasedArchiveDescriptor Maven / Gradle / Ivy

There is a newer version: 7.0.0.Alpha1
Show newest version
/*
 * 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.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.hibernate.boot.archive.spi.AbstractArchiveDescriptor;
import org.hibernate.boot.archive.spi.ArchiveContext;
import org.hibernate.boot.archive.spi.ArchiveDescriptorFactory;
import org.hibernate.boot.archive.spi.ArchiveEntry;
import org.hibernate.boot.archive.spi.ArchiveEntryHandler;
import org.hibernate.boot.archive.spi.ArchiveException;
import org.hibernate.boot.archive.spi.InputStreamAccess;

import static org.hibernate.internal.log.UrlMessageBundle.URL_LOGGER;

/**
 * An ArchiveDescriptor implementation leveraging the {@link java.util.jar.JarFile} API for processing.
 *
 * @author Steve Ebersole
 */
public class JarFileBasedArchiveDescriptor extends AbstractArchiveDescriptor {
	/**
	 * Constructs a JarFileBasedArchiveDescriptor
	 *
	 * @param archiveDescriptorFactory The factory creating this
	 * @param archiveUrl The url to the JAR file
	 * @param entry The prefix for entries within the JAR url
	 */
	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 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 ) )) {
					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();
					}
				}
				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 (InputStream is = jarFile.getInputStream( zipEntry )) {
					inputStreamAccess = buildByteBasedInputStreamAccess( name, is );
				}
				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 {
			final 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) {
			URL_LOGGER.logUnableToFindFileByUrl( getArchiveUrl(), e );
		}
		catch (URISyntaxException e) {
			URL_LOGGER.logMalformedUrl( getArchiveUrl(), e );
		}
		return null;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy