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