Skip to content

Commit

Permalink
Refactoring of Move
Browse files Browse the repository at this point in the history
  • Loading branch information
themerius committed Jun 2, 2014
1 parent a06fe4e commit 2a87ab2
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 90 deletions.
8 changes: 4 additions & 4 deletions src/main/scala/scaltex/BaseActor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,14 @@ abstract class BaseActor(updater: ActorRef) extends Actor with DiscoverReference

case DocumentHome(url) => this.documentHome = url

case "Debug" => updater ! this.id
case "Next" => sender ! this.nextId
case "FirstChild" => sender ! this.firstChild.path.name
case "Debug" => updater ! this.id
case "Next" => sender ! this.nextId
case "FirstChild" => sender ! this.firstChild.path.name
}

def id = this.state._id.as[String].get
def refs: Refs = new Refs(next, updater, self, firstChild) // TODO: make static object?
def currentState = this.state ++ documentElement.state
def currentState = this.state ++ documentElement.state
def assignedDocElem = this.state.documentElement.as[String].get

def documentElement: DocumentElement =
Expand Down
151 changes: 73 additions & 78 deletions src/main/scala/scaltex/RootActor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -87,90 +87,29 @@ class RootActor(updater: ActorRef, docProps: Props) extends Actor {
}

case InsertFirstChildRequest(newId, msgs) => {
println("HIER", newId, msgs)
val newChild = context.actorOf(docProps, newId)
msgs.map(msg => newChild ! msg)
newChild ! DocumentHome(this.documentHome)
self ! InsertFirstChild(newChild, at = self)
}

