1 // Copyright 2016 Google Inc. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package com.google.archivepatcher.generator; 16 17 import java.util.Iterator; 18 import java.util.List; 19 20 import com.google.archivepatcher.shared.JreDeflateParameters; 21 import com.google.archivepatcher.shared.TypedRange; 22 23 /** 24 * A plan for transforming the old and the new archive prior to running a diffing algorithm and for 25 * recompressing the delta-friendly new archive afterwards. 26 * <p> 27 * The plan for uncompressing the old file is a {@link List} of {@link TypedRange} entries with void 28 * metadata. This describes the chunks of the old file that need to be uncompressed prior to 29 * diffing, in file order. The file produced by executing this plan is the "delta-friendly" old 30 * archive. 31 * <p> 32 * The plan for uncompressing the new file is similarly a {@link List} of {@link TypedRange} 33 * entries, but this time the metadata is of the type {@link JreDeflateParameters}. This describes 34 * the chunks of the new file that need to be uncompressed prior to diffing, in file order. The 35 * {@link JreDeflateParameters} metadata indicate the settings that need to be used to generate the 36 * inverse transform (the delta friendly new file recompression plan; see below). The file produced 37 * by executing this plan is the "delta-friendly" new archive. 38 * <p> 39 * The plan for recompressing the delta-friendly new archive is again a {@link List} of 40 * {@link TypedRange} entries with {@link JreDeflateParameters} metadata. This describes the chunks 41 * of the delta-friendly new file that need to be recompressed after diffing, again in file order. 42 * The {@link JreDeflateParameters} metadata indicate the settings to use during recompression. The 43 * file produced by executing this plan is the new archive, i.e. it reverse the transform of the 44 * new file uncompression plan. 45 * <p> 46 * Finally, a {@link List} of all the {@link QualifiedRecommendation}s upon which all the plans are 47 * based is available via {@link #getQualifiedRecommendations()}. 48 */ 49 public class PreDiffPlan { 50 /** 51 * The plan for uncompressing the old file, in file order. 52 */ 53 private final List<TypedRange<Void>> oldFileUncompressionPlan; 54 55 /** 56 * The plan for uncompressing the new file, in file order. 57 */ 58 private final List<TypedRange<JreDeflateParameters>> newFileUncompressionPlan; 59 60 /** 61 * The plan for recompressing the delta-friendly new file, in file order. 62 */ 63 private final List<TypedRange<JreDeflateParameters>> deltaFriendlyNewFileRecompressionPlan; 64 65 /** 66 * The recommendations upon which the plans are based. 67 */ 68 private final List<QualifiedRecommendation> qualifiedRecommendations; 69 70 /** 71 * Constructs a new plan. 72 * @param qualifiedRecommendations the recommendations upon which the plans are based 73 * @param oldFileUncompressionPlan the plan for uncompressing the old file, in file order 74 * @param newFileUncompressionPlan the plan for uncompressing the new file, in file order 75 */ PreDiffPlan( List<QualifiedRecommendation> qualifiedRecommendations, List<TypedRange<Void>> oldFileUncompressionPlan, List<TypedRange<JreDeflateParameters>> newFileUncompressionPlan)76 public PreDiffPlan( 77 List<QualifiedRecommendation> qualifiedRecommendations, 78 List<TypedRange<Void>> oldFileUncompressionPlan, 79 List<TypedRange<JreDeflateParameters>> newFileUncompressionPlan) { 80 this(qualifiedRecommendations, oldFileUncompressionPlan, newFileUncompressionPlan, null); 81 } 82 83 /** 84 * Constructs a new plan. 85 * @param qualifiedRecommendations the recommendations upon which the plans are based 86 * @param oldFileUncompressionPlan the plan for uncompressing the old file, in file order 87 * @param newFileUncompressionPlan the plan for uncompressing the new file, in file order 88 * @param deltaFriendlyNewFileRecompressionPlan the plan for recompression the delta-friendly new 89 * file, in file order 90 */ PreDiffPlan( List<QualifiedRecommendation> qualifiedRecommendations, List<TypedRange<Void>> oldFileUncompressionPlan, List<TypedRange<JreDeflateParameters>> newFileUncompressionPlan, List<TypedRange<JreDeflateParameters>> deltaFriendlyNewFileRecompressionPlan)91 public PreDiffPlan( 92 List<QualifiedRecommendation> qualifiedRecommendations, 93 List<TypedRange<Void>> oldFileUncompressionPlan, 94 List<TypedRange<JreDeflateParameters>> newFileUncompressionPlan, 95 List<TypedRange<JreDeflateParameters>> deltaFriendlyNewFileRecompressionPlan) { 96 ensureOrdered(oldFileUncompressionPlan); 97 ensureOrdered(newFileUncompressionPlan); 98 ensureOrdered(deltaFriendlyNewFileRecompressionPlan); 99 this.qualifiedRecommendations = qualifiedRecommendations; 100 this.oldFileUncompressionPlan = oldFileUncompressionPlan; 101 this.newFileUncompressionPlan = newFileUncompressionPlan; 102 this.deltaFriendlyNewFileRecompressionPlan = deltaFriendlyNewFileRecompressionPlan; 103 } 104 105 /** 106 * Ensures that the lists passed into the constructors are ordered and throws an exception if 107 * they are not. Null lists and lists whose size is less than 2 are ignored. 108 * @param list the list to check 109 */ ensureOrdered(List<TypedRange<T>> list)110 private <T> void ensureOrdered(List<TypedRange<T>> list) { 111 if (list != null && list.size() >= 2) { 112 Iterator<TypedRange<T>> iterator = list.iterator(); 113 TypedRange<T> lastEntry = iterator.next(); 114 while (iterator.hasNext()) { 115 TypedRange<T> nextEntry = iterator.next(); 116 if (lastEntry.compareTo(nextEntry) > 0) { 117 throw new IllegalArgumentException("List must be ordered"); 118 } 119 } 120 } 121 } 122 123 /** 124 * Returns the plan for uncompressing the old file to create the delta-friendly old file. 125 * @return the plan 126 */ getOldFileUncompressionPlan()127 public final List<TypedRange<Void>> getOldFileUncompressionPlan() { 128 return oldFileUncompressionPlan; 129 } 130 131 /** 132 * Returns the plan for uncompressing the new file to create the delta-friendly new file. 133 * @return the plan 134 */ getNewFileUncompressionPlan()135 public final List<TypedRange<JreDeflateParameters>> getNewFileUncompressionPlan() { 136 return newFileUncompressionPlan; 137 } 138 139 /** 140 * Returns the plan for recompressing the delta-friendly new file to regenerate the original new 141 * file. 142 * @return the plan 143 */ getDeltaFriendlyNewFileRecompressionPlan()144 public final List<TypedRange<JreDeflateParameters>> getDeltaFriendlyNewFileRecompressionPlan() { 145 return deltaFriendlyNewFileRecompressionPlan; 146 } 147 148 /** 149 * Returns the recommendations upon which the plans are based. 150 * @return the recommendations 151 */ getQualifiedRecommendations()152 public final List<QualifiedRecommendation> getQualifiedRecommendations() { 153 return qualifiedRecommendations; 154 } 155 } 156