1 10 package org.mmbase.module.corebuilders; 11 12 import java.io.*; 13 import java.util.*; 14 15 import org.xml.sax.InputSource ; 16 17 import org.mmbase.storage.search.implementation.*; 18 import org.mmbase.storage.search.*; 19 import org.mmbase.module.core.*; 20 import org.mmbase.util.*; 21 import org.mmbase.util.logging.*; 22 import org.mmbase.util.xml.BuilderReader; 23 24 37 public class TypeDef extends MMObjectBuilder { 38 39 43 public static final String PROPERTY_DEPLOY_DIR = "deploy-dir"; 44 45 private static final Logger log = Logging.getLoggerInstance(TypeDef.class); 47 String defaultDeploy = null; 49 50 54 private Map numberToNameCache = null; 56 60 private Map nameToNumberCache = null; 62 65 private Vector typedefsLoaded = new Vector(); 67 71 public boolean init() { 72 broadCastChanges = false; 73 boolean result = super.init(); 74 if (defaultDeploy == null) { 75 String builderDeployDir = getInitParameter(PROPERTY_DEPLOY_DIR); 77 if (builderDeployDir == null) { 78 builderDeployDir = "applications"; 79 } 80 defaultDeploy = builderDeployDir; 81 if (!defaultDeploy.endsWith("/") && !defaultDeploy.endsWith("\\")) { 82 defaultDeploy+="/"; 83 } 84 log.service("Using '" + defaultDeploy + "' as default deploy dir for our builders."); 85 } 86 return result; 87 } 88 89 protected Map getNumberToNameCache() { 90 if (numberToNameCache == null) readCache(); 91 return numberToNameCache; 92 } 93 94 protected Map getNameToNumberCache() { 95 if (nameToNumberCache == null) readCache(); 96 return nameToNumberCache; 97 } 98 99 108 public int insert(String owner, MMObjectNode node) { 109 return insert(owner, node, true); 110 } 111 112 122 public int insert(String owner, MMObjectNode node, boolean loadBuilder) { 123 if (log.isDebugEnabled()) { 124 log.debug("Insert of builder-node with name '" + node.getStringValue("name") + "', loadBuilder = " + loadBuilder); 126 } 127 String path = getBuilderConfiguration(node); 129 java.net.URL url = mmb.getBuilderLoader().getResource(path); 130 try { 131 if (! url.openConnection().getDoInput()) { 132 storeBuilderConfiguration(node); 134 } 135 } catch (Exception e) { 136 throw new RuntimeException (e.getMessage(), e); 137 } 138 int result = getIntValue(node.getStringValue("name")); 141 if (result < 0) { 142 result = super.insert(owner, node); 144 } 145 if (result != -1) { 146 Integer number = new Integer (result); 148 String name = node.getStringValue("name"); 149 getNameToNumberCache().put(name, number); 150 getNumberToNameCache().put(number, name); 151 if (loadBuilder) { 153 loadBuilder(node); 154 } 155 } 156 return result; 157 } 158 159 160 166 167 public boolean commit(MMObjectNode node) { 168 log.service("Commit of builder-node with name '" + node.getStringValue("name") + "' ( #" + node.getNumber() + ")"); 169 try { 170 MMObjectBuilder builder = getBuilder(node); 171 BuilderReader originalBuilderXml = new BuilderReader(mmb.getBuilderLoader().getDocument(getBuilderConfiguration(node)), getMMBase()); 172 String config = node.getStringValue("config"); 173 StringReader stringReader; 174 if (config.indexOf("xmlns=\"http://www.mmbase.org/xmlns/builder\"") > 0) { 175 stringReader = new StringReader("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + config); 176 } else { 177 stringReader = new StringReader("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + 178 "<!DOCTYPE builder PUBLIC \"" + BuilderReader.PUBLIC_ID_BUILDER + 179 "\" \":http://www.mmbase.org/dtd/" + BuilderReader.DTD_BUILDER + "\" >\n" + 180 config); 181 } 182 BuilderReader newBuilderXml = new BuilderReader(new InputSource (stringReader), getMMBase()); 183 if (!originalBuilderXml.equals(newBuilderXml)) { 184 try { 185 builder = unloadBuilder(node); 187 if (! originalBuilderXml.storageEquals(newBuilderXml)) { 190 builder.delete(); 191 } 192 storeBuilderConfiguration(node); 194 } finally { 195 node.storeValue("config", null); 197 loadBuilder(node); 199 } 200 } 201 } catch (Exception ioe) { 202 log.error(ioe.getMessage(), ioe); 203 } 204 return super.commit(node); 205 } 206 207 208 214 public void removeNode(MMObjectNode node) { 215 log.info("Remove of builder-node with name '" + node.getStringValue("name") + "' ( #" + node.getNumber() + ")"); 216 MMObjectBuilder builder = getBuilder(node); 218 testBuilderRemovable(builder, node); 219 builder = unloadBuilder(node); 220 if (builder != null) { 222 builder.delete(); 223 } 224 if (!deleteBuilderConfiguration(node)) { 226 loadBuilder(node); 228 throw new RuntimeException ("Could not delete builder config"); 229 } 230 Integer number = node.getIntegerValue("number"); 231 String name = node.getStringValue("name"); 232 super.removeNode(node); 233 getNameToNumberCache().remove(name); 234 getNumberToNameCache().remove(number); 235 } 236 237 243 private boolean readCache() { 244 log.service("Reading typedef caches"); 246 numberToNameCache = Collections.synchronizedMap(new HashMap()); 247 nameToNumberCache = Collections.synchronizedMap(new HashMap()); 248 NodeSearchQuery query = new NodeSearchQuery(this); 249 try { 250 Iterator typedefs = getNodes(query).iterator(); 251 while (typedefs.hasNext()) { 252 MMObjectNode n = (MMObjectNode) typedefs.next(); 253 Integer number = n.getIntegerValue("number"); 254 String name = n.getStringValue("name"); 255 if (number != null && name != null) { 256 nameToNumberCache.put(name,number); 257 numberToNameCache.put(number,name); 258 } else { 259 log.error("Could not add typedef cache-entry number/name= " + number + "/" + name); 260 } 261 } 262 } catch (SearchQueryException sqe) { 263 log.error(sqe); 265 } 266 return true; 267 } 268 269 275 public int getIntValue(String builderName) { 276 Integer result = (Integer ) getNameToNumberCache().get(builderName); 277 if (result != null) { 278 return result.intValue(); 279 } else { 280 return -1; 281 } 282 } 283 284 289 public String getValue(int type) { 290 String result = (String ) getNumberToNameCache().get(new Integer (type)); 291 if (result == null) { 292 log.warn("Could not find builder name for typedef number " + type); 293 } 294 return result; 295 } 296 297 303 public String getValue(String type) { 304 try { 305 return (String ) getNumberToNameCache().get(new Integer (Integer.parseInt(type))); 306 } catch(Exception e) { 307 return "unknown"; 308 } 309 } 310 311 314 public String getSingularName(String builderName, String language) { 315 if (builderName == null) return "unknown"; 316 MMObjectBuilder bul = mmb.getBuilder(builderName); 317 if (bul!=null) { 318 if (language == null) { 319 return bul.getSingularName(); 320 } else { 321 return bul.getSingularName(language); 322 } 323 } else { 324 return "inactive ("+builderName+")"; 325 } 326 } 327 328 331 public boolean isRelationTable(String name) { 332 return mmb.getRelDef().isRelationTable(name); 333 } 334 335 350 public Object getValue(MMObjectNode node, String field) { 351 if (log.isDebugEnabled()) { 352 log.debug("node:" + node.getNumber() + " field: " + field); 353 } 354 if (field.equals("config")) { 356 Object o = super.getValue(node, field); 358 if (o != null) { 359 return o; 360 } 361 if (log.isDebugEnabled()) { 363 log.debug("retrieving the document for node #" + node.getNumber()); 364 } 365 366 String path = getBuilderConfiguration(node); 368 org.w3c.dom.Document doc; 369 try { 370 doc = mmb.getBuilderLoader().getDocument(path); 371 } catch (Exception e) { 372 log.warn("Error reading builder with name: " + path + " " + e.getMessage()); 373 return null; 374 } 375 if (doc == null) { 376 log.warn("Resource with name: " + path + " didnt exist, getValue will return null for builder config"); 377 return null; 378 } 379 node.setValue(field, doc); 380 return doc; 381 } else if (field.equals("state")) { 382 int val=node.getIntValue("state"); 383 if (val==-1) { 386 node.setValue("state",1); 388 } 389 return ""+val; 390 } else if (field.equals("dutchs(name)")) { 391 return getGUIIndicator("name",node); 394 } 395 return super.getValue(node, field); 396 } 397 398 409 public boolean setValue(MMObjectNode node, String fieldName, Object originalValue) { 410 Object newValue = node.retrieveValue(fieldName); 411 if (fieldName.equals("name")) { 412 if (originalValue != null && ! originalValue.equals("") && !originalValue.equals(newValue)) { 416 node.storeValue(fieldName, originalValue); 418 throw new RuntimeException ("Cannot change a builder's name from '" + originalValue + "' to '" + newValue + "' typedef node " + node.getNumber()); 419 430 } 431 } 432 return true; 433 } 434 435 438 public boolean fieldLocalChanged(String number, String builder, String field, String value) { 439 if (field.equals("state")) { 440 if (value.equals("4")) { 441 log.service("Reload wanted on : " + builder); 443 MMObjectNode node = getNode(number); 445 String objectname = node.getStringValue("name"); 446 reloadBuilder(objectname); 447 if (node != null) { 448 node.setValue("state", 1); 449 } 450 } 451 } 452 return true; 453 } 454 455 462 protected String getBuilderConfiguration(MMObjectNode node) { 463 String path = getBuilderPath(node); 465 if (path == null) { 467 log.error("field 'path' was empty."); 468 return null; 469 } 470 return path + node.getStringValue("name") + ".xml"; 471 } 472 473 474 480 public MMObjectBuilder getBuilder(MMObjectNode node) { 481 String builderName = node.getStringValue("name"); 482 return mmb.getMMObject(builderName); 483 } 484 485 488 public boolean reloadBuilder(String objectname) { 489 log.service("Trying to reload builder : "+objectname); 490 MMObjectBuilder oldbul = mmb.getBuilder(objectname); 492 String classname = oldbul.getClass().getName(); 493 String description = oldbul.getDescription(); 494 495 try { 496 Class newclass = Class.forName("org.mmbase.module.builders." + classname); 497 log.debug("Loaded load class : "+newclass); 498 499 MMObjectBuilder bul = (MMObjectBuilder)newclass.newInstance(); 500 log.debug("Started : "+newclass); 501 502 bul.setMMBase(mmb); 503 bul.setTableName(objectname); 504 bul.setDescription(description); 505 bul.init(); 506 mmb.addBuilder(objectname, bul); 507 } catch (Exception e) { 508 log.error(Logging.stackTrace(e)); 509 return false; 510 } 511 return true; 512 } 513 514 520 public String getGUIIndicator(MMObjectNode node) { 521 return getSingularName(node.getStringValue("name"), null); 522 } 523 524 525 529 protected String getLocaleGUIIndicator(Locale locale, String field, MMObjectNode node) { 530 if (field == null || "".equals(field)) { 531 return getLocaleGUIIndicator(locale, node); 532 } else if ("description".equals(field)) { 533 MMObjectBuilder bul = mmb.getBuilder(node.getStringValue("name")); 534 if (bul != null) { 535 return bul.getDescription(locale.getLanguage()); 536 } 537 } 538 return null; 539 } 540 541 protected String getLocaleGUIIndicator(Locale locale, MMObjectNode node) { 542 String rtn = getSingularName(node.getStringValue("name"), locale.getLanguage()); 543 if (rtn == null) return node.getStringValue("name"); 544 return rtn; 545 } 546 547 550 public void loadTypeDef(String name) { 551 if(!typedefsLoaded.contains(name)) { 552 typedefsLoaded.add(name); 553 } else { 554 if (log.isDebugEnabled()) log.debug("Builder "+name+" is already loaded!"); 555 } 556 } 557 558 561 public void unloadTypeDef(String name) { 562 if(typedefsLoaded.contains(name)) { 563 typedefsLoaded.remove(name); 564 } else { 565 log.debug("Builder "+name+" is not loaded!"); 566 } 567 } 568 569 572 public Vector getList(PageInfo sp,StringTagger tagger, StringTokenizer tok) { 573 if (tok.hasMoreTokens()) { 574 String cmd=tok.nextToken(); 575 if (cmd.equals("builders")) { 576 return typedefsLoaded; 577 } 578 } 579 return null; 580 } 581 582 protected Object executeFunction(MMObjectNode node, String function, List args) { 583 log.debug("executefunction of typedef"); 584 if (function.equals("info")) { 585 List empty = new ArrayList(); 586 java.util.Map info = (java.util.Map ) super.executeFunction(node, function, empty); 587 info.put("gui", info.get("info") + " (localized)"); 588 if (args == null || args.size() == 0) { 589 return info; 590 } else { 591 return info.get(args.get(0)); 592 } 593 } else if (function.equals("gui")) { 594 log.debug("GUI of servlet builder with " + args); 595 if (args == null || args.size() ==0) { 596 return getGUIIndicator(node); 597 } else { 598 String rtn; 599 if (args.size() <= 1) { 600 rtn = getGUIIndicator((String ) args.get(0), node); 601 } else { 602 String language = (String ) args.get(1); 603 if (language == null) language = mmb.getLanguage(); 604 Locale locale = new Locale(language, ""); 605 rtn = getLocaleGUIIndicator(locale, (String ) args.get(0), node); 606 } 607 if (rtn == null) return super.executeFunction(node, function, args); 608 return rtn; 609 } 610 } else if (function.equals("defaultsearchage")) { 611 return new Integer (getBuilder(node).getSearchAge()); 612 } else { 613 return super.executeFunction(node, function, args); 614 } 615 } 616 617 private void testBuilderRemovable(MMObjectBuilder builder, MMObjectNode typeDefNode) { 618 if (builder != null && builder.size() > 0) { 619 throw new RuntimeException ("Cannot delete this builder, it still contains nodes"); 620 } else if (builder == null) { 621 MMObjectBuilder rootBuilder = mmb.getRootBuilder(); 623 NodeSearchQuery q = new NodeSearchQuery(rootBuilder); 624 Integer value = new Integer (typeDefNode.getNumber()); 625 Constraint constraint = new BasicFieldValueConstraint(q.getField(rootBuilder.getField("otype")), value); 626 q.setConstraint(constraint); 627 try { 628 if (rootBuilder.count(q) > 0) { 629 throw new RuntimeException ("Cannot delete this (inactive) builder, it still contains nodes"); 630 } 631 } catch (SearchQueryException sqe) { 632 log.error(sqe); 634 } 635 } 636 637 { 639 if (builder instanceof InsRel) { 640 MMObjectNode reldef = mmb.getRelDef().getDefaultForBuilder((InsRel)builder); 641 if (reldef != null) { 642 throw new RuntimeException ("Cannot delete this builder, it is referenced in reldef #" + reldef.getNumber()); 643 } 644 } 645 try { 646 MMObjectBuilder typeRel = mmb.getTypeRel(); 647 NodeSearchQuery q = new NodeSearchQuery(typeRel); 648 Integer value = new Integer (typeDefNode.getNumber()); 649 BasicCompositeConstraint constraint = new BasicCompositeConstraint(CompositeConstraint.LOGICAL_OR); 650 Constraint constraint1 = new BasicFieldValueConstraint(q.getField(typeRel.getField("snumber")), value); 651 Constraint constraint2 = new BasicFieldValueConstraint(q.getField(typeRel.getField("dnumber")), value); 652 constraint.addChild(constraint1); 653 constraint.addChild(constraint2); 654 q.setConstraint(constraint); 655 List typerels = typeRel.getNodes(q); 656 if (typerels.size() > 0) { 657 throw new RuntimeException ("Cannot delete this builder, it is referenced by typerels: " + typerels); 658 } 659 } catch (SearchQueryException sqe) { 660 log.error(sqe); 662 } 663 } 664 } 665 666 672 protected String getBuilderPath(MMObjectNode node) { 673 if (log.isDebugEnabled()) { 674 log.debug("retrieving the path for node #" + node.getNumber()); 675 } 676 if (node == null) { 678 log.error("node was null"); 679 return null; 680 } 681 if (node.getStringValue("name") == null) { 682 log.error("field 'name' was null"); 683 return null; 684 } 685 if (node.getStringValue("name").trim().length() == 0) { 686 log.error("field 'name' was empty."); 687 return null; 688 } 689 690 String pathInBuilderDir = mmb.getBuilderPath(node.getStringValue("name"), ""); 691 if (pathInBuilderDir != null) { 692 String file = pathInBuilderDir; 694 if (log.isDebugEnabled()) { 695 log.debug("builder file:" + file); 696 } 697 return file; 698 } 699 if (defaultDeploy != null) { 701 String file = defaultDeploy; 702 if (log.isDebugEnabled()) { 703 log.debug("builder file:" + file); 704 } 705 return file; 706 } 707 return null; 708 } 709 710 712 protected MMObjectBuilder loadBuilder(MMObjectNode node) { 713 if (log.isDebugEnabled()) { 714 log.debug("Load builder '" + node.getStringValue("name") + "' ( #" + node.getNumber() + ")"); 715 } 716 String path = getBuilderPath(node); 717 log.info("Loading builder from " + path); 718 MMObjectBuilder builder = mmb.loadBuilderFromXML(node.getStringValue("name"), path); 719 if (builder == null) { 720 log.info("could not load builder from xml, is in inactive?(name: '" + node.getStringValue("name") + "' path: '" + path + "')"); 722 return null; 723 } 724 mmb.initBuilder(builder); 725 return builder; 726 } 727 728 730 protected void storeBuilderConfiguration(MMObjectNode node) throws java.io.IOException { 731 if (log.isDebugEnabled()) { 732 log.debug("Store builder '" + node.getStringValue("name") + "' ( #" + node.getNumber() + ")"); 733 } 734 735 org.w3c.dom.Document doc = node.getXMLValue("config"); 736 if (doc == null) { 737 log.error("Field config was null! Could not save the file for " + node.getStringValue("name") + Logging.stackTrace(new Throwable ())); 738 return; 739 } 740 String path = getBuilderConfiguration(node); 741 log.info("Store builder '" + node.getStringValue("name") + "' ( #" + node.getNumber() + ") to " + path); 742 mmb.getBuilderLoader().storeDocument(path, doc); 743 744 } 745 746 748 protected MMObjectBuilder unloadBuilder(MMObjectNode node) { 749 if (log.isDebugEnabled()) { 750 log.debug("Unload builder '" + node.getStringValue("name") + "' ( #" + node.getNumber() + ")"); 751 } 752 MMObjectBuilder builder = getBuilder(node); 754 if (builder != null) { 755 mmb.unloadBuilder(builder); 756 } 757 return builder; 758 } 759 760 762 protected boolean deleteBuilderConfiguration(MMObjectNode node) { 763 if (log.isDebugEnabled()) { 764 log.debug("Delete file of builder '" + node.getStringValue("name") + "' ( #" + node.getNumber() + ")"); 765 } 766 File file = new File(getBuilderConfiguration(node)); 767 if (file.exists()) { 768 if (!file.canWrite()) { 769 log.error("file: " + file + " had no write rights for me."); 770 return false; 771 } 772 file.delete(); 774 if (log.isDebugEnabled()) { 775 log.debug("file: " + file + " has been deleted"); 776 } 777 } 778 return true; 779 } 780 } 781 | Popular Tags |