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

org.apache.jackrabbit.vault.fs.io.ZipNioArchive Maven / Gradle / Ivy

There is a newer version: 2024.11.18751.20241128T090041Z-241100
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.jackrabbit.vault.fs.io;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.ProviderNotFoundException;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.jackrabbit.vault.fs.api.VaultInputSource;
import org.apache.jackrabbit.vault.fs.config.ConfigurationException;
import org.apache.jackrabbit.vault.fs.config.DefaultMetaInf;
import org.apache.jackrabbit.vault.fs.config.MetaInf;
import org.apache.jackrabbit.vault.fs.config.VaultSettings;
import org.apache.jackrabbit.vault.util.Constants;
import org.h2.util.CloseWatcher;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Archive leveraging Java NIO File and its Zip File System Provider.
 * 

* It doesn't support accessing nested zip files (for subpackages, compare with JDK-8247441) * @since 3.5.2 (package version 2.11.0) */ public class ZipNioArchive extends AbstractArchive { /** * default logger */ private static final Logger log = LoggerFactory.getLogger(ZipNioArchive.class); private final Path path; private final boolean deleteAtClose; /** * The (loaded) meta info */ private DefaultMetaInf inf; private FileSystem zipFileSystem; /** The watcher for unclosed archives */ private CloseWatcher watcher; /** * Shortcut for {@link ZipNioArchive#ZipNioArchive(Path, boolean)} with {@code false} as second parameter. * * @param path the path of the zip file */ public ZipNioArchive(Path path) { this(path, false); } /** * * @param path the path of the zip file * @param deleteAtClose if {@code true} removes the file with the given path during {@link #close()} */ public ZipNioArchive(Path path, boolean deleteAtClose) { super(); this.path = path; zipFileSystem = null; this.deleteAtClose = deleteAtClose; } @Override public void open(boolean strict) throws IOException { if (zipFileSystem != null) { log.debug("Archive already open"); return; } try { zipFileSystem = FileSystems.newFileSystem(path, (ClassLoader)null); } catch (ProviderNotFoundException e) { throw new IOException("Can not open zip file '" + path + "'", e); } dumpUnclosedArchives(); watcher = CloseWatcher.register(this, zipFileSystem, SHOULD_CREATE_STACK_TRACE); } @Override @Nullable public InputStream openInputStream(@Nullable Entry entry) throws IOException { if (entry == null) { return null; } if (zipFileSystem == null) { throw new ArchiveNotOpenException(path.toString()); } return Files.newInputStream(((EntryImpl)entry).path); } @Override @Nullable public VaultInputSource getInputSource(@Nullable Entry entry) throws IOException { if (entry == null) { return null; } if (zipFileSystem == null) { throw new ArchiveNotOpenException(path.toString()); } final EntryImpl entryImpl = (EntryImpl)entry; return new VaultInputSourceImpl(entryImpl); } @Override public @NotNull Entry getRoot() throws IOException { // use first root directory return new EntryImpl(zipFileSystem.getRootDirectories().iterator().next()); } @Override public @NotNull MetaInf getMetaInf() { if (inf == null) { try { inf = parseMetaInf(); } catch (IOException e) { throw new IllegalStateException("Could not retrieve meta data from " + path.toString(), e); } } return inf; } private @NotNull DefaultMetaInf parseMetaInf() throws IOException { if (zipFileSystem == null) { throw new ArchiveNotOpenException(path.toString()); } final DefaultMetaInf defaultMetaInf = new DefaultMetaInf(); // check for meta inf try (Stream metaDirFiles = Files.list(zipFileSystem.getPath(Constants.META_INF, Constants.VAULT_DIR))) { Iterator filesIterator = metaDirFiles.iterator(); while (filesIterator.hasNext()) { Path file = filesIterator.next(); if (Files.isDirectory(file)) { continue; } try (InputStream input = Files.newInputStream(file)) { defaultMetaInf.load(input, getSystemId(path, file)); } catch (ConfigurationException e1) { throw new IOException(e1); } } } if (defaultMetaInf.getFilter() == null) { log.debug("Zip {} does not contain filter definition.", path); } if (defaultMetaInf.getConfig() == null) { log.debug("Zip {} does not contain vault config.", path); } if (defaultMetaInf.getSettings() == null) { log.debug("Zip {} does not contain vault settings. using default.", path); VaultSettings settings = new VaultSettings(); settings.getIgnoredNames().add(".svn"); defaultMetaInf.setSettings(settings); } if (defaultMetaInf.getProperties() == null) { log.debug("Zip {} does not contain properties.", path); } if (defaultMetaInf.getNodeTypes().isEmpty()) { log.debug("Zip {} does not contain nodetypes.", path); } return defaultMetaInf; } private static String getSystemId(Path zipPath, Path pathInZip) { String systemId = zipPath.toString(); systemId += "!/" + pathInZip; return systemId; } @Override public void close() { if (zipFileSystem != null) { CloseWatcher.unregister(watcher); try { zipFileSystem.close(); } catch (IOException e) { log.warn("Error during close.", e); } } if (deleteAtClose) { try { Files.delete(path); } catch (IOException e) { log.warn("Could not delete " + path, e); } } } private static final class VaultInputSourceImpl extends VaultInputSource { private final EntryImpl entryImpl; private VaultInputSourceImpl(EntryImpl entryImpl) { this.entryImpl = entryImpl; } @Override public InputStream getByteStream() { try { return Files.newInputStream(entryImpl.path); } catch (IOException e) { throw new IllegalStateException("Could not retrieve byte stream", e); } } @Override public long getContentLength() { try { return Files.size(entryImpl.path); } catch (IOException e) { throw new IllegalStateException("Could not retrieve file size", e); } } @Override public long getLastModified() { try { return Files.getLastModifiedTime(entryImpl.path).toMillis(); } catch (IOException e) { throw new IllegalStateException("Could not retrieve last modification time", e); } } } /** * Implements the entry for this archive */ private static final class EntryImpl implements Entry { protected final Path path; private Map children; private EntryImpl(@NotNull Path path) { this.path = path; } @Override @NotNull public String getName() { int numNames = path.getNameCount(); if (numNames == 0) { return ""; } String name = path.getName(numNames-1).toString(); // strip trailing slashes (returned by Zip File System provider for directories) if (name.endsWith("/")) { name = name.substring(0, name.length()-1); } return name; } @Override public boolean isDirectory() { return Files.isDirectory(path); } @Override @NotNull public Collection getChildren() { if (children == null) { children = populateChildren(); } return children.values(); } private @NotNull Map populateChildren() { try (Stream childStream = Files.list(path)) { return childStream.map(EntryImpl::new).collect(Collectors.toMap(EntryImpl::getName, Function.identity())); } catch (IOException e) { throw new IllegalStateException("Could not retrieve children", e); } } @Override @Nullable public Entry getChild(@NotNull String name) { if (children == null) { children = populateChildren(); } return children.get(name); } } public final class ArchiveNotOpenException extends IllegalStateException { /** * */ private static final long serialVersionUID = 5634035426424134529L; public ArchiveNotOpenException(String archivePath) { super("Archive '" + archivePath + "' not open"); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy