1   /*
2    * Copyright 2017 LINE Corporation
3    *
4    * LINE Corporation licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  /*
17   * Copyright (c) 2014, Francis Galiegue (fgaliegue@gmail.com)
18   *
19   * This software is dual-licensed under:
20   *
21   * - the Lesser General Public License (LGPL) version 3.0 or, at your option, any
22   *   later version;
23   * - the Apache Software License (ASL) version 2.0.
24   *
25   * The text of this file and of both licenses is available at the root of this
26   * project or, if you have the jar distribution, in directory META-INF/, under
27   * the names LGPL-3.0.txt and ASL-2.0.txt respectively.
28   *
29   * Direct link to the sources:
30   *
31   * - LGPL 3.0: https://www.gnu.org/licenses/lgpl-3.0.txt
32   * - ASL 2.0: https://www.apache.org/licenses/LICENSE-2.0.txt
33   */
34  
35  package com.linecorp.centraldogma.internal.jsonpatch;
36  
37  import java.io.IOException;
38  
39  import com.fasterxml.jackson.core.JsonGenerator;
40  import com.fasterxml.jackson.core.JsonPointer;
41  import com.fasterxml.jackson.databind.JsonNode;
42  import com.fasterxml.jackson.databind.SerializerProvider;
43  import com.fasterxml.jackson.databind.annotation.JsonSerialize;
44  import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
45  import com.google.common.base.Equivalence;
46  
47  /**
48   * Base class for patch operations taking a value in addition to a path.
49   */
50  abstract class PathValueOperation extends JsonPatchOperation {
51  
52      private static final Equivalence<JsonNode> EQUIVALENCE = JsonNumEquals.getInstance();
53  
54      @JsonSerialize
55      private final JsonNode value;
56  
57      /**
58       * Creates a new instance.
59       *
60       * @param op operation name
61       * @param path affected path
62       * @param value JSON value
63       */
64      PathValueOperation(final String op, final JsonPointer path, final JsonNode value) {
65          super(op, path);
66          this.value = value.deepCopy();
67      }
68  
69      public JsonNode value() {
70          return value;
71      }
72  
73      JsonNode valueCopy() {
74          return value.deepCopy();
75      }
76  
77      void ensureEquivalence(JsonNode actual) {
78          if (!EQUIVALENCE.equivalent(actual, value)) {
79              throw new JsonPatchException("mismatching value at '" + path + "': " +
80                                           actual + " (expected: " + value + ')');
81          }
82      }
83  
84      @Override
85      public final void serialize(final JsonGenerator jgen,
86                                  final SerializerProvider provider) throws IOException {
87          jgen.writeStartObject();
88          jgen.writeStringField("op", op);
89          jgen.writeStringField("path", path.toString());
90          jgen.writeFieldName("value");
91          jgen.writeTree(value);
92          jgen.writeEndObject();
93      }
94  
95      @Override
96      public final void serializeWithType(final JsonGenerator jgen,
97                                          final SerializerProvider provider, final TypeSerializer typeSer)
98              throws IOException {
99          serialize(jgen, provider);
100     }
101 
102     @Override
103     public final String toString() {
104         return "op: " + op + "; path: \"" + path + "\"; value: " + value;
105     }
106 }