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