BUG-5280: introduce cookie in LocalHistoryIdentifier
[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 com.google.common.base.MoreObjects;
11 import com.google.common.base.Preconditions;
12 import java.io.DataInput;
13 import java.io.DataOutput;
14 import java.io.Externalizable;
15 import java.io.IOException;
16 import java.io.ObjectInput;
17 import java.io.ObjectOutput;
18 import org.opendaylight.yangtools.concepts.WritableIdentifier;
19 import org.opendaylight.yangtools.concepts.WritableObjects;
20
21 /**
22  * Globally-unique identifier of a local history. This identifier is assigned on the frontend and is composed of
23  * - a {@link ClientIdentifier}, which uniquely identifies a single instantiation of a particular frontend
24  * - an unsigned long, which uniquely identifies the history on the backend
25  * - an unsigned long cookie, assigned by the client and meaningless on the backend, which just reflects it back
26  *
27  * @author Robert Varga
28  */
29 public final class LocalHistoryIdentifier implements WritableIdentifier {
30     /*
31      * Implementation note: cookie is currently required only for module-based sharding, which is implemented as part
32      *                      of normal DataBroker interfaces. For DOMDataTreeProducer cookie will always be zero, hence
33      *                      we may end up not needing cookie at all.
34      *
35      *                      We use WritableObjects.writeLongs() to output historyId and cookie (in that order). If we
36      *                      end up not needing the cookie at all, we can switch to writeLong() and use zero flags for
37      *                      compatibility.
38      */
39     private static final class Proxy implements Externalizable {
40         private static final long serialVersionUID = 1L;
41         private ClientIdentifier clientId;
42         private long historyId;
43         private long cookie;
44
45         public Proxy() {
46             // For Externalizable
47         }
48
49         Proxy(final ClientIdentifier frontendId, final long historyId, final long cookie) {
50             this.clientId = Preconditions.checkNotNull(frontendId);
51             this.historyId = historyId;
52             this.cookie = cookie;
53         }
54
55         @Override
56         public void writeExternal(final ObjectOutput out) throws IOException {
57             clientId.writeTo(out);
58             WritableObjects.writeLongs(out, historyId, cookie);
59         }
60
61         @Override
62         public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
63             clientId = ClientIdentifier.readFrom(in);
64
65             final byte header = WritableObjects.readLongHeader(in);
66             historyId = WritableObjects.readFirstLong(in, header);
67             cookie = WritableObjects.readSecondLong(in, header);
68         }
69
70         private Object readResolve() {
71             return new LocalHistoryIdentifier(clientId, historyId, cookie);
72         }
73     }
74
75     private static final long serialVersionUID = 1L;
76     private final ClientIdentifier clientId;
77     private final long historyId;
78     private final long cookie;
79
80     public LocalHistoryIdentifier(final ClientIdentifier frontendId, final long historyId) {
81         this(frontendId, historyId, 0);
82     }
83
84     public LocalHistoryIdentifier(final ClientIdentifier frontendId, final long historyId, final long cookie) {
85         this.clientId = Preconditions.checkNotNull(frontendId);
86         this.historyId = historyId;
87         this.cookie = cookie;
88     }
89
90     public static LocalHistoryIdentifier readFrom(final DataInput in) throws IOException {
91         final ClientIdentifier clientId = ClientIdentifier.readFrom(in);
92
93         final byte header = WritableObjects.readLongHeader(in);
94         return new LocalHistoryIdentifier(clientId, WritableObjects.readFirstLong(in, header),
95             WritableObjects.readSecondLong(in, header));
96     }
97
98     @Override
99     public void writeTo(final DataOutput out) throws IOException {
100         clientId.writeTo(out);
101         WritableObjects.writeLongs(out, historyId, cookie);
102     }
103
104     public ClientIdentifier getClientId() {
105         return clientId;
106     }
107
108     public long getHistoryId() {
109         return historyId;
110     }
111
112     public long getCookie() {
113         return cookie;
114     }
115
116     @Override
117     public int hashCode() {
118         int ret = clientId.hashCode();
119         ret = 31 * ret + Long.hashCode(historyId);
120         ret = 31 * ret + Long.hashCode(cookie);
121         return ret;
122     }
123
124     @Override
125     public boolean equals(final Object o) {
126         if (this == o) {
127             return true;
128         }
129         if (!(o instanceof LocalHistoryIdentifier)) {
130             return false;
131         }
132
133         final LocalHistoryIdentifier other = (LocalHistoryIdentifier) o;
134         return historyId == other.historyId && cookie == other.cookie && clientId.equals(other.clientId);
135     }
136
137     @Override
138     public String toString() {
139         return MoreObjects.toStringHelper(LocalHistoryIdentifier.class).add("client", clientId)
140                 .add("history", Long.toUnsignedString(historyId, 16))
141                 .add("cookie", Long.toUnsignedString(cookie, 16)).toString();
142     }
143
144     private Object writeReplace() {
145         return new Proxy(clientId, historyId, cookie);
146     }
147 }