diff --git a/akka-docs/_sphinx/themes/akka/static/docs.css b/akka-docs/_sphinx/themes/akka/static/docs.css
index cb29db7526..fbc53ad71b 100644
--- a/akka-docs/_sphinx/themes/akka/static/docs.css
+++ b/akka-docs/_sphinx/themes/akka/static/docs.css
@@ -178,3 +178,6 @@ strong {color: #0B5567; }
.section-marker { position: absolute; width: 1em; margin-left: -1em; display: block; text-decoration: none; visibility: hidden; text-align: center; font-weight: normal; }
.section-marker:hover { text-decoration: none; }
.section h2:hover > a,.section h3:hover > a,.section h4:hover > a,.section h5:hover > a { visibility: visible; }
+
+div.align-center { width: 100%; text-align: center; }
+p.caption { width: 80%; text-align: justify; font-size: 0.95em; font-style: italic; position: relative; left: 10%; }
\ No newline at end of file
diff --git a/akka-docs/rst/experimental/index.rst b/akka-docs/rst/experimental/index.rst
index d94014b5af..8b2bae6a4e 100644
--- a/akka-docs/rst/experimental/index.rst
+++ b/akka-docs/rst/experimental/index.rst
@@ -20,6 +20,7 @@ prior deprecation.
:maxdepth: 1
../scala/persistence
+ ../scala/persistence-schema-evolution
../dev/multi-node-testing
../java/lambda-actors
../java/lambda-fsm
diff --git a/akka-docs/rst/images/persistence-detach-models.graffle b/akka-docs/rst/images/persistence-detach-models.graffle
new file mode 100644
index 0000000000..40c7f808e1
--- /dev/null
+++ b/akka-docs/rst/images/persistence-detach-models.graffle
@@ -0,0 +1,596 @@
+
+
+
+
+ ActiveLayerIndex
+ 0
+ ApplicationVersion
+
+ com.omnigroup.OmniGrafflePro
+ 139.18.0.187838
+
+ AutoAdjust
+
+ BackgroundGraphic
+
+ Bounds
+ {{0, 0}, {559.28997802734375, 782.8900146484375}}
+ Class
+ SolidGraphic
+ ID
+ 2
+ Style
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+
+ BaseZoom
+ 0
+ CanvasOrigin
+ {0, 0}
+ ColumnAlign
+ 1
+ ColumnSpacing
+ 36
+ CreationDate
+ 2015-07-23 08:51:08 +0000
+ Creator
+ Konrad Malawski
+ DisplayScale
+ 1 0/72 in = 1.0000 in
+ ExportLineEnds
+
+
+ Gap
+ 0.5
+ LineGap
+ 1
+ Name
+ NonNavigable
+ Path
+
+ elements
+
+
+ element
+ MOVETO
+ point
+ {0, 0}
+
+
+ element
+ LINETO
+ point
+ {14, 0}
+
+
+ element
+ MOVETO
+ point
+ {6, -4}
+
+
+ element
+ LINETO
+ point
+ {14, 4}
+
+
+ element
+ MOVETO
+ point
+ {14, -4}
+
+
+ element
+ LINETO
+ point
+ {6, 4}
+
+
+
+ ShouldExport
+ YES
+ Width
+ 14
+
+
+ GraphDocumentVersion
+ 8
+ GraphicsList
+
+
+ Bounds
+ {{145.63265806103379, 72.749998636153364}, {19, 24}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ FontInfo
+
+ Color
+
+ w
+ 0
+
+ Font
+ Helvetica
+ Size
+ 12
+
+ ID
+ 55
+ Line
+
+ ID
+ 54
+ Position
+ 0.43243709206581116
+ RotationType
+ 0
+
+ Shape
+ Rectangle
+ Style
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 E}
+
+ Wrap
+ NO
+
+
+ Class
+ LineGraphic
+ ID
+ 54
+ Points
+
+ {187.09439086914062, 84.749998636153364}
+ {113.18368016802742, 84.749998636153364}
+
+ Style
+
+ stroke
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ LineType
+ 1
+ TailArrow
+ 0
+
+
+
+
+ Bounds
+ {{280.05209427608111, 48.612242837540641}, {20, 24}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ FontInfo
+
+ Color
+
+ w
+ 0
+
+ Font
+ Helvetica
+ Size
+ 12
+
+ ID
+ 51
+ Line
+
+ ID
+ 50
+ Position
+ 0.46999874711036682
+ RotationType
+ 0
+
+ Shape
+ Rectangle
+ Style
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 O}
+
+ Wrap
+ NO
+
+
+ Class
+ LineGraphic
+ ID
+ 50
+ Points
+
+ {329.8431396484375, 60.612242837540641}
+ {245.18111529837574, 60.612242837540641}
+
+ Style
+
+ stroke
+
+ HeadArrow
+ NonNavigable
+ Legacy
+
+ LineType
+ 1
+ TailArrow
+ 0
+
+
+
+
+ Bounds
+ {{280.55209530438208, 70.749999613371074}, {19, 24}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ FontInfo
+
+ Color
+
+ w
+ 0
+
+ Font
+ Helvetica
+ Size
+ 12
+
+ ID
+ 49
+ Line
+
+ ID
+ 48
+ Position
+ 0.46999874711036682
+ RotationType
+ 0
+
+ Shape
+ Rectangle
+ Style
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 E}
+
+ Wrap
+ NO
+
+
+ Class
+ LineGraphic
+ ID
+ 48
+ Points
+
+ {329.84314158862338, 82.749999613371074}
+ {245.18111529837574, 82.749999613371074}
+
+ Style
+
+ stroke
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ LineType
+ 1
+ TailArrow
+ 0
+
+
+
+
+ Bounds
+ {{329.84315457120567, 27.964286256094354}, {54, 79.897956848144531}}
+ Class
+ ShapedGraphic
+ ID
+ 10
+ Magnets
+
+ {0, 1}
+ {0, -1}
+ {1, 0}
+ {-1, 0}
+
+ Shape
+ Cylinder
+ Style
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 Journal}
+ VerticalPad
+ 0
+
+
+
+ Bounds
+ {{187.09438968957969, 27.964285076097411}, {57.586738586425781, 79.897956848144531}}
+ Class
+ ShapedGraphic
+ ID
+ 13
+ Shape
+ Rectangle
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 Event\
+Adapter}
+
+
+
+ Bounds
+ {{9.9872450012231155, 51.61224533855227}, {102.19643402099609, 45.275508880615234}}
+ Class
+ ShapedGraphic
+ ID
+ 1
+ Shape
+ Rectangle
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 PersistentActor}
+
+
+
+ GridInfo
+
+ GuidesLocked
+ NO
+ GuidesVisible
+ YES
+ HPages
+ 1
+ ImageCounter
+ 1
+ KeepToScale
+
+ Layers
+
+
+ Lock
+ NO
+ Name
+ Layer 1
+ Print
+ YES
+ View
+ YES
+
+
+ LayoutInfo
+
+ Animate
+ NO
+ circoMinDist
+ 18
+ circoSeparation
+ 0.0
+ layoutEngine
+ dot
+ neatoSeparation
+ 0.0
+ twopiSeparation
+ 0.0
+
+ LinksVisible
+ NO
+ MagnetsVisible
+ NO
+ MasterSheets
+
+ ModificationDate
+ 2015-07-24 08:44:48 +0000
+ Modifier
+ Konrad Malawski
+ NotesVisible
+ NO
+ Orientation
+ 2
+ OriginVisible
+ NO
+ PageBreaks
+ YES
+ PrintInfo
+
+ NSBottomMargin
+
+ float
+ 41
+
+ NSHorizonalPagination
+
+ coded
+ BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG
+
+ NSLeftMargin
+
+ float
+ 18
+
+ NSPaperSize
+
+ size
+ {595.28997802734375, 841.8900146484375}
+
+ NSPrintReverseOrientation
+
+ int
+ 0
+
+ NSRightMargin
+
+ float
+ 18
+
+ NSTopMargin
+
+ float
+ 18
+
+
+ PrintOnePage
+
+ ReadOnly
+ NO
+ RowAlign
+ 1
+ RowSpacing
+ 36
+ SheetTitle
+ Canvas 1
+ SmartAlignmentGuidesActive
+ YES
+ SmartDistanceGuidesActive
+ YES
+ UniqueID
+ 1
+ UseEntirePage
+
+ VPages
+ 1
+ WindowInfo
+
+ CurrentSheet
+ 0
+ ExpandedCanvases
+
+
+ name
+ Canvas 1
+
+
+ FitInWindow
+
+ Frame
+ {{288, -0}, {1920, 1417}}
+ ListView
+
+ OutlineWidth
+ 142
+ RightSidebar
+
+ ShowRuler
+
+ Sidebar
+
+ SidebarWidth
+ 120
+ VisibleRegion
+ {{-268, 0}, {1096.1999781692175, 782.99998440658374}}
+ Zoom
+ 1.6283525228500366
+ ZoomValues
+
+
+ Canvas 1
+ 0.0
+ 1
+
+
+
+
+
diff --git a/akka-docs/rst/images/persistence-detach-models.png b/akka-docs/rst/images/persistence-detach-models.png
new file mode 100644
index 0000000000..721ddf0ba7
Binary files /dev/null and b/akka-docs/rst/images/persistence-detach-models.png differ
diff --git a/akka-docs/rst/images/persistence-detach-models.svg b/akka-docs/rst/images/persistence-detach-models.svg
new file mode 100644
index 0000000000..b579a437d5
--- /dev/null
+++ b/akka-docs/rst/images/persistence-detach-models.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/akka-docs/rst/images/persistence-drop-event-serializer.graffle b/akka-docs/rst/images/persistence-drop-event-serializer.graffle
new file mode 100644
index 0000000000..73ee045051
--- /dev/null
+++ b/akka-docs/rst/images/persistence-drop-event-serializer.graffle
@@ -0,0 +1,786 @@
+
+
+
+
+ ActiveLayerIndex
+ 0
+ ApplicationVersion
+
+ com.omnigroup.OmniGrafflePro
+ 139.18.0.187838
+
+ AutoAdjust
+
+ BackgroundGraphic
+
+ Bounds
+ {{0, 0}, {559.28997802734375, 782.8900146484375}}
+ Class
+ SolidGraphic
+ ID
+ 2
+ Style
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+
+ BaseZoom
+ 0
+ CanvasOrigin
+ {0, 0}
+ ColumnAlign
+ 1
+ ColumnSpacing
+ 36
+ CreationDate
+ 2015-07-23 08:51:08 +0000
+ Creator
+ Konrad Malawski
+ DisplayScale
+ 1 0/72 in = 1.0000 in
+ ExportLineEnds
+
+
+ Gap
+ 0.5
+ LineGap
+ 1
+ Name
+ NonNavigable
+ Path
+
+ elements
+
+
+ element
+ MOVETO
+ point
+ {0, 0}
+
+
+ element
+ LINETO
+ point
+ {14, 0}
+
+
+ element
+ MOVETO
+ point
+ {6, -4}
+
+
+ element
+ LINETO
+ point
+ {14, 4}
+
+
+ element
+ MOVETO
+ point
+ {14, -4}
+
+
+ element
+ LINETO
+ point
+ {6, 4}
+
+
+
+ ShouldExport
+ YES
+ Width
+ 14
+
+
+ GraphDocumentVersion
+ 8
+ GraphicsList
+
+
+ Bounds
+ {{263.4039515357976, 48.112230402415705}, {18, 24}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ FontInfo
+
+ Color
+
+ w
+ 0
+
+ Font
+ Helvetica
+ Size
+ 12
+
+ ID
+ 61
+ Line
+
+ ID
+ 60
+ Position
+ 0.46999874711036682
+ RotationType
+ 0
+
+ Shape
+ Rectangle
+ Style
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 T}
+
+ Wrap
+ NO
+
+
+ Class
+ LineGraphic
+ ID
+ 60
+ Points
+
+ {296.98822404239763, 60.112230402415705}
+ {244.68112182617185, 60.112230402415705}
+
+ Style
+
+ stroke
+
+ HeadArrow
+ NonNavigable
+ Legacy
+
+ LineType
+ 1
+ TailArrow
+ 0
+
+
+
+
+ Bounds
+ {{262.90395153579766, 70.874989110500337}, {19, 24}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ FontInfo
+
+ Color
+
+ w
+ 0
+
+ Font
+ Helvetica
+ Size
+ 12
+
+ ID
+ 59
+ Line
+
+ ID
+ 58
+ Position
+ 0.46999874711036682
+ RotationType
+ 0
+
+ Shape
+ Rectangle
+ Style
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 E}
+
+ Wrap
+ NO
+
+
+ Class
+ LineGraphic
+ ID
+ 58
+ Points
+
+ {296.98822404239769, 82.874989110500337}
+ {244.68112182617188, 82.874989110500337}
+
+ Style
+
+ stroke
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ LineType
+ 1
+ TailArrow
+ 0
+
+
+
+
+ Bounds
+ {{296.34996616998893, 27.964282227528443}, {63.018733978271484, 79.897956848144531}}
+ Class
+ ShapedGraphic
+ ID
+ 57
+ Shape
+ Rectangle
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 Serializer}
+
+
+
+ Bounds
+ {{145.63265806103379, 72.749998636153364}, {19, 24}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ FontInfo
+
+ Color
+
+ w
+ 0
+
+ Font
+ Helvetica
+ Size
+ 12
+
+ ID
+ 55
+ Line
+
+ ID
+ 54
+ Position
+ 0.43243709206581116
+ RotationType
+ 0
+
+ Shape
+ Rectangle
+ Style
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 E}
+
+ Wrap
+ NO
+
+
+ Class
+ LineGraphic
+ ID
+ 54
+ Points
+
+ {187.09439086914062, 84.749998636153364}
+ {113.18368016802742, 84.749998636153364}
+
+ Style
+
+ stroke
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ LineType
+ 1
+ TailArrow
+ 0
+
+
+
+
+ Bounds
+ {{394.23969235661161, 48.612232334669955}, {20, 24}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ FontInfo
+
+ Color
+
+ w
+ 0
+
+ Font
+ Helvetica
+ Size
+ 12
+
+ ID
+ 51
+ Line
+
+ ID
+ 50
+ Position
+ 0.46999874711036682
+ RotationType
+ 0
+
+ Shape
+ Rectangle
+ Style
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 O}
+
+ Wrap
+ NO
+
+
+ Class
+ LineGraphic
+ ID
+ 50
+ Points
+
+ {444.03073772896801, 60.612232334669955}
+ {359.36871337890625, 60.612232334669955}
+
+ Style
+
+ stroke
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ LineType
+ 1
+ TailArrow
+ 0
+
+
+
+
+ Bounds
+ {{394.73969338491258, 70.74998911050038}, {19, 24}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ FontInfo
+
+ Color
+
+ w
+ 0
+
+ Font
+ Helvetica
+ Size
+ 12
+
+ ID
+ 49
+ Line
+
+ ID
+ 48
+ Position
+ 0.46999874711036682
+ RotationType
+ 0
+
+ Shape
+ Rectangle
+ Style
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 E}
+
+ Wrap
+ NO
+
+
+ Class
+ LineGraphic
+ ID
+ 48
+ Points
+
+ {444.03073966915389, 82.74998911050038}
+ {359.36871337890625, 82.74998911050038}
+
+ Style
+
+ stroke
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ LineType
+ 1
+ TailArrow
+ 0
+
+
+
+
+ Bounds
+ {{444.03075265173618, 27.964275753223664}, {54, 79.897956848144531}}
+ Class
+ ShapedGraphic
+ ID
+ 10
+ Magnets
+
+ {0, 1}
+ {0, -1}
+ {1, 0}
+ {-1, 0}
+
+ Shape
+ Cylinder
+ Style
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 Journal}
+ VerticalPad
+ 0
+
+
+
+ Bounds
+ {{187.09438968957969, 27.964285076097411}, {57.586738586425781, 79.897956848144531}}
+ Class
+ ShapedGraphic
+ ID
+ 13
+ Shape
+ Rectangle
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 Event\
+Adapter}
+
+
+
+ Bounds
+ {{9.9872450012231155, 51.61224533855227}, {102.19643402099609, 45.275508880615234}}
+ Class
+ ShapedGraphic
+ ID
+ 1
+ Shape
+ Rectangle
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 PersistentActor}
+
+
+
+ GridInfo
+
+ GuidesLocked
+ NO
+ GuidesVisible
+ YES
+ HPages
+ 1
+ ImageCounter
+ 1
+ KeepToScale
+
+ Layers
+
+
+ Lock
+ NO
+ Name
+ Layer 1
+ Print
+ YES
+ View
+ YES
+
+
+ LayoutInfo
+
+ Animate
+ NO
+ circoMinDist
+ 18
+ circoSeparation
+ 0.0
+ layoutEngine
+ dot
+ neatoSeparation
+ 0.0
+ twopiSeparation
+ 0.0
+
+ LinksVisible
+ NO
+ MagnetsVisible
+ NO
+ MasterSheets
+
+ ModificationDate
+ 2015-07-24 11:04:44 +0000
+ Modifier
+ Konrad Malawski
+ NotesVisible
+ NO
+ Orientation
+ 2
+ OriginVisible
+ NO
+ PageBreaks
+ YES
+ PrintInfo
+
+ NSBottomMargin
+
+ float
+ 41
+
+ NSHorizonalPagination
+
+ coded
+ BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG
+
+ NSLeftMargin
+
+ float
+ 18
+
+ NSPaperSize
+
+ size
+ {595.28997802734375, 841.8900146484375}
+
+ NSPrintReverseOrientation
+
+ int
+ 0
+
+ NSRightMargin
+
+ float
+ 18
+
+ NSTopMargin
+
+ float
+ 18
+
+
+ PrintOnePage
+
+ ReadOnly
+ NO
+ RowAlign
+ 1
+ RowSpacing
+ 36
+ SheetTitle
+ Canvas 1
+ SmartAlignmentGuidesActive
+ YES
+ SmartDistanceGuidesActive
+ YES
+ UniqueID
+ 1
+ UseEntirePage
+
+ VPages
+ 1
+ WindowInfo
+
+ CurrentSheet
+ 0
+ ExpandedCanvases
+
+
+ name
+ Canvas 1
+
+
+ FitInWindow
+
+ Frame
+ {{271, 0}, {1920, 1417}}
+ ListView
+
+ OutlineWidth
+ 142
+ RightSidebar
+
+ ShowRuler
+
+ Sidebar
+
+ SidebarWidth
+ 120
+ VisibleRegion
+ {{-268, 0}, {1096.199978169217, 782.99998440658374}}
+ Zoom
+ 1.6283525228500366
+ ZoomValues
+
+
+ Canvas 1
+ 0.0
+ 1
+
+
+
+
+
diff --git a/akka-docs/rst/images/persistence-drop-event-serializer.png b/akka-docs/rst/images/persistence-drop-event-serializer.png
new file mode 100644
index 0000000000..fbffc89f23
Binary files /dev/null and b/akka-docs/rst/images/persistence-drop-event-serializer.png differ
diff --git a/akka-docs/rst/images/persistence-drop-event-serializer.svg b/akka-docs/rst/images/persistence-drop-event-serializer.svg
new file mode 100644
index 0000000000..9c366f4554
--- /dev/null
+++ b/akka-docs/rst/images/persistence-drop-event-serializer.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/akka-docs/rst/images/persistence-drop-event.graffle b/akka-docs/rst/images/persistence-drop-event.graffle
new file mode 100644
index 0000000000..84f0697818
--- /dev/null
+++ b/akka-docs/rst/images/persistence-drop-event.graffle
@@ -0,0 +1,596 @@
+
+
+
+
+ ActiveLayerIndex
+ 0
+ ApplicationVersion
+
+ com.omnigroup.OmniGrafflePro
+ 139.18.0.187838
+
+ AutoAdjust
+
+ BackgroundGraphic
+
+ Bounds
+ {{0, 0}, {559.28997802734375, 782.8900146484375}}
+ Class
+ SolidGraphic
+ ID
+ 2
+ Style
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+
+ BaseZoom
+ 0
+ CanvasOrigin
+ {0, 0}
+ ColumnAlign
+ 1
+ ColumnSpacing
+ 36
+ CreationDate
+ 2015-07-23 08:51:08 +0000
+ Creator
+ Konrad Malawski
+ DisplayScale
+ 1 0/72 in = 1.0000 in
+ ExportLineEnds
+
+
+ Gap
+ 0.5
+ LineGap
+ 1
+ Name
+ NonNavigable
+ Path
+
+ elements
+
+
+ element
+ MOVETO
+ point
+ {0, 0}
+
+
+ element
+ LINETO
+ point
+ {14, 0}
+
+
+ element
+ MOVETO
+ point
+ {6, -4}
+
+
+ element
+ LINETO
+ point
+ {14, 4}
+
+
+ element
+ MOVETO
+ point
+ {14, -4}
+
+
+ element
+ LINETO
+ point
+ {6, 4}
+
+
+
+ ShouldExport
+ YES
+ Width
+ 14
+
+
+ GraphDocumentVersion
+ 8
+ GraphicsList
+
+
+ Bounds
+ {{145.63265806103379, 72.749998636153364}, {19, 24}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ FontInfo
+
+ Color
+
+ w
+ 0
+
+ Font
+ Helvetica
+ Size
+ 12
+
+ ID
+ 55
+ Line
+
+ ID
+ 54
+ Position
+ 0.43243709206581116
+ RotationType
+ 0
+
+ Shape
+ Rectangle
+ Style
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 E}
+
+ Wrap
+ NO
+
+
+ Class
+ LineGraphic
+ ID
+ 54
+ Points
+
+ {187.09439086914062, 84.749998636153364}
+ {113.18368016802742, 84.749998636153364}
+
+ Style
+
+ stroke
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ LineType
+ 1
+ TailArrow
+ 0
+
+
+
+
+ Bounds
+ {{280.05209427608111, 48.612242837540641}, {20, 24}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ FontInfo
+
+ Color
+
+ w
+ 0
+
+ Font
+ Helvetica
+ Size
+ 12
+
+ ID
+ 51
+ Line
+
+ ID
+ 50
+ Position
+ 0.46999874711036682
+ RotationType
+ 0
+
+ Shape
+ Rectangle
+ Style
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 O}
+
+ Wrap
+ NO
+
+
+ Class
+ LineGraphic
+ ID
+ 50
+ Points
+
+ {329.8431396484375, 60.612242837540641}
+ {245.18111529837574, 60.612242837540641}
+
+ Style
+
+ stroke
+
+ HeadArrow
+ NonNavigable
+ Legacy
+
+ LineType
+ 1
+ TailArrow
+ 0
+
+
+
+
+ Bounds
+ {{280.55209530438208, 70.749999613371074}, {19, 24}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ FontInfo
+
+ Color
+
+ w
+ 0
+
+ Font
+ Helvetica
+ Size
+ 12
+
+ ID
+ 49
+ Line
+
+ ID
+ 48
+ Position
+ 0.46999874711036682
+ RotationType
+ 0
+
+ Shape
+ Rectangle
+ Style
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 E}
+
+ Wrap
+ NO
+
+
+ Class
+ LineGraphic
+ ID
+ 48
+ Points
+
+ {329.84314158862338, 82.749999613371074}
+ {245.18111529837574, 82.749999613371074}
+
+ Style
+
+ stroke
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ LineType
+ 1
+ TailArrow
+ 0
+
+
+
+
+ Bounds
+ {{329.84315457120567, 27.964286256094354}, {54, 79.897956848144531}}
+ Class
+ ShapedGraphic
+ ID
+ 10
+ Magnets
+
+ {0, 1}
+ {0, -1}
+ {1, 0}
+ {-1, 0}
+
+ Shape
+ Cylinder
+ Style
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 Journal}
+ VerticalPad
+ 0
+
+
+
+ Bounds
+ {{187.09438968957969, 27.964285076097411}, {57.586738586425781, 79.897956848144531}}
+ Class
+ ShapedGraphic
+ ID
+ 13
+ Shape
+ Rectangle
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 Event\
+Adapter}
+
+
+
+ Bounds
+ {{9.9872450012231155, 51.61224533855227}, {102.19643402099609, 45.275508880615234}}
+ Class
+ ShapedGraphic
+ ID
+ 1
+ Shape
+ Rectangle
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 PersistentActor}
+
+
+
+ GridInfo
+
+ GuidesLocked
+ NO
+ GuidesVisible
+ YES
+ HPages
+ 1
+ ImageCounter
+ 1
+ KeepToScale
+
+ Layers
+
+
+ Lock
+ NO
+ Name
+ Layer 1
+ Print
+ YES
+ View
+ YES
+
+
+ LayoutInfo
+
+ Animate
+ NO
+ circoMinDist
+ 18
+ circoSeparation
+ 0.0
+ layoutEngine
+ dot
+ neatoSeparation
+ 0.0
+ twopiSeparation
+ 0.0
+
+ LinksVisible
+ NO
+ MagnetsVisible
+ NO
+ MasterSheets
+
+ ModificationDate
+ 2015-07-24 10:59:39 +0000
+ Modifier
+ Konrad Malawski
+ NotesVisible
+ NO
+ Orientation
+ 2
+ OriginVisible
+ NO
+ PageBreaks
+ YES
+ PrintInfo
+
+ NSBottomMargin
+
+ float
+ 41
+
+ NSHorizonalPagination
+
+ coded
+ BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG
+
+ NSLeftMargin
+
+ float
+ 18
+
+ NSPaperSize
+
+ size
+ {595.28997802734375, 841.8900146484375}
+
+ NSPrintReverseOrientation
+
+ int
+ 0
+
+ NSRightMargin
+
+ float
+ 18
+
+ NSTopMargin
+
+ float
+ 18
+
+
+ PrintOnePage
+
+ ReadOnly
+ NO
+ RowAlign
+ 1
+ RowSpacing
+ 36
+ SheetTitle
+ Canvas 1
+ SmartAlignmentGuidesActive
+ YES
+ SmartDistanceGuidesActive
+ YES
+ UniqueID
+ 1
+ UseEntirePage
+
+ VPages
+ 1
+ WindowInfo
+
+ CurrentSheet
+ 0
+ ExpandedCanvases
+
+
+ name
+ Canvas 1
+
+
+ FitInWindow
+
+ Frame
+ {{323, 0}, {1920, 1417}}
+ ListView
+
+ OutlineWidth
+ 142
+ RightSidebar
+
+ ShowRuler
+
+ Sidebar
+
+ SidebarWidth
+ 120
+ VisibleRegion
+ {{-268, 0}, {1096.199978169217, 782.99998440658374}}
+ Zoom
+ 1.6283525228500366
+ ZoomValues
+
+
+ Canvas 1
+ 0.0
+ 1
+
+
+
+
+
diff --git a/akka-docs/rst/images/persistence-drop-event.png b/akka-docs/rst/images/persistence-drop-event.png
new file mode 100644
index 0000000000..3f040fa161
Binary files /dev/null and b/akka-docs/rst/images/persistence-drop-event.png differ
diff --git a/akka-docs/rst/images/persistence-drop-event.svg b/akka-docs/rst/images/persistence-drop-event.svg
new file mode 100644
index 0000000000..6d1aeab8c8
--- /dev/null
+++ b/akka-docs/rst/images/persistence-drop-event.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/akka-docs/rst/images/persistence-event-adapter-1-n.graffle b/akka-docs/rst/images/persistence-event-adapter-1-n.graffle
new file mode 100644
index 0000000000..90e4ce719c
--- /dev/null
+++ b/akka-docs/rst/images/persistence-event-adapter-1-n.graffle
@@ -0,0 +1,493 @@
+
+
+
+
+ ActiveLayerIndex
+ 0
+ ApplicationVersion
+
+ com.omnigroup.OmniGrafflePro
+ 139.18.0.187838
+
+ AutoAdjust
+
+ BackgroundGraphic
+
+ Bounds
+ {{0, 0}, {559.28997802734375, 782.8900146484375}}
+ Class
+ SolidGraphic
+ ID
+ 2
+ Style
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+
+ BaseZoom
+ 0
+ CanvasOrigin
+ {0, 0}
+ ColumnAlign
+ 1
+ ColumnSpacing
+ 36
+ CreationDate
+ 2015-07-23 08:51:08 +0000
+ Creator
+ Konrad Malawski
+ DisplayScale
+ 1 0/72 in = 1.0000 in
+ GraphDocumentVersion
+ 8
+ GraphicsList
+
+
+ Bounds
+ {{329.84315457120567, 27.964286256094354}, {54, 79.897956848144531}}
+ Class
+ ShapedGraphic
+ ID
+ 10
+ Magnets
+
+ {0, 1}
+ {0, -1}
+ {1, 0}
+ {-1, 0}
+
+ Shape
+ Cylinder
+ Style
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 Journal}
+ VerticalPad
+ 0
+
+
+
+ Bounds
+ {{144.29847089815703, 62.227041518775934}, {17, 24}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ FontInfo
+
+ Color
+
+ w
+ 0
+
+ Font
+ Helvetica
+ Size
+ 12
+
+ ID
+ 46
+ Line
+
+ ID
+ 43
+ Offset
+ -3.9948978424072266
+ Position
+ 0.46160221099853516
+ RotationType
+ 0
+
+ Shape
+ Rectangle
+ Style
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 n}
+
+ Wrap
+ NO
+
+
+ Bounds
+ {{281.55210828696437, 55.91326468016662}, {17, 24}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ FontInfo
+
+ Color
+
+ w
+ 0
+
+ Font
+ Helvetica
+ Size
+ 12
+
+ ID
+ 45
+ Line
+
+ ID
+ 39
+ Position
+ 0.46999874711036682
+ RotationType
+ 0
+
+ Shape
+ Rectangle
+ Style
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 1}
+
+ Wrap
+ NO
+
+
+ Class
+ LineGraphic
+ ID
+ 44
+ Points
+
+ {187.23724704207191, 79.232143676368707}
+ {113.32653634095871, 79.232143676368707}
+
+ Style
+
+ stroke
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ LineType
+ 1
+ TailArrow
+ 0
+
+
+
+
+ Class
+ LineGraphic
+ ID
+ 43
+ Points
+
+ {186.91581837426398, 70.232143676368707}
+ {113.00510767315077, 70.232143676368707}
+
+ Style
+
+ stroke
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ LineType
+ 1
+ TailArrow
+ 0
+
+
+
+
+ Class
+ LineGraphic
+ Head
+
+ ID
+ 13
+
+ ID
+ 39
+ Points
+
+ {329.84315457120567, 67.91326468016662}
+ {245.18112828095803, 67.91326468016662}
+
+ Style
+
+ stroke
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ LineType
+ 1
+ TailArrow
+ 0
+
+
+ Tail
+
+ ID
+ 10
+ Info
+ 4
+
+
+
+ Bounds
+ {{187.09438968957969, 27.964285076097411}, {57.586738586425781, 79.897956848144531}}
+ Class
+ ShapedGraphic
+ ID
+ 13
+ Shape
+ Rectangle
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 Event\
+Adapter}
+
+
+
+ Bounds
+ {{9.9872450012231155, 51.61224533855227}, {102.19643402099609, 45.275508880615234}}
+ Class
+ ShapedGraphic
+ ID
+ 1
+ Shape
+ Rectangle
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 PersistentActor}
+
+
+
+ GridInfo
+
+ GuidesLocked
+ NO
+ GuidesVisible
+ YES
+ HPages
+ 1
+ ImageCounter
+ 1
+ KeepToScale
+
+ Layers
+
+
+ Lock
+ NO
+ Name
+ Layer 1
+ Print
+ YES
+ View
+ YES
+
+
+ LayoutInfo
+
+ Animate
+ NO
+ circoMinDist
+ 18
+ circoSeparation
+ 0.0
+ layoutEngine
+ dot
+ neatoSeparation
+ 0.0
+ twopiSeparation
+ 0.0
+
+ LinksVisible
+ NO
+ MagnetsVisible
+ NO
+ MasterSheets
+
+ ModificationDate
+ 2015-07-23 12:19:58 +0000
+ Modifier
+ Konrad Malawski
+ NotesVisible
+ NO
+ Orientation
+ 2
+ OriginVisible
+ NO
+ PageBreaks
+ YES
+ PrintInfo
+
+ NSBottomMargin
+
+ float
+ 41
+
+ NSHorizonalPagination
+
+ coded
+ BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG
+
+ NSLeftMargin
+
+ float
+ 18
+
+ NSPaperSize
+
+ size
+ {595.28997802734375, 841.8900146484375}
+
+ NSPrintReverseOrientation
+
+ int
+ 0
+
+ NSRightMargin
+
+ float
+ 18
+
+ NSTopMargin
+
+ float
+ 18
+
+
+ PrintOnePage
+
+ ReadOnly
+ NO
+ RowAlign
+ 1
+ RowSpacing
+ 36
+ SheetTitle
+ Canvas 1
+ SmartAlignmentGuidesActive
+ YES
+ SmartDistanceGuidesActive
+ YES
+ UniqueID
+ 1
+ UseEntirePage
+
+ VPages
+ 1
+ WindowInfo
+
+ CurrentSheet
+ 0
+ ExpandedCanvases
+
+
+ name
+ Canvas 1
+
+
+ FitInWindow
+
+ Frame
+ {{288, 79}, {1404, 1318}}
+ ListView
+
+ OutlineWidth
+ 142
+ RightSidebar
+
+ ShowRuler
+
+ Sidebar
+
+ SidebarWidth
+ 120
+ VisibleRegion
+ {{-142, 0}, {844.92092710347549, 783.00000809589221}}
+ Zoom
+ 1.5019156932830811
+ ZoomValues
+
+
+ Canvas 1
+ 0.0
+ 1
+
+
+
+
+
diff --git a/akka-docs/rst/images/persistence-event-adapter-1-n.png b/akka-docs/rst/images/persistence-event-adapter-1-n.png
new file mode 100644
index 0000000000..40536832c1
Binary files /dev/null and b/akka-docs/rst/images/persistence-event-adapter-1-n.png differ
diff --git a/akka-docs/rst/images/persistence-event-adapter-1-n.svg b/akka-docs/rst/images/persistence-event-adapter-1-n.svg
new file mode 100644
index 0000000000..9eac64515b
--- /dev/null
+++ b/akka-docs/rst/images/persistence-event-adapter-1-n.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/akka-docs/rst/images/persistence-manual-rename.graffle b/akka-docs/rst/images/persistence-manual-rename.graffle
new file mode 100644
index 0000000000..58f6b31afd
--- /dev/null
+++ b/akka-docs/rst/images/persistence-manual-rename.graffle
@@ -0,0 +1,680 @@
+
+
+
+
+ ActiveLayerIndex
+ 0
+ ApplicationVersion
+
+ com.omnigroup.OmniGraffle.MacAppStore
+ 139.18
+
+ AutoAdjust
+
+ BackgroundGraphic
+
+ Bounds
+ {{0, 0}, {559.28997802734375, 782.8900146484375}}
+ Class
+ SolidGraphic
+ ID
+ 2
+ Style
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+
+ BaseZoom
+ 0
+ CanvasOrigin
+ {0, 0}
+ ColumnAlign
+ 1
+ ColumnSpacing
+ 36
+ CreationDate
+ 2015-07-23 08:51:08 +0000
+ Creator
+ Konrad Malawski
+ DisplayScale
+ 1 0/72 in = 1.0000 in
+ GraphDocumentVersion
+ 8
+ GraphicsList
+
+
+ Bounds
+ {{156.34123947922424, 144.36435961675622}, {30, 24}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ FontInfo
+
+ Color
+
+ w
+ 0
+
+ Font
+ Helvetica
+ Size
+ 12
+
+ ID
+ 69
+ Shape
+ Rectangle
+ Style
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 [v2]}
+
+ Wrap
+ NO
+
+
+ Bounds
+ {{140.17231558676406, 124.47240374005878}, {57, 24}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ FontInfo
+
+ Color
+
+ w
+ 0
+
+ Font
+ Helvetica
+ Size
+ 12
+
+ ID
+ 68
+ Line
+
+ ID
+ 67
+ Position
+ 0.43243709206581116
+ RotationType
+ 0
+
+ Shape
+ Rectangle
+ Style
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 A.seatNr}
+
+ Wrap
+ NO
+
+
+ Class
+ LineGraphic
+ ID
+ 67
+ Points
+
+ {208.32634070768711, 136.35918075415361}
+ {116.62739570856519, 136.62100608778607}
+
+ Style
+
+ stroke
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ LineType
+ 1
+ TailArrow
+ 0
+
+
+
+
+ Bounds
+ {{283.60994305394411, 125.36436946675957}, {57, 38}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ FontInfo
+
+ Color
+
+ w
+ 0
+
+ Font
+ Helvetica
+ Size
+ 12
+
+ ID
+ 66
+ Line
+
+ ID
+ 65
+ Offset
+ 2.7059365947934566e-07
+ Position
+ 0.46274498105049133
+ RotationType
+ 0
+
+ Shape
+ Rectangle
+ Style
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 A.seatNr\
+[v2]}
+
+ Wrap
+ NO
+
+
+ Class
+ LineGraphic
+ ID
+ 65
+ Points
+
+ {351.286868282196, 144.36436973735323}
+ {266.6248419919483, 144.36436973735323}
+
+ Style
+
+ stroke
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ LineType
+ 1
+ TailArrow
+ 0
+
+
+
+
+ Bounds
+ {{139.9605523938219, 107.01448443883029}, {57, 24}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ FontInfo
+
+ Color
+
+ w
+ 0
+
+ Font
+ Helvetica
+ Size
+ 12
+
+ ID
+ 55
+ Line
+
+ ID
+ 54
+ Position
+ 0.43243709206581116
+ RotationType
+ 0
+
+ Shape
+ Rectangle
+ Style
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 A.seatNr}
+
+ Wrap
+ NO
+
+
+ Class
+ LineGraphic
+ ID
+ 54
+ Points
+
+ {208.11457852770752, 119.3142831598844}
+ {116.41563118613487, 118.62100608778607}
+
+ Style
+
+ stroke
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ LineType
+ 1
+ TailArrow
+ 0
+
+
+
+
+ Bounds
+ {{287.89817853151374, 80.152605485515707}, {48, 38}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ FontInfo
+
+ Color
+
+ w
+ 0
+
+ Font
+ Helvetica
+ Size
+ 12
+
+ ID
+ 60
+ Line
+
+ ID
+ 59
+ Offset
+ -2.7059365947934566e-07
+ Position
+ 0.46274498105049133
+ RotationType
+ 0
+
+ Shape
+ Rectangle
+ Style
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 A.code\
+[v1]}
+
+ Wrap
+ NO
+
+
+ Class
+ LineGraphic
+ ID
+ 59
+ Points
+
+ {351.07510375976562, 99.152605214922048}
+ {266.41307746951793, 99.152605214922048}
+
+ Style
+
+ stroke
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ LineType
+ 1
+ TailArrow
+ 0
+
+
+
+
+ Bounds
+ {{351.07510558931313, 79.835293707727061}, {54, 79.897956848144531}}
+ Class
+ ShapedGraphic
+ ID
+ 10
+ Magnets
+
+ {0, 1}
+ {0, -1}
+ {1, 0}
+ {-1, 0}
+
+ Shape
+ Cylinder
+ Style
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 Journal}
+ VerticalPad
+ 0
+
+
+
+ Bounds
+ {{208.32634070768711, 79.835292527730118}, {57.586738586425781, 79.897956848144531}}
+ Class
+ ShapedGraphic
+ ID
+ 61
+ Shape
+ Rectangle
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs22 \cf0 Serializer}
+
+
+
+ Bounds
+ {{13.219196019330578, 103.48325279018498}, {102.19643402099609, 45.275508880615234}}
+ Class
+ ShapedGraphic
+ ID
+ 1
+ Shape
+ Rectangle
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 PersistentActor}
+
+
+
+ GridInfo
+
+ GuidesLocked
+ NO
+ GuidesVisible
+ YES
+ HPages
+ 1
+ ImageCounter
+ 1
+ KeepToScale
+
+ Layers
+
+
+ Lock
+ NO
+ Name
+ Layer 1
+ Print
+ YES
+ View
+ YES
+
+
+ LayoutInfo
+
+ Animate
+ NO
+ circoMinDist
+ 18
+ circoSeparation
+ 0.0
+ layoutEngine
+ dot
+ neatoSeparation
+ 0.0
+ twopiSeparation
+ 0.0
+
+ LinksVisible
+ NO
+ MagnetsVisible
+ NO
+ MasterSheets
+
+ ModificationDate
+ 2015-08-13 10:04:11 +0000
+ Modifier
+ Konrad Malawski
+ NotesVisible
+ NO
+ Orientation
+ 2
+ OriginVisible
+ NO
+ PageBreaks
+ YES
+ PrintInfo
+
+ NSBottomMargin
+
+ float
+ 41
+
+ NSHorizonalPagination
+
+ coded
+ BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG
+
+ NSLeftMargin
+
+ float
+ 18
+
+ NSPaperSize
+
+ size
+ {595.28997802734375, 841.8900146484375}
+
+ NSPrintReverseOrientation
+
+ int
+ 0
+
+ NSRightMargin
+
+ float
+ 18
+
+ NSTopMargin
+
+ float
+ 18
+
+
+ PrintOnePage
+
+ ReadOnly
+ NO
+ RowAlign
+ 1
+ RowSpacing
+ 36
+ SheetTitle
+ Canvas 1
+ SmartAlignmentGuidesActive
+ YES
+ SmartDistanceGuidesActive
+ YES
+ UniqueID
+ 1
+ UseEntirePage
+
+ VPages
+ 1
+ WindowInfo
+
+ CurrentSheet
+ 0
+ ExpandedCanvases
+
+
+ name
+ Canvas 1
+
+
+ FitInWindow
+
+ Frame
+ {{4, 0}, {1436, 877}}
+ ListView
+
+ OutlineWidth
+ 142
+ RightSidebar
+
+ ShowRuler
+
+ Sidebar
+
+ SidebarWidth
+ 120
+ VisibleRegion
+ {{-413, 0}, {1385.9632356340144, 782.9999832367414}}
+ Zoom
+ 0.93869733810424805
+ ZoomValues
+
+
+ Canvas 1
+ 0.0
+ 1
+
+
+
+
+
diff --git a/akka-docs/rst/images/persistence-manual-rename.png b/akka-docs/rst/images/persistence-manual-rename.png
new file mode 100644
index 0000000000..4ea4f46c42
Binary files /dev/null and b/akka-docs/rst/images/persistence-manual-rename.png differ
diff --git a/akka-docs/rst/images/persistence-serializer-rename.graffle b/akka-docs/rst/images/persistence-serializer-rename.graffle
new file mode 100644
index 0000000000..8798fc5a20
--- /dev/null
+++ b/akka-docs/rst/images/persistence-serializer-rename.graffle
@@ -0,0 +1,679 @@
+
+
+
+
+ ActiveLayerIndex
+ 0
+ ApplicationVersion
+
+ com.omnigroup.OmniGraffle.MacAppStore
+ 139.18
+
+ AutoAdjust
+
+ BackgroundGraphic
+
+ Bounds
+ {{0, 0}, {559.28997802734375, 782.8900146484375}}
+ Class
+ SolidGraphic
+ ID
+ 2
+ Style
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+
+ BaseZoom
+ 0
+ CanvasOrigin
+ {0, 0}
+ ColumnAlign
+ 1
+ ColumnSpacing
+ 36
+ CreationDate
+ 2015-07-23 08:51:08 +0000
+ Creator
+ Konrad Malawski
+ DisplayScale
+ 1 0/72 in = 1.0000 in
+ GraphDocumentVersion
+ 8
+ GraphicsList
+
+
+ Bounds
+ {{140.17231558676406, 124.47240374005878}, {57, 24}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ FontInfo
+
+ Color
+
+ w
+ 0
+
+ Font
+ Helvetica
+ Size
+ 12
+
+ ID
+ 68
+ Line
+
+ ID
+ 67
+ Position
+ 0.43243709206581116
+ RotationType
+ 0
+
+ Shape
+ Rectangle
+ Style
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 A.seatNr}
+
+ Wrap
+ NO
+
+
+ Class
+ LineGraphic
+ ID
+ 67
+ Points
+
+ {208.32634070768711, 136.35918075415361}
+ {116.62739570856519, 136.62100608778607}
+
+ Style
+
+ stroke
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ LineType
+ 1
+ TailArrow
+ 0
+
+
+
+
+ Bounds
+ {{283.60994305394411, 123.36436973735323}, {57, 24}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ FontInfo
+
+ Color
+
+ w
+ 0
+
+ Font
+ Helvetica
+ Size
+ 12
+
+ ID
+ 66
+ Line
+
+ ID
+ 65
+ Position
+ 0.46274498105049133
+ RotationType
+ 0
+
+ Shape
+ Rectangle
+ Style
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 A.seatNr}
+
+ Wrap
+ NO
+
+
+ Class
+ LineGraphic
+ ID
+ 65
+ Points
+
+ {351.286868282196, 135.36436973735323}
+ {266.6248419919483, 135.36436973735323}
+
+ Style
+
+ stroke
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ LineType
+ 1
+ TailArrow
+ 0
+
+
+
+
+ Class
+ LineGraphic
+ Head
+
+ ID
+ 61
+
+ ID
+ 63
+ Points
+
+ {237.119717968369, 50.243527827595514}
+ {237.119717968369, 79.335292523504918}
+
+ Style
+
+ stroke
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ LineType
+ 1
+ TailArrow
+ FilledArrow
+
+
+ Tail
+
+ ID
+ 56
+
+
+
+ Bounds
+ {{183.40465009683402, 20.265881949346891}, {107.43011379637244, 29.477645874023438}}
+ Class
+ ShapedGraphic
+ ID
+ 56
+ Shape
+ Rectangle
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 Protocol\
+IDL}
+
+
+
+ Bounds
+ {{139.9605523938219, 107.01448443883029}, {57, 24}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ FontInfo
+
+ Color
+
+ w
+ 0
+
+ Font
+ Helvetica
+ Size
+ 12
+
+ ID
+ 55
+ Line
+
+ ID
+ 54
+ Position
+ 0.43243709206581116
+ RotationType
+ 0
+
+ Shape
+ Rectangle
+ Style
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 A.seatNr}
+
+ Wrap
+ NO
+
+
+ Class
+ LineGraphic
+ ID
+ 54
+ Points
+
+ {208.11457852770752, 119.3142831598844}
+ {116.41563118613487, 118.62100608778607}
+
+ Style
+
+ stroke
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ LineType
+ 1
+ TailArrow
+ 0
+
+
+
+
+ Bounds
+ {{287.89817853151374, 96.152605214922048}, {48, 24}}
+ Class
+ ShapedGraphic
+ FitText
+ YES
+ Flow
+ Resize
+ FontInfo
+
+ Color
+
+ w
+ 0
+
+ Font
+ Helvetica
+ Size
+ 12
+
+ ID
+ 60
+ Line
+
+ ID
+ 59
+ Position
+ 0.46274498105049133
+ RotationType
+ 0
+
+ Shape
+ Rectangle
+ Style
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 A.code}
+
+ Wrap
+ NO
+
+
+ Class
+ LineGraphic
+ ID
+ 59
+ Points
+
+ {351.07510375976562, 108.15260521492205}
+ {266.41307746951793, 108.15260521492205}
+
+ Style
+
+ stroke
+
+ HeadArrow
+ FilledArrow
+ Legacy
+
+ LineType
+ 1
+ TailArrow
+ 0
+
+
+
+
+ Bounds
+ {{351.07510558931313, 79.835293707727061}, {54, 79.897956848144531}}
+ Class
+ ShapedGraphic
+ ID
+ 10
+ Magnets
+
+ {0, 1}
+ {0, -1}
+ {1, 0}
+ {-1, 0}
+
+ Shape
+ Cylinder
+ Style
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs20 \cf0 Journal}
+ VerticalPad
+ 0
+
+
+
+ Bounds
+ {{208.32634070768711, 79.835292527730118}, {57.586738586425781, 79.897956848144531}}
+ Class
+ ShapedGraphic
+ ID
+ 61
+ Shape
+ Rectangle
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs22 \cf0 Serializer}
+
+
+
+ Bounds
+ {{13.219196019330578, 103.48325279018498}, {102.19643402099609, 45.275508880615234}}
+ Class
+ ShapedGraphic
+ ID
+ 1
+ Shape
+ Rectangle
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 PersistentActor}
+
+
+
+ GridInfo
+
+ GuidesLocked
+ NO
+ GuidesVisible
+ YES
+ HPages
+ 1
+ ImageCounter
+ 1
+ KeepToScale
+
+ Layers
+
+
+ Lock
+ NO
+ Name
+ Layer 1
+ Print
+ YES
+ View
+ YES
+
+
+ LayoutInfo
+
+ Animate
+ NO
+ circoMinDist
+ 18
+ circoSeparation
+ 0.0
+ layoutEngine
+ dot
+ neatoSeparation
+ 0.0
+ twopiSeparation
+ 0.0
+
+ LinksVisible
+ NO
+ MagnetsVisible
+ NO
+ MasterSheets
+
+ ModificationDate
+ 2015-08-13 10:00:21 +0000
+ Modifier
+ Konrad Malawski
+ NotesVisible
+ NO
+ Orientation
+ 2
+ OriginVisible
+ NO
+ PageBreaks
+ YES
+ PrintInfo
+
+ NSBottomMargin
+
+ float
+ 41
+
+ NSHorizonalPagination
+
+ coded
+ BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG
+
+ NSLeftMargin
+
+ float
+ 18
+
+ NSPaperSize
+
+ size
+ {595.28997802734375, 841.8900146484375}
+
+ NSPrintReverseOrientation
+
+ int
+ 0
+
+ NSRightMargin
+
+ float
+ 18
+
+ NSTopMargin
+
+ float
+ 18
+
+
+ PrintOnePage
+
+ ReadOnly
+ NO
+ RowAlign
+ 1
+ RowSpacing
+ 36
+ SheetTitle
+ Canvas 1
+ SmartAlignmentGuidesActive
+ YES
+ SmartDistanceGuidesActive
+ YES
+ UniqueID
+ 1
+ UseEntirePage
+
+ VPages
+ 1
+ WindowInfo
+
+ CurrentSheet
+ 0
+ ExpandedCanvases
+
+
+ name
+ Canvas 1
+
+
+ FitInWindow
+
+ Frame
+ {{4, 0}, {1436, 877}}
+ ListView
+
+ OutlineWidth
+ 142
+ RightSidebar
+
+ ShowRuler
+
+ Sidebar
+
+ SidebarWidth
+ 120
+ VisibleRegion
+ {{-413, 0}, {1385.9632356340144, 782.9999832367414}}
+ Zoom
+ 0.93869733810424805
+ ZoomValues
+
+
+ Canvas 1
+ 0.0
+ 1
+
+
+
+
+
diff --git a/akka-docs/rst/images/persistence-serializer-rename.png b/akka-docs/rst/images/persistence-serializer-rename.png
new file mode 100644
index 0000000000..94d8183a90
Binary files /dev/null and b/akka-docs/rst/images/persistence-serializer-rename.png differ
diff --git a/akka-docs/rst/images/persistence-serializer-rename.svg b/akka-docs/rst/images/persistence-serializer-rename.svg
new file mode 100644
index 0000000000..0153338687
--- /dev/null
+++ b/akka-docs/rst/images/persistence-serializer-rename.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/akka-docs/rst/images/persistent-message-envelope.graffle b/akka-docs/rst/images/persistent-message-envelope.graffle
new file mode 100644
index 0000000000..71ae11948d
--- /dev/null
+++ b/akka-docs/rst/images/persistent-message-envelope.graffle
@@ -0,0 +1,542 @@
+
+
+
+
+ ActiveLayerIndex
+ 0
+ ApplicationVersion
+
+ com.omnigroup.OmniGrafflePro
+ 139.18.0.187838
+
+ AutoAdjust
+
+ BackgroundGraphic
+
+ Bounds
+ {{0, 0}, {559.28997802734375, 782.8900146484375}}
+ Class
+ SolidGraphic
+ ID
+ 2
+ Style
+
+ shadow
+
+ Draws
+ NO
+
+ stroke
+
+ Draws
+ NO
+
+
+
+ BaseZoom
+ 0
+ CanvasOrigin
+ {0, 0}
+ ColumnAlign
+ 1
+ ColumnSpacing
+ 36
+ CreationDate
+ 2015-07-23 08:51:08 +0000
+ Creator
+ Konrad Malawski
+ DisplayScale
+ 1 0/72 in = 1 0/72 in
+ GraphDocumentVersion
+ 8
+ GraphicsList
+
+
+ Bounds
+ {{42.612243483896464, 209.73214502568541}, {208.72704538616881, 16.645408630371094}}
+ Class
+ ShapedGraphic
+ ID
+ 77
+ Shape
+ Rectangle
+ Style
+
+ fill
+
+ Color
+
+ b
+ 0.211198
+ g
+ 0.79545
+ r
+ 1
+
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 payload}
+
+
+
+ Bounds
+ {{122.5076543485809, 187.0943887622513}, {128.83163452148438, 16.645408630371094}}
+ Class
+ ShapedGraphic
+ ID
+ 74
+ Shape
+ Rectangle
+ Style
+
+ fill
+
+ Color
+
+ b
+ 1
+ g
+ 0.990725
+ r
+ 0.795885
+
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 payloadManifest}
+
+
+
+ Bounds
+ {{42.612245338551958, 187.09438968957969}, {73.86474609375, 16.645408630371094}}
+ Class
+ ShapedGraphic
+ ID
+ 70
+ Shape
+ Rectangle
+ Style
+
+ fill
+
+ Color
+
+ b
+ 1
+ g
+ 0.990725
+ r
+ 0.795885
+
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 serializerId}
+
+
+
+ Bounds
+ {{34.880753086927484, 166.78699333426209}, {222.86349779925854, 65.582908630371094}}
+ Class
+ ShapedGraphic
+ ID
+ 76
+ Shape
+ Rectangle
+ Style
+
+ fill
+
+ Color
+
+ b
+ 1
+ g
+ 0.992157
+ r
+ 0.796078
+
+
+
+ Text
+
+ Align
+ 0
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural
+
+\f0\fs24 \cf0 PersistentPayload\
+\
+\
+}
+
+
+
+ Bounds
+ {{113.45474415668954, 146.81250404707274}, {144.28950500488281, 16.645408630371094}}
+ Class
+ ShapedGraphic
+ ID
+ 73
+ Shape
+ Rectangle
+ Style
+
+ fill
+
+ Color
+
+ b
+ 1
+ g
+ 0.990725
+ r
+ 0.795885
+
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 ...}
+
+
+
+ Bounds
+ {{34.880752054212735, 146.81250682905579}, {73.86474609375, 16.645408630371094}}
+ Class
+ ShapedGraphic
+ ID
+ 71
+ Shape
+ Rectangle
+ Style
+
+ fill
+
+ Color
+
+ b
+ 1
+ g
+ 0.990725
+ r
+ 0.795885
+
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 manifest}
+
+
+
+ Bounds
+ {{113.45474588130318, 126.83801404462653}, {144.28950500488281, 16.645408630371094}}
+ Class
+ ShapedGraphic
+ ID
+ 72
+ Shape
+ Rectangle
+ Style
+
+ fill
+
+ Color
+
+ b
+ 1
+ g
+ 0.990725
+ r
+ 0.795885
+
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 persistenceId}
+
+
+
+ Bounds
+ {{34.880753908867661, 126.83801682660956}, {73.86474609375, 16.645408630371094}}
+ Class
+ ShapedGraphic
+ ID
+ 69
+ Shape
+ Rectangle
+ Style
+
+ fill
+
+ Color
+
+ b
+ 1
+ g
+ 0.992157
+ r
+ 0.796078
+
+
+
+ Text
+
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf0 seqNr}
+
+
+
+ Bounds
+ {{27.303571669521091, 106.53061334638005}, {241.34693908691406, 131.16581726074219}}
+ Class
+ ShapedGraphic
+ ID
+ 75
+ Shape
+ Rectangle
+ Style
+
+ fill
+
+ Color
+
+ b
+ 0.920143
+ g
+ 0.851771
+ r
+ 0.237451
+
+
+
+ Text
+
+ Align
+ 0
+ Text
+ {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural
+
+\f0\fs24 \cf0 PersistentMessage\
+\
+\
+\
+\
+\
+\
+\
+}
+
+
+
+ GridInfo
+
+ GuidesLocked
+ NO
+ GuidesVisible
+ YES
+ HPages
+ 1
+ ImageCounter
+ 1
+ KeepToScale
+
+ Layers
+
+
+ Lock
+ NO
+ Name
+ Layer 1
+ Print
+ YES
+ View
+ YES
+
+
+ LayoutInfo
+
+ Animate
+ NO
+ circoMinDist
+ 18
+ circoSeparation
+ 0.0
+ layoutEngine
+ dot
+ neatoSeparation
+ 0.0
+ twopiSeparation
+ 0.0
+
+ LinksVisible
+ NO
+ MagnetsVisible
+ NO
+ MasterSheets
+
+ ModificationDate
+ 2015-07-23 12:16:09 +0000
+ Modifier
+ Konrad Malawski
+ NotesVisible
+ NO
+ Orientation
+ 2
+ OriginVisible
+ NO
+ PageBreaks
+ YES
+ PrintInfo
+
+ NSBottomMargin
+
+ float
+ 41
+
+ NSHorizonalPagination
+
+ coded
+ BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG
+
+ NSLeftMargin
+
+ float
+ 18
+
+ NSPaperSize
+
+ size
+ {595.28997802734375, 841.8900146484375}
+
+ NSPrintReverseOrientation
+
+ int
+ 0
+
+ NSRightMargin
+
+ float
+ 18
+
+ NSTopMargin
+
+ float
+ 18
+
+
+ PrintOnePage
+
+ ReadOnly
+ NO
+ RowAlign
+ 1
+ RowSpacing
+ 36
+ SheetTitle
+ Canvas 1
+ SmartAlignmentGuidesActive
+ YES
+ SmartDistanceGuidesActive
+ YES
+ UniqueID
+ 1
+ UseEntirePage
+
+ VPages
+ 1
+ WindowInfo
+
+ CurrentSheet
+ 0
+ ExpandedCanvases
+
+
+ name
+ Canvas 1
+
+
+ FitInWindow
+
+ Frame
+ {{268, 99}, {1776, 1318}}
+ ListView
+
+ OutlineWidth
+ 142
+ RightSidebar
+
+ ShowRuler
+
+ Sidebar
+
+ SidebarWidth
+ 120
+ VisibleRegion
+ {{-266, 0}, {1092.6046031338085, 783.0000080958921}}
+ Zoom
+ 1.5019156932830811
+ ZoomValues
+
+
+ Canvas 1
+ 0.0
+ 1
+
+
+
+
+
diff --git a/akka-docs/rst/images/persistent-message-envelope.png b/akka-docs/rst/images/persistent-message-envelope.png
new file mode 100644
index 0000000000..4b44036e63
Binary files /dev/null and b/akka-docs/rst/images/persistent-message-envelope.png differ
diff --git a/akka-docs/rst/images/persistent-message-envelope.svg b/akka-docs/rst/images/persistent-message-envelope.svg
new file mode 100644
index 0000000000..45d87252bc
--- /dev/null
+++ b/akka-docs/rst/images/persistent-message-envelope.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/akka-docs/rst/java/code/docs/persistence/LambdaPersistenceDocTest.java b/akka-docs/rst/java/code/docs/persistence/LambdaPersistenceDocTest.java
index 48e746c22a..48a0629c42 100644
--- a/akka-docs/rst/java/code/docs/persistence/LambdaPersistenceDocTest.java
+++ b/akka-docs/rst/java/code/docs/persistence/LambdaPersistenceDocTest.java
@@ -8,6 +8,8 @@ import akka.japi.Procedure;
import akka.japi.pf.ReceiveBuilder;
import akka.pattern.BackoffSupervisor;
import akka.persistence.*;
+import akka.persistence.journal.EventAdapter;
+import akka.persistence.journal.EventSeq;
import scala.Option;
import scala.concurrent.duration.Duration;
import scala.PartialFunction;
diff --git a/akka-docs/rst/java/lambda-persistence.rst b/akka-docs/rst/java/lambda-persistence.rst
index 60c09fc16f..cfb3623ef7 100644
--- a/akka-docs/rst/java/lambda-persistence.rst
+++ b/akka-docs/rst/java/lambda-persistence.rst
@@ -586,6 +586,46 @@ not accept more messages and it will throw ``AtLeastOnceDelivery.MaxUnconfirmedM
The default value can be configured with the ``akka.persistence.at-least-once-delivery.max-unconfirmed-messages``
configuration key. The method can be overridden by implementation classes to return non-default values.
+.. _event-adapters-lambda:
+
+Event Adapters
+==============
+
+In long running projects using event sourcing sometimes the need arises to detach the data model from the domain model
+completely.
+
+Event Adapters help in situations where:
+
+- **Version Migrations** – existing events stored in *Version 1* should be "upcasted" to a new *Version 2* representation,
+ and the process of doing so involves actual code, not just changes on the serialization layer. For these scenarios
+ the ``toJournal`` function is usually an identity function, however the ``fromJournal`` is implemented as
+ ``v1.Event=>v2.Event``, performing the neccessary mapping inside the fromJournal method.
+ This technique is sometimes refered to as "upcasting" in other CQRS libraries.
+- **Separating Domain and Data models** – thanks to EventAdapters it is possible to completely separate the domain model
+ from the model used to persist data in the Journals. For example one may want to use case classes in the
+ domain model, however persist their protocol-buffer (or any other binary serialization format) counter-parts to the Journal.
+ A simple ``toJournal:MyModel=>MyDataModel`` and ``fromJournal:MyDataModel=>MyModel`` adapter can be used to implement this feature.
+- **Journal Specialized Data Types** – exposing data types understood by the underlying Journal, for example for data stores which
+ understand JSON it is possible to write an EventAdapter ``toJournal:Any=>JSON`` such that the Journal can *directly* store the
+ json instead of serializing the object to its binary representation.
+
+Implementing an EventAdapter is rather stright forward:
+
+.. includecode:: code/docs/persistence/PersistenceEventAdapterDocTest.java#identity-event-adapter
+
+Then in order for it to be used on events coming to and from the journal you must bind it using the below configuration syntax:
+
+.. includecode:: ../scala/code/docs/persistence/PersistenceEventAdapterDocSpec.scala#event-adapters-config
+
+It is possible to bind multiple adapters to one class *for recovery*, in which case the ``fromJournal`` methods of all
+bound adapters will be applied to a given matching event (in order of definition in the configuration). Since each adapter may
+return from ``0`` to ``n`` adapted events (called as ``EventSeq``), each adapter can investigate the event and if it should
+indeed adapt it return the adapted event(s) for it, other adapters which do not have anything to contribute during this
+adaptation simply return ``EventSeq.empty``. The adapted events are then delivered in-order to the ``PersistentActor`` during replay.
+
+.. note::
+ For more advanced schema evolution techniques refer to the :ref:`persistence-schema-evolution-scala` documentation.
+
.. _persistent-fsm-java-lambda:
Persistent FSM
@@ -794,6 +834,8 @@ it must add
to the application configuration. If not specified, a default serializer is used.
+For more advanced schema evolution techniques refer to the :ref:`persistence-schema-evolution-scala` documentation.
+
Testing
=======
diff --git a/akka-docs/rst/java/persistence.rst b/akka-docs/rst/java/persistence.rst
index bdbe0f58b7..5c2acd8d9b 100644
--- a/akka-docs/rst/java/persistence.rst
+++ b/akka-docs/rst/java/persistence.rst
@@ -601,10 +601,6 @@ configuration key. The method can be overridden by implementation classes to ret
Event Adapters
==============
-.. note::
-
- Complete documentation featuring use-cases and implementation examples for this feature will follow shortly.
-
In long running projects using event sourcing sometimes the need arises to detach the data model from the domain model
completely.
@@ -638,11 +634,7 @@ indeed adapt it return the adapted event(s) for it, other adapters which do not
adaptation simply return ``EventSeq.empty``. The adapted events are then delivered in-order to the ``PersistentActor`` during replay.
.. note::
- More advanced techniques utilising advanced binary serialization formats such as protocol buffers or kryo / thrift / avro
- will be documented very soon. These schema evolutions often may need to reach into the serialization layer, however
- are much more powerful in terms of flexibly removing unused/deprecated classes from your classpath etc.
-
-
+ For more advanced schema evolution techniques refer to the :ref:`persistence-schema-evolution-scala` documentation.
Storage plugins
===============
@@ -833,6 +825,8 @@ it must add
to the application configuration. If not specified, a default serializer is used.
+For more advanced schema evolution techniques refer to the :ref:`persistence-schema-evolution-scala` documentation.
+
Testing
=======
diff --git a/akka-docs/rst/java/serialization.rst b/akka-docs/rst/java/serialization.rst
index 7b60c5ee86..8f1a2188c3 100644
--- a/akka-docs/rst/java/serialization.rst
+++ b/akka-docs/rst/java/serialization.rst
@@ -111,11 +111,13 @@ bytes to different objects.
Then you only need to fill in the blanks, bind it to a name in your :ref:`configuration` and then
list which classes that should be serialized using it.
+.. _string-manifest-serializer-java:
+
Serializer with String Manifest
-------------------------------
The ``Serializer`` illustrated above supports a class based manifest (type hint).
-For serialization of data that need to evolve over time the `SerializerWithStringManifest`
+For serialization of data that need to evolve over time the ``SerializerWithStringManifest``
is recommended instead of ``Serializer`` because the manifest (type hint) is a ``String``
instead of a ``Class``. That means that the class can be moved/removed and the serializer
can still deserialize old data by matching on the ``String``. This is especially useful
diff --git a/akka-docs/rst/scala/code/docs/persistence/PersistenceSchemaEvolutionDocSpec.scala b/akka-docs/rst/scala/code/docs/persistence/PersistenceSchemaEvolutionDocSpec.scala
new file mode 100644
index 0000000000..6aa3ff66ac
--- /dev/null
+++ b/akka-docs/rst/scala/code/docs/persistence/PersistenceSchemaEvolutionDocSpec.scala
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) 2009-2015 Typesafe Inc.
+ */
+
+package docs.persistence
+
+import scala.language.reflectiveCalls
+import java.nio.charset.Charset
+
+import akka.actor.ActorSystem
+import akka.persistence.journal.{ EventAdapter, EventSeq }
+import akka.serialization.{ SerializationExtension, SerializerWithStringManifest }
+import akka.testkit.TestKit
+import com.typesafe.config._
+import org.scalatest.WordSpec
+import spray.json.JsObject
+
+import scala.concurrent.duration._
+
+class PersistenceSchemaEvolutionDocSpec extends WordSpec {
+
+ val customSerializerConfig =
+ """
+ //#custom-serializer-config
+ akka.actor {
+ serializers {
+ my-payload = "docs.persistence.MyPayloadSerializer"
+ my-snapshot = "docs.persistence.MySnapshotSerializer"
+ }
+ serialization-bindings {
+ "docs.persistence.MyPayload" = my-payload
+ "docs.persistence.MySnapshot" = my-snapshot
+ }
+ }
+ //#custom-serializer-config
+ """
+
+ val system = ActorSystem("PersistenceSchemaEvolutionDocSpec", ConfigFactory.parseString(customSerializerConfig))
+ try {
+ SerializationExtension(system)
+ } finally {
+ TestKit.shutdownActorSystem(system, 10.seconds, false)
+ }
+
+}
+
+class ProtobufReadOptional {
+ object proto {
+ class SeatReserved {
+ def hasSeatType = false
+ def getLetter = ""
+ def getRow = 1
+ def getSeatType = ""
+ }
+ object SeatReserved {
+ def newBuilder = new {
+ def setCode(any: Any): this.type = this
+ def setRow(any: Any): this.type = this
+ def setSeatType(any: Any): this.type = this
+ def build() = new {
+ def toByteArray: Array[Byte] = Array()
+ }
+ }
+ def parseFrom(any: Any) = new SeatReserved
+ }
+ }
+
+ //#protobuf-read-optional-model
+ sealed abstract class SeatType { def code: String }
+ object SeatType {
+ def fromString(s: String) = s match {
+ case Window.code => Window
+ case Aisle.code => Aisle
+ case Other.code => Other
+ case _ => Unknown
+ }
+ case object Window extends SeatType { override val code = "W" }
+ case object Aisle extends SeatType { override val code = "A" }
+ case object Other extends SeatType { override val code = "O" }
+ case object Unknown extends SeatType { override val code = "" }
+
+ }
+
+ case class SeatReserved(letter: String, row: Int, seatType: SeatType)
+ //#protobuf-read-optional-model
+
+ val protoIDL = """
+ //#protobuf-read-optional-proto
+ // FlightAppModels.proto
+ option java_package = "docs.persistence.proto";
+ option optimize_for = SPEED;
+
+ message SeatReserved {
+ required string letter = 1;
+ required string row = 2;
+ optional string seatType = 3; // the new field
+ }
+ //#protobuf-read-optional-proto
+ """
+
+ //#protobuf-read-optional
+ /**
+ * Example serializer impl which uses protocol buffers generated classes (proto.*)
+ * to perform the to/from binary marshalling.
+ */
+ class AddedFieldsSerializerWithProtobuf extends SerializerWithStringManifest {
+ override def identifier = 67876
+
+ final val SeatReservedManifest = classOf[SeatReserved].getName
+
+ override def manifest(o: AnyRef): String = o.getClass.getName
+
+ override def fromBinary(bytes: Array[Byte], manifest: String): AnyRef =
+ manifest match {
+ case SeatReservedManifest =>
+ seatReserved(proto.SeatReserved.parseFrom(bytes)) // use generated protobuf serializer
+ case _ =>
+ throw new IllegalArgumentException("Unable to handle manifest: " + manifest)
+ }
+
+ override def toBinary(o: AnyRef): Array[Byte] = o match {
+ case s: SeatReserved =>
+ proto.SeatReserved.newBuilder
+ .setCode(s.letter)
+ .setSeatType(s.seatType)
+ .build().toByteArray
+ }
+
+ // -- fromBinary helpers --
+
+ private def seatReserved(p: proto.SeatReserved): SeatReserved =
+ SeatReserved(p.getLetter, p.getRow, seatType(p))
+
+ // handle missing field by assigning "Unknown" value
+ private def seatType(p: proto.SeatReserved): SeatType =
+ if (p.hasSeatType) SeatType.fromString(p.getSeatType) else SeatType.Unknown
+
+ }
+ //#protobuf-read-optional
+}
+
+class ProtoBufRename {
+ val protoIDL = """
+ //#protobuf-rename-proto
+ // protobuf message definition, BEFORE:
+ message SeatReserved {
+ required string code = 1;
+ }
+
+ // protobuf message definition, AFTER:
+ message SeatReserved {
+ required string seatNr = 1; // field renamed, id remains the same
+ }
+ //#protobuf-rename-proto
+ """
+}
+
+class RenamePlainJson {
+ //#rename-plain-json
+ class JsonRenamedFieldAdapter extends EventAdapter {
+ val marshaller = new ExampleJsonMarshaller
+
+ val V1 = "v1"
+ val V2 = "v2"
+
+ // this could be done independently for each event type
+ override def manifest(event: Any): String = "v2"
+
+ override def toJournal(event: Any): JsObject =
+ marshaller.toJson(event)
+
+ override def fromJournal(event: Any, manifest: String): EventSeq = event match {
+ case json: JsObject => EventSeq(marshaller.fromJson(manifest match {
+ case V1 => rename(json, "code" -> "seatNr")
+ case V2 => json // pass-through
+ case unknown => throw new IllegalArgumentException(s"Unknown manifest: $unknown")
+ }))
+ case _ =>
+ val c = event.getClass
+ throw new IllegalArgumentException("Can only work with JSON, was: %s".format(c))
+ }
+
+ def rename(json: JsObject, fromTo: (String, String)): JsObject = {
+ val value = json.fields(fromTo._1)
+ val withoutOld = json.fields - fromTo._1
+ JsObject(withoutOld + (fromTo._2 -> value))
+ }
+
+ }
+ //#rename-plain-json
+}
+
+class SimplestCustomSerializer {
+
+ //#simplest-custom-serializer-model
+ final case class Person(name: String, surname: String)
+ //#simplest-custom-serializer-model
+
+ //#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.
+ */
+ class SimplestPossiblePersonSerializer extends SerializerWithStringManifest {
+ val Utf8 = Charset.forName("UTF-8")
+
+ val PersonManifest = classOf[Person].getName
+
+ // unique identifier of the serializer
+ def identifier = 1234567
+
+ // extract manifest to be stored together with serialized object
+ override def manifest(o: AnyRef): String = o.getClass.getName
+
+ // serialize the object
+ def toBinary(obj: AnyRef): Array[Byte] = obj match {
+ case p: Person => s"""${p.name}|${p.surname}""".getBytes(Utf8)
+ case _ => throw new IllegalArgumentException(
+ s"Unable to serialize to bytes, clazz was: ${obj.getClass}!")
+ }
+
+ // deserialize the object, using the manifest to indicate which logic to apply
+ def fromBinary(bytes: Array[Byte], clazz: String): AnyRef = clazz match {
+ case PersonManifest =>
+ val nameAndSurname = new String(bytes, Utf8)
+ val Array(name, surname) = nameAndSurname.split("[|]")
+ Person(name, surname)
+ case _ => throw new IllegalArgumentException(
+ s"Unable to deserialize from bytes, clazz was: $clazz! Bytes length: ${bytes.length}")
+ }
+
+ }
+
+ //#simplest-custom-serializer
+}
+
+class PersonSerializerSettingsBox {
+ val PersonSerializerSettings = """
+ //#simplest-custom-serializer-config
+ # application.conf
+ akka {
+ actor {
+ serializers {
+ person = "docs.persistence.SimplestPossiblePersonSerializer"
+ }
+
+ serialization-bindings {
+ "docs.persistence.Person" = person
+ }
+ }
+ }
+ //#simplest-custom-serializer-config
+ """
+}
+
+final case class SamplePayload(p: Any)
+
+//#split-events-during-recovery
+trait V1
+trait V2
+
+// V1 event:
+final case class UserDetailsChanged(name: String, address: String) extends V1
+
+// corresponding V2 events:
+final case class UserNameChanged(name: String) extends V2
+final case class UserAddressChanged(address: String) extends V2
+
+// event splitting adapter:
+class UserEventsAdapter extends EventAdapter {
+ override def manifest(event: Any): String = ""
+
+ override def fromJournal(event: Any, manifest: String): EventSeq = event match {
+ case UserDetailsChanged(null, address) => EventSeq(UserAddressChanged(address))
+ case UserDetailsChanged(name, null) => EventSeq(UserNameChanged(name))
+ case UserDetailsChanged(name, address) => EventSeq(UserNameChanged(name),
+ UserAddressChanged(address))
+ case event: V2 => EventSeq(event)
+ }
+
+ override def toJournal(event: Any): Any = event
+}
+//#split-events-during-recovery
+
+final case class CustomerBlinked(customerId: Long)
+
+//#string-serializer-skip-deleved-event-by-manifest
+case object EventDeserializationSkipped
+
+class RemovedEventsAwareSerializer extends SerializerWithStringManifest {
+ val Utf8 = Charset.forName("UTF-8")
+ override def identifier: Int = 8337
+
+ val SkipEventManifestsEvents = Set(
+ "docs.persistence.CustomerBlinked" // ...
+ )
+ val MyPayloadClassName = classOf[SamplePayload].getName
+
+ override def manifest(o: AnyRef): String = o.getClass.getName
+
+ override def toBinary(o: AnyRef): Array[Byte] = o match {
+ case _ => o.toString.getBytes(Utf8) // example serialization
+ }
+
+ override def fromBinary(bytes: Array[Byte], manifest: String): AnyRef = manifest match {
+ case m if SkipEventManifestsEvents.contains(m) =>
+ EventDeserializationSkipped
+
+ case other => new String(bytes)
+ }
+}
+//#string-serializer-skip-deleved-event-by-manifest
+
+//#string-serializer-skip-deleved-event-by-manifest-adapter
+class SkippedEventsAwareAdapter extends EventAdapter {
+ override def manifest(event: Any) = ""
+ override def toJournal(event: Any) = event
+
+ override def fromJournal(event: Any, manifest: String) = event match {
+ case EventDeserializationSkipped => EventSeq.empty
+ case _ => EventSeq(event)
+ }
+}
+//#string-serializer-skip-deleved-event-by-manifest-adapter
+
+//#string-serializer-handle-rename
+class RenamedEventAwareSerializer extends SerializerWithStringManifest {
+ val Utf8 = Charset.forName("UTF-8")
+ override def identifier: Int = 8337
+
+ val OldPayloadClassName = "docs.persistence.OldPayload" // class NOT available anymore
+ val MyPayloadClassName = classOf[SamplePayload].getName
+
+ override def manifest(o: AnyRef): String = o.getClass.getName
+
+ override def toBinary(o: AnyRef): Array[Byte] = o match {
+ case SamplePayload(data) => s"""$data""".getBytes(Utf8)
+ // previously also handled "old" events here.
+ }
+
+ override def fromBinary(bytes: Array[Byte], manifest: String): AnyRef = manifest match {
+ case OldPayloadClassName => SamplePayload(new String(bytes, Utf8))
+ case MyPayloadClassName => SamplePayload(new String(bytes, Utf8))
+ case other => throw new Exception(s"unexpected manifest [$other]")
+ }
+}
+//#string-serializer-handle-rename
+
+//#detach-models
+/** Domain model - highly optimised for domain language and maybe "fluent" usage */
+object DomainModel {
+ final case class Customer(name: String)
+ final case class Seat(code: String) {
+ def bookFor(customer: Customer): SeatBooked = SeatBooked(code, customer)
+ }
+
+ final case class SeatBooked(code: String, customer: Customer)
+}
+
+/** Data model - highly optimised for schema evolution and persistence */
+object DataModel {
+ final case class SeatBooked(code: String, customerName: String)
+}
+//#detach-models
+
+//#detach-models-adapter
+class DetachedModelsAdapter extends EventAdapter {
+ override def manifest(event: Any): String = ""
+
+ override def toJournal(event: Any): Any = event match {
+ case DomainModel.SeatBooked(code, customer) =>
+ DataModel.SeatBooked(code, customer.name)
+ }
+ override def fromJournal(event: Any, manifest: String): EventSeq = event match {
+ case DataModel.SeatBooked(code, customerName) =>
+ EventSeq(DomainModel.SeatBooked(code, DomainModel.Customer(customerName)))
+ }
+}
+//#detach-models-adapter
+
+// act as-if JSON library
+class ExampleJsonMarshaller {
+ def toJson(any: Any): JsObject = JsObject()
+ def fromJson(json: JsObject): Any = new Object
+}
+
+//#detach-models-adapter-json
+class JsonDataModelAdapter extends EventAdapter {
+ override def manifest(event: Any): String = ""
+
+ val marshaller = new ExampleJsonMarshaller
+
+ override def toJournal(event: Any): JsObject =
+ marshaller.toJson(event)
+
+ override def fromJournal(event: Any, manifest: String): EventSeq = event match {
+ case json: JsObject =>
+ EventSeq(marshaller.fromJson(json))
+ case _ =>
+ throw new IllegalArgumentException(
+ "Unable to fromJournal a non-JSON object! Was: " + event.getClass)
+ }
+}
+//#detach-models-adapter-json
diff --git a/akka-docs/rst/scala/index-actors.rst b/akka-docs/rst/scala/index-actors.rst
index ca09504ab7..31babc0126 100644
--- a/akka-docs/rst/scala/index-actors.rst
+++ b/akka-docs/rst/scala/index-actors.rst
@@ -12,6 +12,7 @@ Actors
routing
fsm
persistence
+ persistence-schema-evolution
persistence-query
testing
actordsl
diff --git a/akka-docs/rst/scala/persistence-schema-evolution.rst b/akka-docs/rst/scala/persistence-schema-evolution.rst
new file mode 100644
index 0000000000..b390da3b87
--- /dev/null
+++ b/akka-docs/rst/scala/persistence-schema-evolution.rst
@@ -0,0 +1,476 @@
+.. _persistence-schema-evolution-scala:
+
+##############################
+Persistence - Schema Evolution
+##############################
+
+When working on long running projects using :ref:`persistence-scala`, or any kind of `Event Sourcing`_ architectures,
+schema evolution becomes one of the more important technical aspects of developing your application.
+The requirements as well as our own understanding of the business domain may (and will) change in time.
+
+In fact, if a project matures to the point where you need to evolve its schema to adapt to changing business
+requirements you can view this as first signs of its success – if you wouldn't need to adapt anything over an apps
+lifecycle that could mean that no-one is really using it actively.
+
+In this chapter we will investigate various schema evolution strategies and techniques from which you can pick and
+choose the ones that match your domain and challenge at hand.
+
+.. note::
+ This page proposes a number of possible solutions to the schema evolution problem and explains how some of the
+ utilities Akka provides can be used to achieve this, it is by no means a complete (closed) set of solutions.
+
+ Sometimes, based on the capabilities of your serialization formats, you may be able to evolve your schema in
+ different ways than outlined in the sections below. If you discover useful patterns or techniques for schema
+ evolution feel free to submit Pull Requests to this page to extend it.
+
+
+Schema evolution in event-sourced systems
+=========================================
+
+In recent years we have observed a tremendous move towards immutable append-only datastores, with event-sourcing being
+the prime technique successfully being used in these settings. For an excellent overview why and how immutable data makes scalability
+and systems design much simpler you may want to read Pat Helland's excellent `Immutability Changes Everything`_ whitepaper.
+
+Since with `Event Sourcing`_ the **events are immutable** and usually never deleted – the way schema evolution is handled
+differs from how one would go about it in a mutable database setting (e.g. in typical CRUD database applications).
+The system needs to be able to continue to work in the presence of "old" events which were stored under the "old" schema.
+We also want to limit complexity in the business logic layer, exposing a consistent view over all of the events of a given
+type to :class:`PersistentActor` s and :ref:`persistence queries `. This allows the business logic layer to focus on solving business problems
+instead of having to explicitly deal with different schemas.
+
+The system needs to be able to continue to work in the presence of "old" events which were stored under the "old" schema,
+and we want to limit the complexity to the data layer, exposing a consistent view over all of the events of a given type
+to :class:`PersistentActor` s and persistence queries, which allows these layers to focus on the business problems instead
+handling the different schemas explicitly in the business logic layers.
+
+
+In summary, schema evolution in event sourced systems exposes the following characteristics:
+ - Allow the system to continue operating without large scale migrations to be applied,
+ - Allow the system to read "old" events from the underlying storage, however present them in a "new" view to the application logic,
+ - Transparently promote events to the latest versions during recovery (or queries) such that the business logic need not consider multiple versions of events
+
+.. _Immutability Changes Everything: http://www.cidrdb.org/cidr2015/Papers/CIDR15_Paper16.pdf
+.. _Event Sourcing: http://martinfowler.com/eaaDev/EventSourcing.html
+
+Types of schema evolution
+-------------------------
+Before we explain the various techniques that can be used to safely evolve the schema of your persistent events
+over time, we first need to define what the actual problem is, and what the typical styles of changes are.
+
+Since events are never deleted, we need to have a way to be able to replay (read) old events, in such way
+that does not force the ``PersistentActor`` to be aware of all possible versions of an event that it may have
+persisted in the past. Instead, we want the Actors to work on some form of "latest" version of the event and provide some
+means of either converting old "versions" of stored events into this "latest" event type, or constantly evolve the event
+definition - in a backwards compatible way - such that the new deserialization code can still read old events.
+
+The most common schema changes you will likely are:
+
+- :ref:`adding a field to an event type `,
+- :ref:`remove or rename field in event type `,
+- :ref:`remove event type `,
+- :ref:`split event into multiple smaller events `.
+
+The following sections will explain some patterns which can be used to safely evolve your schema when facing those changes.
+
+Picking the right serialization format
+======================================
+
+Picking the serialization format is a very important decision you will have to make while building your application.
+It affects which kind of evolutions are simple (or hard) to do, how much work is required to add a new datatype, and,
+last but not least, serialization performanceion.
+
+If you find yourself realising you have picked "the wrong" serialization format, it is always possible to change
+the format used for storing new events, however you would have to keep the old deserialization code in order to
+be able to replay events that were persisted using the old serialization scheme. It is possible to "rebuild"
+an event-log from one serialization format to another one, however it may be a more involved process if you need
+to perform this on a live system.
+
+Binary serialization formats that we have seen work well for long-lived applications include the very flexible IDL based:
+`Google Protobuf`_, `Apache Thrift`_ or `Apache Avro`_. Avro schema evolution is more "entire schema" based, instead of
+single fields focused like in protobuf or thrift, and usually requires using some kind of schema registry.
+
+Users who want their data to be human-readable directly in the write-side
+datastore may opt to use plain-old `JSON`_ as the storage format, though that comes at a cost of lacking support for schema
+evolution and relatively large marshalling latency.
+
+There are plenty excellent blog posts explaining the various trade-offs between popular serialization formats,
+one post we would like to highlight is the very well illustrated `Schema evolution in Avro, Protocol Buffers and Thrift`_
+by Martin Kleppmann.
+
+.. _Google Protobuf: https://developers.google.com/protocol-buffers
+.. _Apache Avro: https://avro.apache.org
+.. _JSON: http://json.org
+.. _Schema evolution in Avro, Protocol Buffers and Thrift: http://martin.kleppmann.com/2012/12/05/schema-evolution-in-avro-protocol-buffers-thrift.html
+
+Provided default serializers
+----------------------------
+
+Akka Persistence provides `Google Protocol Buffers`_ based serializers (using :ref:`Akka Serialization `)
+for it's own message types such as ``PersistentRepr``, ``AtomicWrite`` and snapshots. Journal plugin implementations
+*may* choose to use those provided serializers, or pick a serializer which suits the underlying database better.
+
+.. note::
+ Serialization is **NOT** handled automatically by Akka Persistence itself. Instead, it only provides the above described
+ serializers, and in case a ``AsyncWriteJournal`` plugin implementation chooses to use them directly, the above serialization
+ scheme will be used.
+
+ Please refer to your write journal's documentation to learn more about how it handles serialization!
+
+ For example, some journals may choose to not use Akka Serialization *at all* and instead store the data in a format
+ that is more "native" for the underlying datastore, e.g. using JSON or some other kind of format that the target
+ datastore understands directly.
+
+The below figure explains how the default serialization scheme works, and how it fits together with serializing the
+user provided message itself, which we will from here on refer to as the ``payload`` (highlighted in yellow):
+
+.. figure:: ../images/persistent-message-envelope.png
+ :align: center
+
+ Akka Persistence provided serializers wrap the user payload in an envelope containing all persistence-relevant information.
+ **If the Journal uses provided Protobuf serializers for the wrapper types (e.g. PersistentRepr), then the payload will
+ be serialized using the user configured serializer, and if none is provided explicitly, Java serialization will be used for it.**
+
+The blue colored regions of the ``PersistentMessage`` indicate what is serialized using the generated protocol buffers
+serializers, and the yellow payload indicates the user provided event (by calling ``persist(payload)(...)``).
+As you can see, the ``PersistentMessage`` acts as an envelope around the payload, adding various fields related to the
+origin of the event (``persistenceId``, ``sequenceNr`` and more).
+
+More advanced techniques (e.g. :ref:`remove-event-class-scala`) will dive into using the manifests for increasing the
+flexibility of the persisted vs. exposed types even more. Hhowever for now we will focus on the simpler evolution techniques,
+concerning simply configuring the payload serializers.
+
+By default the ``payload`` will be serialized using Java Serialization. This is fine for testing and initial phases
+of your development (while you're still figuring out things and the data will not need to stay persisted forever).
+However, once you move to production you should really *pick a different serializer for your payloads*.
+
+.. warning::
+ Do not rely on Java serialization (which will be picked by Akka by default if you don't specify any serializers)
+ for *serious* application development! It does not lean itself well to evolving schemas over long periods of time,
+ and its performance is also not very high (it never was designed for high-throughput scenarios).
+
+.. _Google Protocol Buffers: https://developers.google.com/protocol-buffers/
+.. _Apache Thrift: https://thrift.apache.org/
+
+Configuring payload serializers
+-------------------------------
+This section aims to highlight the complete basics on how to define custom serializers using :ref:`Akka Serialization `.
+Many journal plugin implementations use Akka Serialization, thus it is tremendously important to understand how to configure
+it to work with your event classes.
+
+.. note::
+ Read the :ref:`Akka Serialization ` docs to learn more about defining custom serializers,
+ to improve performance and maintainability of your system. Do not depend on Java serialization for production deployments.
+
+The below snippet explains in the minimal amount of lines how a custom serializer can be registered.
+For more in-depth explanations on how serialization picks the serializer to use etc, please refer to its documentation.
+
+First we start by defining our domain model class, here representing a person:
+
+.. includecode:: code/docs/persistence/PersistenceSchemaEvolutionDocSpec.scala#simplest-custom-serializer-model
+
+Next we implement a serializer (or extend an existing one to be able to handle the new ``Person`` class):
+
+.. includecode:: code/docs/persistence/PersistenceSchemaEvolutionDocSpec.scala#simplest-custom-serializer
+
+And finally we register the serializer and bind it to handle the ``docs.persistence.Person`` class:
+
+.. includecode:: code/docs/persistence/PersistenceSchemaEvolutionDocSpec.scala#simplest-custom-serializer-config
+
+Deserialization will be performed by the same serializer which serialized the message initially
+because of the ``identifier`` being stored together with the message.
+
+Please refer to the :ref:`Akka Serialization ` documentation for more advanced use of serializers,
+especially the :ref:`string-manifest-serializer-scala` section since it is very useful for Persistence based applications
+dealing with schema evolutions, as we will see in some of the examples below.
+
+Schema evolution in action
+==========================
+
+In this section we will discuss various schema evolution techniques using concrete examples and explaining
+some of the various options one might go about handling the described situation. The list below is by no means
+a complete guide, so feel free to adapt these techniques depending on your serializer's capabilities
+and/or other domain specific limitations.
+
+.. _add-field-scala:
+
+Add fields
+----------
+
+**Situation:**
+You need to add a field to an existing message type. For example, a ``SeatReservation(letter:String, row:Int)`` now
+needs to have an associated code which indicates if it is a window or aisle seat.
+
+**Solution:**
+Adding fields is the most common change you'll need to apply to your messages so make sure the serialization format
+you picked for your payloads can handle it apropriately, i.e. such changes should be *binary compatible*.
+This is easily achieved using the right serializer toolkit – we recommend something like `Google Protocol Buffers`_ or
+`Apache Thrift`_ however other tools may fit your needs just as well – picking a serializer backend is something
+you should research before picking one to run with. In the following examples we will be using protobuf, mostly because
+we are familiar with it, it does its job well and Akka is using it internally as well.
+
+While being able to read messages with missing fields is half of the solution, you also need to deal with the missing
+values somehow. This is usually modeled as some kind of default value, or by representing the field as an ``Option[T]``
+See below for an example how reading an optional field from from a serialized protocol buffers message might look like.
+
+.. includecode:: code/docs/persistence/PersistenceSchemaEvolutionDocSpec.scala#protobuf-read-optional-model
+
+Next we prepare an protocol definition using the protobuf Interface Description Language, which we'll use to generate
+the serializer code to be used on the Akka Serialization layer (notice that the schema aproach allows us to easily rename
+fields, as long as the numeric identifiers of the fields do not change):
+
+.. includecode:: code/docs/persistence/PersistenceSchemaEvolutionDocSpec.scala#protobuf-read-optional-proto
+
+The serializer implementation uses the protobuf generated classes to marshall the payloads.
+Optional fields can be handled explicitly or missing values by calling the ``has...`` methods on the protobuf object,
+which we do for ``seatType`` in order to use a ``Unknown`` type in case the event was stored before we had introduced
+the field to this event type:
+
+.. includecode:: code/docs/persistence/PersistenceSchemaEvolutionDocSpec.scala#protobuf-read-optional
+
+.. _rename-field-scala:
+
+Rename fields
+-------------
+
+**Situation:**
+When first designing the system the ``SeatReverved`` event featured an ``code`` field.
+After some time you discover that what what was originally called ``code`` actually means ``seatNr``, thus the model
+should be changed to reflect this concept more accurately.
+
+
+**Solution 1 - using IDL based serializers:**
+First, we will discuss the most efficient way of dealing with such kinds of schema changes – IDL based serializers.
+
+IDL stands for Interface Description Language, and means that the schema of the messages that will be stored is based
+on this description. Most IDL based serializers also generate the serializer / deserializer code so that using them
+is not too hard. Examples of such serializers are protobuf or thrift.
+
+Using these libraries rename operations are "free", because the field name is never actually stored in the binary
+representation of the message. This is one of the advantages of schema based serializers, even though that they
+add the overhead of having to maintain the schema. When using serializers like this, no additional code change
+(except renaming the field and method used during serialization) is needed to perform such evolution:
+
+.. figure:: ../images/persistence-serializer-rename.png
+ :align: center
+
+This is how such a rename would look in protobuf:
+
+.. includecode:: code/docs/persistence/PersistenceSchemaEvolutionDocSpec.scala#protobuf-rename-proto
+
+It is important to learn about the strengths and limitations of your serializers, in order to be able to move
+swiftly and refactor your models fearlessly as you go on with the project.
+
+.. note::
+ Learn in-depth about the serialization engine you're using as it will impact how you can aproach schema evolution.
+
+ Some operations are "free" in certain serialization formats (more often than not: removing/adding optional fields,
+ sometimes renaming fields etc.), while some other operations are strictly not possible.
+
+**Solution 2 - by manually handling the event versions:**
+Another solution, in case your serialization format does not support renames as easily as the above mentioned formats,
+is versioning your schema. For example, you could have made your events events carry an additional field called ``_version``
+which was set to ``1`` (because it was the initial schema), and once you change the schema you bump this number to ``2``,
+and write an adapter which can perform the rename.
+
+This approach is popular when your serialization format is something like JSON, where renames can not be performed
+automatically by the serializer. You can do these kinds of "promotions" either manually (as shown in the example below)
+or using a library like `Stamina`_ which helps to create those ``V1->V2->V3->...->Vn`` promotion chains without much boilerplate.
+
+.. figure:: ../images/persistence-manual-rename.png
+ :align: center
+
+The following snippet showcases how one could apply renames if working with plain JSON (using ``spray.json.JsObject``):
+
+.. includecode:: code/docs/persistence/PersistenceSchemaEvolutionDocSpec.scala#rename-plain-json
+
+As you can see, manually handling renames induces some boilerplate onto the EventAdapter, however much of it
+you will find is common infrastructure code that can be either provided by an external library (for promotion management)
+or put together in a simple helper trait.
+
+.. note::
+ The technique of versioning events and then promoting them to the latest version using JSON transformations
+ can of course be applied to more than just field renames – it also applies to adding fields and all kinds of
+ changes in the message format.
+
+.. _Stamina: https://github.com/scalapenos/stamina
+
+.. _remove-event-class-scala:
+
+Remove event class and ignore events
+------------------------------------
+
+**Situation:**
+While investigating app performance you notice that insane amounts of ``CustomerBlinked`` events are being stored
+for every customer each time he/she blinks. Upon investigation you decide that the event does not add any value
+and should be deleted. You still have to be able to replay from a journal which contains those old CustomerBlinked events though.
+
+**Naive solution - drop events in EventAdapter:**
+
+The problem of removing an event type from the domain model is not as much its removal, as the implications
+for the recovery mechanisms that this entails. For example, a naive way of filtering out certain kinds of events from
+being delivered to a recovering ``PersistentActor`` is pretty simple, as one can simply filter them out in an :ref:`EventAdapter `:
+
+
+.. figure:: ../images/persistence-drop-event.png
+ :align: center
+
+ The ``EventAdapter`` can drop old events (**O**) by emitting an empty :class:`EventSeq`.
+ Other events can simply be passed through (**E**).
+
+This however does not address the underlying cost of having to deserialize all the events during recovery,
+even those which will be filtered out by the adapter. In the next section we will improve the above explained mechanism
+to avoid deserializing events which would be filtered out by the adapter anyway, thus allowing to save precious time
+during a recovery containing lots of such events (without actually having to delete them).
+
+**Improved solution - deserialize into tombstone:**
+
+In the just described technique we have saved the PersistentActor from receiving un-wanted events by filtering them
+out in the ``EventAdapter``, however the event itself still was deserialized and loaded into memory.
+This has two notable *downsides*:
+
+ - first, that the deserialization was actually performed, so we spent some of out time budget on the
+ deserialization, even though the event does not contribute anything to the persistent actors state.
+ - second, that we are *unable to remove the event class* from the system – since the serializer still needs to create
+ the actuall instance of it, as it does not know it will not be used.
+
+The solution to these problems is to use a serializer that is aware of that event being no longer needed, and can notice
+this before starting to deserialize the object.
+
+This aproach allows us to *remove the original class from our classpath*, which makes for less "old" classes lying around in the project.
+This can for example be implemented by using an ``SerializerWithStringManifest``
+(documented in depth in :ref:`string-manifest-serializer-scala`). By looking at the string manifest, the serializer can notice
+that the type is no longer needed, and skip the deserialization all-together:
+
+.. figure:: ../images/persistence-drop-event-serializer.png
+ :align: center
+
+ The serializer is aware of the old event types that need to be skipped (**O**), and can skip deserializing them alltogether
+ by simply returning a "tombstone" (**T**), which the EventAdapter converts into an empty EventSeq.
+ Other events (**E**) can simply be passed through.
+
+The serializer detects that the string manifest points to a removed event type and skips attempting to deserialize it:
+
+.. includecode:: code/docs/persistence/PersistenceSchemaEvolutionDocSpec.scala#string-serializer-skip-deleved-event-by-manifest
+
+The EventAdapter we implemented is aware of ``EventDeserializationSkipped`` events (our "Tombstones"),
+and emits and empty ``EventSeq`` whenever such object is encoutered:
+
+.. includecode:: code/docs/persistence/PersistenceSchemaEvolutionDocSpec.scala#string-serializer-skip-deleved-event-by-manifest-adapter
+
+.. _detach-domain-from-data-model-scala:
+
+Detach domain model from data model
+-----------------------------------
+
+**Situation:**
+You want to separate the application model (often called the "*domain model*") completely from the models used to
+persist the corresponding events (the "*data model*"). For example because the data representation may change
+independently of the domain model.
+
+Another situation where this technique may be useful is when your serialization tool of choice requires generated
+classes to be used for serialization and deserialization of objects, like for example `Google Protocol Buffers`_ do,
+yet you do not want to leak this implementation detail into the domain model itself, which you'd like to model as
+plain Scala case classes.
+
+**Solution:**
+In order to detach the domain model, which is often represented using pure scala (case) classes, from the data model
+classes which very often may be less user-friendly yet highly optimised for throughput and schema evolution
+(like the classes generated by protobuf for example), it is possible to use a simple EventAdapter which maps between
+these types in a 1:1 style as illustrated below:
+
+.. figure:: ../images/persistence-detach-models.png
+ :align: center
+
+ Domain events (**A**) are adapted to the data model events (**D**) by the ``EventAdapter``.
+ The data model can be a format natively understood by the journal, such that it can store it more efficiently or
+ include additional data for the event (e.g. tags), for ease of later querying.
+
+We will use the following domain and data models to showcase how the separation can be implemented by the adapter:
+
+.. includecode:: code/docs/persistence/PersistenceSchemaEvolutionDocSpec.scala#detach-models
+
+The :class:`EventAdapter` takes care of converting from one model to the other one (in both directions),
+alowing the models to be completely detached from each other, such that they can be optimised independently
+as long as the mapping logic is able to convert between them:
+
+.. includecode:: code/docs/persistence/PersistenceSchemaEvolutionDocSpec.scala#detach-models-adapter
+
+The same technique could also be used directly in the Serializer if the end result of marshalling is bytes.
+Then the serializer can simply convert the bytes do the domain object by using the generated protobuf builders.
+
+.. _store-human-readable-scala:
+
+Store events as human-readable data model
+-----------------------------------------
+**Situation:**
+You want to keep your persisted events in a human-readable format, for example JSON.
+
+**Solution:**
+This is a special case of the :ref:`detach-domain-from-data-model-scala` pattern, and thus requires some co-operation
+from the Journal implementation to achieve this.
+
+An example of a Journal which may implement this pattern is MongoDB, however other databases such as PostgreSQL
+and Cassandra could also do it because of their built-in JSON capabilities.
+
+In this aproach, the :class:`EventAdapter` is used as the marshalling layer: it serializes the events to/from JSON.
+The journal plugin notices that the incoming event type is JSON (for example by performing a ``match`` on the incoming
+event) and stores the incoming object directly.
+
+.. includecode:: code/docs/persistence/PersistenceSchemaEvolutionDocSpec.scala#detach-models-adapter-json
+
+.. note::
+ This technique only applies if the Akka Persistence plugin you are using provides this capability.
+ Check the documentation of your favourite plugin to see if it supports this style of persistence.
+
+ If it doesn't, you may want to skim the `list of existing journal plugins`_, just in case some other plugin
+ for your favourite datastore *does* provide this capability.
+
+**Alternative solution:**
+
+In fact, an AsyncWriteJournal implementation could natively decide to not use binary serialization at all,
+and *always* serialize the incoming messages as JSON - in which case the ``toJournal`` implementation of the
+:class:`EventAdapter` would be an identity function, and the ``fromJournal`` would need to de-serialize messages
+from JSON.
+
+.. note::
+ If in need of human-readable events on the *write-side* of your application reconsider whether preparing materialized views
+ using :ref:`persistence-query-scala` would not be an efficient way to go about this, without compromising the
+ write-side's throughput characteristics.
+
+ If indeed you want to use a human-readable representation on the write-side, pick a Persistence plugin
+ that provides that functionality, or – implement one yourself.
+
+
+.. _list of existing journal plugins: http://akka.io/community/#journal-plugins
+
+.. _split-large-event-into-smaller-scala:
+
+Split large event into fine-grained events
+------------------------------------------
+
+**Situation:**
+While refactoring your domain events, you find that one of the events has become too large (coarse-grained)
+and needs to be split up into multiple fine-grained events.
+
+**Solution:**
+Let us consider a situation where an event represents "user details changed". After some time we discover that this
+event is too coarse, and needs to be split into "user name changed" and "user address changed", because somehow
+users keep changing their usernames a lot and we'd like to keep this as a separate event.
+
+The write side change is very simple, we simply persist ``UserNameChanged`` or ``UserAddressChanged`` depending
+on what the user actually intended to change (instead of the composite ``UserDetailsChanged`` that we had in version 1
+of our model).
+
+.. figure:: ../images/persistence-event-adapter-1-n.png
+ :align: center
+
+ The ``EventAdapter`` splits the incoming event into smaller more fine grained events during recovery.
+
+During recovery however, we now need to convert the old ``V1`` model into the ``V2`` representation of the change.
+Depending if the old event contains a name change, we either emit the ``UserNameChanged`` or we don't,
+and the address change is handled similarily:
+
+.. includecode:: code/docs/persistence/PersistenceSchemaEvolutionDocSpec.scala#split-events-during-recovery
+
+By returning an :class:`EventSeq` from the event adapter, the recovered event can be converted to multiple events before
+being delivered to the persistent actor.
diff --git a/akka-docs/rst/scala/persistence.rst b/akka-docs/rst/scala/persistence.rst
index 946c81c8a0..db11a50c69 100644
--- a/akka-docs/rst/scala/persistence.rst
+++ b/akka-docs/rst/scala/persistence.rst
@@ -597,10 +597,6 @@ configuration key. The method can be overridden by implementation classes to ret
Event Adapters
==============
-.. note::
-
- Complete documentation featuring use-cases and implementation examples for this feature will follow shortly.
-
In long running projects using event sourcing sometimes the need arises to detach the data model from the domain model
completely.
@@ -634,10 +630,7 @@ indeed adapt it return the adapted event(s) for it, other adapters which do not
adaptation simply return ``EventSeq.empty``. The adapted events are then delivered in-order to the ``PersistentActor`` during replay.
.. note::
- More advanced techniques utilising advanced binary serialization formats such as protocol buffers or kryo / thrift / avro
- will be documented very soon. These schema evolutions often may need to reach into the serialization layer, however
- are much more powerful in terms of flexibly removing unused/deprecated classes from your classpath etc.
-
+ For more advanced schema evolution techniques refer to the :ref:`persistence-schema-evolution-scala` documentation.
.. _persistent-fsm:
@@ -885,6 +878,8 @@ it must add
to the application configuration. If not specified, a default serializer is used.
+For more advanced schema evolution techniques refer to the :ref:`persistence-schema-evolution-scala` documentation.
+
Testing
=======
diff --git a/akka-docs/rst/scala/serialization.rst b/akka-docs/rst/scala/serialization.rst
index d4d1da4301..b8c2a98d5a 100644
--- a/akka-docs/rst/scala/serialization.rst
+++ b/akka-docs/rst/scala/serialization.rst
@@ -103,11 +103,13 @@ bytes to different objects.
Then you only need to fill in the blanks, bind it to a name in your :ref:`configuration` and then
list which classes that should be serialized using it.
+.. _string-manifest-serializer-scala:
+
Serializer with String Manifest
-------------------------------
The ``Serializer`` illustrated above supports a class based manifest (type hint).
-For serialization of data that need to evolve over time the `SerializerWithStringManifest`
+For serialization of data that need to evolve over time the ``SerializerWithStringManifest``
is recommended instead of ``Serializer`` because the manifest (type hint) is a ``String``
instead of a ``Class``. That means that the class can be moved/removed and the serializer
can still deserialize old data by matching on the ``String``. This is especially useful