case Move(ontoId) => { // TODO: refactor this shit
val elem = sender
val elemId = sender.path.name

case Move(ontoId) => {
if (addresses.contains(ontoId)) {
val ontoElem = addresses(ontoId)
val mover = new utils.ParentPreviousHelper(sender, immutableTopology)
val onto = new utils.ParentPreviousHelper(addresses(ontoId), immutableTopology)

// fill the gap
val elemPrev = topology.filter(_._2("next") == elemId)
val `elem.previous` = if (elemPrev.nonEmpty) elemPrev.keys.head else ""
val `elem.previous.firstChild` = topology.getOrElse(`elem.previous`, Map("firstChild" -> ""))("firstChild")

val `elem.next` = topology(elemId)("next")
val `elem.firstChild` = topology(elemId)("firstChild")

val ontoPrev = topology.filter(_._2("next") == ontoId)
val `ontoElem.previous` = if (ontoPrev.nonEmpty) ontoPrev.keys.head else ""
val `ontoElem.previous.firstChild` = topology.getOrElse(`ontoElem.previous`, Map("firstChild" -> ""))("firstChild")

val `ontoElem.parent` = ontoElem.path.parent.name
val `ontoElem.parent.firstChild` = topology.getOrElse(`ontoElem.parent`, Map("firstChild" -> ""))("firstChild")
val `ontoElem.parent.next` = topology.getOrElse(`ontoElem.parent`, Map("next" -> ""))("next")

val `elem.parent` = elem.path.parent.name
val `elem.parent.firstChild` = topology.getOrElse(`elem.parent`, Map("firstChild" -> ""))("firstChild")
val `elem.parent.next` = topology.getOrElse(`elem.parent`, Map("next" -> ""))("next")

if (elemId != `ontoElem.previous`) {
// change the topology
if (`ontoElem.parent.firstChild` == ontoId)
this.update(`ontoElem.parent`, `ontoElem.parent.next`, elemId)
if (`elem.parent.firstChild` == elemId)
this.update(`elem.parent`, `elem.parent.next`, `elem.next`)

this.update(`ontoElem.previous`, elemId, `ontoElem.previous.firstChild`)
this.update(`elem.previous`, `elem.next`, `elem.previous.firstChild`)
this.update(elemId, ontoId, `elem.firstChild`)

// send the new next and firstChild references, to the elements
// which are not poisened
if (`ontoElem.parent.firstChild` == ontoId) {
if (`ontoElem.parent`.nonEmpty)
addresses(`ontoElem.parent`) ! Next(`ontoElem.parent.next`)
}
if (`elem.parent.firstChild` == elemId) {
if (`elem.parent`.nonEmpty)
addresses(`elem.parent`) ! FirstChild(addresses(`elem.next`))
}
if (`elem.previous`.nonEmpty) {
addresses(`elem.previous`) ! Next(`elem.next`)
addresses(`elem.previous`) ! FirstChild(addresses(`elem.previous.firstChild`))
}
if (`ontoElem.previous`.nonEmpty) {
addresses(`ontoElem.previous`) ! Next(elemId)
addresses(`ontoElem.previous`) ! FirstChild(addresses(`ontoElem.previous.firstChild`))
}

// then update the addresses here?
if (mover.id != onto.previous) {
this.moveChangeTopology(mover, onto)

// kill the hierarchy of the element which is hung somewhere else
context.watch(elem)
elem ! akka.actor.PoisonPill
context.watch(mover.ref)
mover.ref ! akka.actor.PoisonPill

// let the leaf or subtree build from database
val ontoParent = context.actorSelection(ontoElem.path.parent)
val docHome = DocumentHome(this.documentHome)
val setFirstChild = `ontoElem.parent.firstChild` == ontoId
val isLeaf = `elem.firstChild`.isEmpty
val after = if (`ontoElem.previous`.nonEmpty) `ontoElem.previous` else `ontoElem.parent`
val delta =
if (topology(after)("firstChild").nonEmpty && after != "root")
Delta(this.order(elemId), this.order(after).last)
else
Delta(this.order(elemId), after)
if (isLeaf)
moving(elemId) = (ontoParent, SetupLeaf(elemId, ontoId, docHome, setFirstChild), delta)
else // is non-leaf
moving(elemId) = (ontoParent, SetupSubtree(this.immutableTopology, elemId, docHome, setFirstChild), delta)
// note: when mover is terminated, this means root got
// the Terminate message from the poisoned mover
this.rebuildSubtreeFromDb(mover, onto)

this.persistTopology
}
Expand All @@ -182,12 +121,14 @@ class RootActor(updater: ActorRef, docProps: Props) extends Actor {
case akka.actor.Terminated(ref) => {
// if leaf or subtree is dead,
// let the leaf or subtree rebuild from database (at new position)
val parent = moving(ref.path.name)._1
val message = moving(ref.path.name)._2
val delta = moving(ref.path.name)._3
updater ! delta
parent ! message
moving.remove(ref.path.name)
if (moving.contains(ref.path.name)) {
val parent = moving(ref.path.name)._1
val message = moving(ref.path.name)._2
val delta = moving(ref.path.name)._3
updater ! delta
parent ! message
moving.remove(ref.path.name)
}
context.unwatch(ref)
}

Expand Down Expand Up @@ -281,6 +222,60 @@ class RootActor(updater: ActorRef, docProps: Props) extends Actor {
}
}

def moveChangeTopology(mover: utils.ParentPreviousHelper, onto: utils.ParentPreviousHelper) = {
if (onto.parentFirstChild == onto.id)
this.update(onto.parent, onto.parentNext, mover.id)
if (mover.parentFirstChild == mover.id)
this.update(mover.parent, mover.parentNext, mover.next)

this.update(onto.previous, mover.id, onto.previousFirstChild)
this.update(mover.previous, mover.next, mover.previousFirstChild)
this.update(mover.id, onto.id, mover.firstChild)

// send the new next and firstChild references
// to the elements which are not poisened
if (onto.parentFirstChild == onto.id) {
if (onto.parent.nonEmpty)
addresses(onto.parent) ! Next(onto.parentNext)
}
if (mover.parentFirstChild == mover.id) {
if (mover.parent.nonEmpty)
addresses(mover.parent) ! FirstChild(addresses(mover.next))
}
if (mover.previous.nonEmpty) {
addresses(mover.previous) ! Next(mover.next)
addresses(mover.previous) ! FirstChild(addresses(mover.previousFirstChild))
}
if (onto.previous.nonEmpty) {
addresses(onto.previous) ! Next(mover.id)
addresses(onto.previous) ! FirstChild(addresses(onto.previousFirstChild))
}
}

def rebuildSubtreeFromDb(mover: utils.ParentPreviousHelper, onto: utils.ParentPreviousHelper) = {
val ontoParent = context.actorSelection(onto.ref.path.parent)
val docHome = DocumentHome(this.documentHome)
val setFirstChild = onto.parentFirstChild == onto.id
val isLeaf = mover.firstChild.isEmpty
val after = if (onto.previous.nonEmpty) onto.previous else onto.parent
val delta =
if (topology(after)("firstChild").nonEmpty && after != "root")
Delta(this.order(mover.id), this.order(after).last)
else
Delta(this.order(mover.id), after)

if (isLeaf)
moving(mover.id) = (
ontoParent,
SetupLeaf(mover.id, onto.id, docHome, setFirstChild),
delta)
else // is non-leaf
moving(mover.id) = (
ontoParent,
SetupSubtree(this.immutableTopology, mover.id, docHome, setFirstChild),
delta)
}

def initTopology(json: Json[_]) = {
val newTopo = json.toMap.map(kv => (kv._1, Map() ++ kv._2.toMap.map(kv => (kv._1, kv._2.as[String].get))))
for (pair <- newTopo) topology.update(pair._1, pair._2)
Expand Down
4 changes: 2 additions & 2 deletions src/main/scala/scaltex/server/Boot.scala
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ class WebSocket extends WebSocketAction {
case Some("changeContentAndDocElem") => changeContentAndDocElem(json)
case Some("insertNext") => insertNext(json)
case Some("insertFirstChild") => insertFirstChild(json)
case Some("move") => move(json)
case Some("move") => move(json)
case Some(x) => println("onTextMessage: not supportet function.")
case None => println("onTextMessage: supplied wrong data type.")
}
Expand Down Expand Up @@ -192,7 +192,7 @@ class WebSocket extends WebSocketAction {
json.insert = dijon.`{}`
json.insert.afterId = afterId
json.insert.ids = dijon.`[]`
for((entry, idx) <- subtree.view.zipWithIndex)
for ((entry, idx) <- subtree.view.zipWithIndex)
json.insert.ids(idx) = entry
respondWebSocketText(json)
Boot.root ! Update
Expand Down
27 changes: 27 additions & 0 deletions src/main/scala/scaltex/utils/ParentPreviousHelper.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package scaltex.utils

import scaltex.RootActor
import akka.actor.ActorRef

class ParentPreviousHelper(val ref: ActorRef, topology: Map[String, Map[String, String]]) {

val id = ref.path.name

def next(id: String) = if (topology.contains(id)) topology(id)("next") else ""
def firstChild(id: String) = if (topology.contains(id)) topology(id)("firstChild") else ""
def next: String = next(id)
def firstChild: String = firstChild(id)

def parent = ref.path.parent.name
def previous = {
val elemPrev = topology.filter(_._2("next") == id)
if (elemPrev.nonEmpty) elemPrev.keys.head else ""
}

def previousNext = next(previous)
def previousFirstChild = firstChild(previous)

def parentNext = next(parent)
def parentFirstChild = firstChild(parent)

}
4 changes: 2 additions & 2 deletions src/test/scala/scaltex/RootSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -124,15 +124,15 @@ class RootSpec

val `sec-a` = TestActorRef(props, "sec-a")
val `new-elem` = TestActorRef(props, "new-elem")
addr.contains(`new-elem`.path.name) should be (false)
addr.contains(`new-elem`.path.name) should be(false)

root ! InsertNext(`new-elem`, after = `sec-a`)
updater.expectMsg(InsertDelta("new-elem", after = "sec-a"))

topo("sec-a")("next") should be("new-elem")
topo("new-elem")("next") should be("par-a")
topo("par-a")("next") should be("")
addr(`new-elem`.path.name) should be (`new-elem`)
addr(`new-elem`.path.name) should be(`new-elem`)

root ! Remove("new-elem")

Expand Down
6 changes: 3 additions & 3 deletions src/test/scala/scaltex/models/CouchDbSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ class CouchDbSpec
}

"NOT integrate _id and _rev from CouchDB into the topology" in {
root.underlyingActor.topology.contains("_id") should be (false)
root.underlyingActor.topology.contains("_rev") should be (false)
root.underlyingActor.topology.contains("_id") should be(false)
root.underlyingActor.topology.contains("_rev") should be(false)
}

"persist the topology on changes" in {
Expand Down Expand Up @@ -174,7 +174,7 @@ class CouchDbSpec
allActorsLoaded

val reply = HTTP.get(url + "/sec_e")
reply.getStatus should be (404) // not existent
reply.getStatus should be(404) // not existent

val sec_e = system.actorSelection("/user/root/back_matter/sec_e")
sec_e ! Content("test")
Expand Down
2 changes: 1 addition & 1 deletion src/test/scala/scaltex/models/MoveElementSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ class MoveElementSpec
body_matter ! Move(onto = "sec_e")

val messages = updater.receiveN(5).asInstanceOf[Seq[RemoveDelta]]
val foundIds = messages.map(_.id) // remove requests to the front end
val foundIds = messages.map(_.id) // remove requests to the front end

foundIds should contain("body_matter")
foundIds should contain("sec_b")
Expand Down

0 comments on commit 2a87ab2

Please sign in to comment.