You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by bo...@apache.org on 2018/04/29 17:02:03 UTC
commons-compress git commit: COMPRESS-118 provide a more fluent
archiving interface
Repository: commons-compress
Updated Branches:
refs/heads/master eee4d197d -> f62c52315
COMPRESS-118 provide a more fluent archiving interface
Project: http://git-wip-us.apache.org/repos/asf/commons-compress/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-compress/commit/f62c5231
Tree: http://git-wip-us.apache.org/repos/asf/commons-compress/tree/f62c5231
Diff: http://git-wip-us.apache.org/repos/asf/commons-compress/diff/f62c5231
Branch: refs/heads/master
Commit: f62c523154dfedcf49a87a865db545bb8c55e795
Parents: eee4d19
Author: Stefan Bodewig <bo...@apache.org>
Authored: Sun Apr 29 19:01:25 2018 +0200
Committer: Stefan Bodewig <bo...@apache.org>
Committed: Sun Apr 29 19:01:25 2018 +0200
----------------------------------------------------------------------
.../compress/archivers/examples/Archive.java | 128 +++++++++++++++++++
.../compress/archivers/examples/ArchiveCli.java | 44 +++++++
.../compress/archivers/examples/Chain.java | 42 ++++++
.../archivers/examples/ChainDefinition.java | 70 ++++++++++
.../archivers/examples/ChainPayload.java | 68 ++++++++++
.../compress/archivers/examples/ChainStep.java | 40 ++++++
.../examples/DirectoryBasedSupplier.java | 107 ++++++++++++++++
.../archivers/examples/FileFilterAdapter.java | 37 ++++++
.../archivers/examples/FileToArchiveSink.java | 123 ++++++++++++++++++
.../compress/archivers/examples/Filter.java | 44 +++++++
.../examples/SevenZOutputFileSink.java | 78 +++++++++++
.../compress/archivers/examples/Sink.java | 47 +++++++
.../compress/archivers/examples/Supplier.java | 30 +++++
.../archivers/examples/ThrowingIterator.java | 30 +++++
14 files changed, 888 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/f62c5231/src/main/java/org/apache/commons/compress/archivers/examples/Archive.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/examples/Archive.java b/src/main/java/org/apache/commons/compress/archivers/examples/Archive.java
new file mode 100644
index 0000000..c451170
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/archivers/examples/Archive.java
@@ -0,0 +1,128 @@
+/*
+ * 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.commons.compress.archivers.examples;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import org.apache.commons.compress.archivers.ArchiveException;
+
+/**
+ * Consumes files and passes them to a sink, usually used to create an archive of them.
+ * @since 1.17
+ */
+public class Archive {
+ /**
+ * Sets up a chain of operations and consumes the files from a supplier of files.
+ * @since 1.17
+ */
+ public interface ChainBuilder {
+ /**
+ * Adds a filter to the chain.
+ */
+ ChainBuilder filter(Filter<File> filter);
+ /**
+ * Adds a filter to the chain.
+ */
+ ChainBuilder filter(FileFilter filter);
+ /**
+ * Adds a filter to the chain that filters out entries that cannot be read.
+ */
+ ChainBuilder skipUnreadable();
+ /**
+ * Adds a filter to the chain that filters out everything that is not a file.
+ */
+ ChainBuilder skipNonFiles();
+ /**
+ * Actually consumes all the files supplied.
+ */
+ void to(Sink<File> sink) throws IOException, ArchiveException;
+ }
+
+ /**
+ * Sets the source of files to be a directory.
+ */
+ public static ChainBuilder directory(File f) {
+ return source(new DirectoryBasedSupplier(f));
+ }
+
+ /**
+ * Sets the source of files to process.
+ */
+ public static ChainBuilder source(Supplier<ThrowingIterator<ChainPayload<File>>> supplier) {
+ return new Builder(supplier);
+ }
+
+ private static class Builder implements ChainBuilder {
+ private final Supplier<ThrowingIterator<ChainPayload<File>>> supplier;
+ private ChainDefinition<File> chainDef = new ChainDefinition<>();
+
+ Builder(Supplier<ThrowingIterator<ChainPayload<File>>> supplier) {
+ this.supplier = supplier;
+ }
+
+ public ChainBuilder filter(Filter<File> filter) {
+ chainDef.add(filter);
+ return this;
+ }
+ public ChainBuilder filter(FileFilter filter) {
+ return filter(new FileFilterAdapter(filter));
+ }
+ public ChainBuilder skipUnreadable() {
+ return filter(new FileFilter() {
+ @Override
+ public boolean accept(File f) {
+ return f.canRead();
+ }
+ });
+ }
+ public ChainBuilder skipNonFiles() {
+ return filter(new FileFilter() {
+ @Override
+ public boolean accept(File f) {
+ return f.isFile();
+ }
+ });
+ }
+ public void to(Sink<File> sink) throws IOException, ArchiveException {
+ chainDef.add(sink);
+ chainDef.freeze();
+ new Archive(supplier, chainDef, sink).run();
+ }
+ }
+
+ private final Supplier<ThrowingIterator<ChainPayload<File>>> supplier;
+ private final ChainDefinition<File> chainDef;
+ private final Sink<File> sink;
+
+ private Archive(Supplier<ThrowingIterator<ChainPayload<File>>> supplier, ChainDefinition<File> chainDef,
+ Sink<File> sink) {
+ this.supplier = supplier;
+ this.chainDef = chainDef;
+ this.sink = sink;
+ }
+
+ private void run() throws IOException, ArchiveException {
+ ThrowingIterator<ChainPayload<File>> iter = supplier.get();
+ while (iter.hasNext()) {
+ chainDef.chain().next(iter.next());
+ }
+ sink.finish();
+ }
+}
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/f62c5231/src/main/java/org/apache/commons/compress/archivers/examples/ArchiveCli.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/examples/ArchiveCli.java b/src/main/java/org/apache/commons/compress/archivers/examples/ArchiveCli.java
new file mode 100644
index 0000000..7df4a82
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/archivers/examples/ArchiveCli.java
@@ -0,0 +1,44 @@
+/*
+ * 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.commons.compress.archivers.examples;
+
+import java.io.File;
+import java.io.IOException;
+import org.apache.commons.compress.archivers.ArchiveException;
+
+/**
+ * Simple command line tool that creates an archive from the contents of a directory.
+ *
+ * <p>Usage: <code>ArchiveCli dir format archive</code></p>
+ * @since 1.17
+ */
+public class ArchiveCli {
+
+ public static void main(String[] args) throws IOException, ArchiveException {
+ if (args.length != 3) {
+ System.err.println("Usage: ArchiveCli dir format target");
+ System.exit(1);
+ }
+ try (Sink<File> sink = FileToArchiveSink.forFile(args[1], new File(args[2]))) {
+ Archive.directory(new File(args[0]))
+ .to(sink);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/f62c5231/src/main/java/org/apache/commons/compress/archivers/examples/Chain.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/examples/Chain.java b/src/main/java/org/apache/commons/compress/archivers/examples/Chain.java
new file mode 100644
index 0000000..9989395
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/archivers/examples/Chain.java
@@ -0,0 +1,42 @@
+/*
+ * 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.commons.compress.archivers.examples;
+
+import java.io.IOException;
+import java.util.Iterator;
+import org.apache.commons.compress.archivers.ArchiveException;
+
+/**
+ * Encapsulates the execution flow of a chain of operations.
+ * @since 1.17
+ */
+public class Chain<T> {
+
+ private final Iterator<ChainStep<T>> chain;
+
+ public Chain(Iterator<ChainStep<T>> chain) {
+ this.chain = chain;
+ }
+
+ public void next(ChainPayload<T> payload) throws IOException, ArchiveException {
+ if (chain.hasNext()) {
+ chain.next().process(payload, this);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/f62c5231/src/main/java/org/apache/commons/compress/archivers/examples/ChainDefinition.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/examples/ChainDefinition.java b/src/main/java/org/apache/commons/compress/archivers/examples/ChainDefinition.java
new file mode 100644
index 0000000..5136b1d
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/archivers/examples/ChainDefinition.java
@@ -0,0 +1,70 @@
+/*
+ * 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.commons.compress.archivers.examples;
+
+import java.util.Deque;
+import java.util.LinkedList;
+
+/**
+ * The recipe for building a {@link Chain}.
+ * @since 1.17
+ */
+public class ChainDefinition<T> {
+ private final Deque<ChainStep<T>> steps = new LinkedList<>();
+ private volatile boolean frozen = false;
+
+ /**
+ * Adds a step.
+ * @throws IllegalStateException if the definition is already frozen.
+ */
+ public void add(ChainStep<T> step) {
+ if (frozen) {
+ throw new IllegalStateException("the definition is already frozen");
+ }
+ steps.addLast(step);
+ }
+
+ /**
+ * Freezes the definition.
+ *
+ * <p>Once this method has been invoked {@link #add} can no longer be invoked.</p>
+ *
+ * @throws IllegalStateException if the last step of the definition is not a sink.
+ */
+ public void freeze() {
+ if (!frozen) {
+ frozen = true;
+ if (!(steps.getLast() instanceof Sink)) {
+ throw new IllegalStateException("this definition doesn't end in a sink");
+ }
+ }
+ }
+
+ /**
+ * Returns a chain for this definition.
+ *
+ * @throws IllegalStateException if the definition is not frozen.
+ */
+ public Chain<T> chain() {
+ if (!frozen) {
+ throw new IllegalStateException("the definition hasn't been frozen, yet");
+ }
+ return new Chain(steps.iterator());
+ }
+}
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/f62c5231/src/main/java/org/apache/commons/compress/archivers/examples/ChainPayload.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/examples/ChainPayload.java b/src/main/java/org/apache/commons/compress/archivers/examples/ChainPayload.java
new file mode 100644
index 0000000..82d96fb
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/archivers/examples/ChainPayload.java
@@ -0,0 +1,68 @@
+/*
+ * 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.commons.compress.archivers.examples;
+
+import java.io.InputStream;
+
+/**
+ * The data that is pushed through a chain.
+ * @since 1.17
+ */
+public class ChainPayload<T> {
+ private final T entry;
+ private final String entryName;
+ private final Supplier<InputStream> input;
+ /**
+ * Constructs the payload.
+ * @param T entry the actual payload
+ * @param entryName the local name of the entry. This may - for
+ * example - be the file name relative to a directory.
+ * @param input supplies an input stream to the entry's
+ * content. Is not expected to be called more than once.
+ */
+ public ChainPayload(T entry, String entryName, Supplier<InputStream> input) {
+ this.entry = entry;
+ this.entryName = entryName;
+ this.input = input;
+ }
+ /**
+ * Provides the real payload.
+ */
+ public T getEntry() {
+ return entry;
+ }
+ /**
+ * Provides the local name of the entry.
+ *
+ * <p>This may - for example - be the file name relative to a
+ * directory.</p>
+ */
+ public String getEntryName() {
+ return entryName;
+ }
+ /**
+ * Returns a {@link Supplier} that can be used to read the entry's content.
+ *
+ * <p>The supplier is not required to be callable more than
+ * once.</p>
+ */
+ public Supplier<InputStream> getInput() {
+ return input;
+ }
+}
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/f62c5231/src/main/java/org/apache/commons/compress/archivers/examples/ChainStep.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/examples/ChainStep.java b/src/main/java/org/apache/commons/compress/archivers/examples/ChainStep.java
new file mode 100644
index 0000000..9edb5aa
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/archivers/examples/ChainStep.java
@@ -0,0 +1,40 @@
+/*
+ * 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.commons.compress.archivers.examples;
+
+import java.io.IOException;
+import org.apache.commons.compress.archivers.ArchiveException;
+
+/**
+ * A step inside of a {@link Chain}.
+ * @since 1.17
+ */
+public interface ChainStep<T> {
+ /**
+ * Process the chain's payload.
+ *
+ * <p>Any non-terminal step that invokes the {@link Supplier} of
+ * the payload is responsible for providing a fresh supplier if
+ * the chain is to be continued.</p>
+ *
+ * @param payload the payload.
+ * @param chain chain to return control to once processing is done.
+ */
+ void process(ChainPayload<T> payload, Chain<T> chain) throws IOException, ArchiveException;
+}
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/f62c5231/src/main/java/org/apache/commons/compress/archivers/examples/DirectoryBasedSupplier.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/examples/DirectoryBasedSupplier.java b/src/main/java/org/apache/commons/compress/archivers/examples/DirectoryBasedSupplier.java
new file mode 100644
index 0000000..7bfe58b
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/archivers/examples/DirectoryBasedSupplier.java
@@ -0,0 +1,107 @@
+/*
+ * 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.commons.compress.archivers.examples;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * Recursively returns all files and directories contained inside of a base directory.
+ * @since 1.17
+ */
+public class DirectoryBasedSupplier
+ implements Supplier<ThrowingIterator<ChainPayload<File>>> {
+
+ private final File dir;
+
+ /**
+ * @param dir the directory to provide entries from.
+ */
+ public DirectoryBasedSupplier(File dir) {
+ if (!dir.isDirectory()) {
+ throw new IllegalArgumentException("dir is not a readable directory");
+ }
+ this.dir = dir;
+ }
+
+ @Override
+ public ThrowingIterator<ChainPayload<File>> get() throws IOException {
+ return new DirectoryIterator("", dir);
+ }
+
+ private class DirectoryIterator implements ThrowingIterator<ChainPayload<File>> {
+ private final Iterator<File> files;
+ private final String namePrefix;
+ private DirectoryIterator nestedIterator;
+ DirectoryIterator(String namePrefix, File dir) throws IOException {
+ this.namePrefix = namePrefix;
+ File[] fs = dir.listFiles();
+ files = fs == null
+ ? new Iterator<File>() {
+ @Override
+ public boolean hasNext() {
+ return false;
+ }
+ @Override
+ public File next() {
+ throw new NoSuchElementException();
+ }
+ }
+ : Arrays.asList(fs).iterator();
+ }
+
+ @Override
+ public boolean hasNext() throws IOException {
+ if (nestedIterator != null && nestedIterator.hasNext()) {
+ return true;
+ }
+ if (nestedIterator != null) {
+ nestedIterator = null;
+ }
+ return files.hasNext();
+ }
+
+ @Override
+ public ChainPayload<File> next() throws IOException {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ if (nestedIterator != null) {
+ return nestedIterator.next();
+ }
+ final File f = files.next();
+ String entryName = namePrefix + f.getName();
+ if (f.isDirectory()) {
+ entryName += "/";
+ nestedIterator = new DirectoryIterator(entryName, f);
+ }
+ return new ChainPayload(f, entryName, new Supplier<InputStream>() {
+ @Override
+ public InputStream get() throws IOException {
+ return new FileInputStream(f);
+ }
+ });
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/f62c5231/src/main/java/org/apache/commons/compress/archivers/examples/FileFilterAdapter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/examples/FileFilterAdapter.java b/src/main/java/org/apache/commons/compress/archivers/examples/FileFilterAdapter.java
new file mode 100644
index 0000000..9f5a846
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/archivers/examples/FileFilterAdapter.java
@@ -0,0 +1,37 @@
+/*
+ * 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.commons.compress.archivers.examples;
+
+import java.io.File;
+import java.io.FileFilter;
+
+/**
+ * @since 1.17
+ */
+public class FileFilterAdapter extends Filter<File> {
+ private final FileFilter filter;
+ public FileFilterAdapter(FileFilter f) {
+ filter = f;
+ }
+
+ @Override
+ public boolean accept(String entryName, File entry) {
+ return filter.accept(entry);
+ }
+}
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/f62c5231/src/main/java/org/apache/commons/compress/archivers/examples/FileToArchiveSink.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/examples/FileToArchiveSink.java b/src/main/java/org/apache/commons/compress/archivers/examples/FileToArchiveSink.java
new file mode 100644
index 0000000..5afdb75
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/archivers/examples/FileToArchiveSink.java
@@ -0,0 +1,123 @@
+/*
+ * 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.commons.compress.archivers.examples;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.FileOutputStream;
+import java.nio.channels.Channels;
+import java.nio.channels.FileChannel;
+import java.nio.channels.SeekableByteChannel;
+import java.nio.file.StandardOpenOption;
+import org.apache.commons.compress.archivers.ArchiveEntry;
+import org.apache.commons.compress.archivers.ArchiveException;
+import org.apache.commons.compress.archivers.ArchiveOutputStream;
+import org.apache.commons.compress.archivers.ArchiveStreamFactory;
+import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
+import org.apache.commons.compress.utils.IOUtils;
+
+/**
+ * Sink that creates an archive from files.
+ * @since 1.17
+ */
+public class FileToArchiveSink extends Sink<File> {
+ private final ArchiveOutputStream os;
+
+ /**
+ * Wraps an ArchiveOutputStream.
+ */
+ public FileToArchiveSink(ArchiveOutputStream os) {
+ this.os = os;
+ }
+
+ @Override
+ public void consume(ChainPayload<File> payload) throws IOException, ArchiveException {
+ ArchiveEntry e = os.createArchiveEntry(payload.getEntry(), payload.getEntryName());
+ os.putArchiveEntry(e);
+ if (!payload.getEntry().isDirectory()) {
+ try (InputStream in = new BufferedInputStream(payload.getInput().get())) {
+ IOUtils.copy(in, os);
+ }
+ }
+ os.closeArchiveEntry();
+ }
+
+ @Override
+ public void finish() throws IOException {
+ os.finish();
+ }
+
+ @Override
+ public void close() throws IOException {
+ os.close();
+ }
+
+ /**
+ * Wraps an ArchiveOutputStream.
+ */
+ public static Sink<File> forStream(ArchiveOutputStream os) {
+ return new FileToArchiveSink(os);
+ }
+
+ /**
+ * Uses {@link ArchiveFactory#createArchiveOutputStream}.
+ *
+ * <p>Will not support 7z.</p>
+ */
+ public static Sink<File> forStream(String format, OutputStream os) throws IOException, ArchiveException {
+ return new FileToArchiveSink(new ArchiveStreamFactory().createArchiveOutputStream(format, os));
+ }
+
+ /**
+ * Uses {@link ArchiveFactory#createArchiveOutputStream} unless
+ * special handling for ZIP or 7z is required.
+ */
+ public static Sink<File> forFile(String format, File target) throws IOException, ArchiveException {
+ if (prefersSeekableByteChannel(format)) {
+ return forChannel(format, FileChannel.open(target.toPath(), StandardOpenOption.WRITE,
+ StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING));
+ }
+ return new FileToArchiveSink(new ArchiveStreamFactory()
+ .createArchiveOutputStream(format, new FileOutputStream(target)));
+ }
+
+ /**
+ * Uses {@link ArchiveFactory#createArchiveOutputStream} unless
+ * special handling for ZIP or 7z is required.
+ */
+ public static Sink<File> forChannel(String format, SeekableByteChannel c) throws IOException, ArchiveException {
+ if (!prefersSeekableByteChannel(format)) {
+ return forStream(format, Channels.newOutputStream(c));
+ } else if (ArchiveStreamFactory.ZIP.equalsIgnoreCase(format)) {
+ return forStream(new ZipArchiveOutputStream(c));
+ } else if (ArchiveStreamFactory.SEVEN_Z.equalsIgnoreCase(format)) {
+ return new SevenZOutputFileSink(c);
+ } else {
+ throw new ArchiveException("don't know how to handle format " + format);
+ }
+ }
+
+ private static boolean prefersSeekableByteChannel(String format) {
+ return ArchiveStreamFactory.ZIP.equalsIgnoreCase(format) || ArchiveStreamFactory.SEVEN_Z.equalsIgnoreCase(format);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/f62c5231/src/main/java/org/apache/commons/compress/archivers/examples/Filter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/examples/Filter.java b/src/main/java/org/apache/commons/compress/archivers/examples/Filter.java
new file mode 100644
index 0000000..924864c
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/archivers/examples/Filter.java
@@ -0,0 +1,44 @@
+/*
+ * 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.commons.compress.archivers.examples;
+
+import java.io.IOException;
+import org.apache.commons.compress.archivers.ArchiveException;
+
+/**
+ * Filtering stage of a {@link Expand} or {@link Archive} chain.
+ * @since 1.17
+ */
+public abstract class Filter<T> implements ChainStep<T> {
+ /**
+ * Decides whether to process an entry or not.
+ *
+ * @param name of the entry
+ * @param entry the entry
+ * @return true if the entry shall be processed.
+ */
+ public abstract boolean accept(String entryName, T entry);
+
+ @Override
+ public void process(ChainPayload<T> payload, Chain<T> chain) throws IOException, ArchiveException {
+ if (accept(payload.getEntryName(), payload.getEntry())) {
+ chain.next(payload);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/f62c5231/src/main/java/org/apache/commons/compress/archivers/examples/SevenZOutputFileSink.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/examples/SevenZOutputFileSink.java b/src/main/java/org/apache/commons/compress/archivers/examples/SevenZOutputFileSink.java
new file mode 100644
index 0000000..f9a1e14
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/archivers/examples/SevenZOutputFileSink.java
@@ -0,0 +1,78 @@
+/*
+ * 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.commons.compress.archivers.examples;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.channels.SeekableByteChannel;
+import org.apache.commons.compress.archivers.ArchiveEntry;
+import org.apache.commons.compress.archivers.ArchiveException;
+import org.apache.commons.compress.archivers.sevenz.SevenZOutputFile;
+import org.apache.commons.compress.utils.IOUtils;
+
+/**
+ * Sink that creates a 7z archive from files.
+ * @since 1.17
+ */
+public class SevenZOutputFileSink extends Sink<File> {
+
+ private final SevenZOutputFile outFile;
+
+ public SevenZOutputFileSink(File f) throws IOException {
+ this(new SevenZOutputFile(f));
+ }
+
+ public SevenZOutputFileSink(SeekableByteChannel c) throws IOException {
+ this(new SevenZOutputFile(c));
+ }
+
+ public SevenZOutputFileSink(SevenZOutputFile outFile) {
+ this.outFile = outFile;
+ }
+
+ @Override
+ public void consume(ChainPayload<File> payload) throws IOException, ArchiveException {
+ ArchiveEntry e = outFile.createArchiveEntry(payload.getEntry(), payload.getEntryName());
+ outFile.putArchiveEntry(e);
+ if (!payload.getEntry().isDirectory()) {
+ final byte[] buffer = new byte[8024];
+ int n = 0;
+ long count = 0;
+ try (InputStream in = new BufferedInputStream(payload.getInput().get())) {
+ while (-1 != (n = in.read(buffer))) {
+ outFile.write(buffer, 0, n);
+ count += n;
+ }
+ }
+ }
+ outFile.closeArchiveEntry();
+ }
+
+ @Override
+ public void finish() throws IOException {
+ outFile.finish();
+ }
+
+ @Override
+ public void close() throws IOException {
+ outFile.close();
+ }
+}
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/f62c5231/src/main/java/org/apache/commons/compress/archivers/examples/Sink.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/examples/Sink.java b/src/main/java/org/apache/commons/compress/archivers/examples/Sink.java
new file mode 100644
index 0000000..eb81c1c
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/archivers/examples/Sink.java
@@ -0,0 +1,47 @@
+/*
+ * 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.commons.compress.archivers.examples;
+
+import java.io.Closeable;
+import java.io.IOException;
+import org.apache.commons.compress.archivers.ArchiveException;
+
+/**
+ * Final stage of a {@link Expand} or {@link Archive} chain.
+ * @since 1.17
+ */
+public abstract class Sink<T> implements ChainStep<T>, Closeable {
+ /**
+ * Consume a single entry.
+ */
+ public abstract void consume(ChainPayload<T> payload) throws IOException, ArchiveException;
+
+ /**
+ * Is invoked once all entries have been processed.
+ *
+ * <p>This implementation is empty.
+ */
+ public void finish() throws IOException, ArchiveException {
+ }
+
+ @Override
+ public void process(ChainPayload<T> payload, Chain<T> chain) throws IOException, ArchiveException {
+ consume(payload);
+ }
+}
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/f62c5231/src/main/java/org/apache/commons/compress/archivers/examples/Supplier.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/examples/Supplier.java b/src/main/java/org/apache/commons/compress/archivers/examples/Supplier.java
new file mode 100644
index 0000000..6c73f91
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/archivers/examples/Supplier.java
@@ -0,0 +1,30 @@
+/*
+ * 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.commons.compress.archivers.examples;
+
+import java.io.IOException;
+import org.apache.commons.compress.archivers.ArchiveException;
+
+/**
+ * Used inside of {@link ChainPayload} as well as {@link Archive} and {@link Expand}.
+ * @since 1.12
+ */
+public interface Supplier<T> {
+ T get() throws IOException, ArchiveException;
+}
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/f62c5231/src/main/java/org/apache/commons/compress/archivers/examples/ThrowingIterator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/examples/ThrowingIterator.java b/src/main/java/org/apache/commons/compress/archivers/examples/ThrowingIterator.java
new file mode 100644
index 0000000..4a7bad8
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/archivers/examples/ThrowingIterator.java
@@ -0,0 +1,30 @@
+/*
+ * 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.commons.compress.archivers.examples;
+
+import java.io.IOException;
+import org.apache.commons.compress.archivers.ArchiveException;
+
+/**
+ * Specialized iterator that is allowed to throw Exceptions.
+ */
+public interface ThrowingIterator<T> {
+ boolean hasNext() throws IOException, ArchiveException;
+ T next() throws IOException, ArchiveException;
+}