1 package org.sapia.regis.impl; 2 3 import java.io.Serializable ; 4 import java.util.ArrayList ; 5 import java.util.Collection ; 6 import java.util.Collections ; 7 import java.util.Date ; 8 import java.util.HashMap ; 9 import java.util.Iterator ; 10 import java.util.LinkedList ; 11 import java.util.List ; 12 import java.util.Map ; 13 import java.util.TreeMap ; 14 15 import org.sapia.regis.DuplicateNodeException; 16 import org.sapia.regis.Node; 17 import org.sapia.regis.Path; 18 import org.sapia.regis.Property; 19 import org.sapia.regis.Query; 20 import org.sapia.regis.RWNode; 21 import org.sapia.regis.util.CompositeHashMap; 22 import org.sapia.util.text.MapContext; 23 import org.sapia.util.text.TemplateContextIF; 24 import org.sapia.util.text.TemplateException; 25 import org.sapia.util.text.TemplateFactory; 26 27 public class NodeImpl implements RWNode, Serializable { 28 29 static final long serialVersionUID = 1L; 30 31 private Long id; 32 private boolean inheritsParent; 33 private int version; 34 private Date createDate = new Date (); 35 private Date modifDate = new Date (); 36 private String editUser; 37 private String name = ROOT_NAME; 38 private String type; 39 private NodeImpl parent; 40 private Map valueMap = new TreeMap (); 41 private Map childrenMap = new TreeMap (); 42 private List appendedLinks = new ArrayList (); 43 private List prependedLinks = new ArrayList (); 44 private List includes = new ArrayList (); 45 46 static final NullContext NULL_CONTEXT = new NullContext(); 47 48 public NodeImpl(){ 49 } 50 51 public NodeImpl(NodeImpl parent, String name){ 52 this.parent = parent; 53 this.name = name; 54 if(name.equals(ROOT_NAME) && parent != null){ 55 throw new IllegalStateException ("Name of child node cannot have null or empty name"); 56 } 57 } 58 59 public String getName(){ 60 return this.name; 61 } 62 63 public String getType(){ 64 return this.type; 65 } 66 67 public void setType(String type){ 68 this.type = type; 69 } 70 71 public Path getAbsolutePath() { 72 List tokens = new ArrayList (); 73 doGetPath(tokens); 74 return new Path(tokens); 75 } 76 public long lastModifChecksum() { 77 Checksum chk = new Checksum(); 78 doCalculateChecksum(chk); 79 return chk.result(); 80 } 81 82 public Node getParent(){ 83 return this.parent; 84 } 85 86 public boolean isRoot(){ 87 return getParent() == null; 88 } 89 90 public Map getProperties() { 91 return doGetProperties(Collections.EMPTY_MAP); 92 } 93 94 public Map getProperties(Map values) { 95 return doGetProperties(values); 96 } 97 98 public Collection getPropertyKeys() { 99 List keys = new ArrayList (); 100 doGetPropertyKeys(keys); 101 return keys; 102 } 103 104 public Node createChild(String name) throws DuplicateNodeException{ 105 if(getChildrenMap().get(name) != null){ 106 throw new DuplicateNodeException(name); 107 } 108 if(name.equals(Node.ROOT_NAME)){ 109 throw new IllegalStateException ("Empty name is invalid"); 110 } 111 NodeImpl node = new NodeImpl(this, name); 112 getChildrenMap().put(name, node); 113 return node; 114 } 115 116 public Node getChild(String name){ 117 if(name.equals(ROOT_NAME)){ 118 return this; 119 } 120 Node node = (Node)getChildrenMap().get(name); 121 if(node == null){ 122 Iterator itr = getIncludes().iterator(); 123 while(itr.hasNext()){ 124 node = (Node)itr.next(); 125 if(node.getName().equals(name)){ 126 return node; 127 } 128 } 129 return null; 130 } 131 else{ 132 return node; 133 } 134 } 135 136 public Node getChild(Path path){ 137 return doGetChild(path.tokens()); 138 } 139 140 public void deleteChild(String name) { 141 getChildrenMap().remove(name); 142 } 143 144 public void deleteChildren() { 145 getChildrenMap().clear(); 146 } 147 148 public Collection getChildren(){ 149 Collection children = getChildrenMap().values(); 150 List toReturn = new ArrayList (children); 151 toReturn.addAll(this.getIncludes()); 152 return toReturn; 153 } 154 155 public void setProperty(String key, String value) { 156 getValueMap().put(key, value); 157 } 158 159 public Property getProperty(String key) { 160 161 Property prop = doGetLinkedProperty(getPrependedLinks(), key); 162 if(prop == null || prop.isNull()){ 163 String value = (String )getValueMap().get(key); 164 if(value == null && isInheritsParent() && getParent() != null){ 165 prop = getParent().getProperty(key); 166 if(!prop.isNull()) return prop; 167 } 168 else if(value != null){ 169 return new PropertyImpl(key, value); 170 } 171 prop = doGetLinkedProperty(getAppendedLinks(), key); 172 if(prop == null){ 173 prop = new PropertyImpl(key, value); 174 } 175 } 176 return prop; 177 } 178 179 public Property renderProperty(String key){ 180 return renderProperty(key, Collections.EMPTY_MAP); 181 } 182 183 public Property renderProperty(String key, Map values) { 184 Property value = getProperty(key); 185 if(value.isNull()){ 186 return value; 187 } 188 doRenderProperty((PropertyImpl)value, values); 189 return value; 190 } 191 192 public void deleteProperties() { 193 getValueMap().clear(); 194 } 195 196 public void deleteProperty(String key) { 197 getValueMap().remove(key); 198 } 199 200 public boolean isInheritsParent() { 201 return inheritsParent; 202 } 203 204 public void setInheritsParent(boolean inheritsParent) { 205 this.inheritsParent = inheritsParent; 206 } 207 208 public void appendLink(Node node) { 209 getAppendedLinks().add(node); 210 } 211 212 public void removeAppendedLink(Node node) { 213 getAppendedLinks().remove(node); 214 } 215 216 public void prependLink(Node node) { 217 getPrependedLinks().add(node); 218 } 219 220 public void removePrependedLink(Node node) { 221 getPrependedLinks().remove(node); 222 } 223 224 public void addInclude(Node node) { 225 getIncludes().add(node); 226 } 227 228 public void removeInclude(Node node) { 229 getIncludes().remove(node); 230 } 231 232 public Collection getLinks(boolean prepended) { 233 if(prepended){ 234 return new ArrayList (getPrependedLinks()); 235 } 236 else{ 237 return new ArrayList (getPrependedLinks()); 238 } 239 } 240 241 public void deleteLinks() { 242 getPrependedLinks().clear(); 243 getAppendedLinks().clear(); 244 } 245 246 public void moveTo(Node newParent) { 247 if(isRoot()){ 248 throw new IllegalStateException ("Cannot move root under another node"); 249 } 250 if(newParent.getChild(getName()) != null){ 251 throw new IllegalStateException ("Node already exists for name: " + getName()); 252 } 253 NodeImpl impl = (NodeImpl)newParent; 254 setParent(impl); 255 impl.getChildrenMap().put(getName(), this); 256 } 257 258 public Map getChildrenMap() { 259 return childrenMap; 260 } 261 262 public void setChildrenMap(Map childrenMap) { 263 this.childrenMap = childrenMap; 264 } 265 266 public Date getCreateDate() { 267 return createDate; 268 } 269 270 public void setCreateDate(Date createDate) { 271 this.createDate = createDate; 272 } 273 274 public String getEditUser() { 275 return editUser; 276 } 277 278 public void setEditUser(String editUser) { 279 this.editUser = editUser; 280 } 281 282 public Long getId() { 283 return id; 284 } 285 286 public void setId(Long id) { 287 this.id = id; 288 } 289 290 public Date getModifDate() { 291 return modifDate; 292 } 293 294 public void setModifDate(Date modifDate) { 295 this.modifDate = modifDate; 296 } 297 298 public Map getValueMap() { 299 return valueMap; 300 } 301 302 public void setValueMap(Map valueMap) { 303 this.valueMap = valueMap; 304 } 305 306 public int getVersion() { 307 return version; 308 } 309 310 public void setVersion(int version) { 311 this.version = version; 312 } 313 314 public void setName(String name) { 315 this.name = name; 316 } 317 318 public void setParent(NodeImpl parent) { 319 this.parent = parent; 320 } 321 322 public List getAppendedLinks() { 323 return appendedLinks; 324 } 325 326 public void setAppendedLinks(List appendedLinks) { 327 this.appendedLinks = appendedLinks; 328 } 329 330 public List getPrependedLinks() { 331 return prependedLinks; 332 } 333 334 public void setPrependedLinks(List prependedLinks) { 335 this.prependedLinks = prependedLinks; 336 } 337 338 public void setIncludes(List includes) { 339 this.includes = includes; 340 } 341 342 public Collection getIncludes() { 343 return includes; 344 } 345 346 public void deleteIncludes() { 347 getIncludes().clear(); 348 } 349 350 public Collection getNodes(Query query) { 351 Path p = query.getPath(); 352 if(p != null){ 353 Node node = getChild(p); 354 if(node == null){ 355 return Collections.EMPTY_LIST; 356 } 357 else{ 358 return ((NodeImpl)node).doGetNodes(query); 359 } 360 } 361 else{ 362 return doGetNodes(query); 363 } 364 } 365 366 public int hashCode(){ 367 if(getId() == null) return super.hashCode(); 368 return getId().hashCode(); 369 } 370 371 public boolean equals(Object other){ 372 if(other instanceof NodeImpl){ 373 NodeImpl node = (NodeImpl)other; 374 if(getId() == null || node.getId() == null){ 375 return super.equals(other); 376 } 377 else{ 378 return getId().equals(node.getId()); 379 } 380 } 381 else{ 382 return false; 383 } 384 } 385 386 protected Node doGetChild(Iterator itr){ 387 if(itr.hasNext()){ 388 String name = (String )itr.next(); 389 NodeImpl child = (NodeImpl)getChildrenMap().get(name); 390 if(child != null){ 391 return child.doGetChild(itr); 392 } 393 else{ 394 Iterator includes = getIncludes().iterator(); 395 while(includes.hasNext()){ 396 child = (NodeImpl)includes.next(); 397 if(child.getName().equals(name)){ 398 return child; 399 } 400 } 401 return null; 402 } 403 } 404 return this; 405 } 406 407 protected Map doGetProperties(Map values){ 408 CompositeHashMap fill = new CompositeHashMap(); 409 fill.addChild(values); 410 fill.putAll(getValueMap()); 411 if(isInheritsParent() && getParent() != null){ 412 Map props = ((NodeImpl)getParent()).doGetProperties(values); 413 doRender(fill, props); 414 } 415 416 List links = getPrependedLinks(); 417 for(int i = 0; i < links.size(); i++){ 418 NodeImpl node = (NodeImpl)links.get(i); 419 doRender(fill, node.doGetProperties(values)); 420 } 421 422 links = getAppendedLinks(); 423 for(int i = 0; i < links.size(); i++){ 424 NodeImpl node = (NodeImpl)links.get(i); 425 Map appended = node.getProperties(); 426 doRender(appended, fill); 427 fill.putAll(appended); 428 } 429 430 fill.putAll(getValueMap()); 431 432 doRender(fill, fill); 433 434 return fill; 435 } 436 437 438 protected void doRender(Map target, Map src){ 439 TemplateFactory fac = new TemplateFactory(); 440 fac.setThrowExcOnMissingVar(false); 441 TemplateContextIF ctx = new MapContext(src, NULL_CONTEXT, false); 442 443 Iterator keys = target.keySet().iterator(); 444 while(keys.hasNext()){ 445 String key = (String )keys.next(); 446 String val = (String )target.get(key); 447 if(val != null){ 448 try{ 449 val = fac.parse(val).render(ctx); 450 target.put(key, val); 451 }catch(TemplateException e){} 452 } 453 } 454 455 keys = src.keySet().iterator(); 456 while(keys.hasNext()){ 457 String key = (String )keys.next(); 458 String val = (String )src.get(key); 459 if(!target.containsKey(key) && val != null){ 460 target.put(key, val); 461 } 462 } 463 } 464 465 protected void doRenderProperty(PropertyImpl prop, Map values){ 466 if(isInheritsParent() && getParent() != null){ 467 ((NodeImpl)getParent()).doRenderProperty(prop, values); 468 } 469 for(int i = 0; i < prependedLinks.size(); i++){ 470 NodeImpl node = (NodeImpl)prependedLinks.get(i); 471 node.doRenderProperty(prop, values); 472 } 473 474 TemplateFactory fac = new TemplateFactory(); 475 fac.setThrowExcOnMissingVar(false); 476 Map vars = new CompositeHashMap().addChild(values); 477 vars.putAll(getValueMap()); 478 TemplateContextIF ctx = new MapContext(vars, NULL_CONTEXT, false); 479 try{ 480 prop._value = fac.parse(prop._value).render(ctx); 481 }catch(TemplateException e){} 482 483 for(int i = 0; i < appendedLinks.size(); i++){ 484 NodeImpl node = (NodeImpl)appendedLinks.get(i); 485 node.doRenderProperty(prop, values); 486 } 487 } 488 489 protected void doGetPropertyKeys(List fill){ 490 if(isInheritsParent() && getParent() != null){ 491 ((NodeImpl)getParent()).doGetPropertyKeys(fill); 492 } 493 for(int i = 0; i < prependedLinks.size(); i++){ 494 NodeImpl node = (NodeImpl)prependedLinks.get(i); 495 node.doGetPropertyKeys(fill); 496 } 497 for(int i = 0; i < appendedLinks.size(); i++){ 498 NodeImpl node = (NodeImpl)appendedLinks.get(i); 499 node.doGetPropertyKeys(fill); 500 } 501 Iterator keys = getValueMap().keySet().iterator(); 502 while(keys.hasNext()){ 503 String key = (String )keys.next(); 504 fill.add(key); 505 } 506 } 507 508 protected void doGetPath(List tokens){ 509 if(getParent() != null){ 510 ((NodeImpl)getParent()).doGetPath(tokens); 511 } 512 String name = getName(); 513 if(name == null || name.equals(ROOT_NAME)){ 514 return; 515 } 516 tokens.add(getName()); 517 } 518 519 protected void doCalculateChecksum(Checksum chk){ 520 chk.calc(getVersion()); 521 if(isInheritsParent() && getParent() != null){ 522 ((NodeImpl)getParent()).doCalculateChecksum(chk); 523 } 524 for(int i = 0; i < prependedLinks.size(); i++){ 525 NodeImpl node = (NodeImpl)prependedLinks.get(i); 526 node.doCalculateChecksum(chk); 527 } 528 for(int i = 0; i < appendedLinks.size(); i++){ 529 NodeImpl node = (NodeImpl)appendedLinks.get(i); 530 node.doCalculateChecksum(chk); 531 } 532 for(int i = 0; i < includes.size(); i++){ 533 NodeImpl node = (NodeImpl)includes.get(i); 534 node.doCalculateChecksum(chk); 535 } 536 } 537 538 539 protected Property doGetLinkedProperty(List links, String key){ 540 Property prop = null; 541 for(int i = 0; i < links.size(); i++){ 542 Node link = (Node)links.get(i); 543 prop = link.getProperty(key); 544 if(!prop.isNull()){ 545 break; 546 } 547 } 548 return prop; 549 } 550 551 private static final class Checksum{ 552 private long result; 553 554 Checksum(){ 555 } 556 557 long result(){ 558 return result; 559 } 560 561 void calc(long version){ 562 result = result ^ version; 563 } 564 } 565 566 protected Collection doGetNodes(Query query){ 567 Map crit = query.getCriteria(); 568 List result = new LinkedList (); 569 Iterator children = getChildren().iterator(); 570 while(children.hasNext()){ 571 Node child = (Node)children.next(); 572 boolean matches = true; 573 Iterator propNames = crit.keySet().iterator(); 574 while(propNames.hasNext()){ 575 String name = (String )propNames.next(); 576 String val = (String )crit.get(name); 577 Property prop = child.getProperty(name); 578 if(prop.isNull()){ 579 matches = false; 580 break; 581 } 582 else if(prop.getValue().equals(val)){ 583 continue; 584 } 585 else{ 586 matches = false; 587 break; 588 } 589 } 590 if(matches){ 591 result.add(child); 592 } 593 } 594 return result; 595 } 596 597 public static final class NullContext implements TemplateContextIF, Serializable { 598 599 static final long serialVersionUID = 1L; 600 601 public Object getValue(String key) { 602 return new StringBuffer ().append("${") 603 .append(key).append("}").toString(); 604 } 605 606 public void put(String arg0, Object arg1) { 607 } 608 } 609 610 } 611 | Popular Tags |