Coverage Report - org.apache.commons.compress.changes.ChangeSet
 
Classes in this File Line Coverage Branch Coverage Complexity
ChangeSet
92%
39/42
76%
29/38
4,286
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one
 3  
  * or more contributor license agreements.  See the NOTICE file
 4  
  * distributed with this work for additional information
 5  
  * regarding copyright ownership.  The ASF licenses this file
 6  
  * to you under the Apache License, Version 2.0 (the
 7  
  * "License"); you may not use this file except in compliance
 8  
  * with the License.  You may obtain a copy of the License at
 9  
  *
 10  
  * http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing,
 13  
  * software distributed under the License is distributed on an
 14  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15  
  * KIND, either express or implied.  See the License for the
 16  
  * specific language governing permissions and limitations
 17  
  * under the License.
 18  
  */
 19  
 package org.apache.commons.compress.changes;
 20  
 
 21  
 import java.io.InputStream;
 22  
 import java.util.Iterator;
 23  
 import java.util.LinkedHashSet;
 24  
 import java.util.Set;
 25  
 
 26  
 import org.apache.commons.compress.archivers.ArchiveEntry;
 27  
 
 28  
 /**
 29  
  * ChangeSet collects and performs changes to an archive.
 30  
  * Putting delete changes in this ChangeSet from multiple threads can
 31  
  * cause conflicts.
 32  
  * 
 33  
  * @NotThreadSafe
 34  
  */
 35  26
 public final class ChangeSet {
 36  
 
 37  26
     private final Set<Change> changes = new LinkedHashSet<Change>();
 38  
 
 39  
     /**
 40  
      * Deletes the file with the filename from the archive. 
 41  
      * 
 42  
      * @param filename
 43  
      *            the filename of the file to delete
 44  
      */
 45  
     public void delete(final String filename) {
 46  18
         addDeletion(new Change(filename, Change.TYPE_DELETE));
 47  18
     }
 48  
 
 49  
     /**
 50  
      * Deletes the directory tree from the archive. 
 51  
      * 
 52  
      * @param dirName
 53  
      *            the name of the directory tree to delete
 54  
      */
 55  
     public void deleteDir(final String dirName) {
 56  10
         addDeletion(new Change(dirName, Change.TYPE_DELETE_DIR));
 57  10
     }
 58  
 
 59  
     /**
 60  
      * Adds a new archive entry to the archive.
 61  
      * 
 62  
      * @param pEntry
 63  
      *            the entry to add
 64  
      * @param pInput
 65  
      *            the datastream to add
 66  
      */
 67  
     public void add(final ArchiveEntry pEntry, final InputStream pInput) {
 68  15
         this.add(pEntry, pInput, true);
 69  15
     }
 70  
 
 71  
     /**
 72  
      * Adds a new archive entry to the archive.
 73  
      * If replace is set to true, this change will replace all other additions
 74  
      * done in this ChangeSet and all existing entries in the original stream.
 75  
      * 
 76  
      * @param pEntry
 77  
      *            the entry to add
 78  
      * @param pInput
 79  
      *            the datastream to add
 80  
      * @param replace
 81  
      *            indicates the this change should replace existing entries
 82  
      */
 83  
     public void add(final ArchiveEntry pEntry, final InputStream pInput, final boolean replace) {
 84  19
         addAddition(new Change(pEntry, pInput, replace));
 85  19
     }
 86  
 
 87  
     /**
 88  
      * Adds an addition change.
 89  
      * 
 90  
      * @param pChange
 91  
      *            the change which should result in an addition
 92  
      */
 93  
     private void addAddition(Change pChange) {
 94  19
         if (Change.TYPE_ADD != pChange.type() ||
 95  
             pChange.getInput() == null) {
 96  0
             return;
 97  
         }
 98  
 
 99  19
         if (!changes.isEmpty()) {
 100  10
             for (Iterator<Change> it = changes.iterator(); it.hasNext();) {
 101  13
                 Change change = it.next();
 102  13
                 if (change.type() == Change.TYPE_ADD
 103  
                         && change.getEntry() != null) {
 104  2
                     ArchiveEntry entry = change.getEntry();
 105  
 
 106  2
                     if(entry.equals(pChange.getEntry())) {
 107  2
                         if(pChange.isReplaceMode()) {
 108  1
                             it.remove();
 109  1
                             changes.add(pChange);
 110  1
                             return;
 111  
                         } else {
 112  
                             // do not add this change
 113  1
                             return;
 114  
                         }
 115  
                     }
 116  
                 }
 117  11
             }
 118  
         }
 119  17
         changes.add(pChange);
 120  17
     }
 121  
 
 122  
     /**
 123  
      * Adds an delete change.
 124  
      * 
 125  
      * @param pChange
 126  
      *            the change which should result in a deletion
 127  
      */
 128  
     private void addDeletion(Change pChange) {
 129  28
         if ((Change.TYPE_DELETE != pChange.type() &&
 130  
             Change.TYPE_DELETE_DIR != pChange.type()) ||
 131  
             pChange.targetFile() == null) {
 132  0
             return;
 133  
         }
 134  28
         String source = pChange.targetFile();
 135  
 
 136  28
         if (!changes.isEmpty()) {
 137  11
             for (Iterator<Change> it = changes.iterator(); it.hasNext();) {
 138  18
                 Change change = it.next();
 139  18
                 if (change.type() == Change.TYPE_ADD
 140  
                         && change.getEntry() != null) {
 141  5
                     String target = change.getEntry().getName();
 142  
 
 143  5
                     if (Change.TYPE_DELETE == pChange.type() && source.equals(target)) {
 144  0
                         it.remove();
 145  5
                     } else if (Change.TYPE_DELETE_DIR == pChange.type() && 
 146  
                                target.matches(source + "/.*")) {
 147  2
                         it.remove();
 148  
                     }
 149  
                 }
 150  18
             }
 151  
         }
 152  28
         changes.add(pChange);
 153  28
     }
 154  
 
 155  
     /**
 156  
      * Returns the list of changes as a copy. Changes on this set
 157  
      * are not reflected on this ChangeSet and vice versa.
 158  
      * @return the changes as a copy
 159  
      */
 160  
     Set<Change> getChanges() {
 161  28
         return new LinkedHashSet<Change>(changes);
 162  
     }
 163  
 }