View Javadoc
1 /* 2 * Copyright (c) 2003 3 * Information Desire GmbH 4 * All rights reserved. 5 */ 6 package com.infodesire.infobit.external.impl; 7 8 import com.infodesire.infobit.InfobitManager; 9 import com.infodesire.infobit.InfobitException; 10 import com.infodesire.infobit.InfobitSecurityException; 11 12 import com.infodesire.infobit.data.Acl; 13 import com.infodesire.infobit.data.Infobit; 14 15 import com.infodesire.infobit.external.ImportMessage; 16 import com.infodesire.infobit.external.InfobitImporter; 17 18 import org.apache.commons.logging.Log; 19 import org.apache.commons.logging.LogFactory; 20 21 import java.io.Reader; 22 23 import java.util.ArrayList; 24 import java.util.Comparator; 25 import java.util.HashMap; 26 import java.util.HashSet; 27 import java.util.Iterator; 28 import java.util.List; 29 import java.util.Map; 30 import java.util.Set; 31 import java.util.SortedSet; 32 import java.util.TreeSet; 33 34 /*** 35 * This class provides a straight-forward implementation to import infobits from 36 * their XML representation, as defined by {@link InfobitImporter}. 37 * 38 * @author peter2 39 * @created 1. September 2003 40 * @version $Revision: 1.1 $ 41 */ 42 public class ImporterImpl 43 implements InfobitImporter, InfobitDictionary, ImportDiagnostics { 44 45 private final static Log _log = LogFactory.getLog(ImporterImpl.class); 46 47 /*** 48 * The ACL used to create infobits and content. 49 */ 50 private Acl _acl; 51 52 /*** 53 * The collaborating manager 54 */ 55 private InfobitManager _manager; 56 57 /*** 58 * System ID of the XML document to import 59 */ 60 private String _path; 61 62 /*** 63 * List of diagnostics messages applicable to the currently processed {@link 64 * importInfobits import operation}. List of {@link ImportMessage}. 65 */ 66 private List _diagnostics; 67 68 /*** 69 * List of all imported infobits after completion, in order of import. List 70 * of {@link Infobit}. 71 */ 72 private List _infobits = new ArrayList(); 73 74 /*** 75 * Lexicon of all infobits involved in the import. Maps <code>String</code> 76 * infobit names to {@link InfobitNode}s representing infobits. 77 */ 78 private Map _infobitRegister = new HashMap(); 79 80 /*** 81 * Collects all buffered infobits and version nodes, ordered by definition 82 * in the XML import document. Set of {@link BufferNode}. 83 */ 84 private List _bufferNodes; 85 86 /*** 87 * Next timestamp value used for {@link #colorGraph depth-first search} 88 */ 89 private int _nextTime = 1; 90 91 /*** 92 * Buffer nodes in linear dependency order, with the least dependent nodes 93 * first. Set of {@link BufferNode}. 94 */ 95 private SortedSet _orderedNodes = 96 new TreeSet( 97 new Comparator() { 98 public int compare(Object a, Object b) { 99 BufferNode x = (BufferNode) a; 100 BufferNode y = (BufferNode) b; 101 102 return x.getCompleteTime() - y.getCompleteTime(); 103 } 104 105 106 public boolean equals(Object obj) { 107 return false; 108 } 109 }); 110 111 /*** 112 * For each dependency cycle, this collection contains an edge closing the 113 * cycle (backward edge). Set of {@link BufferEdges}. 114 */ 115 private Set _backwardEdges = new HashSet(); 116 117 /*** 118 * Maps all processed infobit nodes to their resolved infobits. Map of 119 * {@link InfobitNode} to {@link Infobit}. 120 */ 121 private Map _resolvedInfobits = new HashMap(); 122 123 124 /*** 125 * Creates an instance ready to set the manager and to {@link #init 126 * initialize}. 127 */ 128 public ImporterImpl() { 129 // STUB 130 } 131 132 133 /*** 134 * Gets the manager to work with. 135 * 136 * @return The manager to access infobits 137 */ 138 public InfobitManager getManager() { 139 return _manager; 140 } 141 142 143 /*** 144 * Defines the manager to work with. 145 * 146 * @param manager The manager to access infobits 147 */ 148 public void setManager(InfobitManager manager) { 149 _manager = manager; 150 } 151 152 153 /*** 154 * Defines the ACL used to create imported infobits and content 155 * 156 * @param acl The new Acl value 157 */ 158 public void setAcl(Acl acl) { 159 _acl = acl; 160 } 161 162 163 /*** 164 * Recovers infobits from an XML representation as created by {@link 165 * InfobitExporter#export InfobitExporter.export}, as specified for {@link 166 * InfobitImporter}. <p> 167 * 168 * <em<BUGS</em> : This implementation returns infobits not imported but 169 * referenced from imported ones. 170 * 171 * @param input Source from which to obtain the XML 172 * document representing the infobits to import 173 * @param path System location of <code>input</code> 174 * , used in diagnostic messages 175 * @param diagnostics A list to be filled with {@link 176 * ImportMessage} instances providing diagnostic messages about errors 177 * encountered during the import. 178 * @return A collection of the imported 179 * infobits. 180 * @exception InfobitException Generic processing error 181 * @exception InfobitSecurityException Description of Exception 182 */ 183 public List importInfobits(Reader input, String path, List diagnostics) 184 throws InfobitException, InfobitSecurityException { 185 186 _path = path; 187 _diagnostics = diagnostics; 188 _diagnostics.clear(); 189 _infobits.clear(); 190 _infobitRegister.clear(); 191 192 buildBuffer(input); 193 orderNodes(); 194 checkNodes(); 195 196 if (_diagnostics.size() == 0) { 197 persistNodes(); 198 extractInfobits(); 199 } 200 201 return _infobits; 202 } 203 204 205 /*** 206 * Prepares the instance to be used. No action for this implementation. 207 * 208 * @exception InfobitException Description of Exception 209 */ 210 public void init() throws InfobitException { 211 } 212 213 214 //////////////////////////////////////////////////////////////////////// 215 // InfobitDictionary Implementation 216 //////////////////////////////////////////////////////////////////////// 217 218 /*** 219 * DOCUMENT METHOD 220 * 221 * @param node Description of Parameter 222 */ 223 public void register(InfobitNode node) { 224 _infobitRegister.put(node.getName(), node); 225 node.setDangling(false); 226 } 227 228 229 /*** 230 * DOCUMENT METHOD 231 * 232 * @param name Description of Parameter 233 * @return Description of the Returned Value 234 */ 235 public InfobitNode lookup(String name) { 236 InfobitNode node = (InfobitNode) _infobitRegister.get(name); 237 238 if (node == null) { 239 node = new InfobitNode(); 240 node.setName(name); 241 node.setDangling(true); 242 _infobitRegister.put(name, node); 243 } 244 245 return node; 246 } 247 248 249 //////////////////////////////////////////////////////////////////////// 250 // ImportDiagnostics Implementation 251 //////////////////////////////////////////////////////////////////////// 252 253 /*** 254 * DOCUMENT METHOD 255 * 256 * @param message Description of Parameter 257 */ 258 public void record(ImportMessage message) { 259 _diagnostics.add(message); 260 _log.trace("Import error: " + message.getMessage()); 261 } 262 263 264 //////////////////////////////////////////////////////////////////////// 265 // Implementation private 266 //////////////////////////////////////////////////////////////////////// 267 268 /*** 269 * Converts an XML document representing exported infobits into the buffer 270 * graph. The graph is not coloured, and references are not resolved. Sets 271 * {@link #_bufferNodes}. 272 * 273 * @param input Description of Parameter 274 * @exception InfobitException Description of Exception 275 * @exception InfobitSecurityException Description of Exception 276 */ 277 private void buildBuffer(Reader input) 278 throws InfobitException, InfobitSecurityException { 279 280 InfobitParser parser = new InfobitParser(this, this); 281 parser.setSystemID(_path); 282 parser.buildTree(input); 283 _bufferNodes = parser.getBufferNodes(); 284 } 285 286 287 /*** 288 * Checks the dependency graph fro acyclicity and creates a linear order. 289 */ 290 private void orderNodes() { 291 for (Iterator i = _bufferNodes.iterator(); i.hasNext(); ) { 292 BufferNode node = (BufferNode) i.next(); 293 294 if (node.getColor() == BufferNode.WHITE) { 295 colorGraph(node); 296 } 297 } 298 299 reportCycles(); 300 } 301 302 303 /*** 304 * Checks the linearly ordered items to be imported on consistency. 305 * 306 * @exception InfobitException Description of Exception 307 */ 308 private void checkNodes() throws InfobitException { 309 for (Iterator i = _bufferNodes.iterator(); i.hasNext(); ) { 310 BufferNode node = (BufferNode) i.next(); 311 312 if (node instanceof InfobitNode) { 313 check((InfobitNode) node); 314 } 315 else if (node instanceof ActualVersionNode) { 316 check((ActualVersionNode) node); 317 } 318 } 319 } 320 321 322 /*** 323 * Successively resolves buffer dependencies and persists the items to be 324 * imported. Stores imported infobits to {@link _resolvedInfobits}. 325 * 326 * @exception InfobitException Description of Exception 327 * @exception InfobitSecurityException Description of Exception 328 */ 329 private void persistNodes() 330 throws InfobitException, InfobitSecurityException { 331 332 _resolvedInfobits.clear(); 333 Map persistedNodes = new HashMap(); 334 335 for (Iterator i = _orderedNodes.iterator(); i.hasNext(); ) { 336 BufferNode node = (BufferNode) i.next(); 337 338 node.setManager(_manager); 339 node.setAcl(_acl); 340 341 for (Iterator j = node.getDependencies().iterator(); 342 j.hasNext(); ) { 343 344 BufferNode dep = (BufferNode) j.next(); 345 Object p = persistedNodes.get(dep); 346 347 // NOTE: due to the linear order of dependencies, 348 // p != null is an invariant 349 if (p == null) { 350 String m = "Failed assertion: unresolved dependency of " + 351 node.getClass().getName() + 352 " to " + dep.getClass().getName(); 353 _log.fatal(m); 354 throw new RuntimeException(m); 355 } 356 357 node.resolveDependency(dep, p); 358 } 359 360 Object persisted = node.persistBuffer(); 361 persistedNodes.put(node, persisted); 362 363 if (node instanceof InfobitNode) { 364 InfobitNode n = (InfobitNode) node; 365 366 // TEST 367 // if (!n.isPredefined()) { 368 if (true || !n.isPredefined()) { 369 _resolvedInfobits.put(node, persisted); 370 } 371 } 372 } 373 } 374 375 376 /*** 377 * Sets up the final ordered list of imported infobits. 378 */ 379 private void extractInfobits() { 380 _infobits.clear(); 381 382 for (Iterator i = _bufferNodes.iterator(); i.hasNext(); ) { 383 BufferNode bn = (BufferNode) i.next(); 384 Infobit ib = (Infobit) _resolvedInfobits.get(bn); 385 386 if (ib != null) { 387 _infobits.add(ib); 388 } 389 } 390 } 391 392 393 /*** 394 * Performs depth-first search on the nodes reachable from the specfied 395 * node. Colors all reached nodes and edges. Stores nodes to {@link 396 * _orderedNodes}. 397 * 398 * @param node Description of Parameter 399 */ 400 private void colorGraph(BufferNode node) { 401 node.setColor(BufferNode.GRAY); 402 node.setDiscoverTime(_nextTime++); 403 404 for (Iterator i = node.getEdges().iterator(); i.hasNext(); ) { 405 BufferEdge edge = (BufferEdge) i.next(); 406 BufferNode end = edge.getDependency(); 407 408 switch (end.getColor()) { 409 case BufferNode.WHITE: 410 colorGraph(end); 411 // edge.setKind(BufferEdge.TREE); 412 break; 413 case BufferNode.GRAY: 414 // edge.setKind(BufferEdge.BACKWARD); 415 _backwardEdges.add(edge); 416 break; 417 case BufferNode.BLACK: 418 // edge.setKind(BufferEdge.FORWARD_OR_CROSS); 419 break; 420 } 421 } 422 423 node.setColor(BufferNode.BLACK); 424 node.setCompleteTime(_nextTime++); 425 _orderedNodes.add(node); 426 } 427 428 429 /*** 430 * Creates error messages on cyclic dependencies from {@link 431 * _backwardNodes}. 432 */ 433 private void reportCycles() { 434 for (Iterator i = _backwardEdges.iterator(); i.hasNext(); ) { 435 BufferEdge edge = (BufferEdge) i.next(); 436 BufferNode node = edge.getDependency(); 437 error(node, "This node infers a cyclic dependency"); 438 } 439 440 // Currently, no cycles are possible 441 // if (_backwardEdges.size() > 0) { 442 // _log.fatal("Failed assertion: cyclic dependency"); 443 // throw new RuntimeException("Failed assertion: cyclic dependency"); 444 // } 445 } 446 447 448 /*** 449 * Checks consistency of an infobit to create. Adds error messges. 450 * 451 * @param node Description of Parameter 452 * @exception InfobitException Description of Exception 453 */ 454 private void check(InfobitNode node) 455 throws InfobitException { 456 457 String name = node.getName(); 458 boolean predefined = _manager.hasInfobit(name); 459 node.setPredefined(predefined); 460 461 if (node.isDangling()) { 462 node.setDangling(predefined); 463 } 464 else if (predefined) { 465 error(node, 466 "The node '" + name + "' to import already exists" + 467 " in the system."); 468 } 469 470 if (node.isDangling()) { 471 error(node, 472 "The referenced Node '" + name + "' is neither" + 473 " imported nor pre-existent in the system"); 474 475 for (Iterator i = node.getDependents().iterator(); i.hasNext(); ) { 476 BufferEdge edge = (BufferEdge) i.next(); 477 error(node, "Node '" + name + "' referenced from here"); 478 } 479 } 480 481 } 482 483 484 /*** 485 * Checks the assignement of an actual version for consistency. Emits error 486 * messages if appropriate. 487 * 488 * @param node Description of Parameter 489 */ 490 private void check(ActualVersionNode node) { 491 if (node.getActualVersionNode() == null) { 492 error(node, 493 "Node '" + 494 node.getInfobitNode().getName() + "' has" + 495 "an undefined version set as its actual version."); 496 } 497 } 498 499 500 /*** 501 * Records an error condition for the specified buffer node. Additionally, 502 * logs the error. 503 * 504 * @param node The node to which <code>message</code> applies 505 * @param msg Description of Parameter 506 */ 507 private void error(BufferNode node, String msg) { 508 String path = node.locateSystemID(); 509 int line = node.locateLine(); 510 511 StringBuffer b = new StringBuffer(); 512 if (path != null) { 513 b.append(path); 514 b.append(":"); 515 } 516 517 if (b.length() > 0 && line > 0) { 518 b.append(":"); 519 b.append(line); 520 } 521 522 b.append(" Error in import: "); 523 b.append(msg); 524 525 _log.error(b.toString()); 526 _diagnostics.add(new ImportMessage(path, line, 0, msg)); 527 } 528 529 } 530

This page was automatically generated by Maven