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.loggers; 028 import org.opends.messages.Message; 029 030 031 032 import java.util.concurrent.CopyOnWriteArrayList; 033 import java.util.List; 034 import java.util.ArrayList; 035 import java.lang.reflect.Method; 036 import java.lang.reflect.InvocationTargetException; 037 038 import org.opends.server.api.ClientConnection; 039 import org.opends.server.api.AccessLogPublisher; 040 import org.opends.server.core.*; 041 import org.opends.server.types.*; 042 import org.opends.server.admin.std.server.AccessLogPublisherCfg; 043 import org.opends.server.admin.std.meta.AccessLogPublisherCfgDefn; 044 import org.opends.server.admin.server.ConfigurationAddListener; 045 import org.opends.server.admin.server.ConfigurationChangeListener; 046 import org.opends.server.admin.server.ConfigurationDeleteListener; 047 import org.opends.server.admin.ClassPropertyDefinition; 048 import org.opends.server.config.ConfigException; 049 import static org.opends.server.loggers.debug.DebugLogger.*; 050 import org.opends.server.loggers.debug.DebugTracer; 051 import static org.opends.messages.ConfigMessages. 052 ERR_CONFIG_LOGGER_CANNOT_CREATE_LOGGER; 053 import static org.opends.messages.ConfigMessages. 054 ERR_CONFIG_LOGGER_INVALID_ACCESS_LOGGER_CLASS; 055 056 import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString; 057 058 059 /** 060 * This class defines the wrapper that will invoke all registered access loggers 061 * for each type of request received or response sent. 062 */ 063 public class AccessLogger implements 064 ConfigurationAddListener<AccessLogPublisherCfg>, 065 ConfigurationDeleteListener<AccessLogPublisherCfg>, 066 ConfigurationChangeListener<AccessLogPublisherCfg> 067 { 068 /** 069 * The tracer object for the debug logger. 070 */ 071 private static final DebugTracer TRACER = getTracer(); 072 073 // The set of access loggers that have been registered with the server. It 074 // will initially be empty. 075 static CopyOnWriteArrayList<AccessLogPublisher> accessPublishers = 076 new CopyOnWriteArrayList<AccessLogPublisher>(); 077 078 // The singleton instance of this class for configuration purposes. 079 static final AccessLogger instance = new AccessLogger(); 080 081 082 083 /** 084 * Retrieve the singleton instance of this class. 085 * 086 * @return The singleton instance of this logger. 087 */ 088 public static AccessLogger getInstance() 089 { 090 return instance; 091 } 092 093 /** 094 * Add an access log publisher to the access logger. 095 * 096 * @param publisher The access log publisher to add. 097 */ 098 public synchronized static void addAccessLogPublisher( 099 AccessLogPublisher publisher) 100 { 101 accessPublishers.add(publisher); 102 } 103 104 /** 105 * Remove an access log publisher from the access logger. 106 * 107 * @param publisher The access log publisher to remove. 108 * @return The publisher that was removed or null if it was not found. 109 */ 110 public synchronized static boolean removeAccessLogPublisher( 111 AccessLogPublisher publisher) 112 { 113 boolean removed = accessPublishers.remove(publisher); 114 115 if(removed) 116 { 117 publisher.close(); 118 } 119 120 return removed; 121 } 122 123 /** 124 * Removes all existing access log publishers from the logger. 125 */ 126 public synchronized static void removeAllAccessLogPublishers() 127 { 128 for(AccessLogPublisher publisher : accessPublishers) 129 { 130 publisher.close(); 131 } 132 133 accessPublishers.clear(); 134 } 135 136 /** 137 * Initializes all the access log publishers. 138 * 139 * @param configs The access log publisher configurations. 140 * @throws ConfigException 141 * If an unrecoverable problem arises in the process of 142 * performing the initialization as a result of the server 143 * configuration. 144 * @throws InitializationException 145 * If a problem occurs during initialization that is not 146 * related to the server configuration. 147 */ 148 public void initializeAccessLogger(List<AccessLogPublisherCfg> configs) 149 throws ConfigException, InitializationException 150 { 151 for(AccessLogPublisherCfg config : configs) 152 { 153 config.addAccessChangeListener(this); 154 155 if(config.isEnabled()) 156 { 157 AccessLogPublisher AccessLogPublisher = getAccessPublisher(config); 158 159 addAccessLogPublisher(AccessLogPublisher); 160 } 161 } 162 } 163 164 /** 165 * {@inheritDoc} 166 */ 167 public boolean isConfigurationAddAcceptable( 168 AccessLogPublisherCfg config, 169 List<Message> unacceptableReasons) 170 { 171 return !config.isEnabled() || 172 isJavaClassAcceptable(config, unacceptableReasons); 173 } 174 175 /** 176 * {@inheritDoc} 177 */ 178 public boolean isConfigurationChangeAcceptable( 179 AccessLogPublisherCfg config, 180 List<Message> unacceptableReasons) 181 { 182 return !config.isEnabled() || 183 isJavaClassAcceptable(config, unacceptableReasons); 184 } 185 186 /** 187 * {@inheritDoc} 188 */ 189 public ConfigChangeResult applyConfigurationAdd(AccessLogPublisherCfg config) 190 { 191 // Default result code. 192 ResultCode resultCode = ResultCode.SUCCESS; 193 boolean adminActionRequired = false; 194 ArrayList<Message> messages = new ArrayList<Message>(); 195 196 config.addAccessChangeListener(this); 197 198 if(config.isEnabled()) 199 { 200 try 201 { 202 AccessLogPublisher AccessLogPublisher = getAccessPublisher(config); 203 204 addAccessLogPublisher(AccessLogPublisher); 205 } 206 catch(ConfigException e) 207 { 208 if (debugEnabled()) 209 { 210 TRACER.debugCaught(DebugLogLevel.ERROR, e); 211 } 212 messages.add(e.getMessageObject()); 213 resultCode = DirectoryServer.getServerErrorResultCode(); 214 } 215 catch (Exception e) 216 { 217 if (debugEnabled()) 218 { 219 TRACER.debugCaught(DebugLogLevel.ERROR, e); 220 } 221 222 messages.add(ERR_CONFIG_LOGGER_CANNOT_CREATE_LOGGER.get( 223 String.valueOf(config.dn().toString()), 224 stackTraceToSingleLineString(e))); 225 resultCode = DirectoryServer.getServerErrorResultCode(); 226 } 227 } 228 return new ConfigChangeResult(resultCode, adminActionRequired, messages); 229 } 230 231 /** 232 * {@inheritDoc} 233 */ 234 public ConfigChangeResult applyConfigurationChange( 235 AccessLogPublisherCfg config) 236 { 237 // Default result code. 238 ResultCode resultCode = ResultCode.SUCCESS; 239 boolean adminActionRequired = false; 240 ArrayList<Message> messages = new ArrayList<Message>(); 241 242 DN dn = config.dn(); 243 244 AccessLogPublisher accessLogPublisher = null; 245 for(AccessLogPublisher publisher : accessPublishers) 246 { 247 if(publisher.getDN().equals(dn)) 248 { 249 accessLogPublisher = publisher; 250 break; 251 } 252 } 253 254 if(accessLogPublisher == null) 255 { 256 if(config.isEnabled()) 257 { 258 // Needs to be added and enabled. 259 return applyConfigurationAdd(config); 260 } 261 } 262 else 263 { 264 if(config.isEnabled()) 265 { 266 // The publisher is currently active, so we don't need to do anything. 267 // Changes to the class name cannot be 268 // applied dynamically, so if the class name did change then 269 // indicate that administrative action is required for that 270 // change to take effect. 271 String className = config.getJavaClass(); 272 if(!className.equals(accessLogPublisher.getClass().getName())) 273 { 274 adminActionRequired = true; 275 } 276 } 277 else 278 { 279 // The publisher is being disabled so shut down and remove. 280 removeAccessLogPublisher(accessLogPublisher); 281 } 282 } 283 284 return new ConfigChangeResult(resultCode, adminActionRequired, messages); 285 } 286 287 /** 288 * {@inheritDoc} 289 */ 290 public boolean isConfigurationDeleteAcceptable( 291 AccessLogPublisherCfg config, 292 List<Message> unacceptableReasons) 293 { 294 DN dn = config.dn(); 295 296 AccessLogPublisher accessLogPublisher = null; 297 for(AccessLogPublisher publisher : accessPublishers) 298 { 299 if(publisher.getDN().equals(dn)) 300 { 301 accessLogPublisher = publisher; 302 break; 303 } 304 } 305 306 return accessLogPublisher != null; 307 308 } 309 310 /** 311 * {@inheritDoc} 312 */ 313 public ConfigChangeResult applyConfigurationDelete( 314 AccessLogPublisherCfg config) 315 { 316 // Default result code. 317 ResultCode resultCode = ResultCode.SUCCESS; 318 boolean adminActionRequired = false; 319 320 AccessLogPublisher accessLogPublisher = null; 321 for(AccessLogPublisher publisher : accessPublishers) 322 { 323 if(publisher.getDN().equals(config.dn())) 324 { 325 accessLogPublisher = publisher; 326 break; 327 } 328 } 329 330 if(accessLogPublisher != null) 331 { 332 removeAccessLogPublisher(accessLogPublisher); 333 } 334 else 335 { 336 resultCode = ResultCode.NO_SUCH_OBJECT; 337 } 338 339 return new ConfigChangeResult(resultCode, adminActionRequired); 340 } 341 342 private boolean isJavaClassAcceptable(AccessLogPublisherCfg config, 343 List<Message> unacceptableReasons) 344 { 345 String className = config.getJavaClass(); 346 AccessLogPublisherCfgDefn d = AccessLogPublisherCfgDefn.getInstance(); 347 ClassPropertyDefinition pd = 348 d.getJavaClassPropertyDefinition(); 349 // Load the class and cast it to a DebugLogPublisher. 350 AccessLogPublisher publisher = null; 351 Class<? extends AccessLogPublisher> theClass; 352 try { 353 theClass = pd.loadClass(className, AccessLogPublisher.class); 354 publisher = theClass.newInstance(); 355 } catch (Exception e) { 356 Message message = ERR_CONFIG_LOGGER_INVALID_ACCESS_LOGGER_CLASS.get( 357 className, 358 config.dn().toString(), 359 String.valueOf(e)); 360 unacceptableReasons.add(message); 361 return false; 362 } 363 // Check that the implementation class implements the correct interface. 364 try { 365 // Determine the initialization method to use: it must take a 366 // single parameter which is the exact type of the configuration 367 // object. 368 Method method = theClass.getMethod("isConfigurationAcceptable", 369 AccessLogPublisherCfg.class, 370 List.class); 371 Boolean acceptable = (Boolean) method.invoke(publisher, config, 372 unacceptableReasons); 373 374 if (! acceptable) 375 { 376 return false; 377 } 378 } catch (Exception e) { 379 Message message = ERR_CONFIG_LOGGER_INVALID_ACCESS_LOGGER_CLASS.get( 380 className, 381 config.dn().toString(), 382 String.valueOf(e)); 383 unacceptableReasons.add(message); 384 return false; 385 } 386 // The class is valid as far as we can tell. 387 return true; 388 } 389 390 private AccessLogPublisher getAccessPublisher(AccessLogPublisherCfg config) 391 throws ConfigException { 392 String className = config.getJavaClass(); 393 AccessLogPublisherCfgDefn d = AccessLogPublisherCfgDefn.getInstance(); 394 ClassPropertyDefinition pd = 395 d.getJavaClassPropertyDefinition(); 396 // Load the class and cast it to a AccessLogPublisher. 397 Class<? extends AccessLogPublisher> theClass; 398 AccessLogPublisher AccessLogPublisher; 399 try { 400 theClass = pd.loadClass(className, AccessLogPublisher.class); 401 AccessLogPublisher = theClass.newInstance(); 402 403 // Determine the initialization method to use: it must take a 404 // single parameter which is the exact type of the configuration 405 // object. 406 Method method = theClass.getMethod("initializeAccessLogPublisher", config 407 .configurationClass()); 408 method.invoke(AccessLogPublisher, config); 409 } 410 catch (InvocationTargetException ite) 411 { 412 // Rethrow the exceptions thrown be the invoked method. 413 Throwable e = ite.getTargetException(); 414 Message message = ERR_CONFIG_LOGGER_INVALID_ACCESS_LOGGER_CLASS.get( 415 className, config.dn().toString(), stackTraceToSingleLineString(e)); 416 throw new ConfigException(message, e); 417 } 418 catch (Exception e) 419 { 420 Message message = ERR_CONFIG_LOGGER_INVALID_ACCESS_LOGGER_CLASS.get( 421 className, config.dn().toString(), String.valueOf(e)); 422 throw new ConfigException(message, e); 423 } 424 425 // The access publisher has been successfully initialized. 426 return AccessLogPublisher; 427 } 428 429 430 431 432 /** 433 * Writes a message to the access logger with information about a new client 434 * connection that has been established, regardless of whether it will be 435 * immediately terminated. 436 * 437 * @param clientConnection The client connection that has been established. 438 */ 439 public static void logConnect(ClientConnection clientConnection) 440 { 441 for (AccessLogPublisher publisher : accessPublishers) 442 { 443 publisher.logConnect(clientConnection); 444 } 445 } 446 447 448 449 /** 450 * Writes a message to the access logger with information about the 451 * termination of an existing client connection. 452 * 453 * @param clientConnection The client connection that has been terminated. 454 * @param disconnectReason A generic disconnect reason for the connection 455 * termination. 456 * @param message A human-readable message that can provide 457 * additional information about the disconnect. 458 */ 459 public static void logDisconnect(ClientConnection clientConnection, 460 DisconnectReason disconnectReason, 461 Message message) 462 { 463 for (AccessLogPublisher publisher : accessPublishers) 464 { 465 publisher.logDisconnect(clientConnection, disconnectReason, message); 466 } 467 } 468 469 470 /** 471 * Writes a message to the access logger with information about the abandon 472 * request associated with the provided abandon operation. 473 * 474 * @param abandonOperation The abandon operation containing the information 475 * to use to log the abandon request. 476 */ 477 public static void logAbandonRequest(AbandonOperation abandonOperation) 478 { 479 for (AccessLogPublisher publisher : accessPublishers) 480 { 481 publisher.logAbandonRequest(abandonOperation); 482 } 483 } 484 485 486 487 /** 488 * Writes a message to the access logger with information about the result of 489 * the provided abandon operation. 490 * 491 * @param abandonOperation The abandon operation containing the information 492 * to use to log the abandon result. 493 */ 494 public static void logAbandonResult(AbandonOperation abandonOperation) 495 { 496 for (AccessLogPublisher publisher : accessPublishers) 497 { 498 publisher.logAbandonResult(abandonOperation); 499 } 500 } 501 502 503 504 /** 505 * Writes a message to the access logger with information about the add 506 * request associated with the provided add operation. 507 * 508 * @param addOperation The add operation containing the information to use 509 * to log the add request. 510 */ 511 public static void logAddRequest(AddOperation addOperation) 512 { 513 for (AccessLogPublisher publisher : accessPublishers) 514 { 515 publisher.logAddRequest(addOperation); 516 } 517 } 518 519 520 521 /** 522 * Writes a message to the access logger with information about the add 523 * response associated with the provided add operation. 524 * 525 * @param addOperation The add operation containing the information to use 526 * to log the add response. 527 */ 528 public static void logAddResponse(AddOperation addOperation) 529 { 530 for (AccessLogPublisher publisher : accessPublishers) 531 { 532 publisher.logAddResponse(addOperation); 533 } 534 } 535 536 537 538 /** 539 * Writes a message to the access logger with information about the bind 540 * request associated with the provided bind operation. 541 * 542 * @param bindOperation The bind operation containing the information to use 543 * to log the bind request. 544 */ 545 public static void logBindRequest(BindOperation bindOperation) 546 { 547 for (AccessLogPublisher publisher : accessPublishers) 548 { 549 publisher.logBindRequest(bindOperation); 550 } 551 } 552 553 554 555 /** 556 * Writes a message to the access logger with information about the bind 557 * response associated with the provided bind operation. 558 * 559 * @param bindOperation The bind operation containing the information to use 560 * to log the bind response. 561 */ 562 public static void logBindResponse(BindOperation bindOperation) 563 { 564 for (AccessLogPublisher publisher : accessPublishers) 565 { 566 publisher.logBindResponse(bindOperation); 567 } 568 } 569 570 571 572 /** 573 * Writes a message to the access logger with information about the compare 574 * request associated with the provided compare operation. 575 * 576 * @param compareOperation The compare operation containing the information 577 * to use to log the compare request. 578 */ 579 public static void logCompareRequest(CompareOperation compareOperation) 580 { 581 for (AccessLogPublisher publisher : accessPublishers) 582 { 583 publisher.logCompareRequest(compareOperation); 584 } 585 } 586 587 588 589 /** 590 * Writes a message to the access logger with information about the compare 591 * response associated with the provided compare operation. 592 * 593 * @param compareOperation The compare operation containing the information 594 * to use to log the compare response. 595 */ 596 public static void logCompareResponse(CompareOperation compareOperation) 597 { 598 for (AccessLogPublisher publisher : accessPublishers) 599 { 600 publisher.logCompareResponse(compareOperation); 601 } 602 } 603 604 605 606 /** 607 * Writes a message to the access logger with information about the delete 608 * request associated with the provided delete operation. 609 * 610 * @param deleteOperation The delete operation containing the information to 611 * use to log the delete request. 612 */ 613 public static void logDeleteRequest(DeleteOperation deleteOperation) 614 { 615 for (AccessLogPublisher publisher : accessPublishers) 616 { 617 publisher.logDeleteRequest(deleteOperation); 618 } 619 } 620 621 622 623 /** 624 * Writes a message to the access logger with information about the delete 625 * response associated with the provided delete operation. 626 * 627 * @param deleteOperation The delete operation containing the information to 628 * use to log the delete response. 629 */ 630 public static void logDeleteResponse(DeleteOperation deleteOperation) 631 { 632 for (AccessLogPublisher publisher : accessPublishers) 633 { 634 publisher.logDeleteResponse(deleteOperation); 635 } 636 } 637 638 639 640 /** 641 * Writes a message to the access logger with information about the extended 642 * request associated with the provided extended operation. 643 * 644 * @param extendedOperation The extended operation containing the 645 * information to use to log the extended request. 646 */ 647 public static void logExtendedRequest(ExtendedOperation extendedOperation) 648 { 649 for (AccessLogPublisher publisher : accessPublishers) 650 { 651 publisher.logExtendedRequest(extendedOperation); 652 } 653 } 654 655 656 657 /** 658 * Writes a message to the access logger with information about the extended 659 * response associated with the provided extended operation. 660 * 661 * @param extendedOperation The extended operation containing the 662 * information to use to log the extended response. 663 */ 664 public static void logExtendedResponse(ExtendedOperation extendedOperation) 665 { 666 for (AccessLogPublisher publisher : accessPublishers) 667 { 668 publisher.logExtendedResponse(extendedOperation); 669 } 670 } 671 672 673 674 /** 675 * Writes a message to the access logger with information about the modify 676 * request associated with the provided modify operation. 677 * 678 * @param modifyOperation The modify operation containing the information to 679 * use to log the modify request. 680 */ 681 public static void logModifyRequest(ModifyOperation modifyOperation) 682 { 683 for (AccessLogPublisher publisher : accessPublishers) 684 { 685 publisher.logModifyRequest(modifyOperation); 686 } 687 } 688 689 690 691 /** 692 * Writes a message to the access logger with information about the modify 693 * response associated with the provided modify operation. 694 * 695 * @param modifyOperation The modify operation containing the information to 696 * use to log the modify response. 697 */ 698 public static void logModifyResponse(ModifyOperation modifyOperation) 699 { 700 for (AccessLogPublisher publisher : accessPublishers) 701 { 702 publisher.logModifyResponse(modifyOperation); 703 } 704 } 705 706 707 708 /** 709 * Writes a message to the access logger with information about the modify DN 710 * request associated with the provided modify DN operation. 711 * 712 * @param modifyDNOperation The modify DN operation containing the 713 * information to use to log the modify DN request. 714 */ 715 public static void logModifyDNRequest(ModifyDNOperation modifyDNOperation) 716 { 717 for (AccessLogPublisher publisher : accessPublishers) 718 { 719 publisher.logModifyDNRequest(modifyDNOperation); 720 } 721 } 722 723 724 725 /** 726 * Writes a message to the access logger with information about the modify DN 727 * response associated with the provided modify DN operation. 728 * 729 * @param modifyDNOperation The modify DN operation containing the 730 * information to use to log the modify DN 731 * response. 732 */ 733 public static void logModifyDNResponse(ModifyDNOperation modifyDNOperation) 734 { 735 for (AccessLogPublisher publisher : accessPublishers) 736 { 737 publisher.logModifyDNResponse(modifyDNOperation); 738 } 739 } 740 741 742 743 /** 744 * Writes a message to the access logger with information about the search 745 * request associated with the provided search operation. 746 * 747 * @param searchOperation The search operation containing the information to 748 * use to log the search request. 749 */ 750 public static void logSearchRequest(SearchOperation searchOperation) 751 { 752 for (AccessLogPublisher publisher : accessPublishers) 753 { 754 publisher.logSearchRequest(searchOperation); 755 } 756 } 757 758 759 760 /** 761 * Writes a message to the access logger with information about the search 762 * result entry that matches the criteria associated with the provided search 763 * operation. 764 * 765 * @param searchOperation The search operation with which the search result 766 * entry is associated. 767 * @param searchEntry The search result entry to be logged. 768 */ 769 public static void logSearchResultEntry(SearchOperation searchOperation, 770 SearchResultEntry searchEntry) 771 { 772 for (AccessLogPublisher publisher : accessPublishers) 773 { 774 publisher.logSearchResultEntry(searchOperation, searchEntry); 775 } 776 } 777 778 779 780 /** 781 * Writes a message to the access logger with information about the search 782 * result reference returned while processing the associated search operation. 783 * 784 * @param searchOperation The search operation with which the search result 785 * reference is associated. 786 * @param searchReference The search result reference to be logged. 787 */ 788 public static void logSearchResultReference(SearchOperation searchOperation, 789 SearchResultReference searchReference) 790 { 791 for (AccessLogPublisher publisher : accessPublishers) 792 { 793 publisher.logSearchResultReference(searchOperation, searchReference); 794 } 795 } 796 797 798 799 /** 800 * Writes a message to the access logger with information about the completion 801 * of the provided search operation. 802 * 803 * @param searchOperation The search operation containing the information 804 * to use to log the search result done message. 805 */ 806 public static void logSearchResultDone(SearchOperation searchOperation) 807 { 808 for (AccessLogPublisher publisher : accessPublishers) 809 { 810 publisher.logSearchResultDone(searchOperation); 811 } 812 } 813 814 815 816 /** 817 * Writes a message to the access logger with information about the unbind 818 * request associated with the provided unbind operation. 819 * 820 * @param unbindOperation The unbind operation containing the information to 821 * use to log the unbind request. 822 */ 823 public static void logUnbind(UnbindOperation unbindOperation) 824 { 825 for (AccessLogPublisher publisher : accessPublishers) 826 { 827 publisher.logUnbind(unbindOperation); 828 } 829 } 830 } 831