| // 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)); |
| } |
| } |