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 2013-2016 ForgeRock AS. 015 */ 016package org.opends.server.protocols.http; 017 018import java.util.Arrays; 019import java.util.HashMap; 020import java.util.List; 021import java.util.Map; 022import java.util.Map.Entry; 023import java.util.concurrent.atomic.AtomicInteger; 024import java.util.concurrent.atomic.AtomicLong; 025 026import org.opends.server.api.MonitorData; 027import org.opends.server.protocols.ldap.LDAPStatistics; 028 029/** 030 * Collects statistics for HTTP. This class inherits from {@link LDAPStatistics} 031 * to show the administrator how the underlying LDAP internal operations are 032 * performing. 033 */ 034public class HTTPStatistics extends LDAPStatistics 035{ 036 037 /** 038 * Map containing the total number of requests per HTTP methods. 039 * <p> 040 * key: HTTP method => value: number of requests for that method. 041 * </p> 042 * Not using a ConcurrentMap implementation here because the keys are static. 043 * The keys are static because they need to be listed in the schema which is 044 * static. 045 */ 046 private Map<String, AtomicInteger> requestMethodsTotalCount = new HashMap<>(); 047 /** 048 * Map containing the total execution time for the requests per HTTP methods. 049 * <p> 050 * key: HTTP method => value: total execution time for requests using that 051 * method. 052 * </p> 053 * Not using a ConcurrentMap implementation here because the keys are static. 054 * The keys are static because they need to be listed in the schema which is 055 * static. 056 */ 057 private Map<String, AtomicLong> requestMethodsTotalTime = new HashMap<>(); 058 /** 059 * Total number of requests. The total number may be different than the sum of 060 * the supported HTTP methods above because clients could use unsupported HTTP 061 * methods. 062 */ 063 private AtomicInteger requestsTotalCount = new AtomicInteger(0); 064 065 /** 066 * Constructor for this class. 067 * 068 * @param instanceName 069 * The name for this monitor provider instance. 070 */ 071 public HTTPStatistics(String instanceName) 072 { 073 super(instanceName); 074 075 // List the HTTP methods supported by Rest2LDAP 076 final List<String> supportedHttpMethods = 077 Arrays.asList("delete", "get", "patch", "post", "put"); 078 for (String method : supportedHttpMethods) 079 { 080 requestMethodsTotalCount.put(method, new AtomicInteger(0)); 081 requestMethodsTotalTime.put(method, new AtomicLong(0)); 082 } 083 } 084 085 /** {@inheritDoc} */ 086 @Override 087 public void clearStatistics() 088 { 089 this.requestMethodsTotalCount.clear(); 090 this.requestMethodsTotalTime.clear(); 091 this.requestsTotalCount.set(0); 092 093 super.clearStatistics(); 094 } 095 096 @Override 097 public MonitorData getMonitorData() 098 { 099 final MonitorData results = super.getMonitorData(); 100 addAll(results, requestMethodsTotalCount, "ds-mon-http-", "-requests-total-count"); 101 addAll(results, requestMethodsTotalTime, "ds-mon-resident-time-http-", "-requests-total-time"); 102 results.add("ds-mon-http-requests-total-count", requestsTotalCount.get()); 103 return results; 104 } 105 106 private void addAll(final MonitorData results, 107 final Map<String, ?> toOutput, String prefix, String suffix) 108 { 109 for (Entry<String, ?> entry : toOutput.entrySet()) 110 { 111 final String httpMethod = entry.getKey(); 112 final String nb = entry.getValue().toString(); 113 results.add(prefix + httpMethod + suffix, nb); 114 } 115 } 116 117 /** 118 * Adds a request to the stats using the provided HTTP method. 119 * 120 * @param httpMethod 121 * the method of the HTTP request to add to the stats 122 * @throws NullPointerException 123 * if the httpMethod is null 124 */ 125 public void addRequest(String httpMethod) throws NullPointerException 126 { 127 AtomicInteger nb = 128 this.requestMethodsTotalCount.get(httpMethod.toLowerCase()); 129 if (nb != null) 130 { 131 nb.incrementAndGet(); 132 } // else this is an unsupported HTTP method 133 // always count any requests regardless of whether the method is supported 134 this.requestsTotalCount.incrementAndGet(); 135 } 136 137 /** 138 * Adds to the total time of an HTTP request method. 139 * 140 * @param httpMethod 141 * the method of the HTTP request to add to the stats 142 * @param time 143 * the time to add to the total 144 * @throws NullPointerException 145 * if the httpMethod is null 146 */ 147 public void updateRequestMonitoringData(String httpMethod, long time) 148 throws NullPointerException 149 { 150 AtomicLong nb = this.requestMethodsTotalTime.get(httpMethod.toLowerCase()); 151 if (nb != null) 152 { 153 nb.addAndGet(time); 154 } // else this is an unsupported HTTP method 155 } 156}