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}