| // Copyright (C) 2010 The Android Open Source Project | |
| // | |
| // Licensed 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 com.google.gerrit.server.patch; | |
| import static com.google.gerrit.server.ioutil.BasicSerialization.readEnum; | |
| import static com.google.gerrit.server.ioutil.BasicSerialization.readVarInt32; | |
| import static com.google.gerrit.server.ioutil.BasicSerialization.writeEnum; | |
| import static com.google.gerrit.server.ioutil.BasicSerialization.writeVarInt32; | |
| import static java.util.stream.Collectors.toList; | |
| import com.google.common.collect.ImmutableList; | |
| import com.google.gerrit.entities.CodedEnum; | |
| import com.google.gerrit.jgit.diff.ReplaceEdit; | |
| import java.io.IOException; | |
| import java.io.InputStream; | |
| import java.io.ObjectInputStream; | |
| import java.io.ObjectOutputStream; | |
| import java.io.OutputStream; | |
| import java.io.Serializable; | |
| import java.util.Arrays; | |
| import java.util.Collections; | |
| import java.util.List; | |
| import org.eclipse.jgit.diff.Edit; | |
| public class IntraLineDiff implements Serializable { | |
| static final long serialVersionUID = IntraLineDiffKey.serialVersionUID; | |
| public enum Status implements CodedEnum { | |
| EDIT_LIST('e'), | |
| DISABLED('D'), | |
| TIMEOUT('T'), | |
| ERROR('E'); | |
| private final char code; | |
| Status(char code) { | |
| this.code = code; | |
| } | |
| @Override | |
| public char getCode() { | |
| return code; | |
| } | |
| } | |
| private transient Status status; | |
| private transient ImmutableList<Edit> edits; | |
| IntraLineDiff(Status status) { | |
| this.status = status; | |
| this.edits = ImmutableList.of(); | |
| } | |
| IntraLineDiff(List<Edit> edits) { | |
| this.status = Status.EDIT_LIST; | |
| this.edits = ImmutableList.copyOf(edits); | |
| } | |
| public Status getStatus() { | |
| return status; | |
| } | |
| public ImmutableList<Edit> getEdits() { | |
| // Edits are mutable objects. As we serialize IntraLineDiff asynchronously in H2CacheImpl, we | |
| // must ensure that its state isn't modified until it was properly stored in the cache. | |
| return deepCopyEdits(edits); | |
| } | |
| private void writeObject(ObjectOutputStream out) throws IOException { | |
| writeEnum(out, status); | |
| writeVarInt32(out, edits.size()); | |
| for (Edit e : edits) { | |
| writeEdit(out, e); | |
| if (e instanceof ReplaceEdit) { | |
| ReplaceEdit r = (ReplaceEdit) e; | |
| writeVarInt32(out, r.getInternalEdits().size()); | |
| for (Edit i : r.getInternalEdits()) { | |
| writeEdit(out, i); | |
| } | |
| } else { | |
| writeVarInt32(out, 0); | |
| } | |
| } | |
| } | |
| private void readObject(ObjectInputStream in) throws IOException { | |
| status = readEnum(in, Status.values()); | |
| int editCount = readVarInt32(in); | |
| Edit[] editArray = new Edit[editCount]; | |
| for (int i = 0; i < editCount; i++) { | |
| editArray[i] = readEdit(in); | |
| int innerCount = readVarInt32(in); | |
| if (0 < innerCount) { | |
| Edit[] inner = new Edit[innerCount]; | |
| for (int j = 0; j < innerCount; j++) { | |
| inner[j] = readEdit(in); | |
| } | |
| editArray[i] = new ReplaceEdit(editArray[i], asList(inner)); | |
| } | |
| } | |
| edits = ImmutableList.copyOf(editArray); | |
| } | |
| private static ImmutableList<Edit> deepCopyEdits(List<Edit> edits) { | |
| return edits.stream().map(IntraLineDiff::copy).collect(ImmutableList.toImmutableList()); | |
| } | |
| private static Edit copy(Edit edit) { | |
| if (edit instanceof ReplaceEdit) { | |
| return copy((ReplaceEdit) edit); | |
| } | |
| return new Edit(edit.getBeginA(), edit.getEndA(), edit.getBeginB(), edit.getEndB()); | |
| } | |
| private static ReplaceEdit copy(ReplaceEdit edit) { | |
| List<Edit> internalEdits = | |
| edit.getInternalEdits().stream().map(IntraLineDiff::copy).collect(toList()); | |
| return new ReplaceEdit( | |
| edit.getBeginA(), edit.getEndA(), edit.getBeginB(), edit.getEndB(), internalEdits); | |
| } | |
| private static void writeEdit(OutputStream out, Edit e) throws IOException { | |
| writeVarInt32(out, e.getBeginA()); | |
| writeVarInt32(out, e.getEndA()); | |
| writeVarInt32(out, e.getBeginB()); | |
| writeVarInt32(out, e.getEndB()); | |
| } | |
| private static Edit readEdit(InputStream in) throws IOException { | |
| int beginA = readVarInt32(in); | |
| int endA = readVarInt32(in); | |
| int beginB = readVarInt32(in); | |
| int endB = readVarInt32(in); | |
| return new Edit(beginA, endA, beginB, endB); | |
| } | |
| private static List<Edit> asList(Edit[] l) { | |
| return Collections.unmodifiableList(Arrays.asList(l)); | |
| } | |
| } |