Source code: com/aendvari/common/model/ModelUtil.java
1 /*
2 * ModelUtil.java
3 *
4 * Copyright (c) 2001, 2002 Aendvari, Ltd. All Rights Reserved.
5 *
6 * See the file LICENSE for terms of use.
7 *
8 */
9
10 package com.aendvari.common.model;
11
12 import java.util.Collection;
13 import java.util.Iterator;
14 import java.util.Map;
15
16 import java.io.Writer;
17 import java.io.StringWriter;
18 import java.io.IOException;
19
20 import com.aendvari.common.model.*;
21
22 import com.aendvari.common.osm.*;
23 import com.aendvari.common.model.osm.*;
24
25 /**
26 * <p>Provides various utility methods for the model classes.</p>
27 *
28 * @author Scott Milne
29 *
30 */
31
32 public class ModelUtil
33 {
34 /* Transfer */
35
36
37 /**
38 * Updates the children of the specified {@link ModelNode} using the
39 * values stored within other {@link ModelNode ModelNodes}.
40 *
41 * @param sourceNode The {@link ModelNode} to read data from.
42 * @param sourceExpression An expression selecting the source node.
43 * Null to use <code>sourceNode</code>.
44 *
45 * @param destinationNode The {@link ModelNode} containing the data to update.
46 * @param destinationExpression An expression selecting the destination node.
47 * Null to use <code>destinationNode</code>.
48 *
49 * @param createNodes True creates destination nodes if they do not exist. False ignores unmatched nodes.
50 *
51 */
52
53 public static void updateNodes(
54 ModelNode sourceNode, String sourceExpression,
55 ModelNode destinationNode, String destinationExpression,
56 boolean createNodes)
57 {
58 ModelTree sourceTree = sourceNode.getOwnerModelTree();
59 ModelTree destinationTree = destinationNode.getOwnerModelTree();
60
61 // get root source node
62 ModelNode rootSource = sourceNode;
63
64 if (sourceExpression != null)
65 {
66 // get specified node
67 rootSource = sourceTree.getNode(sourceNode, sourceExpression);
68
69 // can not continue if root doesn't exist
70 if (rootSource == null)
71 {
72 throw new ModelException("Node can not be found at '" + sourceExpression + "'.");
73 }
74 }
75
76 // get root destination node
77 ModelNode rootDestination = destinationNode;
78
79 if (destinationExpression != null)
80 {
81 // get specified node
82 rootDestination = destinationTree.getNode(destinationNode, destinationExpression);
83
84 // can not continue if root doesn't exist
85 if (rootDestination == null)
86 {
87 throw new ModelException("Node can not be found at '" + destinationExpression + "'.");
88 }
89 }
90
91 // the updateNode() method requires that the 'source' node be a child
92 // and that 'destination' be the parent of the similar named child
93
94 // traverse through the children of the source root and
95 // send to updateNode()
96
97 Iterator nodeIterator = rootSource.getChildNodes().iterator();
98
99 while (nodeIterator.hasNext())
100 {
101 ModelNode sourceChild = (ModelNode)nodeIterator.next();
102
103 // read children and store in children of current destination node
104 updateNode(destinationTree, sourceChild, rootDestination, createNodes);
105 }
106 }
107
108 /**
109 * Updates the value of the supplied node. Each child node is then recursively
110 * updated.
111 *
112 * @param destinationTree The {@link ModelTree} being updated.
113 * @param sourceNode The {@link ModelNode} to read data from.
114 * @param destinationParent The {@link ModelNode} containing the child to update.
115 * @param createNodes True creates destination nodes if they do not exist. False ignores unmatched nodes.
116 *
117 */
118
119 protected static void updateNode(
120 ModelTree destinationTree, ModelNode sourceNode, ModelNode destinationParent, boolean createNodes)
121 {
122 // use the name of the source node to find the destination node
123 ModelNode updateNode = destinationTree.getNode(destinationParent, sourceNode.getNodeName());
124
125 // check if node exists
126 if (updateNode == null)
127 {
128 // if not, then create output node if requested
129 if (createNodes)
130 {
131 updateNode = destinationTree.createNode(
132 sourceNode.getNodeName(), sourceNode.getNodeValue());
133 }
134 else
135 {
136 // ignore source value
137 return;
138 }
139 }
140 // if so, then copy value
141 else
142 {
143 // update node value from source node
144 updateNode.setNodeValue(sourceNode.getNodeValue().toString());
145 }
146
147 // update children
148 Iterator nodeIterator = sourceNode.getChildNodes().iterator();
149
150 while (nodeIterator.hasNext())
151 {
152 ModelNode sourceChild = (ModelNode)nodeIterator.next();
153
154 // read children and store in children of current destination node
155 updateNode(destinationTree, sourceChild, updateNode, createNodes);
156 }
157 }
158
159
160 /* Deletion */
161
162
163 /**
164 * Sets the values of the supplied node and all of its children to an
165 * empty string. Each child is then recursively visited and cleared.
166 *
167 * @param baseNode The base {@link ModelNode} of the nodes to clear.
168 *
169 */
170
171 public static void clearNodes(ModelNode baseNode)
172 {
173 // update node value
174 baseNode.setNodeValue("");
175
176 // update children
177 Iterator nodeIterator = baseNode.getChildNodes().iterator();
178
179 while (nodeIterator.hasNext())
180 {
181 ModelNode child = (ModelNode)nodeIterator.next();
182
183 clearNodes(child);
184 }
185 }
186
187 /**
188 * Removes the children having the specified name from the supplied node.
189 *
190 * @param modelNode The parent {@link ModelNode}.
191 * @param childName The name of the children to remove.
192 *
193 */
194
195 public static void removeNamedChildren(ModelNode modelNode, String childName)
196 {
197 // retrieve list of node name 'childName'
198 Iterator nodeIterator = modelNode.getOwnerModelTree().getNodes(modelNode, childName).iterator();
199
200 // remove all of the selected nodes from the parent
201 while (nodeIterator.hasNext())
202 {
203 ModelNode entry = (ModelNode)nodeIterator.next();
204 modelNode.removeChild(entry);
205 }
206 }
207
208 /**
209 * Removes all children of the supplied node.
210 *
211 * @param modelNode The parent {@link ModelNode}.
212 *
213 */
214
215 public static void removeAllChildren(ModelNode modelNode)
216 {
217 // retrieve list of children
218 Iterator nodeIterator = modelNode.getChildNodes().iterator();
219
220 // remove all children
221 while (nodeIterator.hasNext())
222 {
223 ModelNode entry = (ModelNode)nodeIterator.next();
224 modelNode.removeChild(entry);
225 }
226 }
227
228 /**
229 * Removes all children of the selected node.
230 *
231 * @param modelNode The parent {@link ModelNode}.
232 * @param selectExpression An expression selecting a single {@link ModelNode}.
233 * Relative to <code>modelNode</code>.
234 *
235 */
236
237 public static void removeAllChildren(ModelNode modelNode, String selectExpression)
238 {
239 // determine specified node
240 ModelNode removeNode = modelNode.getOwnerModelTree().getNode(modelNode, selectExpression);
241
242 // check for valid selection
243 if (removeNode == null)
244 {
245 throw new ModelException("Node can not be found at '" + selectExpression + "'.");
246 }
247
248 // remove children of node
249 removeAllChildren(removeNode);
250 }
251
252
253 /* OSM methods */
254
255
256 /**
257 * Copies data from the specified location in the supplied {@link Osm OSM} to the
258 * destination {@link ModelNode}.
259 *
260 * @param sourceNode The {@link OsmNode} to read data from.
261 * @param sourceExpression An expression selecting the source node.
262 * Null to use <code>sourceNode</code>.
263 * @param destinationNode The {@link ModelNode} containing the data to update.
264 * @param createNodes True creates destination nodes if they do not exist. False ignores unmatched nodes.
265 *
266 */
267
268 public static void osmToModel(
269 OsmNode sourceNode, String sourceExpression, ModelNode destinationNode, boolean createNodes)
270 {
271 OsmNode selectedNode = sourceNode;
272
273 // select OSM node if expression if provided
274 if (sourceExpression != null)
275 {
276 // select the OSM node
277 selectedNode = SimpleOsmPath.getNode(sourceNode, sourceExpression, false);
278
279 // check for valid selection
280 if (selectedNode == null)
281 {
282 // if OSM node doesn't exist, then nothing to copy
283 return;
284 }
285 }
286
287 // create a ModelNode from the selected node
288 OsmModelTree modelTree = new OsmModelTree();
289 ModelNode modelNode = modelTree.createNode(selectedNode);
290
291 // copy data
292 updateNodes(modelNode, null, destinationNode, null, createNodes);
293 }
294
295 /**
296 * Copies data from the {@link ModelNode} into the specified location of the
297 * supplied {@link Osm OSM}.
298 *
299 * @param sourceNode The {@link ModelNode} to read data from.
300 * @param destinationNode The {@link OsmNode} containing the data to update.
301 * @param destinationExpression An expression selecting the destination node.
302 * Null to use <code>destinationNode</code>.
303 * @param createNodes True creates destination nodes if they do not exist. False ignores unmatched nodes.
304 *
305 */
306
307 public static void modelToOsm(
308 ModelNode sourceNode, OsmNode destinationNode, String destinationExpression, boolean createNodes)
309 {
310 OsmNode selectedNode = destinationNode;
311
312 // select OSM node if expression if provided
313 if (destinationExpression != null)
314 {
315 // select the OSM node
316 selectedNode = SimpleOsmPath.getNode(destinationNode, destinationExpression, false);
317
318 // check for valid selection
319 if (selectedNode == null)
320 {
321 throw new ModelException("Node can not be found at '" + destinationExpression + "'.");
322 }
323 }
324
325 // create a ModelNode from the selected node
326 OsmModelTree modelTree = new OsmModelTree();
327 ModelNode modelNode = modelTree.createNode(selectedNode);
328
329 // copy data
330 updateNodes(sourceNode, null, modelNode, null, createNodes);
331 }
332
333
334 /* Output */
335
336
337 /**
338 * Writes the supplied {@link ModelNode} and its children to a string.
339 *
340 * @param modelNode The {@link ModelNode} to read data from.
341 *
342 * @return A string containing the {@link ModelNode} data.
343 *
344 */
345
346 public static String writeNode(ModelNode modelNode)
347 {
348 StringWriter buffer = new StringWriter();
349
350 try
351 {
352 examineNode(modelNode, buffer, "");
353 }
354 catch (IOException exception)
355 {
356 // ignore exception
357 }
358
359 return buffer.toString();
360 }
361
362 /**
363 * Writes the supplied {@link ModelNode} and its children to output.
364 *
365 * @param modelNode The {@link ModelNode} to read data from.
366 * @param output The {@link Writer} to output text to.
367 *
368 * @exception IOException Error writing to {@link Writer}.
369 *
370 */
371
372 public static void writeNode(ModelNode modelNode, Writer output)
373 throws IOException
374 {
375 examineNode(modelNode, output, "");
376 }
377
378 /**
379 * Outputs a single {@link ModelNode}, then recursively examines children.
380 *
381 * @param modelNode The {@link ModelNode} instance to examine.
382 * @param output The {@link Writer} to output text to.
383 * @param indent The indentation level for the display.
384 *
385 * @exception IOException Error writing to {@link Writer}.
386 *
387 */
388
389 protected static void examineNode(ModelNode modelNode, Writer output, String indent)
390 throws IOException
391 {
392 // start tag
393 output.write(indent);
394 output.write("<");
395 output.write(modelNode.getNodeName());
396
397 // output attributes
398 Iterator attributeIterator = modelNode.getAttributes().values().iterator();
399
400 while (attributeIterator.hasNext())
401 {
402 Map.Entry attribute = (Map.Entry)attributeIterator.next();
403
404 output.write(" ");
405 output.write(attribute.getKey().toString());
406 output.write("=\"");
407 output.write(attribute.getValue().toString());
408 output.write("\"");
409 }
410
411 output.write(">");
412
413 // track when a child node has been output
414 boolean childOutput = false;
415
416 // check for children
417 if (modelNode.hasChildNodes())
418 {
419 // output children
420 Iterator childIterator = modelNode.getChildNodes().iterator();
421
422 while (childIterator.hasNext())
423 {
424 ModelNode childNode = (ModelNode)childIterator.next();
425
426 // skip internal nodes
427 if (childNode.getNodeName().startsWith("#")) continue;
428
429 // start a new line at first child node
430 if (!childOutput)
431 {
432 output.write("\n");
433 childOutput = true;
434 }
435
436 // examine child
437 examineNode(childNode, output, indent + " ");
438 }
439
440 // prepare for close tag
441 if (childOutput)
442 {
443 output.write(indent);
444 }
445 }
446
447 // check for value
448 if ((modelNode.getNodeValue() != null) && (!childOutput))
449 {
450 // output node value
451 output.write(modelNode.getNodeValue());
452 }
453
454 // close tag
455 output.write("</");
456 output.write(modelNode.getNodeName());
457 output.write(">\n");
458 }
459 }
460