Line data Source code
1 : // Copyright (C) 2010 The Android Open Source Project 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.gerrit.server.patch; 16 : 17 : import static com.google.gerrit.server.ioutil.BasicSerialization.readEnum; 18 : import static com.google.gerrit.server.ioutil.BasicSerialization.readVarInt32; 19 : import static com.google.gerrit.server.ioutil.BasicSerialization.writeEnum; 20 : import static com.google.gerrit.server.ioutil.BasicSerialization.writeVarInt32; 21 : import static java.util.stream.Collectors.toList; 22 : 23 : import com.google.common.collect.ImmutableList; 24 : import com.google.gerrit.entities.CodedEnum; 25 : import com.google.gerrit.jgit.diff.ReplaceEdit; 26 : import java.io.IOException; 27 : import java.io.InputStream; 28 : import java.io.ObjectInputStream; 29 : import java.io.ObjectOutputStream; 30 : import java.io.OutputStream; 31 : import java.io.Serializable; 32 : import java.util.Arrays; 33 : import java.util.Collections; 34 : import java.util.List; 35 : import org.eclipse.jgit.diff.Edit; 36 : 37 : public class IntraLineDiff implements Serializable { 38 : static final long serialVersionUID = IntraLineDiffKey.serialVersionUID; 39 : 40 6 : public enum Status implements CodedEnum { 41 6 : EDIT_LIST('e'), 42 6 : DISABLED('D'), 43 6 : TIMEOUT('T'), 44 6 : ERROR('E'); 45 : 46 : private final char code; 47 : 48 6 : Status(char code) { 49 6 : this.code = code; 50 6 : } 51 : 52 : @Override 53 : public char getCode() { 54 0 : return code; 55 : } 56 : } 57 : 58 : private transient Status status; 59 : private transient ImmutableList<Edit> edits; 60 : 61 0 : IntraLineDiff(Status status) { 62 0 : this.status = status; 63 0 : this.edits = ImmutableList.of(); 64 0 : } 65 : 66 6 : IntraLineDiff(List<Edit> edits) { 67 6 : this.status = Status.EDIT_LIST; 68 6 : this.edits = ImmutableList.copyOf(edits); 69 6 : } 70 : 71 : public Status getStatus() { 72 6 : return status; 73 : } 74 : 75 : public ImmutableList<Edit> getEdits() { 76 : // Edits are mutable objects. As we serialize IntraLineDiff asynchronously in H2CacheImpl, we 77 : // must ensure that its state isn't modified until it was properly stored in the cache. 78 6 : return deepCopyEdits(edits); 79 : } 80 : 81 : private void writeObject(ObjectOutputStream out) throws IOException { 82 0 : writeEnum(out, status); 83 0 : writeVarInt32(out, edits.size()); 84 0 : for (Edit e : edits) { 85 0 : writeEdit(out, e); 86 : 87 0 : if (e instanceof ReplaceEdit) { 88 0 : ReplaceEdit r = (ReplaceEdit) e; 89 0 : writeVarInt32(out, r.getInternalEdits().size()); 90 0 : for (Edit i : r.getInternalEdits()) { 91 0 : writeEdit(out, i); 92 0 : } 93 0 : } else { 94 0 : writeVarInt32(out, 0); 95 : } 96 0 : } 97 0 : } 98 : 99 : private void readObject(ObjectInputStream in) throws IOException { 100 0 : status = readEnum(in, Status.values()); 101 0 : int editCount = readVarInt32(in); 102 0 : Edit[] editArray = new Edit[editCount]; 103 0 : for (int i = 0; i < editCount; i++) { 104 0 : editArray[i] = readEdit(in); 105 : 106 0 : int innerCount = readVarInt32(in); 107 0 : if (0 < innerCount) { 108 0 : Edit[] inner = new Edit[innerCount]; 109 0 : for (int j = 0; j < innerCount; j++) { 110 0 : inner[j] = readEdit(in); 111 : } 112 0 : editArray[i] = new ReplaceEdit(editArray[i], asList(inner)); 113 : } 114 : } 115 0 : edits = ImmutableList.copyOf(editArray); 116 0 : } 117 : 118 : private static ImmutableList<Edit> deepCopyEdits(List<Edit> edits) { 119 6 : return edits.stream().map(IntraLineDiff::copy).collect(ImmutableList.toImmutableList()); 120 : } 121 : 122 : private static Edit copy(Edit edit) { 123 6 : if (edit instanceof ReplaceEdit) { 124 6 : return copy((ReplaceEdit) edit); 125 : } 126 6 : return new Edit(edit.getBeginA(), edit.getEndA(), edit.getBeginB(), edit.getEndB()); 127 : } 128 : 129 : private static ReplaceEdit copy(ReplaceEdit edit) { 130 6 : List<Edit> internalEdits = 131 6 : edit.getInternalEdits().stream().map(IntraLineDiff::copy).collect(toList()); 132 6 : return new ReplaceEdit( 133 6 : edit.getBeginA(), edit.getEndA(), edit.getBeginB(), edit.getEndB(), internalEdits); 134 : } 135 : 136 : private static void writeEdit(OutputStream out, Edit e) throws IOException { 137 0 : writeVarInt32(out, e.getBeginA()); 138 0 : writeVarInt32(out, e.getEndA()); 139 0 : writeVarInt32(out, e.getBeginB()); 140 0 : writeVarInt32(out, e.getEndB()); 141 0 : } 142 : 143 : private static Edit readEdit(InputStream in) throws IOException { 144 0 : int beginA = readVarInt32(in); 145 0 : int endA = readVarInt32(in); 146 0 : int beginB = readVarInt32(in); 147 0 : int endB = readVarInt32(in); 148 0 : return new Edit(beginA, endA, beginB, endB); 149 : } 150 : 151 : private static List<Edit> asList(Edit[] l) { 152 0 : return Collections.unmodifiableList(Arrays.asList(l)); 153 : } 154 : }