Add cds-access-api SODIUM_SR1 version
[controller.git] / opendaylight / md-sal / cds-access-api / src / main / java / org / opendaylight / controller / cluster / access / concepts / Message.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.annotations.Beta;
14 import com.google.common.annotations.VisibleForTesting;
15 import com.google.common.base.MoreObjects;
16 import com.google.common.base.MoreObjects.ToStringHelper;
17 import java.io.Serializable;
18 import org.eclipse.jdt.annotation.NonNull;
19 import org.opendaylight.controller.cluster.access.ABIVersion;
20 import org.opendaylight.yangtools.concepts.Immutable;
21 import org.opendaylight.yangtools.concepts.WritableIdentifier;
22
23 /**
24  * An abstract concept of a Message. This class cannot be instantiated directly, use its specializations {@link Request}
25  * and {@link Response}.
26  *
27  * <p>
28  * Messages have a target and a sequence number. Sequence numbers are expected to be assigned monotonically on a
29  * per-target basis, hence two targets can observe the same sequence number.
30  *
31  * <p>
32  * This class includes explicit versioning for forward- and backward- compatibility of serialization format. This is
33  * achieved by using the serialization proxy pattern. Subclasses are in complete control of what proxy is used to
34  * serialize a particular object on the wire. This class can serve as an explicit version marker, hence no further
35  * action is necessary in the deserialization path.
36  *
37  * <p>
38  * For the serialization path an explicit call from the user is required to select the appropriate serialization
39  * version. This is done via {@link #toVersion(ABIVersion)} method, which should return a copy of this object with
40  * the requested ABI version recorded and should return the appropriate serialization proxy.
41  *
42  * <p>
43  * This workflow allows least disturbance across ABI versions, as all messages not affected by a ABI version bump
44  * will remain working with the same serialization format for the new ABI version.
45  *
46  * <p>
47  * Note that this class specifies the {@link Immutable} contract, which means that all subclasses must follow this API
48  * contract.
49  *
50  * @author Robert Varga
51  *
52  * @param <T> Target identifier type
53  * @param <C> Message type
54  */
55 @Beta
56 public abstract class Message<T extends WritableIdentifier, C extends Message<T, C>> implements Immutable,
57         Serializable {
58     private static final long serialVersionUID = 1L;
59
60     private final @NonNull ABIVersion version;
61     private final long sequence;
62     private final @NonNull T target;
63
64     private Message(final ABIVersion version, final T target, final long sequence) {
65         this.target = requireNonNull(target);
66         this.version = requireNonNull(version);
67         this.sequence = sequence;
68     }
69
70     Message(final T target, final long sequence) {
71         this(ABIVersion.current(), target, sequence);
72     }
73
74     Message(final C msg, final ABIVersion version) {
75         this(version, msg.getTarget(), msg.getSequence());
76     }
77
78     /**
79      * Get the target identifier for this message.
80      *
81      * @return Target identifier
82      */
83     public final @NonNull T getTarget() {
84         return target;
85     }
86
87     /**
88      * Get the logical sequence number.
89      *
90      * @return logical sequence number
91      */
92     public final long getSequence() {
93         return sequence;
94     }
95
96     @VisibleForTesting
97     public final @NonNull ABIVersion getVersion() {
98         return version;
99     }
100
101     /**
102      * Return a message which will end up being serialized in the specified {@link ABIVersion}.
103      *
104      * @param toVersion Request {@link ABIVersion}
105      * @return A new message which will use ABIVersion as its serialization.
106      */
107     @SuppressWarnings("unchecked")
108     public final @NonNull C toVersion(final @NonNull ABIVersion toVersion) {
109         if (this.version == toVersion) {
110             return (C)this;
111         }
112
113         switch (toVersion) {
114             case BORON:
115             case NEON_SR2:
116             case SODIUM_SR1:
117                 return verifyNotNull(cloneAsVersion(toVersion));
118             case TEST_PAST_VERSION:
119             case TEST_FUTURE_VERSION:
120             default:
121                 throw new IllegalArgumentException("Unhandled ABI version " + toVersion);
122         }
123     }
124
125     /**
126      * Create a copy of this message which will serialize to a stream corresponding to the specified method. This
127      * method should be implemented by the concrete final message class and should invoke the equivalent of
128      * {@link #Message(Message, ABIVersion)}.
129      *
130      * @param targetVersion target ABI version
131      * @return A message with the specified serialization stream
132      * @throws IllegalArgumentException if this message does not support the target ABI
133      */
134     protected abstract @NonNull C cloneAsVersion(@NonNull ABIVersion targetVersion);
135
136     @Override
137     public final String toString() {
138         return addToStringAttributes(MoreObjects.toStringHelper(this).omitNullValues()).toString();
139     }
140
141     /**
142      * Add attributes to the output of {@link #toString()}. Subclasses wanting to contribute additional information
143      * should override this method. Any null attributes will be omitted from the output.
144      *
145      * @param toStringHelper a {@link ToStringHelper} instance
146      * @return The {@link ToStringHelper} passed in as argument
147      * @throws NullPointerException if toStringHelper is null
148      */
149     protected @NonNull ToStringHelper addToStringAttributes(final @NonNull ToStringHelper toStringHelper) {
150         return toStringHelper.add("target", target).add("sequence", Long.toUnsignedString(sequence));
151     }
152
153     /**
154      * Instantiate a serialization proxy for this object for the target ABI version. Implementations should return
155      * different objects for incompatible {@link ABIVersion}s. This method should never fail, as any compatibility
156      * checks should have been done by {@link #cloneAsVersion(ABIVersion)}.
157      *
158      * @param reqVersion Requested ABI version
159      * @return Proxy for this object
160      */
161     abstract @NonNull AbstractMessageProxy<T, C> externalizableProxy(@NonNull ABIVersion reqVersion);
162
163     protected final Object writeReplace() {
164         return externalizableProxy(version);
165     }
166 }

©2013 OpenDaylight, A Linux Foundation Collaborative Project. All Rights Reserved.
OpenDaylight is a registered trademark of The OpenDaylight Project, Inc.
Linux Foundation and OpenDaylight are registered trademarks of the Linux Foundation.
Linux is a registered trademark of Linus Torvalds.