# -*- Tcl -*- package provide xotcl::scriptCreation::recoveryPoint 2.0 package require XOTcl 2.0 namespace eval ::xotcl::scriptCreation::recoveryPoint { namespace import ::xotcl::* ## fehlt noch: filter, mixins, metadata, ass, assoption, etc ## beim recover Class's,Object's proc instproc vars nicht ueberschreiben ## filter dann anhaengen etc ... ## der Recovery Filter darf durch Object filter "" nicht gelöscht werden # # filter to ensure that recovering doesn't overwrite # existing objs/classes # Object instproc recoveryFilter args { ::set method [self calledproc] switch -- $method { create { # don't overwrite objects if {![::Object isobject [lindex $args 0]]} { next } else { # puts stderr "Recovery Filter: omitting [lindex $args 0]" } } proc { if {[lsearch [my info procs] [lindex $args 0]] == -1} { next } else { # puts stderr "Recovery Filter: omitting proc [self]::[lindex $args 0]" } } instproc { if {[lsearch [my info instprocs] [lindex $args 0]] == -1} { next } else { # puts stderr "Recovery Filter: omitting instproc [self]::[lindex $args 0]" } } set { if {[lsearch [my info vars] [lindex $args 0]] == -1} { next } else { # puts stderr "Recovery Filter: omitting var [self]::[lindex $args 0]" } } default {next} } } # # remove filter from object # Object instproc filterremove f { ::set fl [my info filter] puts stderr "filterremove on [self] with $f; fullName: [my filtersearch $f]" while {[::set index [lsearch $fl [my filtersearch $f]]] != -1} { ::set fl [lreplace $fl $index $index] } my filter $fl } # # remove mixin from object # Object instproc mixinremove m { puts stderr "mixinremove on [self] with $m" ::set ml [my info mixins] while {[::set index [lsearch $ml $m]] != -1} { ::set ml [lreplace $ml $index $index] } my mixin $ml } Class RecoveryPoint \ -parameter { {appendedObjs ""} {appendedCls ""} {appendedNamespaces ""} {withState 0} {appendToFile 0} {definedObjs [list Object \ Class \ Class::Parameter]} {excludeNames ""} } # # queries the definedObjs variable whether a given object # is already defined/predefined or not # -> a way to exclude classes/objs from saving # RecoveryPoint instproc isDefined {n} { my instvar definedObjs puts stderr "Checking Defined: $n in $definedObjs" if {[lsearch $definedObjs [string trimleft $n :]] == -1} { return 0 } else { return 1 } } RecoveryPoint instproc appendDefined {n} { my instvar definedObjs lappend definedObjs [string trimleft $n :] } # # check whether an obj/cls/namespace is appended already # append obj/cls/namespace # foreach method {Obj Cl Namespace} { set r { my instvar {appended${method}s name}} set r [subst -nocommands -nobackslash $r] set s $r append s { if {[lsearch $name [string trimleft $n :]] == -1} { return 0 } else { return 1 } } RecoveryPoint instproc isAppended$method {n} $s append r { lappend name [string trimleft $n :] } RecoveryPoint instproc append$method {n} $r } # # compare command for lsort # RecoveryPoint instproc namespaceDepth {a b} { set aCount 0 set bCount 0 for {set i 0} {$i < [string length $a]} {incr i} { if {[string index $a $i] eq ":"} { incr aCount } } for {set i 0} {$i < [string length $b]} {incr i} { if {[string index $b $i] eq ":"} { incr bCount } } if {$aCount == $bCount} { return 0 } elseif {$aCount > $bCount} { return 1 } return -1 } # # produces a script containing the current state of # the given obj # RecoveryPoint instproc stateScript {obj} { set script "" foreach v [$obj info vars] { if {[lsearch [my set excludeNames] $v] == -1} { $obj instvar $v if {[array exists $v]} { foreach name [array names $v] { set arr ${v}($name) set value [$obj set $arr] append script "$obj set $arr \"$value\"\n" } } else { set value [set $v] append script "$obj set $v \"$value\"\n" } } } return $script } # # produces a script containing the procs of the given obj # RecoveryPoint instproc procScript {obj} { set script "" foreach p [$obj info procs] { if {[lsearch [my set excludeNames] $v] == -1} { append script \ "$obj proc $p \{[$obj info args $p]\} \{[$obj info body $p]\}\n" } } return $script } # # produces a script containing the instprocs of the given class # RecoveryPoint instproc instprocScript {cl} { set script "" foreach p [$cl info instprocs] { if {[lsearch [my set excludeNames] $v] == -1} { append script \ "$cl instproc $p \{[$cl info instargs $p]\} \{[$cl info instbody $p]\}\n" } } return $script } # # append parent obj/classes/namespaces of an object completely # RecoveryPoint instproc appendParents {name} { # puts stderr "Recovery -- appendParents $name " set p "" set script "" set n $name while {[set np [namespace parent ::$n]] != "::"} { lappend p $np set n $np } set p [lsort -command {[self] namespaceDepth} $p] foreach n $p { if {[Object isobject $n]} { if {[$n isclass]} { append script [my classScript $n] } else { append script [my objectScript $n] } } else { if {![my isAppendedNamespace $n]} { append script "namespace eval $n \{\}\n" # puts stderr "Recovery -- Appending Namespace: $n" my appendedNamespace $n } } } return $script } # # produces a script recovering the given obj with all children # without state # RecoveryPoint instproc objectScript {obj} { # puts stderr "Recovery -- Object Script $obj" my instvar withState set script "" if {![my isDefined $obj] && ![my isAppendedObj $obj]} { # if the object's class is not yet appended => do it now set objClass [$obj info class] append script [my classScript $objClass] # append all parent namespaces append script [my appendParents $obj] # append the obj append script "$objClass $obj\n" append script [my procScript $obj] if {$withState == 1} { append script [my stateScript $obj] } # puts stderr "Recovery -- Appending Object: $obj" my appendObj $obj # append its children foreach o [$obj info children] { append script [my objectScript $o] } } return $script } # # produces a script recovering the given class with all children # without state # RecoveryPoint instproc classScript {cl} { # puts stderr "Recovery -- Class Script $cl" my instvar withState set script "" if {![my isDefined $cl] && ![my isAppendedCl $cl]} { # if the class's meta-class is not yet appended => do it now set metaClass [$cl info class] append script [my classScript $metaClass] # append all parent namespaces append script [my appendParents $cl] # append the class append script "$metaClass $cl" set sl [$cl info superclass] if {$sl ne ""} { append script " -superclass \{$sl\}\n" } else { append script "\n" } append script [my instprocScript $cl] append script [my procScript $cl] if {$withState == 1} { append script [my stateScript $cl] } # puts stderr "Recovery -- Appending Class: $cl \n $script" my appendCl $cl # append children set children [$cl info children] set classChildren [$cl info classchildren] foreach c $children { if {[lsearch $classChildren $c] != -1} { append script [my classScript $c] } else { append script [my objectScript $c] } } } return $script } # # produces a script recovering the given class and all subclasses # with all their children and all instances # # RecoveryPoint instproc hierarchyScript {cl} { set script [my classScript $cl] set sortedInstances \ [lsort -command {[self] namespaceDepth} [$cl info instances]] foreach o $sortedInstances { append script [my objectScript $o] } foreach c [$cl info subclass] { append script [my hierarchyScript $c] } return $script } # # saves a script to a file # RecoveryPoint instproc saveScript {filename script} { my instvar appendToFile if {$appendToFile} { set mode a } else { set mode w } set f [open $filename $mode] puts $f $script close $f } # # load a script from a file # RecoveryPoint instproc loadScript {filename} { set f [open $filename r] set r [read $f] close $f return $r } # # produce methods to save/recover an object script to/from a file # with/without state/only state # foreach method { Object ObjectState ObjectWithState Class ClassWithState \ Hierarchy HierarchyWithState } { set s { my set withState } if {[regexp {(.*)WithState} $method _ m]} { set call $m append s "1" } else { set call $method append s "0" } scan $call %c l set ::low "[format %c [expr {$l + 32}]][string range $call 1 end]" append s { my appendedObjs "" my appendedCls "" my appendedNamespaces "" } append s " foreach a \$args \{" set r { set script [my ${low}Script } set r [subst -nocommands -nobackslash $r] append s $r append s {$a] my saveScript $filename $script} append s " \} " RecoveryPoint instproc save$method {filename args} $s } RecoveryPoint instproc recover {filename} { set r [my loadScript $filename] Object filterappend recoveryFilter # puts stderr "RecoveryFilter appended for $filename" eval $r Object filterremove recoveryFilter # puts stderr "RecoveryFilter removed for $filename" return } namespace export RecoveryPoint } namespace import ::xotcl::scriptCreation::recoveryPoint::*