org.apache.commons.compress.changes.ChangeSet Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of commons-compress Show documentation
Show all versions of commons-compress Show documentation
Apache Commons Compress software defines an API for working with
compression and archive formats. These include: bzip2, gzip, pack200,
lzma, xz, Snappy, traditional Unix Compress, DEFLATE, DEFLATE64, LZ4,
Brotli, Zstandard and ar, cpio, jar, tar, zip, dump, 7z, arj.
/*
* 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.changes;
import java.io.InputStream;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.regex.Pattern;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.changes.Change.ChangeType;
/**
* ChangeSet collects and performs changes to an archive. Putting delete changes in this ChangeSet from multiple threads can cause conflicts.
*
* @param The ArchiveEntry type.
* @NotThreadSafe
*/
public final class ChangeSet {
private final Set> changes = new LinkedHashSet<>();
/**
* Adds a new archive entry to the archive.
*
* @param entry the entry to add
* @param input the data stream to add
*/
public void add(final E entry, final InputStream input) {
this.add(entry, input, true);
}
/**
* Adds a new archive entry to the archive. If replace is set to true, this change will replace all other additions done in this ChangeSet and all existing
* entries in the original stream.
*
* @param entry the entry to add
* @param input the data stream to add
* @param replace indicates the this change should replace existing entries
*/
public void add(final E entry, final InputStream input, final boolean replace) {
addAddition(new Change<>(entry, input, replace));
}
/**
* Adds an addition change.
*
* @param addChange the change which should result in an addition
*/
@SuppressWarnings("resource") // InputStream is NOT allocated
private void addAddition(final Change addChange) {
if (Change.ChangeType.ADD != addChange.getType() || addChange.getInputStream() == null) {
return;
}
if (!changes.isEmpty()) {
for (final Iterator> it = changes.iterator(); it.hasNext();) {
final Change change = it.next();
if (change.getType() == Change.ChangeType.ADD && change.getEntry() != null) {
final ArchiveEntry entry = change.getEntry();
if (entry.equals(addChange.getEntry())) {
if (addChange.isReplaceMode()) {
it.remove();
changes.add(addChange);
}
// do not add this change
return;
}
}
}
}
changes.add(addChange);
}
/**
* Adds an delete change.
*
* @param deleteChange the change which should result in a deletion
*/
private void addDeletion(final Change deleteChange) {
if (ChangeType.DELETE != deleteChange.getType() && ChangeType.DELETE_DIR != deleteChange.getType() || deleteChange.getTargetFileName() == null) {
return;
}
final String source = deleteChange.getTargetFileName();
final Pattern pattern = Pattern.compile(source + "/.*");
if (source != null && !changes.isEmpty()) {
for (final Iterator> it = changes.iterator(); it.hasNext();) {
final Change change = it.next();
if (change.getType() == ChangeType.ADD && change.getEntry() != null) {
final String target = change.getEntry().getName();
if (target == null) {
continue;
}
if (ChangeType.DELETE == deleteChange.getType() && source.equals(target)
|| ChangeType.DELETE_DIR == deleteChange.getType() && pattern.matcher(target).matches()) {
it.remove();
}
}
}
}
changes.add(deleteChange);
}
/**
* Deletes the file with the file name from the archive.
*
* @param fileName the file name of the file to delete
*/
public void delete(final String fileName) {
addDeletion(new Change<>(fileName, ChangeType.DELETE));
}
/**
* Deletes the directory tree from the archive.
*
* @param dirName the name of the directory tree to delete
*/
public void deleteDir(final String dirName) {
addDeletion(new Change<>(dirName, ChangeType.DELETE_DIR));
}
/**
* Gets the list of changes as a copy. Changes on this set are not reflected on this ChangeSet and vice versa.
*
* @return the changes as a copy
*/
Set> getChanges() {
return new LinkedHashSet<>(changes);
}
}