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