'git mv' rst resources to md
This is mainly intended to keep the git history as neat as possible. No actual conversion yet, so now both the rst and the paradox docs are broken, which will be fixed in the next commits.
This commit is contained in:
parent
5507147073
commit
a4a0d308ad
553 changed files with 0 additions and 0 deletions
|
|
@ -1,534 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package jdocs.persistence;
|
||||
|
||||
import docs.persistence.ExampleJsonMarshaller;
|
||||
import docs.persistence.proto.FlightAppModels;
|
||||
import java.nio.charset.Charset;
|
||||
import spray.json.JsObject;
|
||||
|
||||
import akka.persistence.journal.EventAdapter;
|
||||
import akka.persistence.journal.EventSeq;
|
||||
import akka.protobuf.InvalidProtocolBufferException;
|
||||
import akka.serialization.SerializerWithStringManifest;
|
||||
|
||||
public class PersistenceSchemaEvolutionDocTest {
|
||||
|
||||
static
|
||||
//#protobuf-read-optional-model
|
||||
public enum SeatType {
|
||||
Window("W"), Aisle("A"), Other("O"), Unknown("");
|
||||
|
||||
private final String code;
|
||||
|
||||
private SeatType(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public static SeatType fromCode(String c) {
|
||||
if (Window.code.equals(c))
|
||||
return Window;
|
||||
else if (Aisle.code.equals(c))
|
||||
return Aisle;
|
||||
else if (Other.code.equals(c))
|
||||
return Other;
|
||||
else
|
||||
return Unknown;
|
||||
}
|
||||
}
|
||||
//#protobuf-read-optional-model
|
||||
|
||||
static
|
||||
//#protobuf-read-optional-model
|
||||
public class SeatReserved {
|
||||
public final String letter;
|
||||
public final int row;
|
||||
public final SeatType seatType;
|
||||
|
||||
public SeatReserved(String letter, int row, SeatType seatType) {
|
||||
this.letter = letter;
|
||||
this.row = row;
|
||||
this.seatType = seatType;
|
||||
}
|
||||
}
|
||||
//#protobuf-read-optional-model
|
||||
|
||||
static
|
||||
//#protobuf-read-optional
|
||||
/**
|
||||
* Example serializer impl which uses protocol buffers generated classes (proto.*)
|
||||
* to perform the to/from binary marshalling.
|
||||
*/
|
||||
public class AddedFieldsSerializerWithProtobuf extends SerializerWithStringManifest {
|
||||
@Override public int identifier() {
|
||||
return 67876;
|
||||
}
|
||||
|
||||
private final String seatReservedManifest = SeatReserved.class.getName();
|
||||
|
||||
@Override public String manifest(Object o){
|
||||
return o.getClass().getName();
|
||||
}
|
||||
|
||||
@Override public Object fromBinary(byte[] bytes, String manifest) {
|
||||
if (seatReservedManifest.equals(manifest)) {
|
||||
// use generated protobuf serializer
|
||||
try {
|
||||
return seatReserved(FlightAppModels.SeatReserved.parseFrom(bytes));
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw new IllegalArgumentException(e.getMessage());
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unable to handle manifest: " + manifest);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public byte[] toBinary(Object o) {
|
||||
if (o instanceof SeatReserved) {
|
||||
SeatReserved s = (SeatReserved) o;
|
||||
return FlightAppModels.SeatReserved.newBuilder()
|
||||
.setRow(s.row)
|
||||
.setLetter(s.letter)
|
||||
.setSeatType(s.seatType.code)
|
||||
.build().toByteArray();
|
||||
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unable to handle: " + o);
|
||||
}
|
||||
}
|
||||
|
||||
// -- fromBinary helpers --
|
||||
|
||||
private SeatReserved seatReserved(FlightAppModels.SeatReserved p) {
|
||||
return new SeatReserved(p.getLetter(), p.getRow(), seatType(p));
|
||||
}
|
||||
|
||||
// handle missing field by assigning "Unknown" value
|
||||
private SeatType seatType(FlightAppModels.SeatReserved p) {
|
||||
if (p.hasSeatType())
|
||||
return SeatType.fromCode(p.getSeatType());
|
||||
else
|
||||
return SeatType.Unknown;
|
||||
}
|
||||
|
||||
}
|
||||
//#protobuf-read-optional
|
||||
|
||||
|
||||
public static class RenamePlainJson {
|
||||
static
|
||||
//#rename-plain-json
|
||||
public class JsonRenamedFieldAdapter implements EventAdapter {
|
||||
// use your favorite json library
|
||||
private final ExampleJsonMarshaller marshaller = new ExampleJsonMarshaller();
|
||||
|
||||
private final String V1 = "v1";
|
||||
private final String V2 = "v2";
|
||||
|
||||
// this could be done independently for each event type
|
||||
@Override public String manifest(Object event) {
|
||||
return V2;
|
||||
}
|
||||
|
||||
@Override public JsObject toJournal(Object event) {
|
||||
return marshaller.toJson(event);
|
||||
}
|
||||
|
||||
@Override public EventSeq fromJournal(Object event, String manifest) {
|
||||
if (event instanceof JsObject) {
|
||||
JsObject json = (JsObject) event;
|
||||
if (V1.equals(manifest))
|
||||
json = rename(json, "code", "seatNr");
|
||||
return EventSeq.single(json);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Can only work with JSON, was: " +
|
||||
event.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
private JsObject rename(JsObject json, String from, String to) {
|
||||
// use your favorite json library to rename the field
|
||||
JsObject renamed = json;
|
||||
return renamed;
|
||||
}
|
||||
|
||||
}
|
||||
//#rename-plain-json
|
||||
}
|
||||
|
||||
public static class SimplestCustomSerializer {
|
||||
|
||||
static
|
||||
//#simplest-custom-serializer-model
|
||||
public class Person {
|
||||
public final String name;
|
||||
public final String surname;
|
||||
public Person(String name, String surname) {
|
||||
this.name = name;
|
||||
this.surname = surname;
|
||||
}
|
||||
}
|
||||
//#simplest-custom-serializer-model
|
||||
|
||||
static
|
||||
//#simplest-custom-serializer
|
||||
/**
|
||||
* Simplest possible serializer, uses a string representation of the Person class.
|
||||
*
|
||||
* Usually a serializer like this would use a library like:
|
||||
* protobuf, kryo, avro, cap'n proto, flatbuffers, SBE or some other dedicated serializer backend
|
||||
* to perform the actual to/from bytes marshalling.
|
||||
*/
|
||||
public class SimplestPossiblePersonSerializer extends SerializerWithStringManifest {
|
||||
private final Charset utf8 = Charset.forName("UTF-8");
|
||||
|
||||
private final String personManifest = Person.class.getName();
|
||||
|
||||
// unique identifier of the serializer
|
||||
@Override public int identifier() {
|
||||
return 1234567;
|
||||
}
|
||||
|
||||
// extract manifest to be stored together with serialized object
|
||||
@Override public String manifest(Object o) {
|
||||
return o.getClass().getName();
|
||||
}
|
||||
|
||||
// serialize the object
|
||||
@Override public byte[] toBinary(Object obj) {
|
||||
if (obj instanceof Person) {
|
||||
Person p = (Person) obj;
|
||||
return (p.name + "|" + p.surname).getBytes(utf8);
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Unable to serialize to bytes, clazz was: " + obj.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
// deserialize the object, using the manifest to indicate which logic to apply
|
||||
@Override public Object fromBinary(byte[] bytes, String manifest) {
|
||||
if (personManifest.equals(manifest)) {
|
||||
String nameAndSurname = new String(bytes, utf8);
|
||||
String[] parts = nameAndSurname.split("[|]");
|
||||
return new Person(parts[0], parts[1]);
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Unable to deserialize from bytes, manifest was: " + manifest +
|
||||
"! Bytes length: " + bytes.length);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//#simplest-custom-serializer
|
||||
}
|
||||
|
||||
|
||||
public static class SamplePayload {
|
||||
private final Object payload;
|
||||
|
||||
public SamplePayload(Object payload) {
|
||||
this.payload = payload;
|
||||
}
|
||||
|
||||
public Object getPayload() {
|
||||
return payload;
|
||||
}
|
||||
}
|
||||
|
||||
//#split-events-during-recovery
|
||||
interface V1 {};
|
||||
interface V2 {}
|
||||
|
||||
//#split-events-during-recovery
|
||||
static
|
||||
//#split-events-during-recovery
|
||||
// V1 event:
|
||||
public class UserDetailsChanged implements V1 {
|
||||
public final String name;
|
||||
public final String address;
|
||||
public UserDetailsChanged(String name, String address) {
|
||||
this.name = name;
|
||||
this.address = address;
|
||||
}
|
||||
}
|
||||
|
||||
//#split-events-during-recovery
|
||||
static
|
||||
//#split-events-during-recovery
|
||||
// corresponding V2 events:
|
||||
public class UserNameChanged implements V2 {
|
||||
public final String name;
|
||||
|
||||
public UserNameChanged(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
//#split-events-during-recovery
|
||||
static
|
||||
//#split-events-during-recovery
|
||||
public class UserAddressChanged implements V2 {
|
||||
public final String address;
|
||||
|
||||
public UserAddressChanged(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
}
|
||||
|
||||
//#split-events-during-recovery
|
||||
static
|
||||
//#split-events-during-recovery
|
||||
// event splitting adapter:
|
||||
public class UserEventsAdapter implements EventAdapter {
|
||||
@Override public String manifest(Object event) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override public EventSeq fromJournal(Object event, String manifest) {
|
||||
if (event instanceof UserDetailsChanged) {
|
||||
UserDetailsChanged c = (UserDetailsChanged) event;
|
||||
if (c.name == null)
|
||||
return EventSeq.single(new UserAddressChanged(c.address));
|
||||
else if (c.address == null)
|
||||
return EventSeq.single(new UserNameChanged(c.name));
|
||||
else
|
||||
return EventSeq.create(
|
||||
new UserNameChanged(c.name),
|
||||
new UserAddressChanged(c.address));
|
||||
} else {
|
||||
return EventSeq.single(event);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public Object toJournal(Object event) {
|
||||
return event;
|
||||
}
|
||||
}
|
||||
//#split-events-during-recovery
|
||||
|
||||
|
||||
static public class CustomerBlinked {
|
||||
public final long customerId;
|
||||
|
||||
public CustomerBlinked(long customerId) {
|
||||
this.customerId = customerId;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
//#string-serializer-skip-deleved-event-by-manifest
|
||||
public class EventDeserializationSkipped {
|
||||
public static EventDeserializationSkipped instance =
|
||||
new EventDeserializationSkipped();
|
||||
|
||||
private EventDeserializationSkipped() {
|
||||
}
|
||||
}
|
||||
|
||||
//#string-serializer-skip-deleved-event-by-manifest
|
||||
static
|
||||
//#string-serializer-skip-deleved-event-by-manifest
|
||||
public class RemovedEventsAwareSerializer extends SerializerWithStringManifest {
|
||||
private final Charset utf8 = Charset.forName("UTF-8");
|
||||
private final String customerBlinkedManifest = "blinked";
|
||||
|
||||
// unique identifier of the serializer
|
||||
@Override public int identifier() {
|
||||
return 8337;
|
||||
}
|
||||
|
||||
// extract manifest to be stored together with serialized object
|
||||
@Override public String manifest(Object o) {
|
||||
if (o instanceof CustomerBlinked)
|
||||
return customerBlinkedManifest;
|
||||
else
|
||||
return o.getClass().getName();
|
||||
}
|
||||
|
||||
@Override public byte[] toBinary(Object o) {
|
||||
return o.toString().getBytes(utf8); // example serialization
|
||||
}
|
||||
|
||||
@Override public Object fromBinary(byte[] bytes, String manifest) {
|
||||
if (customerBlinkedManifest.equals(manifest))
|
||||
return EventDeserializationSkipped.instance;
|
||||
else
|
||||
return new String(bytes, utf8);
|
||||
}
|
||||
}
|
||||
//#string-serializer-skip-deleved-event-by-manifest
|
||||
|
||||
static
|
||||
//#string-serializer-skip-deleved-event-by-manifest-adapter
|
||||
public class SkippedEventsAwareAdapter implements EventAdapter {
|
||||
@Override public String manifest(Object event) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override public Object toJournal(Object event) {
|
||||
return event;
|
||||
}
|
||||
|
||||
@Override public EventSeq fromJournal(Object event, String manifest) {
|
||||
if (event == EventDeserializationSkipped.instance)
|
||||
return EventSeq.empty();
|
||||
else
|
||||
return EventSeq.single(event);
|
||||
}
|
||||
}
|
||||
//#string-serializer-skip-deleved-event-by-manifest-adapter
|
||||
|
||||
|
||||
//#string-serializer-handle-rename
|
||||
static
|
||||
//#string-serializer-handle-rename
|
||||
public class RenamedEventAwareSerializer extends SerializerWithStringManifest {
|
||||
private final Charset utf8 = Charset.forName("UTF-8");
|
||||
|
||||
// unique identifier of the serializer
|
||||
@Override public int identifier() {
|
||||
return 8337;
|
||||
}
|
||||
|
||||
private final String oldPayloadClassName =
|
||||
"docs.persistence.OldPayload"; // class NOT available anymore
|
||||
private final String myPayloadClassName =
|
||||
SamplePayload.class.getName();
|
||||
|
||||
// extract manifest to be stored together with serialized object
|
||||
@Override public String manifest(Object o) {
|
||||
return o.getClass().getName();
|
||||
}
|
||||
|
||||
@Override public byte[] toBinary(Object o) {
|
||||
if (o instanceof SamplePayload) {
|
||||
SamplePayload s = (SamplePayload) o;
|
||||
return s.payload.toString().getBytes(utf8);
|
||||
} else {
|
||||
// previously also handled "old" events here.
|
||||
throw new IllegalArgumentException(
|
||||
"Unable to serialize to bytes, clazz was: " + o.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override public Object fromBinary(byte[] bytes, String manifest) {
|
||||
if (oldPayloadClassName.equals(manifest))
|
||||
return new SamplePayload(new String(bytes, utf8));
|
||||
else if (myPayloadClassName.equals(manifest))
|
||||
return new SamplePayload(new String(bytes, utf8));
|
||||
else throw new IllegalArgumentException("unexpected manifest [" + manifest + "]");
|
||||
}
|
||||
}
|
||||
//#string-serializer-handle-rename
|
||||
|
||||
static
|
||||
//#detach-models
|
||||
// Domain model - highly optimised for domain language and maybe "fluent" usage
|
||||
public class Customer {
|
||||
public final String name;
|
||||
|
||||
public Customer(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
//#detach-models
|
||||
static
|
||||
//#detach-models
|
||||
public class Seat {
|
||||
public final String code;
|
||||
|
||||
public Seat(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public SeatBooked bookFor(Customer customer) {
|
||||
return new SeatBooked(code, customer);
|
||||
}
|
||||
}
|
||||
|
||||
//#detach-models
|
||||
static
|
||||
//#detach-models
|
||||
public class SeatBooked {
|
||||
public final String code;
|
||||
public final Customer customer;
|
||||
|
||||
public SeatBooked(String code, Customer customer) {
|
||||
this.code = code;
|
||||
this.customer = customer;
|
||||
}
|
||||
}
|
||||
|
||||
//#detach-models
|
||||
static
|
||||
//#detach-models
|
||||
// Data model - highly optimised for schema evolution and persistence
|
||||
public class SeatBookedData {
|
||||
public final String code;
|
||||
public final String customerName;
|
||||
|
||||
public SeatBookedData(String code, String customerName) {
|
||||
this.code = code;
|
||||
this.customerName = customerName;
|
||||
}
|
||||
}
|
||||
//#detach-models
|
||||
|
||||
//#detach-models-adapter
|
||||
class DetachedModelsAdapter implements EventAdapter {
|
||||
@Override public String manifest(Object event) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override public Object toJournal(Object event) {
|
||||
if (event instanceof SeatBooked) {
|
||||
SeatBooked s = (SeatBooked) event;
|
||||
return new SeatBookedData(s.code, s.customer.name);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported: " + event.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
@Override public EventSeq fromJournal(Object event, String manifest) {
|
||||
if (event instanceof SeatBookedData) {
|
||||
SeatBookedData d = (SeatBookedData) event;
|
||||
return EventSeq.single(new SeatBooked(d.code, new Customer(d.customerName)));
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported: " + event.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
//#detach-models-adapter
|
||||
|
||||
static
|
||||
//#detach-models-adapter-json
|
||||
public class JsonDataModelAdapter implements EventAdapter {
|
||||
|
||||
// use your favorite json library
|
||||
private final ExampleJsonMarshaller marshaller =
|
||||
new ExampleJsonMarshaller();
|
||||
|
||||
@Override public String manifest(Object event) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override public JsObject toJournal(Object event) {
|
||||
return marshaller.toJson(event);
|
||||
}
|
||||
|
||||
@Override public EventSeq fromJournal(Object event, String manifest) {
|
||||
if (event instanceof JsObject) {
|
||||
JsObject json = (JsObject) event;
|
||||
return EventSeq.single(marshaller.fromJson(json));
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Unable to fromJournal a non-JSON object! Was: " + event.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
//#detach-models-adapter-json
|
||||
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue