001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2007-2010 Sun Microsystems, Inc. 015 * Portions Copyright 2011-2015 ForgeRock AS. 016 */ 017package org.opends.server.admin.doc; 018 019import java.io.File; 020import java.io.PrintWriter; 021import java.util.Collection; 022import java.util.Date; 023import java.util.Iterator; 024import java.util.Properties; 025import java.util.TreeMap; 026import java.util.TreeSet; 027import org.forgerock.i18n.LocalizableMessage; 028import org.opends.server.admin.ACIPropertyDefinition; 029import org.opends.server.admin.AbsoluteInheritedDefaultBehaviorProvider; 030import org.opends.server.admin.AbstractManagedObjectDefinition; 031import org.opends.server.admin.AdministratorAction.Type; 032import org.opends.server.admin.RelationDefinition; 033import org.opends.server.admin.std.meta.RootCfgDefn; 034import org.opends.server.admin.*; 035import org.opends.server.types.InitializationException; 036import org.opends.server.util.EmbeddedUtils; 037import org.opends.server.util.DynamicConstants; 038 039/** 040 * This class allow Configuration Guide documentation generation (html format). 041 * It is based on the Admin Framework Introspection API 042 * 043 */ 044public class ConfigGuideGeneration { 045 046 // Note : still to be done : 047 // I18n support. Today all the strings are hardcoded in this file 048 049 private static final String ACI_SYNTAX_REL_URL = 050 "/doc/admin-guide/#about-acis"; 051 private static final String DURATION_SYNTAX_REL_URL = 052 "duration-syntax.html"; 053 private final String CSS_FILE = "opendj-config.css"; 054 055 private final String MAIN_FILE = "index.html"; 056 private final String INHERITANCE_TREE_FILE = 057 "ManagedObjectInheritanceTree.html"; 058 private final String RELATION_TREE_FILE = "ManagedObjectRelationTree.html"; 059 private final String MO_LIST_FILE = "ManagedObjectList.html"; 060 private final String PROPERTIES_INDEX_FILE = "PropertiesIndex.html"; 061 private final String WELCOME_FILE = "welcome.html"; 062 private final String MAINTOP_FILE = "maintop.html"; 063 private final String INDEX_FILE = "index.html"; 064 private final String FAVICON = "http://forgerock.org/favicon.ico"; 065 066 private static final String CONFIG_GUIDE_DIR = "opendj_config_guide"; 067 private final String MAIN_FRAME = "mainFrame"; 068 069 /** 070 * Entry point for documentation generation. 071 * 072 * Properties: 073 * GenerationDir - The directory where the doc is generated 074 * (default is /var/tmp/[CONFIG_GUIDE_DIR>]) 075 * LdapMapping - Presence means that the LDAP mapping section is to be 076 * generated (default is no) 077 * OpenDJWiki - The URL of the OpenDJ Wiki 078 * (default is 079 * "http://wikis.forgerock.org/confluence/display/OPENDJ") 080 * OpenDJHome - The URL of the OpenDJ project Home page 081 * (default is "http://opendj.forgerock.org") 082 * 083 * @param args none. 084 */ 085 public static void main(String[] args) { 086 Properties properties = System.getProperties(); 087 generationDir = properties.getProperty("GenerationDir"); 088 if (generationDir == null) { 089 // Default dir is prefixed by the system-dependent default temporary dir 090 generationDir = System.getProperty("java.io.tmpdir") + File.separator + 091 CONFIG_GUIDE_DIR; 092 } 093 // Create new dir if necessary 094 try { 095 new File(generationDir).mkdir(); 096 } catch (Exception e) { 097 e.printStackTrace(); 098 System.exit(1); 099 } 100 System.out.println("Generation directory is : " + generationDir); 101 102 if (properties.getProperty("LdapMapping") != null) { 103 ldapMapping = true; 104 } 105 106 OpenDJWiki = properties.getProperty("OpenDJWiki"); 107 if (OpenDJWiki == null) { 108 // Default is current wiki 109 OpenDJWiki = "http://wikis.forgerock.org/confluence/display/OPENDJ"; 110 } 111 112 OpenDJHome = properties.getProperty("OpenDJHome"); 113 if (OpenDJHome == null) { 114 // Default is current OpenDJ project home 115 OpenDJHome = "http://opendj.forgerock.org"; 116 } 117 118 aciSyntaxPage = OpenDJHome + ACI_SYNTAX_REL_URL; 119 durationSyntaxPage = DURATION_SYNTAX_REL_URL; 120 121 ConfigGuideGeneration myGen = new ConfigGuideGeneration(); 122 myGen.generate(); 123 } 124 125 private void generate() { 126 init(); 127 128 // Generate the relation tree of all the managed objects 129 genManagedObjectRelationTree(catTopRelList); 130 131 // Generate the inheritance tree of all the managed objects 132 genManagedObjectInheritanceTree(catTopMoList); 133 134 // Generate all the managed objects and their children 135 genAllManagedObject(topMoList); 136 137 // Generate a list of managed objects 138 genManagedObjectList(moList); 139 140 // Generate an index of properties 141 genPropertiesIndex(); 142 143 // Generate the Index page 144 genIndexPage(); 145 146 // Generate the Main Top page 147 genMainTopPage(); 148 149 // Generate the Welcome page 150 genWelcomePage(); 151 } 152 153 private void init() { 154 155 // Build a list of top relations 156 RootCfgDefn rootCfg = RootCfgDefn.getInstance(); 157 for (RelationDefinition rel : rootCfg.getAllRelationDefinitions()) { 158 topRelList.put(rel.getChildDefinition().getName(), rel); 159 } 160 161 // Enable the client-side class loader to explicitly load classes 162 // which are not directly reachable from the root configuration 163 EmbeddedUtils.initializeForClientUse(); 164 // Bootstrap definition classes. 165 try { 166 ClassLoaderProvider.getInstance().enable(); 167 } catch (InitializationException e) { 168 System.err.println("ERROR : Cannot enable the client-side class loader."); 169 e.printStackTrace(); 170 System.exit(1); 171 } 172 // Switch off class name validation in client. 173 ClassPropertyDefinition.setAllowClassValidation(false); 174 // Switch off attribute type name validation in client. 175 AttributeTypePropertyDefinition.setCheckSchema(false); 176 177 // Build a sorted list of top managed objects 178 TopCfgDefn topCfg = TopCfgDefn.getInstance(); 179 Collection<AbstractManagedObjectDefinition<?, ?>> topObjects = 180 topCfg.getChildren(); 181 for (AbstractManagedObjectDefinition topObject : topObjects) { 182 if (topObject.getName().equals("")) { 183 // root 184 continue; 185 } 186 if (topObject.hasOption(ManagedObjectOption.HIDDEN)) 187 { 188 continue; 189 } 190 topMoList.put(topObject.getName(), topObject); 191 } 192 193 194 // Build a list of top relations by category (core, database, ...) 195 for (RelationDefinition rel : topRelList.values()) { 196 AbstractManagedObjectDefinition<?, ?> mo = rel.getChildDefinition(); 197 Collection<Tag> tags = mo.getAllTags(); 198 for (Tag tag : tags) { 199 TreeMap<String, RelationDefinition> catMap = 200 catTopRelList.get(tag.getName()); 201 if (catMap == null) { 202 catMap = new TreeMap<>(); 203 catTopRelList.put(tag.getName(), catMap); 204 } 205 catMap.put(mo.getName(), rel); 206 } 207 } 208 209 // Build a list of top managed objects by category (core, database, ...) 210 for (AbstractManagedObjectDefinition<?, ?> topObject : topMoList.values()) { 211 Collection<Tag> tags = topObject.getAllTags(); 212 for (Tag tag : tags) { 213 TreeMap<String, AbstractManagedObjectDefinition> catMap = 214 catTopMoList.get(tag.getName()); 215 if (catMap == null) { 216 catMap = new TreeMap<>(); 217 catTopMoList.put(tag.getName(), catMap); 218 } 219 catMap.put(topObject.getName(), topObject); 220 } 221 } 222 223 } 224 225 /** 226 * Generate the inheritance tree of all the managed objects. 227 */ 228 @SuppressWarnings("unchecked") 229 private void genManagedObjectInheritanceTree( 230 TreeMap<String, TreeMap<String, AbstractManagedObjectDefinition>> list) { 231 232 htmlHeader(DynamicConstants.PRODUCT_NAME + " " + 233 "Configuration Reference - Inheritance View"); 234 tabMenu(INHERITANCE_TREE_FILE); 235 viewHelp("This view represents the inheritance relationships between " + 236 "configuration components."); 237 jumpSection(); 238 239 for (String catName : list.keySet()) { 240 heading3(getFriendlyName(catName)); 241 // Get the list of the category 242 TreeMap<String, AbstractManagedObjectDefinition> catList = list.get(catName); 243 for (AbstractManagedObjectDefinition mo : catList.values()) { 244 RelationDefinition relDefn = relList.get(mo.getName()); 245 if (relDefn != null && relDefn.hasOption(RelationOption.HIDDEN)) { 246 continue; 247 } 248 paragraph( 249 getLink(mo.getUserFriendlyName().toString(), 250 mo.getName() + ".html", MAIN_FRAME)); 251 if (mo.hasChildren()) { 252 genMoInheritanceTree(makeMOTreeMap(mo.getChildren())); 253 } 254 } 255 } 256 257 htmlFooter(); 258 generateFile(INHERITANCE_TREE_FILE); 259 } 260 261 @SuppressWarnings("unchecked") 262 private void genMoInheritanceTree( 263 TreeMap<String, AbstractManagedObjectDefinition> catList) { 264 265 beginList(); 266 for (AbstractManagedObjectDefinition mo : catList.values()) { 267 link(mo.getUserFriendlyName().toString(), mo.getName() + ".html", 268 MAIN_FRAME); 269 if (mo.hasChildren()) { 270 genMoInheritanceTree(makeMOTreeMap(mo.getChildren())); 271 } 272 } 273 endList(); 274 } 275 276 private void jumpSection() { 277 htmlBuff.append("<p class=\"category-index\"><strong>Jump To:</strong><br>\n"); 278 279 String[] catNames = catTopMoList.keySet().toArray(new String[0]); 280 for (int ii=0; ii < catNames.length; ii++) { 281 if (ii != 0) { 282 htmlBuff.append(", "); 283 } 284 String catFriendlyName = getFriendlyName(catNames[ii]); 285 htmlBuff.append(getLink(catFriendlyName, "#" + catFriendlyName)); 286 } 287 htmlBuff.append("</p>\n"); 288 } 289 290 291 /** 292 * Generate the relation tree of all the managed objects. 293 */ 294 private void genManagedObjectRelationTree( 295 TreeMap <String, TreeMap<String, RelationDefinition>> list) { 296 297 htmlHeader(DynamicConstants.PRODUCT_NAME + 298 " Configuration Reference - Structure View"); 299 tabMenu(RELATION_TREE_FILE); 300 viewHelp("This view represents the structural relationships between " + 301 "components and indicates how certain components can exist only within " + 302 "container components."); 303 jumpSection(); 304 305 for (String catName : list.keySet()) { 306 heading3(getFriendlyName(catName)); 307 // Get the list of the category 308 TreeMap<String, RelationDefinition> catList = list.get(catName); 309 genMORelationTree(catList); 310 } 311 312 htmlFooter(); 313 generateFile(RELATION_TREE_FILE); 314 } 315 316 317 @SuppressWarnings("unchecked") 318 private void genMORelationTree(TreeMap<String, RelationDefinition> list) { 319 for (RelationDefinition rel : list.values()) { 320 AbstractManagedObjectDefinition childMo = rel.getChildDefinition(); 321 AbstractManagedObjectDefinition parentMo = rel.getParentDefinition(); 322 // Does not generate several entry for the same relation 323 if (relList.put(childMo.getName(), rel) != null) { 324 continue; 325 } 326 if (rel.hasOption(RelationOption.HIDDEN)) { 327 continue; 328 } 329 String linkStr = getLink(childMo.getUserFriendlyName().toString(), 330 childMo.getName() + ".html", MAIN_FRAME); 331 String fromStr = ""; 332 if (!parentMo.getName().equals("")) { 333 fromStr = " (from " + 334 getLink(parentMo.getUserFriendlyName().toString(), 335 parentMo.getName() + ".html", MAIN_FRAME) + ")"; 336 } 337 if (!inList) { 338 paragraph(linkStr + fromStr); 339 } else { 340 bullet(linkStr + fromStr); 341 } 342 genMORelationSubTree(makeRelTreeMap(childMo.getAllRelationDefinitions())); 343 if (childMo.hasChildren()) { 344 for (Iterator<AbstractManagedObjectDefinition> it = 345 childMo.getChildren().iterator(); it.hasNext();) { 346 347 AbstractManagedObjectDefinition mo = it.next(); 348 if (mo.hasOption(ManagedObjectOption.HIDDEN)) 349 { 350 continue; 351 } 352 genMORelationSubTree(makeRelTreeMap(mo.getAllRelationDefinitions())); 353 } 354 } 355 } 356 } 357 358 359 private void genMORelationSubTree(TreeMap<String, RelationDefinition> list) { 360 if (!list.values().isEmpty()) { 361 beginList(); 362 genMORelationTree(list); 363 endList(); 364 } 365 } 366 367 368 /** 369 * Generate all the managed objects HTML pages. 370 */ 371 @SuppressWarnings("unchecked") 372 private void genAllManagedObject( 373 TreeMap<String, AbstractManagedObjectDefinition> list) { 374 375 for (AbstractManagedObjectDefinition mo : list.values()) { 376 RelationDefinition relDefn = relList.get(mo.getName()); 377 if (relDefn != null && relDefn.hasOption(RelationOption.HIDDEN)) { 378 continue; 379 } 380 moList.put(mo.getName(), mo); 381 genManagedObject(mo); 382 if (mo.hasChildren()) { 383 genAllManagedObject(makeMOTreeMap(mo.getChildren())); 384 } 385 } 386 } 387 388 private void genManagedObject(AbstractManagedObjectDefinition mo) { 389 //------------------------------------------------------------------------ 390 // Header 391 //------------------------------------------------------------------------ 392 393 homeLink(); 394 String title = mo.getUserFriendlyName().toString(); 395 htmlHeader(DynamicConstants.PRODUCT_NAME + " - " + title); 396 397 // title 398 heading2(title); 399 400 // Abstract notice 401 if (mo.hasChildren()) { 402 paragraph( 403 "Note: this is an abstract component, that cannot be instantiated.", 404 TextStyle.ITALIC); 405 } 406 407 // description 408 paragraph(mo.getSynopsis()); 409 paragraph(mo.getDescription()); 410 411 // sub-components 412 if (mo.hasChildren()) { 413 heading3("Direct Subcomponents"); 414 paragraph("The following " + mo.getUserFriendlyPluralName() + 415 " are available in the server :"); 416 beginList(); 417 @SuppressWarnings("unchecked") 418 TreeMap<String, AbstractManagedObjectDefinition> children = 419 makeMOTreeMap(mo.getChildren()); 420 for ( AbstractManagedObjectDefinition child : children.values()) { 421 link(child.getUserFriendlyName().toString(), child.getName() + ".html"); 422 } 423 endList(); 424 425 paragraph("These " + mo.getUserFriendlyPluralName() + 426 " inherit from the properties described below."); 427 } 428 429 // Parent 430 if (!mo.getParent().isTop()) { 431 heading3("Parent Component"); 432 paragraph("The " + mo.getUserFriendlyName() + 433 " component inherits from the " + 434 getLink(mo.getParent().getUserFriendlyName().toString(), 435 mo.getParent().getName() + ".html")); 436 } 437 438 // Relations 439 generateRelationsSection(mo); 440 441 // Page links in case of LDAP mapping 442 if (ldapMapping) { 443 newline(); 444 horizontalLine(); 445 newline(); 446 paragraph("This page describes the " + mo.getUserFriendlyName() + ":"); 447 beginList(); 448 link("Properties", "#Properties"); 449 link("LDAP Mapping", "#LDAP Mapping"); 450 endList(); 451 newline(); 452 } 453 454 455 //------------------------------------------------------------------------ 456 // Properties 457 //------------------------------------------------------------------------ 458 459 heading3("Properties"); 460 461 paragraph("A description of each property follows."); 462 newline(); 463 464 TreeMap<String, PropertyDefinition> basicProps = new TreeMap<>(); 465 TreeMap<String, PropertyDefinition> advancedProps = new TreeMap<>(); 466 // Properties actually defined in this managed object 467 @SuppressWarnings("unchecked") 468 Collection<PropertyDefinition> props = mo.getAllPropertyDefinitions(); 469 for ( PropertyDefinition prop : props) { 470 if (prop.hasOption(PropertyOption.ADVANCED)) { 471 advancedProps.put(prop.getName(), prop); 472 } else { 473 basicProps.put(prop.getName(), prop); 474 } 475 } 476 477 propertiesLinkTable(basicProps, advancedProps); 478 479 // basic properties 480 if (!basicProps.isEmpty()) { 481 heading4("Basic Properties"); 482 for ( PropertyDefinition prop : basicProps.values()) { 483 generateProperty(mo, prop); 484 newline(); 485 } 486 newline(); 487 } 488 489 // advanced properties 490 if (!advancedProps.isEmpty()) { 491 heading4("Advanced Properties"); 492 for ( PropertyDefinition prop : advancedProps.values()) { 493 generateProperty(mo, prop); 494 newline(); 495 } 496 newline(); 497 } 498 499 if (ldapMapping) { 500 genLdapMapping(mo); 501 } 502 503 htmlFooter(); 504 505 generateFile(mo.getName() + ".html"); 506 } 507 508 509 private TreeMap<String, PropertyDefinition> 510 getPropertyList(AbstractManagedObjectDefinition mo) { 511 512 @SuppressWarnings("unchecked") 513 Collection<PropertyDefinition> props = mo.getAllPropertyDefinitions(); 514 return makePropTreeMap(props); 515 } 516 517 private void homeLink() { 518 htmlBuff.append("<div style=\"font-size:11px;margin-top:-10px;") 519 .append("margin-bottom:-10px; text-align:right\"><a href=\"") 520 .append(MAIN_FILE) 521 .append("\" target=\"_top\">Configuration Reference Home</a></div>"); 522 } 523 524 525 private void generateRelationsSection(AbstractManagedObjectDefinition mo) { 526 // Composition relations 527 @SuppressWarnings("unchecked") 528 Collection<RelationDefinition> compRels = mo.getRelationDefinitions(); 529 @SuppressWarnings("unchecked") 530 Collection<RelationDefinition> reverseCompRels = 531 mo.getReverseRelationDefinitions(); 532 // Aggregation properties 533 @SuppressWarnings("unchecked") 534 Collection<AggregationPropertyDefinition> aggregProps = 535 mo.getAggregationPropertyDefinitions(); 536 @SuppressWarnings("unchecked") 537 Collection<AggregationPropertyDefinition> reverseAggregProps = 538 mo.getReverseAggregationPropertyDefinitions(); 539 540 541 // Check if something to print in composition relations 542 // (even if the list not empty, it may contain only hidden relations) 543 boolean isCompRelsEmpty = true; 544 if (!compRels.isEmpty()) { 545 for (RelationDefinition rel : compRels) { 546 if (rel.hasOption(RelationOption.HIDDEN)) { 547 continue; 548 } 549 isCompRelsEmpty = false; 550 } 551 } 552 boolean isReverseCompRelsEmpty = true; 553 if (!reverseCompRels.isEmpty()) { 554 for (RelationDefinition rel : reverseCompRels) { 555 if (rel.hasOption(RelationOption.HIDDEN)) { 556 continue; 557 } 558 // check if it is not root 559 if (rel.getParentDefinition().getName().equals("")) { 560 continue; 561 } 562 isReverseCompRelsEmpty = false; 563 } 564 } 565 566 // Check if something to print in reverse aggregation relations 567 // (even if the list not empty, it may contain only relations from 568 // hidden component) 569 boolean isReverseAggregPropsEmpty = true; 570 if (!reverseAggregProps.isEmpty()) { 571 for (AggregationPropertyDefinition agg : reverseAggregProps) { 572 AbstractManagedObjectDefinition fromMo = 573 agg.getManagedObjectDefinition(); 574 @SuppressWarnings("unchecked") 575 Collection<RelationDefinition> rels = 576 fromMo.getAllReverseRelationDefinitions(); 577 for (RelationDefinition rel : rels) { 578 if (rel.hasOption(RelationOption.HIDDEN)) { 579 continue; 580 } 581 isReverseAggregPropsEmpty = false; 582 } 583 } 584 } 585 586 587 // 588 // Relations FROM this component 589 // 590 591 if (!isCompRelsEmpty || !aggregProps.isEmpty()) { 592 heading3("Relations From this Component"); 593 } 594 595 if (!isCompRelsEmpty) { 596 paragraph( 597 "The following components have a direct COMPOSITION relation FROM " + 598 mo.getUserFriendlyPluralName() + " :"); 599 for ( RelationDefinition rel : compRels) { 600 if (rel.hasOption(RelationOption.HIDDEN)) { 601 continue; 602 } 603 beginList(); 604 AbstractManagedObjectDefinition childRel = rel.getChildDefinition(); 605 link(childRel.getUserFriendlyName().toString(), childRel.getName() + 606 ".html"); 607 endList(); 608 } 609 } 610 if (!aggregProps.isEmpty()) { 611 paragraph( 612 "The following components have a direct AGGREGATION relation FROM " + 613 mo.getUserFriendlyPluralName() + " :"); 614 TreeMap<String, AbstractManagedObjectDefinition> componentList = new TreeMap<>(); 615 for ( AggregationPropertyDefinition agg : aggregProps) { 616 RelationDefinition rel = agg.getRelationDefinition(); 617 AbstractManagedObjectDefinition childRel = rel.getChildDefinition(); 618 componentList.put(childRel.getName(), childRel); 619 } 620 for (AbstractManagedObjectDefinition component : componentList.values()) { 621 beginList(); 622 link(component.getUserFriendlyName().toString(), component.getName() + ".html"); 623 endList(); 624 } 625 } 626 627 628 // 629 // Relations TO this component 630 // 631 632 if (!isReverseCompRelsEmpty || !isReverseAggregPropsEmpty) { 633 heading3("Relations To this Component"); 634 } 635 636 if (!mo.getReverseRelationDefinitions().isEmpty() 637 && !isReverseCompRelsEmpty) 638 { 639 paragraph( 640 "The following components have a direct COMPOSITION relation TO " + 641 mo.getUserFriendlyPluralName() + " :"); 642 for ( RelationDefinition rel : reverseCompRels) { 643 beginList(); 644 AbstractManagedObjectDefinition childRel = rel.getParentDefinition(); 645 link(childRel.getUserFriendlyName().toString(), childRel.getName() + ".html"); 646 endList(); 647 } 648 } 649 if (!isReverseAggregPropsEmpty) { 650 paragraph( 651 "The following components have a direct AGGREGATION relation TO " + 652 mo.getUserFriendlyPluralName() + " :"); 653 TreeMap<String, AbstractManagedObjectDefinition> componentList = new TreeMap<>(); 654 for ( AggregationPropertyDefinition agg : reverseAggregProps) { 655 AbstractManagedObjectDefinition fromMo = 656 agg.getManagedObjectDefinition(); 657 componentList.put(fromMo.getName(), fromMo); 658 } 659 for (AbstractManagedObjectDefinition component : componentList.values()) { 660 beginList(); 661 link(component.getUserFriendlyName().toString(), component.getName() + 662 ".html"); 663 endList(); 664 665 } 666 } 667 668 } 669 670 private void generateProperty( 671 AbstractManagedObjectDefinition mo, PropertyDefinition prop) { 672 673 // Property name 674 paragraph(getAnchor(prop.getName()) + prop.getName(), TextStyle.STANDARD, 675 "propertyname"); 676 677 // Property table 678 startTable(); 679 tableRow("Description", 680 ((prop.getSynopsis() != null) ? prop.getSynopsis()+ " " : "") + 681 ((prop.getDescription() != null) ? 682 prop.getDescription().toString() : "")); 683 684 // Default value 685 String defValueStr = getDefaultBehaviorString(prop); 686 tableRow("Default Value", defValueStr); 687 688 tableRow("Allowed Values", getSyntaxStr(prop)); 689 690 tableRow("Multi-valued", 691 prop.hasOption(PropertyOption.MULTI_VALUED) ? "Yes" : "No"); 692 693 if (prop.hasOption(PropertyOption.MANDATORY)) { 694 tableRow("Required", "Yes"); 695 } else { 696 tableRow("Required", "No"); 697 } 698 699 String action = "None"; 700 if (prop.getAdministratorAction() != null) { 701 LocalizableMessage synopsis = prop.getAdministratorAction().getSynopsis(); 702 Type actionType = prop.getAdministratorAction().getType(); 703 String actionStr = ""; 704 if (actionType == Type.COMPONENT_RESTART) { 705 actionStr = "The " + mo.getUserFriendlyName() + 706 " must be disabled and re-enabled for changes to this setting " + 707 "to take effect"; 708 } else if (actionType == Type.SERVER_RESTART) { 709 actionStr = "Restart the server"; 710 } else if (actionType == Type.NONE) { 711 actionStr = "None"; 712 } 713 String dot = actionStr.equals("") ? "" : ". "; 714 action = actionStr + 715 ((synopsis != null) ? dot + synopsis : ""); 716 } 717 tableRow("Admin Action Required", action); 718 719 if (prop.hasOption(PropertyOption.ADVANCED)) { 720 tableRow("Advanced Property", "Yes"); 721 } else { 722 tableRow("Advanced Property", "No"); 723 } 724 725 if (prop.hasOption(PropertyOption.READ_ONLY)) { 726 tableRow("Read-only", "Yes"); 727 } else { 728 tableRow("Read-only", "No"); 729 } 730 731 endTable(); 732 733 } 734 735 736 private void propertiesLinkTable(TreeMap<String, 737 PropertyDefinition> basicProps, 738 TreeMap<String, PropertyDefinition> advancedProps) { 739 htmlBuff.append("<table border=\"0\" cellspacing=\"0\" class=\"jump-table\">\n") 740 .append(" <tr>\n") 741 .append(" <th>Basic Properties:</th>\n") 742 .append(" <th>Advanced Properties:</th>\n") 743 .append(" </tr>\n"); 744 745 PropertyDefinition[] basicPropsArray = 746 basicProps.values().toArray(new PropertyDefinition[0]); 747 PropertyDefinition[] advancedPropsArray = 748 advancedProps.values().toArray(new PropertyDefinition[0]); 749 750 for (int ii=0; 751 ii < basicPropsArray.length || ii < advancedPropsArray.length; 752 ii++) { 753 String basicPropName = 754 ii < basicPropsArray.length ? basicPropsArray[ii].getName() : null; 755 String advancedPropName = 756 ii < advancedPropsArray.length ? 757 advancedPropsArray[ii].getName() : null; 758 759 String basicHtmlCell = ""; 760 if (basicPropName != null) { 761 basicHtmlCell = " <td>↓ <a href=\"#" + basicPropName + "\">" 762 + basicPropName + "</a></td>\n"; 763 } else if (basicPropsArray.length == 0 && ii == 0) { 764 basicHtmlCell = " <td> None</td>\n"; 765 } else if (ii >= basicPropsArray.length) { 766 // Case of nb of basic props < nb of advanced props 767 basicHtmlCell = " <td></td>\n"; 768 } 769 770 String advancedHtmlCell = ""; 771 if (advancedPropName != null) { 772 advancedHtmlCell = " <td>↓ <a href=\"#" + advancedPropName + 773 "\">" + advancedPropName + "</a></td>\n"; 774 } else if (advancedPropsArray.length == 0 && ii == 0) { 775 advancedHtmlCell = " <td> None</td>\n"; 776 } 777 778 htmlBuff.append("<tr>\n"); 779 htmlBuff.append(basicHtmlCell).append(advancedHtmlCell); 780 htmlBuff.append("</tr>\n"); 781 } 782 htmlBuff.append("</table>\n"); 783 } 784 785 786 private void genLdapMapping(AbstractManagedObjectDefinition mo) { 787 //------------------------------------------------------------------------ 788 // LDAP mapping 789 //------------------------------------------------------------------------ 790 791 heading3("LDAP Mapping"); 792 paragraph( 793 "Each configuration property can be mapped to a specific " + 794 "LDAP attribute under the \"cn=config\" entry. " + 795 "The mappings that follow are provided for information only. " + 796 "In general, you should avoid changing the server configuration " + 797 "by manipulating the LDAP attributes directly."); 798 799 // Managed object table 800 startTable(); 801 802 LDAPProfile ldapProfile = LDAPProfile.getInstance(); 803 tableRow("Base DN", getBaseDN(mo, ldapProfile)); 804 805 tableRow("objectclass name", ldapProfile.getObjectClass(mo)); 806 if (mo.getParent().getName() != null) { 807 String superior = ""; 808 if (mo.getParent().getName().equals("top")) { 809 superior = "top"; 810 } else { 811 if (moList.get(mo.getParent().getName()) != null) { 812 superior = 813 ldapProfile.getObjectClass(moList.get(mo.getParent().getName())); 814 } else { 815 System.err.println( 816 "Error: managed object " + mo.getName() + " not found."); 817 } 818 } 819 tableRow("objectclass superior", superior); 820 } else { 821 System.err.println( 822 "Error: objectclass superior not found for " + mo.getName()); 823 } 824 endTable(); 825 826 newline(); 827 // Properties table 828 startTable(); 829 tableRow("Property", "LDAP attribute"); 830 for ( PropertyDefinition prop : getPropertyList(mo).values()) { 831 tableRow(prop.getName(), ldapProfile.getAttributeName(mo, prop)); 832 } 833 834 endTable(); 835 836 } 837 838 private void genManagedObjectList( 839 TreeMap<String, AbstractManagedObjectDefinition> list) { 840 841 htmlHeader(DynamicConstants.PRODUCT_NAME 842 + " Configuration Reference - Components View"); 843 tabMenu(MO_LIST_FILE); 844 viewHelp("This view provides a list of all configuration components, " + 845 "in alphabetical order."); 846 847 newline(); 848 StringBuffer moPointers = new StringBuffer(); 849 String lettersPointers = ""; 850 String firstChar = "."; 851 for (AbstractManagedObjectDefinition mo : list.values()) { 852 if (!mo.getName().startsWith(firstChar)) { 853 firstChar = mo.getName().substring(0, 1); 854 String letter = firstChar.toUpperCase(); 855 moPointers.append(getAnchor(letter)).append(getHeading2(letter)); 856 lettersPointers += getLink(letter, "#" + letter) + " "; 857 } 858 moPointers.append("<p> ") 859 .append(getLink(mo.getUserFriendlyName().toString(), mo.getName() + ".html", MAIN_FRAME)) 860 .append("</p>\n"); 861 } 862 paragraph(lettersPointers); 863 htmlBuff.append(moPointers); 864 htmlFooter(); 865 generateFile(MO_LIST_FILE); 866 } 867 868 private void genPropertiesIndex() { 869 870 // Build a sorted list of (property name + its managed object name) 871 TreeSet<String> propMoList = new TreeSet<>(); 872 for (AbstractManagedObjectDefinition<?, ?> mo : moList.values()) { 873 for (PropertyDefinition<?> prop : mo.getPropertyDefinitions()) { 874 propMoList.add( 875 prop.getName() + "," + prop.getManagedObjectDefinition().getName()); 876 } 877 } 878 879 String lettersPointers = ""; 880 String firstChar = "."; 881 for (String propMoStr : propMoList) { 882 String[] propMoArray = propMoStr.split(","); 883 String propName = propMoArray[0]; 884 AbstractManagedObjectDefinition mo = moList.get(propMoArray[1]); 885 if (!propName.startsWith(firstChar)) { 886 firstChar = propName.substring(0, 1); 887 String letter = firstChar.toUpperCase(); 888 htmlBuff.append(getAnchor(letter)).append(getHeading2(letter)); 889 lettersPointers += getLink(letter, "#" + letter) + " "; 890 } 891 String propLink = getLink(propName, 892 mo.getName() + ".html" + "#" + propName, MAIN_FRAME); 893 String moLink = 894 getLink(mo.getUserFriendlyName().toString(), mo.getName() + ".html", 895 MAIN_FRAME, "#666"); 896 paragraph(propLink + " [ " + moLink + " ]"); 897 } 898 899 String indexBody = htmlBuff.toString(); 900 htmlBuff = new StringBuffer(); 901 htmlHeader(DynamicConstants.PRODUCT_NAME + 902 " Configuration Reference - Properties View"); 903 tabMenu(PROPERTIES_INDEX_FILE); 904 viewHelp("This view provides a list of all configuration properties, " + 905 "in alphabetical order, and indicates the configuration component to " + 906 "which each property applies."); 907 908 newline(); 909 paragraph(lettersPointers); 910 htmlBuff.append(indexBody); 911 htmlFooter(); 912 generateFile(PROPERTIES_INDEX_FILE); 913 } 914 915 private void genWelcomePage() { 916 htmlHeader(DynamicConstants.PRODUCT_NAME + 917 " Configuration Reference - Welcome"); 918 heading2("About This Reference"); 919 paragraph("This reference " + 920 "describes the " + DynamicConstants.PRODUCT_NAME + 921 " configuration properties that can be manipulated " + 922 "with the dsconfig command."); 923 paragraph("Configuration components are grouped according to the area of " + 924 "the server in which they are used, as follows:"); 925 926 beginList(); 927 for (String catName : catTopMoList.keySet()) { 928 bullet(getFriendlyName(catName)); 929 } 930 endList(); 931 932 paragraph( 933 "For ease of reference, the configuration is described on multiple " + 934 "tabs. These tabs provide alternative views of the configuration " + 935 "components:"); 936 beginList(); 937 bullet("The <strong>Inheritance</strong> view represents the inheritance " + 938 "relationships between configuration components. A sub-component " + 939 "inherits all of the properties of its parent component."); 940 bullet("The <strong>Structure</strong> view represents the structural " + 941 "relationships between components and indicates how certain components " + 942 "can exist only within container components. When a container " + 943 "component is deleted, all of the components within it are also " + 944 "deleted."); 945 bullet( 946 "The <strong>Components</strong> view provides an alphabetical list " + 947 "of all configuration components."); 948 bullet( 949 "The <strong>Properties</strong> view provides an alphabetical list " + 950 "of all configuration properties, and indicates the configuration " + 951 "component to which each property applies."); 952 endList(); 953 954 newline(); 955 paragraph("When you set up " + 956 DynamicConstants.PRODUCT_NAME + 957 ", certain components are created in the " + 958 "configuration by default. These components are configured with " + 959 "specific values, which are not necessarily the same as the " + 960 "\"default values\" of new components that you create using dsconfig. " + 961 "The \"default values\" listed in this document refer to the values " + 962 "of the new components that you create using dsconfig."); 963 964 htmlFooter(); 965 generateFile(WELCOME_FILE); 966 967 } 968 969 private void genMainTopPage() { 970 htmlHeader(DynamicConstants.PRODUCT_NAME + 971 " Configuration Reference - Main Top"); 972 // "Home" might be depend on where this is published. 973 /* 974 htmlBuff.append("<div class=\"breadcrumb\"><span class=\"pageactions\">" + 975 "<a href=\"" + OpenDJHome + "\" target=\"_parent\">" + 976 "<span style=\"font-size: 12px;\">« </span>" + 977 "Back to " + 978 DynamicConstants.PRODUCT_NAME + " Home</a></span> </div>\n"); 979 */ 980 htmlBuff.append("<div class=\"breadcrumb\"><span class=\"pageactions\">" + 981 " </span> </div>\n"); 982 htmlBuff.append("<table class=\"titletable\" cellspacing=\"0\" " + 983 "width=\"100%\">\n"); 984 htmlBuff.append("<tbody><tr>\n"); 985 htmlBuff.append(" <td><h2>"+ 986 DynamicConstants.PRODUCT_NAME + 987 " Configuration Reference</h2></td>\n"); 988 /* 989 htmlBuff.append(" <td valign=\"bottom\" width=\"10%\">" + 990 "<a href=\"" + OpenDJHome + "\" target=\"_parent\">" + 991 "<img src=\"opendj_logo_sm.png\" alt=\"OpenDJ Logo\" align=\"bottom\" " + 992 "border=\"0\" height=\"33\" width=\"114\"></a></td>\n"); 993 */ 994 htmlBuff.append(" <td valign=\"bottom\" width=\"10%\">" + 995 "<img src=\"opendj_logo_sm.png\" alt=\"OpenDJ Logo\" align=\"bottom\" " + 996 "border=\"0\" height=\"33\" width=\"114\"></td>\n"); 997 htmlBuff.append("</tr>\n"); 998 htmlBuff.append("</tbody></table>\n"); 999 1000 htmlFooter(); 1001 generateFile(MAINTOP_FILE); 1002 1003 } 1004 1005 private void genIndexPage() { 1006 htmlBuff.append(getHtmlHeader( 1007 DynamicConstants.PRODUCT_NAME + " Configuration Reference")); 1008 1009 htmlBuff.append("<frameset rows=\"80,*\" framespacing=\"1\" " + 1010 "frameborder=\"yes\" border=\"1\" bordercolor=\"#333333\">\n"); 1011 htmlBuff.append(" <frame src=\"" + MAINTOP_FILE + "\" name=\"topFrame\" " + 1012 "id=\"topFrame\" border=\"1\" title=\"topFrame\" scrolling=\"no\">\n"); 1013 htmlBuff.append(" <frameset cols=\"375,*\" frameborder=\"yes\" " + 1014 "border=\"1\" " + 1015 "framespacing=\"1\">\n"); 1016 htmlBuff.append(" <frame src=\"" + INHERITANCE_TREE_FILE + "\" " + 1017 "name=\"leftFrame\" id=\"leftFrame\" title=\"leftFrame\" " + 1018 "scrolling=\"auto\">\n"); 1019 htmlBuff.append(" <frame src=\"" + WELCOME_FILE + 1020 "\" name=\"mainFrame\" " + 1021 "id=\"mainFrame\" title=\"mainFrame\" scrolling=\"auto\">\n"); 1022 htmlBuff.append(" </frameset>\n"); 1023 htmlBuff.append("</frameset>\n"); 1024 htmlBuff.append("<noframes><body>\n"); 1025 htmlBuff.append("</body>\n"); 1026 htmlBuff.append("</noframes>\n"); 1027 htmlBuff.append("</html>\n"); 1028 1029 generateFile(INDEX_FILE); 1030 } 1031 1032 private String getBaseDN( 1033 AbstractManagedObjectDefinition mo, LDAPProfile ldapProfile) { 1034 1035 RelationDefinition rel = relList.get(mo.getName()); 1036 if (rel != null) { 1037 String baseDn = ldapProfile.getRelationRDNSequence(rel); 1038 if (!baseDn.equals("")) { 1039 return baseDn; 1040 } else { 1041 // Check the parent relation 1042 return getBaseDN(rel.getParentDefinition(), ldapProfile); 1043 } 1044 } else if (moList.get(mo.getParent().getName()) != null) { 1045 // check its superior 1046 return getBaseDN(moList.get(mo.getParent().getName()), ldapProfile); 1047 } else { 1048 System.err.println("Error: Base DN not found for " + mo.getName()); 1049 } 1050 return null; 1051 } 1052 1053 @SuppressWarnings("unchecked") 1054 private String getSyntaxStr(PropertyDefinition prop) { 1055 // Create a visitor for performing syntax specific processing. 1056 PropertyDefinitionVisitor<String, Void> visitor = 1057 new PropertyDefinitionVisitor<String, Void>() { 1058 1059 @Override 1060 public String visitACI(ACIPropertyDefinition prop, Void p) { 1061 // Rather than return a link that is coupled to a site location, 1062 // assume that readers can find ACI syntax in the documentation. 1063 // ACI syntax being difficult to understand and to explain, 1064 // it is better not to have to maintain a separate page, either. 1065 return "An ACI syntax"; // getLink("An ACI Syntax", aciSyntaxPage); 1066 } 1067 1068 @Override 1069 public String visitAggregation( 1070 AggregationPropertyDefinition prop, Void p) { 1071 1072 RelationDefinition rel = prop.getRelationDefinition(); 1073 String linkStr = getLink(rel.getUserFriendlyName().toString(), 1074 rel.getName() + ".html"); 1075 return "The DN of any " + linkStr + ". " + 1076 ((prop.getSourceConstraintSynopsis() != null) ? 1077 prop.getSourceConstraintSynopsis().toString() : ""); 1078 } 1079 1080 @Override 1081 public String visitAttributeType( 1082 AttributeTypePropertyDefinition prop, Void p) { 1083 return "The name of an attribute type defined in the server schema."; 1084 } 1085 1086 @Override 1087 public String visitBoolean(BooleanPropertyDefinition prop, Void p) { 1088 return "true" + getNewLine() + "false"; 1089 } 1090 1091 @Override 1092 public String visitClass(ClassPropertyDefinition prop, Void p) { 1093 String classStr = 1094 "A java class that implements or extends the class(es) :"; 1095 for (String clazz : prop.getInstanceOfInterface()) { 1096 classStr += getNewLine() + clazz; 1097 } 1098 return classStr; 1099 } 1100 1101 @Override 1102 public String visitDN(DNPropertyDefinition prop, Void p) { 1103 String retStr = "A valid DN."; 1104 if (prop.getBaseDN() != null) { 1105 retStr += prop.getBaseDN().toString(); 1106 } 1107 return retStr; 1108 } 1109 1110 @Override 1111 public String visitDuration(DurationPropertyDefinition prop, Void p) { 1112 String durationStr = ""; 1113 1114 durationStr += getLink("A duration Syntax", durationSyntaxPage) + 1115 ". "; 1116 if (prop.isAllowUnlimited()) { 1117 durationStr += "A value of \"-1\" or \"unlimited\" for no limit. "; 1118 } 1119 if (prop.getMaximumUnit() != null) { 1120 durationStr += "Maximum unit is \"" + 1121 prop.getMaximumUnit().getLongName() + "\". "; 1122 } 1123 long lowerLimitStr = Double.valueOf(prop.getBaseUnit(). 1124 fromMilliSeconds(prop.getLowerLimit())).longValue(); 1125 durationStr += "Lower limit is " + lowerLimitStr + 1126 " " + prop.getBaseUnit().getLongName() + ". "; 1127 if (prop.getUpperLimit() != null) { 1128 long upperLimitStr = Double.valueOf(prop.getBaseUnit(). 1129 fromMilliSeconds(prop.getUpperLimit())).longValue(); 1130 durationStr += "Upper limit is " + upperLimitStr + 1131 " " + prop.getBaseUnit().getLongName() + ". "; 1132 } 1133 1134 return durationStr; 1135 } 1136 1137 @Override 1138 public String visitEnum(EnumPropertyDefinition prop, Void p) { 1139 String enumStr = ""; 1140 Class en = prop.getEnumClass(); 1141 for (Object cst : en.getEnumConstants()) { 1142 enumStr += cst.toString(); 1143 if (prop.getValueSynopsis((Enum) cst) != null) { 1144 enumStr += " - " + prop.getValueSynopsis((Enum) cst); 1145 } 1146 enumStr += getNewLine() + getNewLine(); 1147 } 1148 return enumStr; 1149 } 1150 1151 @Override 1152 public String visitInteger(IntegerPropertyDefinition prop, Void p) { 1153 String intStr = "An integer value."; 1154 intStr += " Lower value is " + prop.getLowerLimit() + "."; 1155 if (prop.getUpperLimit() != null) { 1156 intStr += " Upper value is " + prop.getUpperLimit() + " ."; 1157 } 1158 if (prop.isAllowUnlimited()) { 1159 intStr += " A value of \"-1\" or \"unlimited\" for no limit."; 1160 } 1161 if (prop.getUnitSynopsis() != null) { 1162 intStr += " Unit is " + prop.getUnitSynopsis() + "."; 1163 } 1164 return intStr; 1165 } 1166 1167 @Override 1168 public String visitIPAddress(IPAddressPropertyDefinition prop, Void p) { 1169 return "An IP address"; 1170 } 1171 1172 @Override 1173 public String visitIPAddressMask( 1174 IPAddressMaskPropertyDefinition prop, Void p) { 1175 1176 return "An IP address mask"; 1177 } 1178 1179 @Override 1180 public String visitSize(SizePropertyDefinition prop, Void p) { 1181 String sizeStr = "A positive integer representing a size."; 1182 if (prop.getLowerLimit() != 0) { 1183 sizeStr += " Lower value is " + prop.getLowerLimit() + "."; 1184 } 1185 if (prop.getUpperLimit() != null) { 1186 sizeStr += " Upper value is " + prop.getUpperLimit() + " ."; 1187 } 1188 if (prop.isAllowUnlimited()) { 1189 sizeStr += " A value of \"-1\" or \"unlimited\" for no limit."; 1190 } 1191 return sizeStr; 1192 } 1193 1194 @Override 1195 public String visitString(StringPropertyDefinition prop, Void p) { 1196 String retStr = "A String"; 1197 if (prop.getPatternSynopsis() != null) { 1198 retStr = prop.getPatternSynopsis().toString(); 1199 } 1200 return retStr; 1201 } 1202 1203 @Override 1204 public String visitUnknown(PropertyDefinition prop, Void p) { 1205 return "Unknown"; 1206 } 1207 }; 1208 1209 // Invoke the visitor against the property definition. 1210 return (String) prop.accept(visitor, null); 1211 1212 } 1213 1214 @SuppressWarnings("unchecked") 1215 private String getDefaultBehaviorString(PropertyDefinition prop) { 1216 DefaultBehaviorProvider defaultBehav = prop.getDefaultBehaviorProvider(); 1217 String defValueStr = ""; 1218 if (defaultBehav instanceof UndefinedDefaultBehaviorProvider) { 1219 defValueStr = "None"; 1220 } else if (defaultBehav instanceof DefinedDefaultBehaviorProvider) { 1221 DefinedDefaultBehaviorProvider defBehav = 1222 (DefinedDefaultBehaviorProvider) defaultBehav; 1223 for (Iterator<String> it = defBehav.getDefaultValues().iterator(); 1224 it.hasNext();) { 1225 1226 String str = it.next(); 1227 defValueStr += str + (it.hasNext() ? "\n" : ""); 1228 } 1229 } else if (defaultBehav instanceof AliasDefaultBehaviorProvider) { 1230 AliasDefaultBehaviorProvider aliasBehav = ( 1231 AliasDefaultBehaviorProvider) defaultBehav; 1232 defValueStr = aliasBehav.getSynopsis().toString(); 1233 } else if 1234 (defaultBehav instanceof RelativeInheritedDefaultBehaviorProvider) { 1235 RelativeInheritedDefaultBehaviorProvider relativBehav = 1236 (RelativeInheritedDefaultBehaviorProvider) defaultBehav; 1237 defValueStr = getDefaultBehaviorString( 1238 relativBehav.getManagedObjectDefinition(). 1239 getPropertyDefinition(relativBehav.getPropertyName())); 1240 } else if 1241 (defaultBehav instanceof AbsoluteInheritedDefaultBehaviorProvider) { 1242 AbsoluteInheritedDefaultBehaviorProvider absoluteBehav = 1243 (AbsoluteInheritedDefaultBehaviorProvider) defaultBehav; 1244 defValueStr = getDefaultBehaviorString( 1245 absoluteBehav.getManagedObjectDefinition(). 1246 getPropertyDefinition(absoluteBehav.getPropertyName())); 1247 } 1248 return defValueStr; 1249 } 1250 1251 private TreeMap<String, AbstractManagedObjectDefinition> makeMOTreeMap( 1252 Collection<AbstractManagedObjectDefinition> coll) { 1253 1254 if (coll == null) { 1255 return null; 1256 } 1257 TreeMap<String, AbstractManagedObjectDefinition> map = new TreeMap<>(); 1258 for (AbstractManagedObjectDefinition mo : coll) { 1259 if (mo.hasOption(ManagedObjectOption.HIDDEN)) 1260 { 1261 continue; 1262 } 1263 map.put(mo.getName(), mo); 1264 } 1265 return map; 1266 } 1267 1268 private TreeMap<String, RelationDefinition> makeRelTreeMap( 1269 Collection<RelationDefinition> coll) { 1270 1271 if (coll == null) { 1272 return null; 1273 } 1274 TreeMap<String, RelationDefinition> map = new TreeMap<>(); 1275 for (RelationDefinition rel : coll) { 1276 map.put(rel.getChildDefinition().getName(), rel); 1277 } 1278 return map; 1279 } 1280 1281 private TreeMap<String, PropertyDefinition> makePropTreeMap( 1282 Collection<PropertyDefinition> coll) { 1283 1284 if (coll == null) { 1285 return null; 1286 } 1287 TreeMap<String, PropertyDefinition> map = new TreeMap<>(); 1288 for (PropertyDefinition prop : coll) { 1289 map.put(prop.getName(), prop); 1290 } 1291 return map; 1292 } 1293 1294 private void horizontalLine() { 1295 htmlBuff.append("<hr style=\"width: 100%; height: 2px;\">"); 1296 } 1297 1298 private void endTable() { 1299 htmlBuff.append("</tbody>\n"); 1300 htmlBuff.append("</table>\n"); 1301 } 1302 1303 private void bullet(String str) { 1304 htmlBuff.append("<li>").append(str).append("</li>\n"); 1305 } 1306 1307 private void heading2(String string) { 1308 heading(string, 2); 1309 } 1310 1311 private void heading3(String string) { 1312 heading(string, 3); 1313 } 1314 1315 private void heading4(String string) { 1316 heading(string, 4); 1317 } 1318 1319 private void heading(String str, int level) { 1320 htmlBuff.append(getHeading(str, level)); 1321 } 1322 1323 private String getHeading(String str, int level) { 1324 String strLevel = Integer.valueOf(level).toString(); 1325 return "<h" + strLevel + ">" + 1326 "<a name=\"" + str + "\"></a>" + 1327 str + 1328 "</h" + strLevel + ">\n"; 1329 } 1330 1331 private String getHeading2(String str) { 1332 return getHeading(str, 2); 1333 } 1334 1335 private String getAnchor(String str) { 1336 return "<a name=\"" + str + "\"></a>"; 1337 } 1338 1339 private void htmlHeader(String pageTitle) { 1340 htmlBuff.append(getHtmlHeader(pageTitle)).append("<body>\n"); 1341 1342 } 1343 1344 private final String Now = new Date().toString(); 1345 private String getHtmlHeader(String pageTitle) { 1346 return "<html>\n" + 1347 "<head>\n" + 1348 "<meta http-equiv=\"content-type\"\n" + 1349 "content=\"text/html; charset=ISO-8859-1\">\n" + 1350 "<title>" + pageTitle + "</title>\n" + 1351 "<link rel=\"stylesheet\" type=\"text/css\"\n" + 1352 "href=\"" + CSS_FILE + "\">\n" + 1353 "<link rel=\"shortcut icon\" href=\"" + FAVICON + "\">\n" + 1354 "<meta name=\"date generated\" content=\"" + Now + "\">\n" + 1355 "</head>\n"; 1356 } 1357 1358 /** Add a Tab Menu, the active tab is the one given as parameter. */ 1359 private void tabMenu(String activeTab) { 1360 htmlBuff.append( 1361 "<div class=\"tabmenu\"> " + 1362 1363 "<span><a " + 1364 (activeTab.equals(INHERITANCE_TREE_FILE) ? "class=\"activetab\" " : "") + 1365 "href=\"" + INHERITANCE_TREE_FILE + "\"" + 1366 " title=\"Inheritance View of Components\">Inheritance</a></span> " + 1367 1368 "<span><a " + 1369 (activeTab.equals(RELATION_TREE_FILE) ? "class=\"activetab\" " : "") + 1370 "href=\"" + RELATION_TREE_FILE + "\"" + 1371 " title=\"Relational View of Components\">Structure</a></span> " + 1372 1373 "<span><a " + 1374 (activeTab.equals(MO_LIST_FILE) ? "class=\"activetab\" " : "") + 1375 "href=\"" + MO_LIST_FILE + "\"" + 1376 " title=\"Alphabetical Index of Components\">Components</a></span> " + 1377 1378 "<span><a " + 1379 (activeTab.equals(PROPERTIES_INDEX_FILE) ? "class=\"activetab\" " : "") + 1380 "href=\"" + PROPERTIES_INDEX_FILE + "\"" + 1381 " title=\"Alphabetical Index of Properties\" >Properties</a></span>" + 1382 1383 "</div>" + 1384 "\n" 1385 ); 1386 } 1387 1388 private String getLink(String str, String link) { 1389 return getLink(str, link, null, null); 1390 } 1391 1392 private String getLink(String str, String link, String target) { 1393 return getLink(str, link, target, null); 1394 } 1395 1396 private String getLink(String str, String link, String target, String color) { 1397 return "<a " + 1398 (color != null ? "style=\"color:" + color + "\" " : "") + 1399 "href=\"" + link + "\"" + 1400 (target == null ? "" : " target=\"" + target + "\"") + 1401 ">" 1402 + str + "</a>"; 1403 } 1404 1405 private void link(String str, String link) { 1406 link(str, link, null, null); 1407 } 1408 1409 private void link(String str, String link, String target) { 1410 link(str, link, target, null); 1411 } 1412 1413 private void link(String str, String link, String target, String color) { 1414 String htmlStr = ""; 1415 if (!inList && getIndentPixels() > 0) { 1416 htmlStr += "<div style=\"margin-left: " + getIndentPixels() + "px;\">"; 1417 } else if (inList) { 1418 htmlStr += "<li>"; 1419 } 1420 htmlStr += getLink(str, link, target, color); 1421 if (!inList && getIndentPixels() > 0) { 1422 htmlStr += "</div>"; 1423 } else if (inList) { 1424 htmlStr += "</li>"; 1425 } 1426 if (!inList) { 1427 htmlStr += "<br>"; 1428 } 1429 htmlBuff.append(htmlStr).append("\n"); 1430 } 1431 1432 private void newline() { 1433 htmlBuff.append( 1434 getNewLine()); 1435 } 1436 1437 private String getNewLine() { 1438 return "<br>\n"; 1439 } 1440 1441 private void paragraph(LocalizableMessage description) { 1442 if (description != null) { 1443 paragraph(description.toString()); 1444 } 1445 } 1446 1447 private void paragraph(String description) { 1448 paragraph(description, TextStyle.STANDARD, null); 1449 } 1450 1451 private void paragraph(String description, TextStyle style) { 1452 paragraph(description, style, null); 1453 } 1454 1455 private void paragraph(String description, TextStyle style, String pClass) { 1456 String indentStr = ""; 1457 String styleStr = ""; 1458 String classStr = ""; 1459 if (getIndentPixels() > 0) { 1460 indentStr = "style=\"margin-left: " + getIndentPixels() + "px;\""; 1461 } 1462 if (style == TextStyle.BOLD) { 1463 styleStr = "style=\"font-weight: bold;\""; 1464 } else if (style == TextStyle.ITALIC) { 1465 styleStr = "style=\"font-style: italic;\""; 1466 } 1467 if (pClass != null) { 1468 classStr = "class=" + pClass; 1469 } 1470 1471 htmlBuff.append("<p ").append(indentStr).append(" ").append(styleStr).append(" ").append(classStr).append(">") 1472 .append(description) 1473 .append("</p>\n"); 1474 } 1475 1476 private int getIndentPixels() { 1477 return ind * 40; 1478 } 1479 1480 private void startTable() { 1481 htmlBuff.append("<table ") 1482 .append("style=\"width: 100%; text-align: left;\"") 1483 .append("border=\"1\"") 1484 .append("cellpadding=\"1\"") 1485 .append("cellspacing=\"0\"") 1486 .append(">\n"); 1487 1488 htmlBuff.append("<tbody>\n"); 1489 } 1490 1491 /** 1492 * Generate a "friendly" name from a string : 1493 * '-' and '_' replaced by space 1494 * first letter of a word in uppercase 1495 */ 1496 private String getFriendlyName(String str) { 1497 String retStr = ""; 1498 String[] words = str.split("\\p{Punct}"); 1499 for (int ii = 0; ii < words.length; ii++) { 1500 if (ii>0) { 1501 retStr += " "; 1502 } 1503 String word = words[ii]; 1504 String firstChar = word.substring(0, 1).toUpperCase(); 1505 retStr += firstChar + word.substring(1, word.length()); 1506 } 1507 return retStr; 1508 } 1509 1510 private void tableRow(String... strings) { 1511 htmlBuff.append( 1512 "<tr>\n"); 1513 for (int ii = 0; ii < strings.length; ii++) { 1514 String string = strings[ii]; 1515 htmlBuff.append("<td style=\"") 1516 .append("vertical-align: top; ") 1517 .append(ii == 0 ? "width: 20%;" : "") 1518 .append("\">") 1519 .append(string) 1520 .append("<br></td>"); 1521 } 1522 htmlBuff.append( 1523 "</tr>\n"); 1524 } 1525 1526 /** 1527 * Text style. 1528 */ 1529 private enum TextStyle { 1530 1531 STANDARD, BOLD, ITALIC, UNDERLINE, FIXED_WIDTH 1532 } 1533 1534 private void beginList() { 1535 inList = true; 1536 listLevel++; 1537 htmlBuff.append( 1538 "<ul>\n"); 1539 } 1540 1541 private void endList() { 1542 listLevel--; 1543 if (listLevel == 0) { 1544 inList = false; 1545 } 1546 htmlBuff.append( 1547 "</ul>\n"); 1548 } 1549 1550 private void htmlFooter() { 1551 htmlBuff.append("</body>\n").append("</html>\n"); 1552 } 1553 1554 private void viewHelp(String helpStr) { 1555 htmlBuff.append("<p class=\"view-help\" >") 1556 .append(helpStr) 1557 .append("</p>") 1558 .append("\n"); 1559 } 1560 1561 private void generateFile(String fileName) { 1562 // Write the html buffer in a file 1563 try { 1564 PrintWriter file = new java.io.PrintWriter( 1565 new java.io.FileWriter(generationDir + File.separator + fileName)); 1566 file.write(htmlBuff.toString()); 1567 file.close(); 1568 } catch (Exception e) { 1569 e.printStackTrace(); 1570 System.exit(1); 1571 } 1572 // re-init html buffer 1573 htmlBuff = new StringBuffer(); 1574 } 1575 1576 /** Relation List from RootConfiguration. */ 1577 private final TreeMap<String, RelationDefinition> topRelList = new TreeMap<>(); 1578 private final TreeMap<String, RelationDefinition> relList = new TreeMap<>(); 1579 private final TreeMap<String, TreeMap<String, RelationDefinition>> catTopRelList = new TreeMap<>(); 1580 /** Managed object list. */ 1581 private final TreeMap<String, AbstractManagedObjectDefinition> moList = new TreeMap<>(); 1582 private final TreeMap<String, AbstractManagedObjectDefinition> topMoList = new TreeMap<>(); 1583 private final TreeMap<String, TreeMap<String, AbstractManagedObjectDefinition>> 1584 catTopMoList = new TreeMap<>(); 1585 private final int ind = 0; 1586 private StringBuffer htmlBuff = new StringBuffer(); 1587 private static String generationDir; 1588 private static boolean ldapMapping; 1589 private static String OpenDJWiki; 1590 private static String OpenDJHome; 1591 private static String aciSyntaxPage; 1592 private static String durationSyntaxPage; 1593 private boolean inList; 1594 private int listLevel; 1595}