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 2006-2010 Sun Microsystems, Inc. 025 * Portions Copyright 2012-2015 ForgeRock AS. 026 */ 027package org.opends.server.backends; 028 029import static org.forgerock.util.Reject.*; 030import static org.opends.messages.BackendMessages.*; 031import static org.opends.messages.ConfigMessages.*; 032import static org.opends.server.config.ConfigConstants.*; 033import static org.opends.server.util.CollectionUtils.*; 034import static org.opends.server.util.ServerConstants.*; 035import static org.opends.server.util.StaticUtils.*; 036 037import java.util.*; 038 039import org.forgerock.i18n.LocalizableMessage; 040import org.forgerock.i18n.slf4j.LocalizedLogger; 041import org.forgerock.opendj.config.server.ConfigChangeResult; 042import org.forgerock.opendj.config.server.ConfigException; 043import org.forgerock.opendj.ldap.ByteString; 044import org.forgerock.opendj.ldap.ConditionResult; 045import org.forgerock.opendj.ldap.ResultCode; 046import org.forgerock.opendj.ldap.SearchScope; 047import org.forgerock.util.Reject; 048import org.opends.server.admin.server.ConfigurationChangeListener; 049import org.opends.server.admin.std.server.MonitorBackendCfg; 050import org.opends.server.api.Backend; 051import org.opends.server.api.MonitorProvider; 052import org.opends.server.config.ConfigEntry; 053import org.opends.server.core.*; 054import org.opends.server.types.*; 055import org.opends.server.util.DynamicConstants; 056import org.opends.server.util.LDIFWriter; 057import org.opends.server.util.TimeThread; 058 059/** 060 * This class defines a backend to hold Directory Server monitor entries. It 061 * will not actually store anything, but upon request will retrieve the 062 * requested monitor and dynamically generate the associated entry. It will also 063 * construct a base monitor entry with some useful server-wide data. 064 */ 065public class MonitorBackend extends Backend<MonitorBackendCfg> implements 066 ConfigurationChangeListener<MonitorBackendCfg> 067{ 068 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 069 070 /** 071 * The set of user-defined attributes that will be included in the base 072 * monitor entry. 073 */ 074 private ArrayList<Attribute> userDefinedAttributes; 075 076 /** The set of objectclasses that will be used in monitor entries. */ 077 private final HashMap<ObjectClass, String> monitorObjectClasses = new LinkedHashMap<>(2); 078 079 /** The DN of the configuration entry for this backend. */ 080 private DN configEntryDN; 081 082 /** The current configuration state. */ 083 private MonitorBackendCfg currentConfig; 084 085 /** The DN for the base monitor entry. */ 086 private DN baseMonitorDN; 087 088 /** The set of base DNs for this backend. */ 089 private DN[] baseDNs; 090 091 /** 092 * Creates a new backend with the provided information. All backend 093 * implementations must implement a default constructor that use 094 * <CODE>super()</CODE> to invoke this constructor. 095 */ 096 public MonitorBackend() 097 { 098 super(); 099 } 100 101 /** {@inheritDoc} */ 102 @Override 103 public void addEntry(final Entry entry, final AddOperation addOperation) 104 throws DirectoryException 105 { 106 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, 107 ERR_BACKEND_ADD_NOT_SUPPORTED.get(entry.getName(), getBackendID())); 108 } 109 110 /** {@inheritDoc} */ 111 @Override 112 public ConfigChangeResult applyConfigurationChange( 113 final MonitorBackendCfg backendCfg) 114 { 115 final ConfigChangeResult ccr = new ConfigChangeResult(); 116 117 // Check to see if there is a new set of user-defined attributes. 118 final ArrayList<Attribute> userAttrs = new ArrayList<>(); 119 try 120 { 121 final ConfigEntry configEntry = DirectoryServer 122 .getConfigEntry(configEntryDN); 123 for (final List<Attribute> attrs : configEntry.getEntry() 124 .getUserAttributes().values()) 125 { 126 for (final Attribute a : attrs) 127 { 128 if (!isMonitorConfigAttribute(a)) 129 { 130 userAttrs.add(a); 131 } 132 } 133 } 134 for (final List<Attribute> attrs : configEntry.getEntry() 135 .getOperationalAttributes().values()) 136 { 137 for (final Attribute a : attrs) 138 { 139 if (!isMonitorConfigAttribute(a)) 140 { 141 userAttrs.add(a); 142 } 143 } 144 } 145 } 146 catch (final Exception e) 147 { 148 logger.traceException(e); 149 150 ccr.addMessage(ERR_CONFIG_BACKEND_ERROR_INTERACTING_WITH_BACKEND_ENTRY.get( 151 configEntryDN, stackTraceToSingleLineString(e))); 152 ccr.setResultCode(DirectoryServer.getServerErrorResultCode()); 153 } 154 155 userDefinedAttributes = userAttrs; 156 157 ccr.addMessage(INFO_MONITOR_USING_NEW_USER_ATTRS.get()); 158 159 currentConfig = backendCfg; 160 return ccr; 161 } 162 163 /** {@inheritDoc} */ 164 @Override 165 public void configureBackend(final MonitorBackendCfg config, ServerContext serverContext) 166 throws ConfigException 167 { 168 Reject.ifNull(config); 169 170 final MonitorBackendCfg cfg = config; 171 final ConfigEntry configEntry = DirectoryServer.getConfigEntry(cfg.dn()); 172 173 // Make sure that a configuration entry was provided. If not, then we will 174 // not be able to complete initialization. 175 if (configEntry == null) 176 { 177 final LocalizableMessage message = ERR_MONITOR_CONFIG_ENTRY_NULL.get(); 178 throw new ConfigException(message); 179 } 180 181 configEntryDN = configEntry.getDN(); 182 183 // Get the set of user-defined attributes for the configuration entry. Any 184 // attributes that we don't recognize will be included directly in the base 185 // monitor entry. 186 userDefinedAttributes = new ArrayList<>(); 187 addAll(userDefinedAttributes, configEntry.getEntry().getUserAttributes().values()); 188 addAll(userDefinedAttributes, configEntry.getEntry().getOperationalAttributes().values()); 189 190 // Construct the set of objectclasses to include in the base monitor entry. 191 final ObjectClass topOC = DirectoryServer.getObjectClass(OC_TOP, true); 192 monitorObjectClasses.put(topOC, OC_TOP); 193 194 final ObjectClass monitorOC = DirectoryServer.getObjectClass( 195 OC_MONITOR_ENTRY, true); 196 monitorObjectClasses.put(monitorOC, OC_MONITOR_ENTRY); 197 198 // Create the set of base DNs that we will handle. In this case, it's just 199 // the DN of the base monitor entry. 200 try 201 { 202 baseMonitorDN = DN.valueOf(DN_MONITOR_ROOT); 203 } 204 catch (final Exception e) 205 { 206 logger.traceException(e); 207 208 final LocalizableMessage message = ERR_MONITOR_CANNOT_DECODE_MONITOR_ROOT_DN 209 .get(getExceptionMessage(e)); 210 throw new ConfigException(message, e); 211 } 212 213 // FIXME -- Deal with this more correctly. 214 this.baseDNs = new DN[] { baseMonitorDN }; 215 216 currentConfig = cfg; 217 } 218 219 private void addAll(ArrayList<Attribute> attributes, Collection<List<Attribute>> attributesToAdd) 220 { 221 for (final List<Attribute> attrs : attributesToAdd) 222 { 223 for (final Attribute a : attrs) 224 { 225 if (!isMonitorConfigAttribute(a)) 226 { 227 attributes.add(a); 228 } 229 } 230 } 231 } 232 233 /** {@inheritDoc} */ 234 @Override 235 public void createBackup(final BackupConfig backupConfig) 236 throws DirectoryException 237 { 238 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, 239 ERR_BACKEND_BACKUP_AND_RESTORE_NOT_SUPPORTED.get(getBackendID())); 240 } 241 242 /** {@inheritDoc} */ 243 @Override 244 public void deleteEntry(final DN entryDN, 245 final DeleteOperation deleteOperation) throws DirectoryException 246 { 247 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, 248 ERR_BACKEND_DELETE_NOT_SUPPORTED.get(entryDN, getBackendID())); 249 } 250 251 /** {@inheritDoc} */ 252 @Override 253 public boolean entryExists(final DN entryDN) throws DirectoryException 254 { 255 return getDIT().containsKey(entryDN); 256 } 257 258 /** {@inheritDoc} */ 259 @Override 260 public void exportLDIF(final LDIFExportConfig exportConfig) 261 throws DirectoryException 262 { 263 // TODO export-ldif reports nonsense for upTime etc. 264 265 // Create the LDIF writer. 266 LDIFWriter ldifWriter; 267 try 268 { 269 ldifWriter = new LDIFWriter(exportConfig); 270 } 271 catch (final Exception e) 272 { 273 logger.traceException(e); 274 275 final LocalizableMessage message = ERR_ROOTDSE_UNABLE_TO_CREATE_LDIF_WRITER 276 .get(stackTraceToSingleLineString(e)); 277 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message); 278 } 279 280 // Write the base monitor entry to the LDIF. 281 try 282 { 283 ldifWriter.writeEntry(getBaseMonitorEntry()); 284 } 285 catch (final Exception e) 286 { 287 logger.traceException(e); 288 289 close(ldifWriter); 290 291 final LocalizableMessage message = ERR_MONITOR_UNABLE_TO_EXPORT_BASE 292 .get(stackTraceToSingleLineString(e)); 293 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message); 294 } 295 296 // Get all the monitor providers, convert them to entries, and write them to 297 // LDIF. 298 for (final MonitorProvider<?> monitorProvider : DirectoryServer 299 .getMonitorProviders().values()) 300 { 301 try 302 { 303 // TODO implementation of export is incomplete 304 } 305 catch (final Exception e) 306 { 307 logger.traceException(e); 308 309 close(ldifWriter); 310 311 final LocalizableMessage message = ERR_MONITOR_UNABLE_TO_EXPORT_PROVIDER_ENTRY 312 .get(monitorProvider.getMonitorInstanceName(), stackTraceToSingleLineString(e)); 313 throw new DirectoryException( 314 DirectoryServer.getServerErrorResultCode(), message); 315 } 316 } 317 318 close(ldifWriter); 319 } 320 321 /** {@inheritDoc} */ 322 @Override 323 public void closeBackend() 324 { 325 currentConfig.removeMonitorChangeListener(this); 326 try 327 { 328 DirectoryServer.deregisterBaseDN(baseMonitorDN); 329 } 330 catch (final Exception e) 331 { 332 logger.traceException(e); 333 } 334 } 335 336 /** {@inheritDoc} */ 337 @Override 338 public DN[] getBaseDNs() 339 { 340 return baseDNs; 341 } 342 343 /** {@inheritDoc} */ 344 @Override 345 public Entry getEntry(final DN entryDN) throws DirectoryException 346 { 347 // If the requested entry was null, then throw an exception. 348 if (entryDN == null) 349 { 350 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 351 ERR_BACKEND_GET_ENTRY_NULL.get(getBackendID())); 352 } 353 354 // If the requested entry was the monitor base entry, then retrieve it 355 // without constructing the DIT. 356 if (entryDN.equals(baseMonitorDN)) 357 { 358 return getBaseMonitorEntry(); 359 } 360 361 // From now on we'll need the DIT. 362 final Map<DN, MonitorProvider<?>> dit = getDIT(); 363 if (!dit.containsKey(entryDN)) 364 { 365 throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, 366 ERR_MONITOR_INVALID_BASE.get(entryDN, baseMonitorDN)); 367 } 368 369 // The DN is associated with a valid monitor/glue entry. 370 return getEntry(entryDN, dit); 371 } 372 373 /** {@inheritDoc} */ 374 @Override 375 public long getEntryCount() 376 { 377 return getDIT().size(); 378 } 379 380 /** {@inheritDoc} */ 381 @Override 382 public Set<String> getSupportedControls() 383 { 384 return Collections.emptySet(); 385 } 386 387 /** {@inheritDoc} */ 388 @Override 389 public Set<String> getSupportedFeatures() 390 { 391 return Collections.emptySet(); 392 } 393 394 /** {@inheritDoc} */ 395 @Override 396 public ConditionResult hasSubordinates(final DN entryDN) 397 throws DirectoryException 398 { 399 final NavigableMap<DN, MonitorProvider<?>> dit = getDIT(); 400 if (dit.containsKey(entryDN)) 401 { 402 final DN nextDN = dit.higherKey(entryDN); 403 return ConditionResult.valueOf(nextDN != null && nextDN.isDescendantOf(entryDN)); 404 } 405 return ConditionResult.UNDEFINED; 406 } 407 408 /** {@inheritDoc} */ 409 @Override 410 public LDIFImportResult importLDIF(final LDIFImportConfig importConfig, ServerContext serverContext) 411 throws DirectoryException 412 { 413 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, 414 ERR_BACKEND_IMPORT_NOT_SUPPORTED.get(getBackendID())); 415 } 416 417 /** {@inheritDoc} */ 418 @Override 419 public void openBackend() throws ConfigException, InitializationException 420 { 421 // Register with the Directory Server as a configurable component. 422 currentConfig.addMonitorChangeListener(this); 423 424 // Register the monitor base as a private suffix. 425 try 426 { 427 DirectoryServer.registerBaseDN(baseMonitorDN, this, true); 428 } 429 catch (final Exception e) 430 { 431 logger.traceException(e); 432 433 final LocalizableMessage message = ERR_BACKEND_CANNOT_REGISTER_BASEDN.get( 434 baseMonitorDN, getExceptionMessage(e)); 435 throw new InitializationException(message, e); 436 } 437 } 438 439 /** {@inheritDoc} */ 440 @Override 441 public boolean isConfigurationChangeAcceptable( 442 final MonitorBackendCfg backendCfg, 443 final List<LocalizableMessage> unacceptableReasons) 444 { 445 // We'll pretty much accept anything here as long as it isn't one of our 446 // private attributes. 447 return true; 448 } 449 450 /** {@inheritDoc} */ 451 @Override 452 public boolean isIndexed(final AttributeType attributeType, 453 final IndexType indexType) 454 { 455 // All searches in this backend will always be considered indexed. 456 return true; 457 } 458 459 /** {@inheritDoc} */ 460 @Override 461 public long getNumberOfEntriesInBaseDN(final DN baseDN) throws DirectoryException { 462 checkNotNull(baseDN, "baseDN must not be null"); 463 return getNumberOfSubordinates(baseDN, true) + 1; 464 } 465 466 /** {@inheritDoc} */ 467 @Override 468 public long getNumberOfChildren(final DN parentDN) throws DirectoryException { 469 checkNotNull(parentDN, "parentDN must not be null"); 470 return getNumberOfSubordinates(parentDN, false); 471 } 472 473 private long getNumberOfSubordinates(final DN entryDN, final boolean includeSubtree) throws DirectoryException 474 { 475 final NavigableMap<DN, MonitorProvider<?>> dit = getDIT(); 476 if (!dit.containsKey(entryDN)) 477 { 478 return -1L; 479 } 480 long count = 0; 481 final int childDNSize = entryDN.size() + 1; 482 for (final DN dn : dit.tailMap(entryDN, false).navigableKeySet()) 483 { 484 if (!dn.isDescendantOf(entryDN)) 485 { 486 break; 487 } 488 else if (includeSubtree || dn.size() == childDNSize) 489 { 490 count++; 491 } 492 } 493 return count; 494 } 495 496 /** {@inheritDoc} */ 497 @Override 498 public void removeBackup(final BackupDirectory backupDirectory, 499 final String backupID) throws DirectoryException 500 { 501 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, 502 ERR_BACKEND_BACKUP_AND_RESTORE_NOT_SUPPORTED.get(getBackendID())); 503 } 504 505 /** {@inheritDoc} */ 506 @Override 507 public void renameEntry(final DN currentDN, final Entry entry, 508 final ModifyDNOperation modifyDNOperation) throws DirectoryException 509 { 510 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, 511 ERR_BACKEND_MODIFY_DN_NOT_SUPPORTED.get(currentDN, getBackendID())); 512 } 513 514 /** {@inheritDoc} */ 515 @Override 516 public void replaceEntry(final Entry oldEntry, final Entry newEntry, 517 final ModifyOperation modifyOperation) throws DirectoryException 518 { 519 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, 520 ERR_MONITOR_MODIFY_NOT_SUPPORTED.get(newEntry.getName(), configEntryDN)); 521 } 522 523 /** {@inheritDoc} */ 524 @Override 525 public void restoreBackup(final RestoreConfig restoreConfig) 526 throws DirectoryException 527 { 528 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, 529 ERR_BACKEND_BACKUP_AND_RESTORE_NOT_SUPPORTED.get(getBackendID())); 530 } 531 532 /** {@inheritDoc} */ 533 @Override 534 public void search(final SearchOperation searchOperation) 535 throws DirectoryException 536 { 537 // Get the base DN, scope, and filter for the search. 538 final DN baseDN = searchOperation.getBaseDN(); 539 final SearchScope scope = searchOperation.getScope(); 540 final SearchFilter filter = searchOperation.getFilter(); 541 542 // Compute the current monitor DIT. 543 final NavigableMap<DN, MonitorProvider<?>> dit = getDIT(); 544 545 // Resolve the base entry and return no such object if it does not exist. 546 if (!dit.containsKey(baseDN)) 547 { 548 // Not found, so find the nearest match. 549 DN matchedDN = baseDN.parent(); 550 while (matchedDN != null) 551 { 552 if (dit.containsKey(matchedDN)) 553 { 554 break; 555 } 556 matchedDN = matchedDN.parent(); 557 } 558 final LocalizableMessage message = ERR_BACKEND_ENTRY_DOESNT_EXIST.get(baseDN, getBackendID()); 559 throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message, 560 matchedDN, null); 561 } 562 563 // Walk through all entries and send the ones that match. 564 for (final Map.Entry<DN, MonitorProvider<?>> e : dit.tailMap(baseDN).entrySet()) 565 { 566 final DN dn = e.getKey(); 567 if (dn.matchesBaseAndScope(baseDN, scope)) 568 { 569 final Entry entry = getEntry(dn, dit); 570 if (filter.matchesEntry(entry)) 571 { 572 searchOperation.returnEntry(entry, null); 573 } 574 } 575 else if (scope == SearchScope.BASE_OBJECT || !dn.isDescendantOf(baseDN)) 576 { 577 // No more entries will be in scope. 578 break; 579 } 580 } 581 } 582 583 /** {@inheritDoc} */ 584 @Override 585 public boolean supports(BackendOperation backendOperation) 586 { 587 // We can export all the monitor entries as a point-in-time snapshot. 588 // TODO implementation of export is incomplete 589 // TODO export-ldif reports nonsense for upTime etc. 590 return false; 591 } 592 593 /** 594 * Retrieves the base monitor entry for the Directory Server. 595 * 596 * @return The base monitor entry for the Directory Server. 597 */ 598 private Entry getBaseMonitorEntry() 599 { 600 final ObjectClass extensibleObjectOC = DirectoryServer.getObjectClass(OC_EXTENSIBLE_OBJECT_LC, true); 601 final HashMap<ObjectClass, String> monitorClasses = newObjectClasses(extensibleObjectOC, OC_EXTENSIBLE_OBJECT); 602 603 final HashMap<AttributeType, List<Attribute>> monitorUserAttrs = new LinkedHashMap<>(); 604 final HashMap<AttributeType, List<Attribute>> monitorOperationalAttrs = new LinkedHashMap<>(); 605 606 put(monitorUserAttrs, Attributes.create(ATTR_COMMON_NAME, "monitor")); 607 put(monitorUserAttrs, Attributes.create(ATTR_PRODUCT_NAME, DynamicConstants.PRODUCT_NAME)); 608 put(monitorUserAttrs, Attributes.create(ATTR_VENDOR_NAME, SERVER_VENDOR_NAME)); 609 put(monitorUserAttrs, Attributes.create(ATTR_VENDOR_VERSION, DirectoryServer.getVersionString())); 610 put(monitorUserAttrs, Attributes.create(ATTR_START_TIME, DirectoryServer.getStartTimeUTC())); 611 put(monitorUserAttrs, Attributes.create(ATTR_CURRENT_TIME, TimeThread.getGMTTime())); 612 put(monitorUserAttrs, Attributes.create(ATTR_UP_TIME, getHumanReadableUpTime())); 613 614 // Add the number of connections currently established. 615 final long currentConns = DirectoryServer.getCurrentConnections(); 616 put(monitorUserAttrs, Attributes.create(ATTR_CURRENT_CONNS, String.valueOf(currentConns))); 617 618 // Add the maximum number of connections established at one time. 619 final long maxConns = DirectoryServer.getMaxConnections(); 620 put(monitorUserAttrs, Attributes.create(ATTR_MAX_CONNS, String.valueOf(maxConns))); 621 622 // Add the total number of connections the server has accepted. 623 final long totalConns = DirectoryServer.getTotalConnections(); 624 put(monitorUserAttrs, Attributes.create(ATTR_TOTAL_CONNS, String.valueOf(totalConns))); 625 626 // Add all the user-defined attributes. 627 for (final Attribute a : userDefinedAttributes) 628 { 629 final AttributeType type = a.getAttributeType(); 630 631 final HashMap<AttributeType, List<Attribute>> attrsMap = 632 type.isOperational() ? monitorOperationalAttrs : monitorUserAttrs; 633 List<Attribute> attrs = attrsMap.get(type); 634 if (attrs == null) 635 { 636 attrs = new ArrayList<>(); 637 attrsMap.put(type, attrs); 638 } 639 attrs.add(a); 640 } 641 642 return newEntry(baseMonitorDN, monitorClasses, monitorUserAttrs, monitorOperationalAttrs); 643 } 644 645 private String getHumanReadableUpTime() 646 { 647 long upSeconds = (System.currentTimeMillis() - DirectoryServer.getStartTime()) / 1000; 648 final long upDays = upSeconds / 86400; 649 upSeconds %= 86400; 650 final long upHours = upSeconds / 3600; 651 upSeconds %= 3600; 652 final long upMinutes = upSeconds / 60; 653 upSeconds %= 60; 654 return INFO_MONITOR_UPTIME.get(upDays, upHours, upMinutes, upSeconds).toString(); 655 } 656 657 private void put(final HashMap<AttributeType, List<Attribute>> attrsMap, final Attribute attr) 658 { 659 attrsMap.put(attr.getAttributeType(), newArrayList(attr)); 660 } 661 662 /** 663 * Retrieves the branch monitor entry for the Directory Server. 664 * 665 * @param dn 666 * to get. 667 * @return The branch monitor entry for the Directory Server. 668 */ 669 private Entry getBranchMonitorEntry(final DN dn) 670 { 671 final ObjectClass monitorOC = DirectoryServer.getObjectClass(OC_MONITOR_BRANCH, true); 672 final HashMap<ObjectClass, String> monitorClasses = newObjectClasses(monitorOC, OC_MONITOR_BRANCH); 673 674 final HashMap<AttributeType, List<Attribute>> monitorUserAttrs = new LinkedHashMap<>(); 675 676 final RDN rdn = dn.rdn(); 677 if (rdn != null) 678 { 679 // Add the RDN values 680 for (int i = 0; i < rdn.getNumValues(); i++) 681 { 682 final AttributeType attributeType = rdn.getAttributeType(i); 683 final ByteString value = rdn.getAttributeValue(attributeType); 684 monitorUserAttrs.put(attributeType, Attributes.createAsList(attributeType, value)); 685 } 686 } 687 688 return newEntry(dn, monitorClasses, monitorUserAttrs, null); 689 } 690 691 /** 692 * Returns a map containing records for each DN in the monitor backend's DIT. 693 * Each record maps the entry DN to the associated monitor provider, or 694 * {@code null} if the entry is a glue (branch) entry. 695 * 696 * @return A map containing records for each DN in the monitor backend's DIT. 697 */ 698 private NavigableMap<DN, MonitorProvider<?>> getDIT() 699 { 700 final NavigableMap<DN, MonitorProvider<?>> dit = new TreeMap<>(); 701 for (final MonitorProvider<?> monitorProvider : DirectoryServer.getMonitorProviders().values()) 702 { 703 DN dn = DirectoryServer.getMonitorProviderDN(monitorProvider); 704 dit.put(dn, monitorProvider); 705 706 // Added glue records. 707 for (dn = dn.parent(); dn != null; dn = dn.parent()) 708 { 709 if (dit.containsKey(dn)) 710 { 711 break; 712 } 713 dit.put(dn, null); 714 } 715 } 716 return dit; 717 } 718 719 720 721 /** 722 * Creates the monitor entry having the specified DN. 723 * 724 * @param entryDN 725 * The name of the monitor entry. 726 * @param dit 727 * The monitor DIT. 728 * @return Returns the monitor entry having the specified DN. 729 */ 730 private Entry getEntry(final DN entryDN, 731 final Map<DN, MonitorProvider<?>> dit) 732 { 733 // Get the monitor provider. 734 final MonitorProvider<?> monitorProvider = dit.get(entryDN); 735 if (monitorProvider != null) 736 { 737 return getMonitorEntry(entryDN, monitorProvider); 738 } 739 else if (entryDN.equals(baseMonitorDN)) 740 { 741 // The monitor base entry needs special treatment. 742 return getBaseMonitorEntry(); 743 } 744 else 745 { 746 // Create a generic glue branch entry. 747 return getBranchMonitorEntry(entryDN); 748 } 749 } 750 751 752 753 /** 754 * Generates and returns a monitor entry based on the contents of the provided 755 * monitor provider. 756 * 757 * @param entryDN 758 * The DN to use for the entry. 759 * @param monitorProvider 760 * The monitor provider to use to obtain the information for the 761 * entry. 762 * @return The monitor entry generated from the information in the provided 763 * monitor provider. 764 */ 765 private Entry getMonitorEntry(final DN entryDN, 766 final MonitorProvider<?> monitorProvider) 767 { 768 final ObjectClass monitorOC = monitorProvider.getMonitorObjectClass(); 769 final HashMap<ObjectClass, String> monitorClasses = newObjectClasses(monitorOC, monitorOC.getPrimaryName()); 770 771 final List<Attribute> monitorAttrs = monitorProvider.getMonitorData(); 772 final HashMap<AttributeType, List<Attribute>> attrMap = new LinkedHashMap<>(monitorAttrs.size() + 1); 773 774 // Make sure to include the RDN attribute. 775 final RDN entryRDN = entryDN.rdn(); 776 final AttributeType rdnType = entryRDN.getAttributeType(0); 777 final ByteString rdnValue = entryRDN.getAttributeValue(0); 778 779 attrMap.put(rdnType, Attributes.createAsList(rdnType, rdnValue)); 780 781 // Take the rest of the information from the monitor data. 782 for (final Attribute a : monitorAttrs) 783 { 784 final AttributeType type = a.getAttributeType(); 785 786 List<Attribute> attrs = attrMap.get(type); 787 if (attrs == null) 788 { 789 attrs = new ArrayList<>(); 790 attrMap.put(type, attrs); 791 } 792 attrs.add(a); 793 } 794 795 return newEntry(entryDN, monitorClasses, attrMap, new HashMap<AttributeType, List<Attribute>>(0)); 796 } 797 798 private HashMap<ObjectClass, String> newObjectClasses(ObjectClass objectClass, String objectClassName) 799 { 800 final HashMap<ObjectClass, String> monitorClasses = new LinkedHashMap<>(monitorObjectClasses.size() + 1); 801 monitorClasses.putAll(monitorObjectClasses); 802 monitorClasses.put(objectClass, objectClassName); 803 return monitorClasses; 804 } 805 806 private Entry newEntry(final DN dn, final Map<ObjectClass, String> objectClasses, 807 final Map<AttributeType, List<Attribute>> userAttrs, Map<AttributeType, List<Attribute>> opAttrs) 808 { 809 final Entry e = new Entry(dn, objectClasses, userAttrs, opAttrs); 810 e.processVirtualAttributes(); 811 return e; 812 } 813 814 /** 815 * Indicates whether the provided attribute is one that is used in the 816 * configuration of this backend. 817 * 818 * @param attribute 819 * The attribute for which to make the determination. 820 * @return <CODE>true</CODE> if the provided attribute is one that is used in 821 * the configuration of this backend, <CODE>false</CODE> if not. 822 */ 823 private boolean isMonitorConfigAttribute(final Attribute attribute) 824 { 825 final AttributeType attrType = attribute.getAttributeType(); 826 return attrType.hasName(ATTR_COMMON_NAME) 827 || attrType.hasName(ATTR_BACKEND_ENABLED.toLowerCase()) 828 || attrType.hasName(ATTR_BACKEND_CLASS.toLowerCase()) 829 || attrType.hasName(ATTR_BACKEND_BASE_DN.toLowerCase()) 830 || attrType.hasName(ATTR_BACKEND_ID.toLowerCase()) 831 || attrType.hasName(ATTR_BACKEND_WRITABILITY_MODE.toLowerCase()); 832 } 833 834}