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-2015 ForgeRock AS.
015 */
016
017package org.forgerock.openig.audit;
018
019import static java.lang.Boolean.*;
020import static org.forgerock.openig.el.Bindings.bindings;
021import static org.forgerock.openig.heap.Keys.AUDIT_SYSTEM_HEAP_KEY;
022import static org.forgerock.openig.util.JsonValues.*;
023
024import org.forgerock.openig.el.Expression;
025import org.forgerock.openig.heap.GenericHeaplet;
026import org.forgerock.openig.heap.HeapException;
027
028/**
029 * A ConditionalAuditEventListener is conditionally invoked {@link AuditEventListener}.
030 * <p>
031 * It delegates to a given {@link AuditEventListener} if the configured condition evaluates to {@code true}.
032 * If the condition evaluates to anything else ({@code false}, {@code null}, ...), the result is considered
033 * as a {@code false}, and the delegate listener will not be invoked.
034 * <p>
035 * This class is not intended to be sub-classed, although its associated {@link org.forgerock.openig.heap.Heaplet} is.
036 */
037@Deprecated
038public class ConditionalAuditEventListener implements AuditEventListener {
039
040    private final AuditEventListener delegate;
041    private final Expression<Boolean> condition;
042
043    /**
044     * Builds a new ConditionalAuditEventListener that will delegates to the given {@code delegate} under the given
045     * {@code condition}.
046     *
047     * @param delegate
048     *         conditionally invoked listener
049     * @param condition
050     *         condition to evaluate
051     */
052    public ConditionalAuditEventListener(final AuditEventListener delegate, final Expression<Boolean> condition) {
053        this.delegate = delegate;
054        this.condition = condition;
055    }
056
057    @Override
058    public void onAuditEvent(final AuditEvent event) {
059        // Only process selected events
060        if (TRUE.equals(condition.eval(bindings("event", event)))) {
061            delegate.onAuditEvent(event);
062        }
063    }
064
065    /**
066     * Creates and initializes a ConditionalListenerHeaplet in a heap environment.
067     * <p>
068     * Here is an example of an extending heap object declaration:
069     * <pre>
070     *     {@code
071     *     {
072     *         "name": "...",
073     *         "type": "MySubTypeExtendingConditionalListener",
074     *         "config": {
075     *             "condition": "${contains(event.tags, 'marker')}",
076     *             "any other": "configuration attributes"
077     *         }
078     *     }
079     *     }
080     * </pre>
081     * The {@literal condition} property declares the condition that needs to be evaluated to {@code true} in order
082     * to forward the event notification to the real listener. It defaults to {@code ${true}} (will always invoke the
083     * delegate).
084     */
085    @Deprecated
086    public abstract static class ConditionalListenerHeaplet extends GenericHeaplet {
087
088        private AuditSystem auditSystem;
089        private ConditionalAuditEventListener conditional;
090
091        @Override
092        public Object create() throws HeapException {
093            Expression<Boolean> condition = asExpression(config.get("condition").defaultTo("${true}"),
094                    Boolean.class);
095            auditSystem = heap.get(AUDIT_SYSTEM_HEAP_KEY, AuditSystem.class);
096            AuditEventListener listener = createListener();
097            conditional = new ConditionalAuditEventListener(listener, condition);
098            auditSystem.registerListener(conditional);
099            return listener;
100        }
101
102        /**
103         * Creates a new {@link AuditEventListener} that will be invoked if condition yields.
104         *
105         * @return a new {@link AuditEventListener} that will be invoked if condition yields.
106         * @throws HeapException
107         *             if an exception occurred during creation of the heap object or any of its dependencies.
108         * @throws org.forgerock.json.JsonValueException
109         *             if the heaplet (or one of its dependencies) has a malformed configuration.
110         */
111        protected abstract AuditEventListener createListener() throws HeapException;
112
113        @Override
114        public void destroy() {
115            super.destroy();
116            auditSystem.unregisterListener(conditional);
117        }
118    }
119}