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 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2006-2008 Sun Microsystems, Inc. 026 */ 027 package org.opends.server.backends; 028 029 030 031 import java.util.ArrayList; 032 import java.util.HashMap; 033 import java.util.HashSet; 034 import java.util.LinkedHashMap; 035 import java.util.LinkedHashSet; 036 import java.util.List; 037 038 import org.opends.messages.Message; 039 import org.opends.server.admin.Configuration; 040 import org.opends.server.admin.server.ConfigurationChangeListener; 041 import org.opends.server.admin.std.server.MonitorBackendCfg; 042 import org.opends.server.admin.std.server.MonitorProviderCfg; 043 import org.opends.server.api.Backend; 044 import org.opends.server.api.MonitorProvider; 045 import org.opends.server.config.ConfigEntry; 046 import org.opends.server.config.ConfigException; 047 import org.opends.server.core.AddOperation; 048 import org.opends.server.core.DeleteOperation; 049 import org.opends.server.core.DirectoryServer; 050 import org.opends.server.core.ModifyOperation; 051 import org.opends.server.core.ModifyDNOperation; 052 import org.opends.server.core.SearchOperation; 053 import org.opends.server.loggers.debug.DebugTracer; 054 import org.opends.server.protocols.asn1.ASN1OctetString; 055 import org.opends.server.types.Attribute; 056 import org.opends.server.types.AttributeType; 057 import org.opends.server.types.AttributeValue; 058 import org.opends.server.types.BackupConfig; 059 import org.opends.server.types.BackupDirectory; 060 import org.opends.server.types.ConditionResult; 061 import org.opends.server.types.ConfigChangeResult; 062 import org.opends.server.types.DebugLogLevel; 063 import org.opends.server.types.DirectoryException; 064 import org.opends.server.types.DN; 065 import org.opends.server.types.Entry; 066 import org.opends.server.types.IndexType; 067 import org.opends.server.types.InitializationException; 068 import org.opends.server.types.LDIFExportConfig; 069 import org.opends.server.types.LDIFImportConfig; 070 import org.opends.server.types.LDIFImportResult; 071 import org.opends.server.types.ObjectClass; 072 import org.opends.server.types.RDN; 073 import org.opends.server.types.RestoreConfig; 074 import org.opends.server.types.ResultCode; 075 import org.opends.server.types.SearchFilter; 076 import org.opends.server.types.SearchScope; 077 import org.opends.server.util.DynamicConstants; 078 import org.opends.server.util.LDIFWriter; 079 import org.opends.server.util.TimeThread; 080 import org.opends.server.util.Validator; 081 082 import static org.opends.server.config.ConfigConstants.*; 083 import static org.opends.server.loggers.debug.DebugLogger.*; 084 import static org.opends.messages.BackendMessages.*; 085 import static org.opends.messages.ConfigMessages.*; 086 import static org.opends.server.util.ServerConstants.*; 087 import static org.opends.server.util.StaticUtils.*; 088 089 090 091 /** 092 * This class defines a backend to hold Directory Server monitor entries. It 093 * will not actually store anything, but upon request will retrieve the 094 * requested monitor and dynamically generate the associated entry. It will 095 * also construct a base monitor entry with some useful server-wide data. 096 */ 097 public class MonitorBackend 098 extends Backend 099 implements ConfigurationChangeListener<MonitorBackendCfg> 100 { 101 /** 102 * The tracer object for the debug logger. 103 */ 104 private static final DebugTracer TRACER = getTracer(); 105 106 107 108 // The set of user-defined attributes that will be included in the base 109 // monitor entry. 110 private ArrayList<Attribute> userDefinedAttributes; 111 112 // The set of objectclasses that will be used in monitor entries. 113 private HashMap<ObjectClass,String> monitorObjectClasses; 114 115 // The DN of the configuration entry for this backend. 116 private DN configEntryDN; 117 118 // The current configuration state. 119 private MonitorBackendCfg currentConfig; 120 121 // The DN for the base monitor entry. 122 private DN baseMonitorDN; 123 124 // The set of base DNs for this backend. 125 private DN[] baseDNs; 126 127 // The set of supported controls for this backend. 128 private HashSet<String> supportedControls; 129 130 // The set of supported features for this backend. 131 private HashSet<String> supportedFeatures; 132 133 134 135 /** 136 * Creates a new backend with the provided information. All backend 137 * implementations must implement a default constructor that use 138 * <CODE>super()</CODE> to invoke this constructor. 139 */ 140 public MonitorBackend() 141 { 142 super(); 143 144 // Perform all initialization in initializeBackend. 145 } 146 147 148 /** 149 * {@inheritDoc} 150 */ 151 @Override() 152 public void configureBackend(Configuration config) 153 throws ConfigException 154 { 155 Validator.ensureNotNull(config); 156 Validator.ensureTrue(config instanceof MonitorBackendCfg); 157 158 MonitorBackendCfg cfg = (MonitorBackendCfg)config; 159 ConfigEntry configEntry = DirectoryServer.getConfigEntry(cfg.dn()); 160 161 162 // Make sure that a configuration entry was provided. If not, then we will 163 // not be able to complete initialization. 164 if (configEntry == null) 165 { 166 Message message = ERR_MONITOR_CONFIG_ENTRY_NULL.get(); 167 throw new ConfigException(message); 168 } 169 170 configEntryDN = configEntry.getDN(); 171 172 173 // Get the set of user-defined attributes for the configuration entry. Any 174 // attributes that we don't recognize will be included directly in the base 175 // monitor entry. 176 userDefinedAttributes = new ArrayList<Attribute>(); 177 for (List<Attribute> attrs : 178 configEntry.getEntry().getUserAttributes().values()) 179 { 180 for (Attribute a : attrs) 181 { 182 if (! isMonitorConfigAttribute(a)) 183 { 184 userDefinedAttributes.add(a); 185 } 186 } 187 } 188 for (List<Attribute> attrs : 189 configEntry.getEntry().getOperationalAttributes().values()) 190 { 191 for (Attribute a : attrs) 192 { 193 if (! isMonitorConfigAttribute(a)) 194 { 195 userDefinedAttributes.add(a); 196 } 197 } 198 } 199 200 201 // Construct the set of objectclasses to include in the base monitor entry. 202 monitorObjectClasses = new LinkedHashMap<ObjectClass,String>(2); 203 ObjectClass topOC = DirectoryServer.getObjectClass(OC_TOP, true); 204 monitorObjectClasses.put(topOC, OC_TOP); 205 206 ObjectClass monitorOC = DirectoryServer.getObjectClass(OC_MONITOR_ENTRY, 207 true); 208 monitorObjectClasses.put(monitorOC, OC_MONITOR_ENTRY); 209 210 211 // Define an empty sets for the supported controls and features. 212 supportedControls = new HashSet<String>(0); 213 supportedFeatures = new HashSet<String>(0); 214 215 // Create the set of base DNs that we will handle. In this case, it's just 216 // the DN of the base monitor entry. 217 try 218 { 219 baseMonitorDN = DN.decode(DN_MONITOR_ROOT); 220 } 221 catch (Exception e) 222 { 223 if (debugEnabled()) 224 { 225 TRACER.debugCaught(DebugLogLevel.ERROR, e); 226 } 227 228 Message message = 229 ERR_MONITOR_CANNOT_DECODE_MONITOR_ROOT_DN.get(getExceptionMessage(e)); 230 throw new ConfigException(message, e); 231 } 232 233 // FIXME -- Deal with this more correctly. 234 this.baseDNs = new DN[] { baseMonitorDN }; 235 236 237 currentConfig = cfg; 238 } 239 240 241 242 /** 243 * {@inheritDoc} 244 */ 245 @Override() 246 public void initializeBackend() 247 throws ConfigException, InitializationException 248 { 249 // Register with the Directory Server as a configurable component. 250 currentConfig.addMonitorChangeListener(this); 251 252 253 // Register the monitor base as a private suffix. 254 try 255 { 256 DirectoryServer.registerBaseDN(baseMonitorDN, this, true); 257 } 258 catch (Exception e) 259 { 260 if (debugEnabled()) 261 { 262 TRACER.debugCaught(DebugLogLevel.ERROR, e); 263 } 264 265 Message message = ERR_BACKEND_CANNOT_REGISTER_BASEDN.get( 266 baseMonitorDN.toString(), getExceptionMessage(e)); 267 throw new InitializationException(message, e); 268 } 269 } 270 271 272 273 /** 274 * {@inheritDoc} 275 */ 276 @Override() 277 public void finalizeBackend() 278 { 279 currentConfig.removeMonitorChangeListener(this); 280 281 try 282 { 283 DirectoryServer.deregisterBaseDN(baseMonitorDN); 284 } 285 catch (Exception e) 286 { 287 if (debugEnabled()) 288 { 289 TRACER.debugCaught(DebugLogLevel.ERROR, e); 290 } 291 } 292 } 293 294 295 296 /** 297 * Indicates whether the provided attribute is one that is used in the 298 * configuration of this backend. 299 * 300 * @param attribute The attribute for which to make the determination. 301 * 302 * @return <CODE>true</CODE> if the provided attribute is one that is used in 303 * the configuration of this backend, <CODE>false</CODE> if not. 304 */ 305 private boolean isMonitorConfigAttribute(Attribute attribute) 306 { 307 AttributeType attrType = attribute.getAttributeType(); 308 if (attrType.hasName(ATTR_COMMON_NAME) || 309 attrType.hasName(ATTR_BACKEND_ENABLED.toLowerCase()) || 310 attrType.hasName(ATTR_BACKEND_CLASS.toLowerCase()) || 311 attrType.hasName(ATTR_BACKEND_BASE_DN.toLowerCase()) || 312 attrType.hasName(ATTR_BACKEND_ID.toLowerCase()) || 313 attrType.hasName(ATTR_BACKEND_WRITABILITY_MODE.toLowerCase())) 314 { 315 return true; 316 } 317 318 return false; 319 } 320 321 322 323 /** 324 * {@inheritDoc} 325 */ 326 @Override() 327 public DN[] getBaseDNs() 328 { 329 return baseDNs; 330 } 331 332 333 334 /** 335 * {@inheritDoc} 336 */ 337 @Override() 338 public long getEntryCount() 339 { 340 return DirectoryServer.getMonitorProviders().size() + 1; 341 } 342 343 344 345 /** 346 * {@inheritDoc} 347 */ 348 @Override() 349 public boolean isLocal() 350 { 351 // For the purposes of this method, this is a local backend. 352 return true; 353 } 354 355 356 357 /** 358 * {@inheritDoc} 359 */ 360 @Override() 361 public boolean isIndexed(AttributeType attributeType, IndexType indexType) 362 { 363 // All searches in this backend will always be considered indexed. 364 return true; 365 } 366 367 368 369 /** 370 * {@inheritDoc} 371 */ 372 @Override() 373 public ConditionResult hasSubordinates(DN entryDN) 374 throws DirectoryException 375 { 376 long ret = numSubordinates(entryDN, false); 377 if(ret < 0) 378 { 379 return ConditionResult.UNDEFINED; 380 } 381 else if(ret == 0) 382 { 383 return ConditionResult.FALSE; 384 } 385 else 386 { 387 return ConditionResult.TRUE; 388 } 389 } 390 391 392 393 /** 394 * {@inheritDoc} 395 */ 396 @Override() 397 public long numSubordinates(DN entryDN, boolean subtree) 398 throws DirectoryException 399 { 400 // If the requested entry was null, then return undefined. 401 if (entryDN == null) 402 { 403 return -1; 404 } 405 406 407 // If the requested entry was the monitor base entry, then return 408 // the number of monitor providers. 409 if (entryDN.equals(baseMonitorDN)) 410 { 411 // This backend is only 1 level deep so the count is the same for 412 // subtree and immediate subordinates. 413 return DirectoryServer.getMonitorProviders().size(); 414 } 415 416 417 // See if the monitor base entry is the immediate parent for the requested 418 // entry. If not, then its undefined. 419 DN parentDN = entryDN.getParentDNInSuffix(); 420 if ((parentDN == null) || (! parentDN.equals(baseMonitorDN))) 421 { 422 return -1; 423 } 424 425 426 // Get the RDN for the requested DN and make sure it is single-valued. 427 RDN entryRDN = entryDN.getRDN(); 428 if (entryRDN.isMultiValued()) 429 { 430 return -1; 431 } 432 433 434 // Get the RDN value and see if it matches the instance name for one of 435 // the directory server monitor providers. 436 String rdnValue = entryRDN.getAttributeValue(0).getStringValue(); 437 MonitorProvider<? extends MonitorProviderCfg> monitorProvider = 438 DirectoryServer.getMonitorProvider(rdnValue.toLowerCase()); 439 if (monitorProvider == null) 440 { 441 return -1; 442 } 443 444 return 0; 445 } 446 447 448 449 /** 450 * {@inheritDoc} 451 */ 452 @Override() 453 public Entry getEntry(DN entryDN) 454 throws DirectoryException 455 { 456 // If the requested entry was null, then throw an exception. 457 if (entryDN == null) 458 { 459 Message message = ERR_MONITOR_GET_ENTRY_NULL.get(); 460 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 461 message); 462 } 463 464 465 // If the requested entry was the monitor base entry, then retrieve it. 466 if (entryDN.equals(baseMonitorDN)) 467 { 468 return getBaseMonitorEntry(); 469 } 470 471 472 // See if the monitor base entry is the immediate parent for the requested 473 // entry. If not, then throw an exception. 474 DN parentDN = entryDN.getParentDNInSuffix(); 475 if ((parentDN == null) || (! parentDN.equals(baseMonitorDN))) 476 { 477 if (baseMonitorDN.isAncestorOf(entryDN)) 478 { 479 Message message = ERR_MONITOR_BASE_TOO_DEEP.get( 480 String.valueOf(entryDN), String.valueOf(baseMonitorDN)); 481 throw new DirectoryException( 482 ResultCode.NO_SUCH_OBJECT, message, baseMonitorDN, null); 483 } 484 else 485 { 486 Message message = ERR_MONITOR_INVALID_BASE.get( 487 String.valueOf(entryDN), String.valueOf(baseMonitorDN)); 488 throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message); 489 } 490 } 491 492 493 // Get the RDN for the requested DN and make sure it is single-valued. 494 RDN entryRDN = entryDN.getRDN(); 495 if (entryRDN.isMultiValued()) 496 { 497 Message message = 498 ERR_MONITOR_MULTIVALUED_RDN.get(String.valueOf(entryDN)); 499 throw new DirectoryException( 500 ResultCode.NO_SUCH_OBJECT, message, baseMonitorDN, null); 501 } 502 503 504 // Get the RDN value and see if it matches the instance name for one of 505 // the directory server monitor providers. 506 String rdnValue = entryRDN.getAttributeValue(0).getStringValue(); 507 MonitorProvider<? extends MonitorProviderCfg> monitorProvider = 508 DirectoryServer.getMonitorProvider(rdnValue.toLowerCase()); 509 if (monitorProvider == null) 510 { 511 Message message = 512 ERR_MONITOR_NO_SUCH_PROVIDER.get(String.valueOf(rdnValue)); 513 throw new DirectoryException( 514 ResultCode.NO_SUCH_OBJECT, message, baseMonitorDN, null); 515 } 516 517 518 // Take the data from the monitor provider and stuff it into an entry. 519 return getMonitorEntry(entryDN, monitorProvider); 520 } 521 522 523 524 /** 525 * {@inheritDoc} 526 */ 527 @Override() 528 public boolean entryExists(DN entryDN) 529 throws DirectoryException 530 { 531 if (entryDN.equals(baseMonitorDN)) 532 { 533 return true; 534 } 535 536 DN parentDN = entryDN.getParentDNInSuffix(); 537 if ((parentDN == null) || (! parentDN.equals(baseMonitorDN))) 538 { 539 return false; 540 } 541 542 RDN rdn = entryDN.getRDN(); 543 if (rdn.isMultiValued()) 544 { 545 return false; 546 } 547 548 String rdnValue = rdn.getAttributeValue(0).getStringValue(); 549 MonitorProvider monitorProvider = 550 DirectoryServer.getMonitorProvider(toLowerCase(rdnValue)); 551 return (monitorProvider != null); 552 } 553 554 555 556 /** 557 * Retrieves the base monitor entry for the Directory Server. 558 * 559 * @return The base monitor entry for the Directory Server. 560 */ 561 public Entry getBaseMonitorEntry() 562 { 563 HashMap<ObjectClass,String> monitorClasses = 564 new LinkedHashMap<ObjectClass,String>(3); 565 monitorClasses.putAll(monitorObjectClasses); 566 567 ObjectClass extensibleObjectOC = 568 DirectoryServer.getObjectClass(OC_EXTENSIBLE_OBJECT_LC, true); 569 monitorClasses.put(extensibleObjectOC, OC_EXTENSIBLE_OBJECT); 570 571 HashMap<AttributeType,List<Attribute>> monitorUserAttrs = 572 new LinkedHashMap<AttributeType,List<Attribute>>(); 573 574 HashMap<AttributeType,List<Attribute>> monitorOperationalAttrs = 575 new LinkedHashMap<AttributeType,List<Attribute>>(); 576 577 578 // Add the "cn" attribute. 579 Attribute cnAttr = createAttribute(ATTR_COMMON_NAME, ATTR_COMMON_NAME, 580 "monitor"); 581 ArrayList<Attribute> cnList = new ArrayList<Attribute>(1); 582 cnList.add(cnAttr); 583 monitorUserAttrs.put(cnAttr.getAttributeType(), cnList); 584 585 586 // Add the server product name. 587 Attribute productNameAttr = createAttribute(ATTR_PRODUCT_NAME, 588 ATTR_PRODUCT_NAME_LC, 589 DynamicConstants.PRODUCT_NAME); 590 ArrayList<Attribute> productNameList = new ArrayList<Attribute>(1); 591 productNameList.add(productNameAttr); 592 monitorUserAttrs.put(productNameAttr.getAttributeType(), productNameList); 593 594 595 // Add the vendor name. 596 Attribute vendorNameAttr = createAttribute(ATTR_VENDOR_NAME, 597 ATTR_VENDOR_NAME_LC, 598 SERVER_VENDOR_NAME); 599 ArrayList<Attribute> vendorNameList = new ArrayList<Attribute>(1); 600 vendorNameList.add(vendorNameAttr); 601 monitorUserAttrs.put(vendorNameAttr.getAttributeType(), vendorNameList); 602 603 604 // Add the vendor version. 605 Attribute versionAttr = createAttribute(ATTR_VENDOR_VERSION, 606 ATTR_VENDOR_VERSION_LC, 607 DirectoryServer.getVersionString()); 608 ArrayList<Attribute> versionList = new ArrayList<Attribute>(1); 609 versionList.add(versionAttr); 610 monitorUserAttrs.put(versionAttr.getAttributeType(), versionList); 611 612 613 // Add the server startup time. 614 Attribute startTimeAttr = 615 createAttribute(ATTR_START_TIME, ATTR_START_TIME_LC, 616 DirectoryServer.getStartTimeUTC()); 617 ArrayList<Attribute> startTimeList = new ArrayList<Attribute>(1); 618 startTimeList.add(startTimeAttr); 619 monitorUserAttrs.put(startTimeAttr.getAttributeType(), startTimeList); 620 621 622 // Add the current time. 623 Attribute currentTimeAttr = 624 createAttribute(ATTR_CURRENT_TIME, ATTR_CURRENT_TIME_LC, 625 TimeThread.getGMTTime()); 626 ArrayList<Attribute> currentTimeList = new ArrayList<Attribute>(1); 627 currentTimeList.add(currentTimeAttr); 628 monitorUserAttrs.put(currentTimeAttr.getAttributeType(), currentTimeList); 629 630 631 // Add the uptime as a human-readable string. 632 long upSeconds = 633 ((System.currentTimeMillis() - DirectoryServer.getStartTime()) / 1000); 634 long upDays = (upSeconds / 86400); 635 upSeconds %= 86400; 636 long upHours = (upSeconds / 3600); 637 upSeconds %= 3600; 638 long upMinutes = (upSeconds / 60); 639 upSeconds %= 60; 640 Message upTimeStr = 641 INFO_MONITOR_UPTIME.get(upDays, upHours, upMinutes, upSeconds); 642 Attribute upTimeAttr = createAttribute(ATTR_UP_TIME, ATTR_UP_TIME_LC, 643 upTimeStr.toString()); 644 ArrayList<Attribute> upTimeList = new ArrayList<Attribute>(1); 645 upTimeList.add(upTimeAttr); 646 monitorUserAttrs.put(upTimeAttr.getAttributeType(), upTimeList); 647 648 649 // Add the number of connections currently established. 650 long currentConns = DirectoryServer.getCurrentConnections(); 651 Attribute currentConnsAttr = createAttribute(ATTR_CURRENT_CONNS, 652 ATTR_CURRENT_CONNS_LC, 653 String.valueOf(currentConns)); 654 ArrayList<Attribute> currentConnsList = new ArrayList<Attribute>(1); 655 currentConnsList.add(currentConnsAttr); 656 monitorUserAttrs.put(currentConnsAttr.getAttributeType(), currentConnsList); 657 658 659 // Add the maximum number of connections established at one time. 660 long maxConns = DirectoryServer.getMaxConnections(); 661 Attribute maxConnsAttr = createAttribute(ATTR_MAX_CONNS, 662 ATTR_MAX_CONNS_LC, 663 String.valueOf(maxConns)); 664 ArrayList<Attribute> maxConnsList = new ArrayList<Attribute>(1); 665 maxConnsList.add(maxConnsAttr); 666 monitorUserAttrs.put(maxConnsAttr.getAttributeType(), maxConnsList); 667 668 669 // Add the total number of connections the server has accepted. 670 long totalConns = DirectoryServer.getTotalConnections(); 671 Attribute totalConnsAttr = createAttribute(ATTR_TOTAL_CONNS, 672 ATTR_TOTAL_CONNS_LC, 673 String.valueOf(totalConns)); 674 ArrayList<Attribute> totalConnsList = new ArrayList<Attribute>(1); 675 totalConnsList.add(totalConnsAttr); 676 monitorUserAttrs.put(totalConnsAttr.getAttributeType(), totalConnsList); 677 678 679 // Add all the user-defined attributes. 680 for (Attribute a : userDefinedAttributes) 681 { 682 AttributeType type = a.getAttributeType(); 683 684 if (type.isOperational()) 685 { 686 List<Attribute> attrs = monitorOperationalAttrs.get(type); 687 if (attrs == null) 688 { 689 attrs = new ArrayList<Attribute>(); 690 attrs.add(a); 691 monitorOperationalAttrs.put(type, attrs); 692 } 693 else 694 { 695 attrs.add(a); 696 } 697 } 698 else 699 { 700 List<Attribute> attrs = monitorUserAttrs.get(type); 701 if (attrs == null) 702 { 703 attrs = new ArrayList<Attribute>(); 704 attrs.add(a); 705 monitorUserAttrs.put(type, attrs); 706 } 707 else 708 { 709 attrs.add(a); 710 } 711 } 712 } 713 714 715 // Construct and return the entry. 716 Entry e = new Entry(baseMonitorDN, monitorClasses, monitorUserAttrs, 717 monitorOperationalAttrs); 718 e.processVirtualAttributes(); 719 return e; 720 } 721 722 723 724 /** 725 * Generates and returns a monitor entry based on the contents of the 726 * provided monitor provider. 727 * 728 * @param entryDN The DN to use for the entry. 729 * @param monitorProvider The monitor provider to use to obtain the 730 * information for the entry. 731 * 732 * @return The monitor entry generated from the information in the provided 733 * monitor provider. 734 */ 735 private Entry getMonitorEntry(DN entryDN, 736 MonitorProvider<? extends MonitorProviderCfg> 737 monitorProvider) 738 { 739 HashMap<ObjectClass,String> monitorClasses = 740 new LinkedHashMap<ObjectClass,String>(3); 741 monitorClasses.putAll(monitorObjectClasses); 742 743 ObjectClass monitorOC = monitorProvider.getMonitorObjectClass(); 744 monitorClasses.put(monitorOC, monitorOC.getPrimaryName()); 745 746 List<Attribute> monitorAttrs = monitorProvider.getMonitorData(); 747 HashMap<AttributeType,List<Attribute>> attrMap = 748 new LinkedHashMap<AttributeType,List<Attribute>>( 749 monitorAttrs.size()+1); 750 751 752 // Make sure to include the RDN attribute. 753 RDN entryRDN = entryDN.getRDN(); 754 AttributeType rdnType = entryRDN.getAttributeType(0); 755 AttributeValue rdnValue = entryRDN.getAttributeValue(0); 756 757 LinkedHashSet<AttributeValue> rdnValues = 758 new LinkedHashSet<AttributeValue>(1); 759 rdnValues.add(rdnValue); 760 761 Attribute rdnAttr = new Attribute(rdnType, entryRDN.getAttributeName(0), 762 rdnValues); 763 ArrayList<Attribute> rdnList = new ArrayList<Attribute>(1); 764 rdnList.add(rdnAttr); 765 attrMap.put(rdnType, rdnList); 766 767 768 // Take the rest of the information from the monitor data. 769 for (Attribute a : monitorAttrs) 770 { 771 AttributeType type = a.getAttributeType(); 772 773 List<Attribute> attrs = attrMap.get(type); 774 if (attrs == null) 775 { 776 attrs = new ArrayList<Attribute>(); 777 attrs.add(a); 778 attrMap.put(type, attrs); 779 } 780 else 781 { 782 attrs.add(a); 783 } 784 } 785 786 Entry e = new Entry(entryDN, monitorClasses, attrMap, 787 new HashMap<AttributeType,List<Attribute>>(0)); 788 e.processVirtualAttributes(); 789 return e; 790 } 791 792 793 794 /** 795 * Creates an attribute for a monitor entry with the following criteria. 796 * 797 * @param name The name for the attribute. 798 * @param lowerName The name for the attribute formatted in all lowercase 799 * characters. 800 * @param value The value to use for the attribute. 801 * 802 * @return The constructed attribute. 803 */ 804 private Attribute createAttribute(String name, String lowerName, 805 String value) 806 { 807 AttributeType type = DirectoryServer.getAttributeType(lowerName); 808 if (type == null) 809 { 810 type = DirectoryServer.getDefaultAttributeType(name); 811 } 812 813 LinkedHashSet<AttributeValue> attrValues = 814 new LinkedHashSet<AttributeValue>(1); 815 attrValues.add(new AttributeValue(type, new ASN1OctetString(value))); 816 817 return new Attribute(type, name, attrValues); 818 } 819 820 821 822 /** 823 * {@inheritDoc} 824 */ 825 @Override() 826 public void addEntry(Entry entry, AddOperation addOperation) 827 throws DirectoryException 828 { 829 Message message = 830 ERR_MONITOR_ADD_NOT_SUPPORTED.get(String.valueOf(entry.getDN())); 831 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); 832 } 833 834 835 836 /** 837 * {@inheritDoc} 838 */ 839 @Override() 840 public void deleteEntry(DN entryDN, DeleteOperation deleteOperation) 841 throws DirectoryException 842 { 843 Message message = 844 ERR_MONITOR_DELETE_NOT_SUPPORTED.get(String.valueOf(entryDN)); 845 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); 846 } 847 848 849 850 /** 851 * {@inheritDoc} 852 */ 853 @Override() 854 public void replaceEntry(Entry entry, ModifyOperation modifyOperation) 855 throws DirectoryException 856 { 857 Message message = ERR_MONITOR_MODIFY_NOT_SUPPORTED.get( 858 String.valueOf(entry.getDN()), String.valueOf(configEntryDN)); 859 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); 860 } 861 862 863 864 /** 865 * {@inheritDoc} 866 */ 867 @Override() 868 public void renameEntry(DN currentDN, Entry entry, 869 ModifyDNOperation modifyDNOperation) 870 throws DirectoryException 871 { 872 Message message = 873 ERR_MONITOR_MODIFY_DN_NOT_SUPPORTED.get(String.valueOf(currentDN)); 874 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); 875 } 876 877 878 879 /** 880 * {@inheritDoc} 881 */ 882 @Override() 883 public void search(SearchOperation searchOperation) 884 throws DirectoryException 885 { 886 // Get the base entry for the search, if possible. If it doesn't exist, 887 // then this will throw an exception. 888 DN baseDN = searchOperation.getBaseDN(); 889 Entry baseEntry = getEntry(baseDN); 890 891 892 // Figure out whether the base is the monitor base entry or one of its 893 // children for a specific monitor. 894 SearchScope scope = searchOperation.getScope(); 895 SearchFilter filter = searchOperation.getFilter(); 896 if (baseMonitorDN.equals(baseDN)) 897 { 898 // If it is a base-level or subtree search, then we need to look at the 899 // base monitor entry. 900 if ((scope == SearchScope.BASE_OBJECT) || 901 (scope == SearchScope.WHOLE_SUBTREE)) 902 { 903 if (filter.matchesEntry(baseEntry)) 904 { 905 searchOperation.returnEntry(baseEntry, null); 906 } 907 908 909 // If it is a base-level search, then we're done. 910 if (scope == SearchScope.BASE_OBJECT) 911 { 912 return; 913 } 914 } 915 916 917 // Iterate through all of the monitor providers defined in the server. 918 // Get an entry for each and compare it against the filter. 919 for (MonitorProvider<? extends MonitorProviderCfg> monitorProvider : 920 DirectoryServer.getMonitorProviders().values()) 921 { 922 DN providerDN = DirectoryServer.getMonitorProviderDN(monitorProvider); 923 Entry monitorEntry = getMonitorEntry(providerDN, monitorProvider); 924 if (filter.matchesEntry(monitorEntry)) 925 { 926 searchOperation.returnEntry(monitorEntry, null); 927 } 928 } 929 } 930 else 931 { 932 // Look at the scope for the search. We only need to return something if 933 // it is a base-level or subtree search. 934 if ((scope == SearchScope.BASE_OBJECT) || 935 (scope == SearchScope.WHOLE_SUBTREE)) 936 { 937 if (filter.matchesEntry(baseEntry)) 938 { 939 searchOperation.returnEntry(baseEntry, null); 940 } 941 } 942 } 943 } 944 945 946 947 /** 948 * {@inheritDoc} 949 */ 950 @Override() 951 public HashSet<String> getSupportedControls() 952 { 953 return supportedControls; 954 } 955 956 957 958 /** 959 * {@inheritDoc} 960 */ 961 @Override() 962 public HashSet<String> getSupportedFeatures() 963 { 964 return supportedFeatures; 965 } 966 967 968 969 /** 970 * {@inheritDoc} 971 */ 972 @Override() 973 public boolean supportsLDIFExport() 974 { 975 // We can export all the monitor entries as a point-in-time snapshot. 976 // TODO implementation of export is incomplete 977 // TODO export-ldif reports nonsense for upTime etc. 978 return false; 979 } 980 981 982 983 /** 984 * {@inheritDoc} 985 */ 986 @Override() 987 public void exportLDIF(LDIFExportConfig exportConfig) 988 throws DirectoryException 989 { 990 // TODO export-ldif reports nonsense for upTime etc. 991 992 // Create the LDIF writer. 993 LDIFWriter ldifWriter; 994 try 995 { 996 ldifWriter = new LDIFWriter(exportConfig); 997 } 998 catch (Exception e) 999 { 1000 if (debugEnabled()) 1001 { 1002 TRACER.debugCaught(DebugLogLevel.ERROR, e); 1003 } 1004 1005 Message message = ERR_ROOTDSE_UNABLE_TO_CREATE_LDIF_WRITER.get( 1006 stackTraceToSingleLineString(e)); 1007 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 1008 message); 1009 } 1010 1011 1012 // Write the base monitor entry to the LDIF. 1013 try 1014 { 1015 ldifWriter.writeEntry(getBaseMonitorEntry()); 1016 } 1017 catch (Exception e) 1018 { 1019 if (debugEnabled()) 1020 { 1021 TRACER.debugCaught(DebugLogLevel.ERROR, e); 1022 } 1023 1024 try 1025 { 1026 ldifWriter.close(); 1027 } 1028 catch (Exception e2) 1029 { 1030 if (debugEnabled()) 1031 { 1032 TRACER.debugCaught(DebugLogLevel.ERROR, e2); 1033 } 1034 } 1035 1036 Message message = ERR_MONITOR_UNABLE_TO_EXPORT_BASE.get( 1037 stackTraceToSingleLineString(e)); 1038 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 1039 message); 1040 } 1041 1042 1043 // Get all the monitor providers, convert them to entries, and write them to 1044 // LDIF. 1045 for (MonitorProvider monitorProvider : 1046 DirectoryServer.getMonitorProviders().values()) 1047 { 1048 try 1049 { 1050 // TODO implementation of export is incomplete 1051 } 1052 catch (Exception e) 1053 { 1054 if (debugEnabled()) 1055 { 1056 TRACER.debugCaught(DebugLogLevel.ERROR, e); 1057 } 1058 1059 try 1060 { 1061 ldifWriter.close(); 1062 } 1063 catch (Exception e2) 1064 { 1065 if (debugEnabled()) 1066 { 1067 TRACER.debugCaught(DebugLogLevel.ERROR, e2); 1068 } 1069 } 1070 1071 Message message = ERR_MONITOR_UNABLE_TO_EXPORT_PROVIDER_ENTRY. 1072 get(monitorProvider.getMonitorInstanceName(), 1073 stackTraceToSingleLineString(e)); 1074 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 1075 message); 1076 } 1077 } 1078 1079 1080 // Close the monitor provider and return. 1081 try 1082 { 1083 ldifWriter.close(); 1084 } 1085 catch (Exception e) 1086 { 1087 if (debugEnabled()) 1088 { 1089 TRACER.debugCaught(DebugLogLevel.ERROR, e); 1090 } 1091 } 1092 } 1093 1094 1095 1096 /** 1097 * {@inheritDoc} 1098 */ 1099 @Override() 1100 public boolean supportsLDIFImport() 1101 { 1102 // This backend does not support LDIF imports. 1103 return false; 1104 } 1105 1106 1107 1108 /** 1109 * {@inheritDoc} 1110 */ 1111 @Override() 1112 public LDIFImportResult importLDIF(LDIFImportConfig importConfig) 1113 throws DirectoryException 1114 { 1115 // This backend does not support LDIF imports. 1116 Message message = ERR_MONITOR_IMPORT_NOT_SUPPORTED.get(); 1117 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); 1118 } 1119 1120 1121 1122 /** 1123 * {@inheritDoc} 1124 */ 1125 @Override() 1126 public boolean supportsBackup() 1127 { 1128 // This backend does not provide a backup/restore mechanism. 1129 return false; 1130 } 1131 1132 1133 1134 /** 1135 * {@inheritDoc} 1136 */ 1137 @Override() 1138 public boolean supportsBackup(BackupConfig backupConfig, 1139 StringBuilder unsupportedReason) 1140 { 1141 // This backend does not provide a backup/restore mechanism. 1142 return false; 1143 } 1144 1145 1146 1147 /** 1148 * {@inheritDoc} 1149 */ 1150 @Override() 1151 public void createBackup(BackupConfig backupConfig) 1152 throws DirectoryException 1153 { 1154 // This backend does not provide a backup/restore mechanism. 1155 Message message = ERR_MONITOR_BACKUP_AND_RESTORE_NOT_SUPPORTED.get(); 1156 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); 1157 } 1158 1159 1160 1161 /** 1162 * {@inheritDoc} 1163 */ 1164 @Override() 1165 public void removeBackup(BackupDirectory backupDirectory, 1166 String backupID) 1167 throws DirectoryException 1168 { 1169 // This backend does not provide a backup/restore mechanism. 1170 Message message = ERR_MONITOR_BACKUP_AND_RESTORE_NOT_SUPPORTED.get(); 1171 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); 1172 } 1173 1174 1175 1176 /** 1177 * {@inheritDoc} 1178 */ 1179 @Override() 1180 public boolean supportsRestore() 1181 { 1182 // This backend does not provide a backup/restore mechanism. 1183 return false; 1184 } 1185 1186 1187 1188 /** 1189 * {@inheritDoc} 1190 */ 1191 @Override() 1192 public void restoreBackup(RestoreConfig restoreConfig) 1193 throws DirectoryException 1194 { 1195 // This backend does not provide a backup/restore mechanism. 1196 Message message = ERR_MONITOR_BACKUP_AND_RESTORE_NOT_SUPPORTED.get(); 1197 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); 1198 } 1199 1200 1201 1202 /** 1203 * {@inheritDoc} 1204 */ 1205 public boolean isConfigurationChangeAcceptable( 1206 MonitorBackendCfg backendCfg, 1207 List<Message> unacceptableReasons) 1208 { 1209 // We'll pretty much accept anything here as long as it isn't one of our 1210 // private attributes. 1211 return true; 1212 } 1213 1214 1215 1216 /** 1217 * {@inheritDoc} 1218 */ 1219 public ConfigChangeResult applyConfigurationChange( 1220 MonitorBackendCfg backendCfg) 1221 { 1222 ResultCode resultCode = ResultCode.SUCCESS; 1223 boolean adminActionRequired = false; 1224 ArrayList<Message> messages = new ArrayList<Message>(); 1225 1226 1227 // Check to see if there is a new set of user-defined attributes. 1228 ArrayList<Attribute> userAttrs = new ArrayList<Attribute>(); 1229 try 1230 { 1231 ConfigEntry configEntry = DirectoryServer.getConfigEntry(configEntryDN); 1232 for (List<Attribute> attrs : 1233 configEntry.getEntry().getUserAttributes().values()) 1234 { 1235 for (Attribute a : attrs) 1236 { 1237 if (! isMonitorConfigAttribute(a)) 1238 { 1239 userAttrs.add(a); 1240 } 1241 } 1242 } 1243 for (List<Attribute> attrs : 1244 configEntry.getEntry().getOperationalAttributes().values()) 1245 { 1246 for (Attribute a : attrs) 1247 { 1248 if (! isMonitorConfigAttribute(a)) 1249 { 1250 userAttrs.add(a); 1251 } 1252 } 1253 } 1254 } 1255 catch (Exception e) 1256 { 1257 if (debugEnabled()) 1258 { 1259 TRACER.debugCaught(DebugLogLevel.ERROR, e); 1260 } 1261 1262 1263 messages.add(ERR_CONFIG_BACKEND_ERROR_INTERACTING_WITH_BACKEND_ENTRY.get( 1264 String.valueOf(configEntryDN), 1265 stackTraceToSingleLineString(e))); 1266 resultCode = DirectoryServer.getServerErrorResultCode(); 1267 } 1268 1269 1270 userDefinedAttributes = userAttrs; 1271 1272 Message message = INFO_MONITOR_USING_NEW_USER_ATTRS.get(); 1273 messages.add(message); 1274 1275 1276 currentConfig = backendCfg; 1277 return new ConfigChangeResult(resultCode, adminActionRequired, messages); 1278 } 1279 1280 1281 1282 /** 1283 * {@inheritDoc} 1284 */ 1285 public void preloadEntryCache() throws UnsupportedOperationException { 1286 throw new UnsupportedOperationException("Operation not supported."); 1287 } 1288 }