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.monitor;
018
019import java.util.LinkedHashMap;
020import java.util.Set;
021import java.util.concurrent.ConcurrentHashMap;
022import java.util.concurrent.atomic.AtomicLong;
023
024import org.forgerock.http.Handler;
025import org.forgerock.http.protocol.Request;
026import org.forgerock.http.protocol.Response;
027import org.forgerock.http.protocol.Status;
028import org.forgerock.openig.heap.GenericHeapObject;
029import org.forgerock.openig.util.EnumUtil;
030import org.forgerock.services.context.Context;
031import org.forgerock.util.promise.NeverThrowsException;
032import org.forgerock.util.promise.Promise;
033import org.forgerock.util.promise.Promises;
034
035
036/**
037 * Sample statistic endpoint provider that returns JSON-formatted collected statistic values.
038 */
039@Deprecated
040public class MonitorEndpointHandler extends GenericHeapObject implements org.forgerock.openig.audit.AuditEventListener,
041                                                                         Handler {
042
043    private static final Set<String> STANDARD_TAG_NAMES = EnumUtil.names(org.forgerock.openig.audit.Tag.class);
044
045    private ConcurrentHashMap<String, TagMetric> metrics = new ConcurrentHashMap<>();
046
047    @Override
048    public Promise<Response, NeverThrowsException> handle(final Context context, final Request request) {
049        Response response = new Response();
050        response.getEntity().setJson(metrics);
051        response.setStatus(Status.OK);
052        return Promises.newResultPromise(response);
053    }
054
055    @Override
056    public void onAuditEvent(final org.forgerock.openig.audit.AuditEvent event) {
057        // Extract the set of additional tags
058        Set<String> tags = event.getTags();
059
060        // Manage counter for each of the additional tags, effectively performing correlations
061        for (String tag : tags) {
062            // Ignore tag if it is a standard one
063            if (STANDARD_TAG_NAMES.contains(tag)) {
064                continue;
065            }
066            TagMetric metric = getMetric(tag);
067            if (tags.contains(org.forgerock.openig.audit.Tag.request.name())) {
068                metric.active.incrementAndGet();
069            }
070            if (tags.contains(org.forgerock.openig.audit.Tag.response.name())) {
071                metric.active.decrementAndGet();
072                if (tags.contains(org.forgerock.openig.audit.Tag.completed.name())) {
073                    metric.completed.incrementAndGet();
074                }
075                if (tags.contains(org.forgerock.openig.audit.Tag.exception.name())) {
076                    metric.errors.incrementAndGet();
077                }
078            }
079        }
080    }
081
082    private TagMetric getMetric(final String name) {
083        TagMetric counter = metrics.get(name);
084        if (counter != null) {
085            return counter;
086        }
087        TagMetric newCounter = new TagMetric();
088        TagMetric oldCounter = metrics.putIfAbsent(name, newCounter);
089        return oldCounter != null ? oldCounter : newCounter;
090    }
091
092    /**
093     * TagMetric extends a Map implementation to benefit of the natural mapping into a JSON object.
094     * Still have 'in progress', 'completed' and 'internal errors' fields for easy programmatic access.
095     * TagMetric is thread-safe because no additional fields are put in the structure after creation.
096     */
097    private static class TagMetric extends LinkedHashMap<String, AtomicLong> {
098
099        public static final long serialVersionUID = 1L;
100
101        final AtomicLong active = new AtomicLong();
102        final AtomicLong completed = new AtomicLong();
103        final AtomicLong errors = new AtomicLong();
104
105        public TagMetric() {
106            put("in progress", active);
107            put("completed", completed);
108            put("internal errors", errors);
109        }
110    }
111
112    /**
113     * Creates and initializes a MonitorEndpointHandler in a heap environment.
114     */
115    @Deprecated
116    public static class Heaplet extends
117            org.forgerock.openig.audit.ConditionalAuditEventListener.ConditionalListenerHeaplet {
118        @Override
119        protected org.forgerock.openig.audit.AuditEventListener createListener() {
120            return new MonitorEndpointHandler();
121        }
122    }
123
124}