source: gsdl/trunk/perllib/ClassifyTreeModel.pm@ 14119

Last change on this file since 14119 was 12844, checked in by mdewsnip, 18 years ago

Incremental building and dynamic GDBM updating code, many thanks to John Rowe and John Thompson at DL Consulting Ltd.

  • Property svn:keywords set to Author Date Id Revision
File size: 8.8 KB
Line 
1package ClassifyTreeModel;
2
3use ClassifyTreeNode;
4use GDBMUtils;
5
6# /** Constructor
7# *
8# * @param $class The name of the class to bless as a string
9# * @param $collection The name of the collection whose GDBM database we
10# * will be accessing as a string
11# * @param $root The oid of the root node of the classifier as a
12# * string
13# * @return A reference to the ClassifyTreeModel object
14# *
15# * @author John Thompson, DL Consulting Ltd.
16# */
17sub new()
18 {
19 my ($class, $collection, $root) = @_;
20 my $debug = 0;
21 print STDERR "ClassifyTreeModel.new(\"$collection\", \"$root\")\n" unless !$debug;
22 # Store the variables
23 my $self = {};
24 $self->{'collection'} = $collection;
25 $self->{'debug'} = $debug;
26 $self->{'root'} = $root;
27 # Bless me father for I have sinned
28 bless $self, $class;
29 return $self;
30 }
31# /** new() **/
32
33# /** Given a path and a document id, add this document to the classifier tree
34# * creating any necessary tree nodes first.
35# *
36# * @param $value The path to store this document in
37# * @param $oid Unique identifier of a document
38# *
39# * @author John Thompson, DL Consulting Ltd.
40# */
41sub addDocument()
42 {
43 my ($self, $value, $oid) = @_;
44 print STDERR "ClassifyTreeModel.addDocument(\"$value\", \"$oid\")\n" unless !$self->{'debug'};
45 # Generate a treepath object from the metadata value, remembering to prefix
46 # with the root nodes path
47 my $root_node_obj = $self->getRootNode();
48 my $path_obj = $root_node_obj->getPath();
49 $path_obj->addPathComponent($value);
50 # Ensure that this classifier node, and if necessary its ancestor nodes,
51 # exist in our tree.
52 my $node_obj = $self->getNodeByPath($path_obj);
53 if (!$node_obj)
54 {
55 # The node doesn't exist, so we need to add it
56 $node_obj = $self->addNode($path_obj);
57 }
58 # Add the document to the node.
59 $node_obj->addDocument($oid);
60 # Done.
61 }
62# /** addDocument() **/
63
64# /** Add a node into the tree first ensuring all its parent nodes are inserted
65# * to.
66# *
67# * @param $path_obj The path to insert the new node at
68# *
69# * @author John Thompson, DL Consulting Ltd.
70# */
71sub addNode()
72 {
73 my ($self, $path_obj) = @_;
74 print STDERR "ClassifyTreeModel.addNode(\"" . $path_obj->toString() . "\")\n" unless !$self->{'debug'};
75 # Ensure the parent exists, assuming we aren't at the root
76 my $parent_path_obj = $path_obj->getParentPath();
77 #rint STDERR "* parent path: " . $parent_path_obj->toString() . "\n";
78 my $parent_node_obj = $self->getNodeByPath($parent_path_obj);
79 #rint STDERR "* does parent node already exist? " . $parent_node_obj . "\n";
80 #rint STDERR "* are we at the root node yet? " . $parent_path_obj->isRootPath() . "\n";
81 if (!$parent_node_obj && !$parent_path_obj->isRootPath())
82 {
83 #rint STDERR "* recursive call!\n";
84 $parent_node_obj = $self->addNode($parent_path_obj);
85 }
86 # Insert this node into it's parent.
87 return $parent_node_obj->insertNode($path_obj);
88 }
89# /** addNode() **/
90
91# /** Retrieve the name of the collection this model is drawing from.
92# *
93# * @return The collection name as a string
94# *
95# * @author John Thompson, DL Consulting Ltd.
96# */
97sub getCollection()
98 {
99 my ($self) = @_;
100 print STDERR "ClassifyTreeModel.getCollection()\n" unless !$self->{'debug'};
101 return $self->{'collection'};
102 }
103# /** getCollection() **/
104
105# /** Retrieve a node from this tree based upon its CLID (OID).
106# * @param $clid The CLID as a string
107# * @return The indicated ClassifyTreeNode or null
108sub getNodeByCLID()
109 {
110 my ($self, $clid) = @_;
111 print STDERR "ClassifyTreeModel.getNodeByCLID(\"$clid\")\n" unless !$self->{'debug'};
112 my $result = 0;
113 # Test if this clid is even in our tree
114 if($clid !~ /^$self->{'root'}/)
115 {
116 print STDERR "Requested node $clid, which isn't part of " . $self->{'root'} . "\n";
117 return 0;
118 }
119 # Unfortunately I have to check that there is text to retrieve before I
120 # create a new node.
121 if(&GDBMUtils::gdbmGet($self->getCollection(), $clid) =~ /\w+/)
122 {
123 # Since the CLID can directly reference the correct entry in the GDBM we
124 # just create the node and return it
125 $result = new ClassifyTreeNode($self, $clid);
126 }
127 return $result;
128 }
129
130# /** Retrieve a node from this tree based upon a path
131# *
132# * @param $path The path to the node as a ClassifyTreePath
133# * @return The indicated ClassifyTreeNode or null
134# *
135# * @author John Thompson, DL Consulting Ltd.
136# */
137sub getNodeByPath()
138 {
139 my ($self, $path_obj) = @_;
140 print STDERR "ClassifyTreeModel.getNodeByPath(\"" . $path_obj->toString() . "\")\n" unless !$self->{'debug'};
141 # Starting at the ROOT of the tree, and with the first path component,
142 # recursively descend through the tree looking for the node - we can assume
143 # that we've found the root node (otherwise we won't be in a tree)
144 my $cur_node_obj = $self->getRootNode();
145 my $cur_path_obj = $cur_node_obj->getPath();
146 my $depth = 1;
147 # Continue till we either find the node we want, or run out a nodes
148 while(!$cur_node_obj->getPath()->equals($path_obj))
149 {
150 # Append the path component at this depth to the current path we
151 # are searching for
152 $cur_path_obj->addPathComponent($path_obj->getPathComponent($depth));
153 $depth++;
154 #rint STDERR "Searching " . $cur_node_obj->getPath()->toString() . "'s children for: " . $cur_path_obj->toString() . "\n";
155 # Search through the current nodes children, looking for one that
156 # matches the current path
157 my $found = 0;
158 foreach my $child_node_obj ($cur_node_obj->getChildren())
159 {
160 #rint STDERR "* testing " . $child_node_obj->getPath()->toString() . "\n";
161 if($child_node_obj->getPath()->equals($cur_path_obj))
162 {
163 $cur_node_obj = $child_node_obj;
164 $found = 1;
165 last;
166 }
167 }
168 # Couldn't find any node with this path
169 if(!$found)
170 {
171 #rint STDERR "* no such node exists!\n";
172 return 0;
173 }
174 }
175 return $cur_node_obj;
176 }
177# /** getChild() **/
178
179# /** Retrieve the parent node of the given node.
180# *
181# * @param $child_node The node whose parent we want to retrieve
182# * @return The parent node, or 0 if this is the root
183# *
184# * @author John Thompson, DL Consulting Ltd.
185# */
186sub getParentNode()
187 {
188 my ($self, $child_node) = @_;
189 print STDERR "ClassifyTreeModel.getParentNode()\n" unless !$self->{'debug'};
190 return $child_node->getParentNode();
191 }
192# /** getParentNode() **/
193
194sub getRootNode()
195{
196 my ($self) = @_;
197 print STDERR "ClassifyTreeModel.getRootNode()\n" unless !$self->{'debug'};
198 return new ClassifyTreeNode($self, $self->{'root'});
199}
200
201# /** Remove the given document from the classifier tree, and then remove any
202# * empty nodes if required.
203# *
204# * @param $value The value which contains the path of the node to remove
205# * the document from
206# * @param $oid The unique identifier of the document to remove
207# * @param $remove_empty Sets whether empty nodes are removed
208# *
209# * @author John Thompson, DL Consulting Ltd.
210# */
211sub removeDocument()
212 {
213 my ($self, $path, $oid, $remove_empty) = @_;
214 print STDERR "ClassifyTreeModel.removeDocument(\"$path\",\"$oid\",$remove_empty)\n" unless !$self->{'debug'};
215 # Append to root path
216 my $root_node_obj = $self->getRootNode();
217 my $path_obj = $root_node_obj->getPath();
218 $path_obj->addPathComponent($path);
219 # Retrieve the node in question
220 my $node_obj = $self->getNodeByPath($path_obj);
221 # Check we retrieved a node
222 if ($node_obj)
223 {
224 # Remove the document
225 $node_obj->removeDocument($oid);
226 # If we have been asked to remove empty nodes, do so now.
227 if ($remove_empty)
228 {
229 my $cur_node_obj = $node_obj;
230 my $empty_node_obj = 0;
231 while ($cur_node_obj->getNumLeafDocs() == 0)
232 {
233 $empty_node_obj = $cur_node_obj;
234 $cur_node_obj = $cur_node_obj->getParentNode();
235 }
236 if ($empty_node_obj)
237 {
238 # Try to retrieve the parent of this node
239 my $parent_node_obj = $empty_node_obj->getParentNode();
240 # As long as we have a parent (i.e. we aren't the root node) go
241 # ahead and delete this subtree starting at empty node
242 if ($parent_node_obj)
243 {
244 $parent_node_obj->removeNode($empty_node_obj);
245 }
246 }
247 }
248 }
249 # If the node doesn't exist in this tree, then we can't very well remove
250 # anything from it!
251 }
252# /** removeDocument() **/
253
2541;
Note: See TracBrowser for help on using the repository browser.