Skip to content

Commit f5c4505

Browse files
authored
Merge pull request #290 from scalecube/feature/issue-283-cluster-codec-artifact-CR2arvy
[CR287] Feature/issue 283 cluster codec artifact
2 parents 69b9fd6 + 13aa047 commit f5c4505

File tree

19 files changed

+401
-77
lines changed

19 files changed

+401
-77
lines changed

cluster-api/src/main/java/io/scalecube/cluster/Member.java

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,26 @@
11
package io.scalecube.cluster;
22

33
import io.scalecube.net.Address;
4+
import java.io.Externalizable;
5+
import java.io.IOException;
6+
import java.io.ObjectInput;
7+
import java.io.ObjectOutput;
48
import java.util.Objects;
59
import java.util.UUID;
610

711
/**
812
* Cluster member which represents node in the cluster and contains its id and address. This class
913
* is essentially immutable.
1014
*/
11-
public final class Member {
15+
public final class Member implements Externalizable {
16+
17+
private static final long serialVersionUID = 1L;
1218

1319
private String id;
1420
private String alias;
1521
private Address address;
1622

17-
/** Instantiates empty member for deserialization purpose. */
18-
Member() {}
23+
public Member() {}
1924

2025
/**
2126
* Constructor.
@@ -63,6 +68,33 @@ public int hashCode() {
6368
return Objects.hash(id, address);
6469
}
6570

71+
@Override
72+
public void writeExternal(ObjectOutput out) throws IOException {
73+
// id
74+
out.writeUTF(id);
75+
// alias
76+
boolean aliasNotNull = alias != null;
77+
out.writeBoolean(aliasNotNull);
78+
if (aliasNotNull) {
79+
out.writeUTF(alias);
80+
}
81+
// address
82+
out.writeUTF(address.toString());
83+
}
84+
85+
@Override
86+
public void readExternal(ObjectInput in) throws IOException {
87+
// id
88+
id = in.readUTF();
89+
// alias
90+
boolean aliasNotNull = in.readBoolean();
91+
if (aliasNotNull) {
92+
alias = in.readUTF();
93+
}
94+
// address
95+
address = Address.from(in.readUTF());
96+
}
97+
6698
@Override
6799
public String toString() {
68100
if (alias == null) {
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package io.scalecube.cluster.metadata;
2+
3+
import java.io.ByteArrayInputStream;
4+
import java.io.ByteArrayOutputStream;
5+
import java.io.ObjectInputStream;
6+
import java.io.ObjectOutputStream;
7+
import java.nio.ByteBuffer;
8+
import reactor.core.Exceptions;
9+
10+
public class DefaultMetadataCodec implements MetadataCodec {
11+
12+
@Override
13+
public Object deserialize(ByteBuffer buffer) {
14+
byte[] bytes = buffer.array();
15+
try (ObjectInputStream is = new ObjectInputStream(new ByteArrayInputStream(bytes))) {
16+
return is.readObject();
17+
} catch (Exception e) {
18+
throw Exceptions.propagate(e);
19+
}
20+
}
21+
22+
@Override
23+
public ByteBuffer serialize(Object metadata) {
24+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
25+
try (ObjectOutputStream os = new ObjectOutputStream(baos)) {
26+
os.writeObject(metadata);
27+
os.flush();
28+
return ByteBuffer.wrap(baos.toByteArray());
29+
} catch (Exception e) {
30+
throw Exceptions.propagate(e);
31+
}
32+
}
33+
}

cluster-api/src/main/java/io/scalecube/cluster/metadata/MetadataCodec.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
/** Contains methods for metadata serializing/deserializing logic. */
77
public interface MetadataCodec {
88

9-
MetadataCodec INSTANCE = ServiceLoaderUtil.findFirst(MetadataCodec.class).orElse(null);
9+
MetadataCodec INSTANCE =
10+
ServiceLoaderUtil.findFirst(MetadataCodec.class).orElseGet(DefaultMetadataCodec::new);
1011

1112
/**
1213
* Deserializes metadata from buffer.

cluster-testlib/pom.xml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,6 @@
2222
<artifactId>scalecube-cluster-api</artifactId>
2323
<version>${project.version}</version>
2424
</dependency>
25-
<dependency>
26-
<groupId>io.scalecube</groupId>
27-
<artifactId>scalecube-codec-jackson</artifactId>
28-
<version>${project.version}</version>
29-
</dependency>
3025
</dependencies>
3126

3227
</project>

cluster/pom.xml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,6 @@
5151
<version>${log4j.version}</version>
5252
<scope>test</scope>
5353
</dependency>
54-
<dependency>
55-
<groupId>io.scalecube</groupId>
56-
<artifactId>scalecube-codec-jackson</artifactId>
57-
<version>${project.version}</version>
58-
<scope>test</scope>
59-
</dependency>
6054
</dependencies>
6155

6256
</project>

cluster/src/main/java/io/scalecube/cluster/ClusterImpl.java

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import io.scalecube.cluster.transport.api.TransportConfig;
2121
import io.scalecube.net.Address;
2222
import io.scalecube.transport.netty.TransportImpl;
23+
import io.scalecube.utils.ServiceLoaderUtil;
24+
import java.io.Serializable;
2325
import java.lang.management.ManagementFactory;
2426
import java.nio.ByteBuffer;
2527
import java.util.Collection;
@@ -225,11 +227,7 @@ public Cluster startAwait() {
225227
}
226228

227229
private Mono<Cluster> doStart() {
228-
return Mono.defer(
229-
() -> {
230-
validateConfiguration();
231-
return doStart0();
232-
});
230+
return Mono.fromRunnable(this::validateConfiguration).then(Mono.defer(this::doStart0));
233231
}
234232

235233
private Mono<Cluster> doStart0() {
@@ -295,28 +293,31 @@ private Mono<Cluster> doStart0() {
295293
}
296294

297295
private void validateConfiguration() {
298-
MetadataDecoder metadataDecoder = config.metadataDecoder();
299-
MetadataEncoder metadataEncoder = config.metadataEncoder();
300-
MetadataCodec metadataCodec = config.metadataCodec();
301-
302-
if (metadataDecoder == null && metadataEncoder == null && metadataCodec == null) {
303-
throw new IllegalArgumentException("Invalid cluster config");
304-
}
296+
final MetadataDecoder metadataDecoder = config.metadataDecoder();
297+
final MetadataEncoder metadataEncoder = config.metadataEncoder();
298+
final MetadataCodec metadataCodec =
299+
ServiceLoaderUtil.findFirst(MetadataCodec.class).orElse(null);
305300

306301
if (metadataDecoder != null && metadataEncoder != null && metadataCodec != null) {
307-
throw new IllegalArgumentException("Invalid cluster config");
302+
throw new IllegalArgumentException(
303+
"Invalid cluster config: either pair of [metadataDecoder, metadataEncoder] "
304+
+ "or metadataCodec must be specified, not both");
308305
}
309306

310-
if (metadataCodec == null) {
311-
Objects.requireNonNull(
312-
metadataDecoder, "Invalid cluster config: metadataDecoder must be specified");
313-
Objects.requireNonNull(
314-
metadataEncoder, "Invalid cluster config: metadataEncoder must be specified");
307+
if ((metadataDecoder == null && metadataEncoder != null)
308+
|| (metadataDecoder != null && metadataEncoder == null)) {
309+
throw new IllegalArgumentException(
310+
"Invalid cluster config: both of [metadataDecoder, metadataEncoder] must be specified");
315311
}
316312

317313
if (metadataDecoder == null && metadataEncoder == null) {
318-
Objects.requireNonNull(
319-
metadataCodec, "Invalid cluster config: metadataCodec must be specified");
314+
if (metadataCodec == null) {
315+
Object metadata = config.metadata();
316+
if (metadata != null && !(metadata instanceof Serializable)) {
317+
throw new IllegalArgumentException(
318+
"Invalid cluster config: metadata must be Serializable");
319+
}
320+
}
320321
}
321322

322323
Objects.requireNonNull(

cluster/src/main/java/io/scalecube/cluster/fdetector/PingData.java

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
package io.scalecube.cluster.fdetector;
22

33
import io.scalecube.cluster.Member;
4+
import java.io.Externalizable;
5+
import java.io.IOException;
6+
import java.io.ObjectInput;
7+
import java.io.ObjectOutput;
48
import java.util.StringJoiner;
59

610
/** DTO class. Supports FailureDetector messages (Ping, Ack, PingReq). */
7-
final class PingData {
11+
final class PingData implements Externalizable {
12+
13+
private static final long serialVersionUID = 1L;
814

915
enum AckType {
1016

@@ -32,8 +38,7 @@ enum AckType {
3238
/** Ping response type. */
3339
private AckType ackType;
3440

35-
/** Instantiates empty ping data for deserialization purpose. */
36-
PingData() {}
41+
public PingData() {}
3742

3843
private PingData(PingData other) {
3944
this.from = other.from;
@@ -78,6 +83,30 @@ public PingData withAckType(AckType ackType) {
7883
return p;
7984
}
8085

86+
@Override
87+
public void writeExternal(ObjectOutput out) throws IOException {
88+
// from
89+
out.writeObject(from);
90+
// to
91+
out.writeObject(to);
92+
// originalIssuer
93+
out.writeObject(originalIssuer);
94+
// ackType
95+
out.writeObject(ackType);
96+
}
97+
98+
@Override
99+
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
100+
// from
101+
from = (Member) in.readObject();
102+
// to
103+
to = (Member) in.readObject();
104+
// originalIssuer
105+
originalIssuer = (Member) in.readObject();
106+
// ackType
107+
ackType = (AckType) in.readObject();
108+
}
109+
81110
@Override
82111
public String toString() {
83112
return new StringJoiner(", ", PingData.class.getSimpleName() + "[", "]")

cluster/src/main/java/io/scalecube/cluster/gossip/Gossip.java

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,24 @@
11
package io.scalecube.cluster.gossip;
22

33
import io.scalecube.cluster.transport.api.Message;
4+
import java.io.Externalizable;
5+
import java.io.IOException;
6+
import java.io.ObjectInput;
7+
import java.io.ObjectOutput;
48
import java.util.Objects;
59
import java.util.StringJoiner;
610

711
/** Data model for gossip, include gossip id, qualifier and object need to disseminate. */
8-
final class Gossip {
12+
final class Gossip implements Externalizable {
13+
14+
private static final long serialVersionUID = 1L;
915

1016
private String gossiperId;
1117
private Message message;
1218
// incremented counter
1319
private long sequenceId;
1420

15-
/** Instantiates empty gossip for deserialization purpose. */
16-
Gossip() {}
21+
public Gossip() {}
1722

1823
public Gossip(String gossiperId, Message message, long sequenceId) {
1924
this.gossiperId = Objects.requireNonNull(gossiperId);
@@ -56,6 +61,26 @@ public int hashCode() {
5661
return Objects.hash(gossiperId, message, sequenceId);
5762
}
5863

64+
@Override
65+
public void writeExternal(ObjectOutput out) throws IOException {
66+
// gossiperId
67+
out.writeUTF(gossiperId);
68+
// message
69+
out.writeObject(message);
70+
// sequenceId
71+
out.writeLong(sequenceId);
72+
}
73+
74+
@Override
75+
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
76+
// gossiperId
77+
gossiperId = in.readUTF();
78+
// message
79+
message = (Message) in.readObject();
80+
// sequenceId
81+
sequenceId = in.readLong();
82+
}
83+
5984
@Override
6085
public String toString() {
6186
return new StringJoiner(", ", Gossip.class.getSimpleName() + "[", "]")

cluster/src/main/java/io/scalecube/cluster/gossip/GossipRequest.java

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,32 @@
11
package io.scalecube.cluster.gossip;
22

3+
import java.io.Externalizable;
4+
import java.io.IOException;
5+
import java.io.ObjectInput;
6+
import java.io.ObjectOutput;
37
import java.util.ArrayList;
48
import java.util.Collections;
59
import java.util.List;
10+
import java.util.Objects;
611
import java.util.StringJoiner;
712

813
/** Gossip request which be transmitted through the network, contains list of gossips. */
9-
final class GossipRequest {
14+
final class GossipRequest implements Externalizable {
15+
16+
private static final long serialVersionUID = 1L;
1017

1118
private List<Gossip> gossips;
1219
private String from;
1320

14-
/** Instantiates empty gossip request for deserialization purpose. */
15-
GossipRequest() {}
21+
public GossipRequest() {}
1622

1723
public GossipRequest(Gossip gossip, String from) {
1824
this(Collections.singletonList(gossip), from);
1925
}
2026

2127
public GossipRequest(List<Gossip> gossips, String from) {
28+
Objects.requireNonNull(gossips);
29+
Objects.requireNonNull(from);
2230
this.gossips = new ArrayList<>(gossips);
2331
this.from = from;
2432
}
@@ -31,6 +39,29 @@ public String from() {
3139
return from;
3240
}
3341

42+
@Override
43+
public void writeExternal(ObjectOutput out) throws IOException {
44+
// gossips
45+
out.writeInt(gossips.size());
46+
for (Gossip gossip : gossips) {
47+
out.writeObject(gossip);
48+
}
49+
// from
50+
out.writeUTF(from);
51+
}
52+
53+
@Override
54+
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
55+
// gossips
56+
int size = in.readInt();
57+
gossips = new ArrayList<>(size);
58+
for (int i = 0; i < size; i++) {
59+
gossips.add((Gossip) in.readObject());
60+
}
61+
// from
62+
from = in.readUTF();
63+
}
64+
3465
@Override
3566
public String toString() {
3667
return new StringJoiner(", ", GossipRequest.class.getSimpleName() + "[", "]")

cluster/src/main/java/io/scalecube/cluster/membership/MembershipProtocolImpl.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,10 @@ private void schedulePeriodicSync() {
493493
private Message prepareSyncDataMsg(String qualifier, String cid) {
494494
List<MembershipRecord> membershipRecords = new ArrayList<>(membershipTable.values());
495495
SyncData syncData = new SyncData(membershipRecords, membershipConfig.syncGroup());
496-
return Message.withData(syncData).qualifier(qualifier).correlationId(cid).build();
496+
return Message.withData(syncData)
497+
.qualifier(qualifier)
498+
.correlationId(Optional.ofNullable(cid).orElse("null"))
499+
.build();
497500
}
498501

499502
private Mono<Void> syncMembership(SyncData syncData, boolean onStart) {

0 commit comments

Comments
 (0)