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