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