0e70edc76fb10d7c63e34f032722c4b5afbb2dfb
[controller.git] / opendaylight / md-sal / cds-access-api / src / main / java / org / opendaylight / controller / cluster / access / concepts / LocalHistoryIdentifier.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.controller.cluster.access.concepts;
9
10 import static com.google.common.base.Verify.verifyNotNull;
11 import static java.util.Objects.requireNonNull;
12
13 import com.google.common.base.MoreObjects;
14 import java.io.DataInput;
15 import java.io.DataOutput;
16 import java.io.Externalizable;
17 import java.io.IOException;
18 import java.io.ObjectInput;
19 import java.io.ObjectOutput;
20 import org.eclipse.jdt.annotation.NonNull;
21 import org.opendaylight.yangtools.concepts.WritableIdentifier;
22 import org.opendaylight.yangtools.concepts.WritableObjects;
23
24 /**
25  * Globally-unique identifier of a local history. This identifier is assigned on the frontend and is composed of
26  * - a {@link ClientIdentifier}, which uniquely identifies a single instantiation of a particular frontend
27  * - an unsigned long, which uniquely identifies the history on the backend
28  * - an unsigned long cookie, assigned by the client and meaningless on the backend, which just reflects it back
29  */
30 public final class LocalHistoryIdentifier implements WritableIdentifier {
31     /**
32      * Serialized form of {@link LocalHistoryIdentifier}.
33      *
34      * @implNote
35      *     cookie is currently required only for module-based sharding, which is implemented as part of normal
36      *     DataBroker interfaces. For DOMDataTreeProducer cookie will always be zero, hence we may end up not needing
37      *     cookie at all.
38      *     We use WritableObjects.writeLongs() to output historyId and cookie (in that order). If we end up not needing
39      *     the cookie at all, we can switch to writeLong() and use zero flags for compatibility.
40      */
41     interface SerialForm extends Externalizable {
42         @NonNull LocalHistoryIdentifier identifier();
43
44         void setIdentifier(@NonNull LocalHistoryIdentifier identifier);
45
46         @java.io.Serial
47         Object readResolve();
48
49         @Override
50         default void writeExternal(final ObjectOutput out) throws IOException {
51             final var id = identifier();
52             id.getClientId().writeTo(out);
53             WritableObjects.writeLongs(out, id.getHistoryId(), id.getCookie());
54         }
55
56         @Override
57         default void readExternal(final ObjectInput in) throws IOException {
58             final var clientId = ClientIdentifier.readFrom(in);
59
60             final byte header = WritableObjects.readLongHeader(in);
61             final var historyId = WritableObjects.readFirstLong(in, header);
62             final var cookie = WritableObjects.readSecondLong(in, header);
63             setIdentifier(new LocalHistoryIdentifier(clientId, historyId, cookie));
64         }
65     }
66
67     private static final class Proxy implements SerialForm {
68         @java.io.Serial
69         private static final long serialVersionUID = 1L;
70
71         private LocalHistoryIdentifier identifier;
72
73         // checkstyle flags the public modifier as redundant however it is explicitly needed for Java serialization to
74         // be able to create instances via reflection.
75         @SuppressWarnings("checkstyle:RedundantModifier")
76         public Proxy() {
77             // For Externalizable
78         }
79
80         Proxy(final LocalHistoryIdentifier identifier) {
81             this.identifier = requireNonNull(identifier);
82         }
83
84         @Override
85         public LocalHistoryIdentifier identifier() {
86             return verifyNotNull(identifier);
87         }
88
89         @Override
90         public void setIdentifier(final LocalHistoryIdentifier identifier) {
91             this.identifier = requireNonNull(identifier);
92         }
93
94         @Override
95         public Object readResolve() {
96             return identifier();
97         }
98     }
99
100     @java.io.Serial
101     private static final long serialVersionUID = 1L;
102
103     private final @NonNull ClientIdentifier clientId;
104     private final long historyId;
105     private final long cookie;
106
107     public LocalHistoryIdentifier(final ClientIdentifier frontendId, final long historyId) {
108         this(frontendId, historyId, 0);
109     }
110
111     public LocalHistoryIdentifier(final ClientIdentifier frontendId, final long historyId, final long cookie) {
112         clientId = requireNonNull(frontendId);
113         this.historyId = historyId;
114         this.cookie = cookie;
115     }
116
117     public static @NonNull LocalHistoryIdentifier readFrom(final DataInput in) throws IOException {
118         final ClientIdentifier clientId = ClientIdentifier.readFrom(in);
119
120         final byte header = WritableObjects.readLongHeader(in);
121         return new LocalHistoryIdentifier(clientId, WritableObjects.readFirstLong(in, header),
122             WritableObjects.readSecondLong(in, header));
123     }
124
125     @Override
126     public void writeTo(final DataOutput out) throws IOException {
127         clientId.writeTo(out);
128         WritableObjects.writeLongs(out, historyId, cookie);
129     }
130
131     public @NonNull ClientIdentifier getClientId() {
132         return clientId;
133     }
134
135     public long getHistoryId() {
136         return historyId;
137     }
138
139     public long getCookie() {
140         return cookie;
141     }
142
143     @Override
144     public int hashCode() {
145         int ret = clientId.hashCode();
146         ret = 31 * ret + Long.hashCode(historyId);
147         ret = 31 * ret + Long.hashCode(cookie);
148         return ret;
149     }
150
151     @Override
152     public boolean equals(final Object obj) {
153         if (this == obj) {
154             return true;
155         }
156         if (!(obj instanceof LocalHistoryIdentifier other)) {
157             return false;
158         }
159
160         return historyId == other.historyId && cookie == other.cookie && clientId.equals(other.clientId);
161     }
162
163     @Override
164     public String toString() {
165         return MoreObjects.toStringHelper(LocalHistoryIdentifier.class).add("client", clientId)
166                 .add("history", Long.toUnsignedString(historyId, 16))
167                 .add("cookie", Long.toUnsignedString(cookie, 16)).toString();
168     }
169
170     @java.io.Serial
171     private Object writeReplace() {
172         return new Proxy(this);
173     }
174 }