/* * The contents of this file are subject to the terms of the Common Development and * Distribution License (the License). You may not use this file except in compliance with the * License. * * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the * specific language governing permission and limitations under the License. * * When distributing Covered Software, include this CDDL Header Notice in each file and include * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL * Header, with the fields enclosed by brackets [] replaced by your own identifying * information: "Portions Copyright [year] [name of copyright owner]". * * Copyright 2013-2015 ForgeRock AS. */ package org.opends.server.protocols.http; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import org.opends.server.protocols.ldap.LDAPStatistics; import org.opends.server.types.Attribute; /** * Collects statistics for HTTP. This class inherits from {@link LDAPStatistics} * to show the administrator how the underlying LDAP internal operations are * performing. */ public class HTTPStatistics extends LDAPStatistics { /** * Map containing the total number of requests per HTTP methods. *

* key: HTTP method => value: number of requests for that method. *

* Not using a ConcurrentMap implementation here because the keys are static. * The keys are static because they need to be listed in the schema which is * static. */ private Map requestMethodsTotalCount = new HashMap<>(); /** * Map containing the total execution time for the requests per HTTP methods. *

* key: HTTP method => value: total execution time for requests using that * method. *

* Not using a ConcurrentMap implementation here because the keys are static. * The keys are static because they need to be listed in the schema which is * static. */ private Map requestMethodsTotalTime = new HashMap<>(); /** * Total number of requests. The total number may be different than the sum of * the supported HTTP methods above because clients could use unsupported HTTP * methods. */ private AtomicInteger requestsTotalCount = new AtomicInteger(0); /** * Constructor for this class. * * @param instanceName * The name for this monitor provider instance. */ public HTTPStatistics(String instanceName) { super(instanceName); // List the HTTP methods supported by Rest2LDAP final List supportedHttpMethods = Arrays.asList("delete", "get", "patch", "post", "put"); for (String method : supportedHttpMethods) { requestMethodsTotalCount.put(method, new AtomicInteger(0)); requestMethodsTotalTime.put(method, new AtomicLong(0)); } } /** {@inheritDoc} */ @Override public void clearStatistics() { this.requestMethodsTotalCount.clear(); this.requestMethodsTotalTime.clear(); this.requestsTotalCount.set(0); super.clearStatistics(); } /** {@inheritDoc} */ @Override public List getMonitorData() { // first take a snapshot of all the data as fast as possible final int totalCount = this.requestsTotalCount.get(); final Map totalCountsSnapshot = new HashMap<>(); for (Entry entry : requestMethodsTotalCount.entrySet()) { totalCountsSnapshot.put(entry.getKey(), entry.getValue().get()); } final Map totalTimesSnapshot = new HashMap<>(); for (Entry entry1 : requestMethodsTotalTime.entrySet()) { totalTimesSnapshot.put(entry1.getKey(), entry1.getValue().get()); } // do the same with the underlying data final List results = super.getMonitorData(); addAll(results, totalCountsSnapshot, "ds-mon-http-", "-requests-total-count"); addAll(results, totalTimesSnapshot, "ds-mon-resident-time-http-", "-requests-total-time"); results.add(createAttribute("ds-mon-http-requests-total-count", Integer.toString(totalCount))); return results; } private void addAll(final List results, final Map toOutput, String prefix, String suffix) { for (Entry entry : toOutput.entrySet()) { final String httpMethod = entry.getKey(); final String nb = entry.getValue().toString(); results.add(createAttribute(prefix + httpMethod + suffix, nb)); } } /** * Adds a request to the stats using the provided HTTP method. * * @param httpMethod * the method of the HTTP request to add to the stats * @throws NullPointerException * if the httpMethod is null */ public void addRequest(String httpMethod) throws NullPointerException { AtomicInteger nb = this.requestMethodsTotalCount.get(httpMethod.toLowerCase()); if (nb != null) { nb.incrementAndGet(); } // else this is an unsupported HTTP method // always count any requests regardless of whether the method is supported this.requestsTotalCount.incrementAndGet(); } /** * Adds to the total time of an HTTP request method. * * @param httpMethod * the method of the HTTP request to add to the stats * @param time * the time to add to the total * @throws NullPointerException * if the httpMethod is null */ public void updateRequestMonitoringData(String httpMethod, long time) throws NullPointerException { AtomicLong nb = this.requestMethodsTotalTime.get(httpMethod.toLowerCase()); if (nb != null) { nb.addAndGet(time); } // else this is an unsupported HTTP method } }