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 2014 ForgeRock AS. 015 */ 016 017package org.forgerock.openig.audit.decoration; 018 019import static org.forgerock.util.Reject.*; 020 021import java.util.Set; 022import java.util.TreeSet; 023 024import org.forgerock.json.fluent.JsonValue; 025import org.forgerock.openig.audit.AuditEvent; 026import org.forgerock.openig.audit.AuditSource; 027import org.forgerock.openig.audit.AuditSystem; 028import org.forgerock.openig.audit.Tag; 029import org.forgerock.openig.decoration.Context; 030import org.forgerock.openig.decoration.helper.AbstractHandlerAndFilterDecorator; 031import org.forgerock.openig.filter.Filter; 032import org.forgerock.openig.handler.Handler; 033import org.forgerock.openig.heap.HeapException; 034 035/** 036 * The audit decorator can decorate both {@link Handler} and {@link Filter} instances. 037 * It triggers notifications ({@link AuditEvent}) to an {@link AuditSystem} sink. 038 * <p> 039 * Each {@link AuditEvent} includes a source marker that will indicate that the event comes 040 * from the decorated component. 041 * <p> 042 * Each notification includes a set of <i>tags</i> that helps the notification receiver to filter the 043 * events with simple matching rules. Here is the list of built-in tags: 044 * <ul> 045 * <li>{@link Tag#request}: The event happens before the delegate {@link Filter}/{@link Handler} is called</li> 046 * <li>{@link Tag#response}: The event happens after the delegate {@link Filter}/{@link Handler} was called</li> 047 * <li>{@link Tag#completed}: The event happens when the exchange has been completely handled <b>successfully</b> 048 * by the processing unit (always complements a {@link Tag#response} tag)</li> 049 * <li>{@link Tag#exception}: The event happens when the exchange has been handled with <b>errors</b> 050 * by the processing unit (always complements a {@link Tag#response} tag). Notice that this does not indicate that 051 * the source heap object is the origin of the failure (it may or may not have thrown the exception itself).</li> 052 * </ul> 053 * <p> 054 * The user can add extra tags to the list of tags that decorates the notification, in order to help 055 * notification qualification: 056 * <pre> 057 * {@code 058 * "audit": "route-#1" // add a single tag to the decorated component 059 * "audit": [ "super-tag", "route-#2" ] // add all of theses tags 060 * "audit": boolean, object, ... // any other format will be ignored 061 * } 062 * </pre> 063 * <p> 064 * Notice that the attribute name in the decorated object <b>has to be</b> the same as the decorator 065 * heap object name ({@code audit} in our example). 066 * <p> 067 * A default {@literal audit} decorator is automatically created when OpenIG starts. 068 * 069 * @see Tag 070 */ 071public class AuditDecorator extends AbstractHandlerAndFilterDecorator { 072 073 /** 074 * Key to retrieve a {@link AuditDecorator} instance from the {@link org.forgerock.openig.heap.Heap}. 075 */ 076 public static final String AUDIT_HEAP_KEY = "audit"; 077 078 private final AuditSystem auditSystem; 079 080 /** 081 * Builds a new AuditDecorator that will send events to the provided AuditSystem. 082 * 083 * @param auditSystem 084 * AuditSystem reference (cannot be {@code null}) 085 */ 086 public AuditDecorator(final AuditSystem auditSystem) { 087 this.auditSystem = checkNotNull(auditSystem); 088 } 089 090 @Override 091 protected Filter decorateFilter(final Filter delegate, final JsonValue decoratorConfig, final Context context) 092 throws HeapException { 093 return new AuditFilter(auditSystem, source(context, delegate), delegate, getAdditionalTags(decoratorConfig)); 094 } 095 096 @Override 097 protected Handler decorateHandler(final Handler delegate, final JsonValue decoratorConfig, final Context context) 098 throws HeapException { 099 return new AuditHandler(auditSystem, source(context, delegate), delegate, getAdditionalTags(decoratorConfig)); 100 } 101 102 private static AuditSource source(final Context context, final Object delegate) { 103 return new AuditSource(context.getName()); 104 } 105 106 private static Set<String> getAdditionalTags(final JsonValue config) { 107 Set<String> tags = new TreeSet<String>(); 108 if (config.isString()) { 109 tags.add(config.asString()); 110 } else if (config.isList()) { 111 tags.addAll(config.asSet(String.class)); 112 } 113 // otherwise, returns an empty set 114 return tags; 115 } 116}