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