opends/resource/config/config.ldif
@@ -487,7 +487,7 @@ ds-cfg-listen-address: 0.0.0.0 ds-cfg-listen-port: 8080 ds-cfg-accept-backlog: 128 #ds-cfg-keep-stats: true ds-cfg-keep-stats: true ds-cfg-use-tcp-keep-alive: true ds-cfg-use-tcp-no-delay: true ds-cfg-allow-tcp-reuse-address: true opends/resource/schema/02-config.ldif
@@ -3677,6 +3677,42 @@ SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'OpenDJ Directory Server' ) attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.120 NAME 'ds-mon-http-requests-total-count' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'OpenDJ Directory Server' ) attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.121 NAME 'ds-mon-http-delete-requests-total-count' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'OpenDJ Directory Server' ) attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.122 NAME 'ds-mon-http-get-requests-total-count' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'OpenDJ Directory Server' ) attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.123 NAME 'ds-mon-http-patch-requests-total-count' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'OpenDJ Directory Server' ) attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.124 NAME 'ds-mon-http-post-requests-total-count' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'OpenDJ Directory Server' ) attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.125 NAME 'ds-mon-http-put-requests-total-count' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'OpenDJ Directory Server' ) objectClasses: ( 1.3.6.1.4.1.26027.1.2.1 NAME 'ds-cfg-access-control-handler' SUP top @@ -3838,7 +3874,7 @@ STRUCTURAL MUST ds-cfg-listen-port MAY ( ds-cfg-listen-address $ # ds-cfg-keep-stats $ ds-cfg-keep-stats $ ds-cfg-use-tcp-keep-alive $ ds-cfg-use-tcp-no-delay $ ds-cfg-allow-tcp-reuse-address $ @@ -5591,7 +5627,13 @@ ds-mon-abandon-operations-total-count $ ds-mon-resident-time-abandon-operations-total-time $ ds-mon-extended-operations-total-count $ ds-mon-resident-time-extended-operations-total-time ) ds-mon-resident-time-extended-operations-total-time $ ds-mon-http-requests-total-count $ ds-mon-http-delete-requests-total-count $ ds-mon-http-get-requests-total-count $ ds-mon-http-patch-requests-total-count $ ds-mon-http-post-requests-total-count $ ds-mon-http-put-requests-total-count ) X-ORIGIN 'OpenDJ Directory Server' ) objectClasses: ( 1.3.6.1.4.1.36733.2.1.2.14 NAME 'ds-cfg-pbkdf2-password-storage-scheme' opends/src/admin/defn/org/opends/server/admin/std/HTTPConnectionHandlerConfiguration.xml
@@ -214,6 +214,32 @@ </ldap:attribute> </adm:profile> </adm:property> <adm:property name="keep-stats"> <adm:synopsis> Indicates whether the <adm:user-friendly-name /> should keep statistics. </adm:synopsis> <adm:description> If enabled, the <adm:user-friendly-name /> maintains statistics about the number and types of operations requested over HTTP and the amount of data sent and received. </adm:description> <adm:default-behavior> <adm:defined> <adm:value>true</adm:value> </adm:defined> </adm:default-behavior> <adm:syntax> <adm:boolean /> </adm:syntax> <adm:profile name="ldap"> <ldap:attribute> <ldap:name>ds-cfg-keep-stats</ldap:name> </ldap:attribute> </adm:profile> </adm:property> <adm:property name="max-request-size" advanced="true"> <adm:synopsis> Specifies the size in bytes of the largest HTTP request message that will opends/src/admin/messages/HTTPConnectionHandlerCfgDefn.properties
@@ -24,6 +24,8 @@ property.denied-client.requires-admin-action.synopsis=Changes to this property take effect immediately and do not interfere with connections that may have already been established. property.enabled.synopsis=Indicates whether the HTTP Connection Handler is enabled. property.java-class.synopsis=Specifies the fully-qualified name of the Java class that provides the HTTP Connection Handler implementation. property.keep-stats.synopsis=Indicates whether the HTTP Connection Handler should keep statistics. property.keep-stats.description=If enabled, the HTTP Connection Handler maintains statistics about the number and types of operations requested over HTTP and the amount of data sent and received. property.key-manager-provider.synopsis=Specifies the name of the key manager that should be used with this HTTP Connection Handler . property.key-manager-provider.requires-admin-action.synopsis=Changes to this property take effect immediately, but only for subsequent attempts to access the key manager provider for associated client connections. property.key-manager-provider.syntax.aggregation.constraint-synopsis=The referenced key manager provider must be enabled when the HTTP Connection Handler is enabled and configured to use SSL. opends/src/server/org/opends/server/protocols/http/CollectClientConnectionsFilter.java
@@ -279,6 +279,11 @@ ctx.requestInfo = new HTTPRequestInfo(ctx.request, clientConnection.getConnectionID()); if (this.connectionHandler.keepStats()) { this.connectionHandler.getStatTracker().addRequest( ctx.request.getMethod()); } try { if (!canProcessRequest(request, clientConnection)) opends/src/server/org/opends/server/protocols/http/HTTPClientConnection.java
@@ -48,9 +48,28 @@ import org.opends.messages.Message; import org.opends.messages.MessageBuilder; import org.opends.server.api.ClientConnection; import org.opends.server.core.AddOperation; import org.opends.server.core.BindOperation; import org.opends.server.core.CompareOperation; import org.opends.server.core.DeleteOperation; import org.opends.server.core.DirectoryServer; import org.opends.server.core.ExtendedOperation; import org.opends.server.core.ModifyDNOperation; import org.opends.server.core.ModifyOperation; import org.opends.server.core.SearchOperation; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.protocols.ldap.AddResponseProtocolOp; import org.opends.server.protocols.ldap.BindResponseProtocolOp; import org.opends.server.protocols.ldap.CompareResponseProtocolOp; import org.opends.server.protocols.ldap.DeleteResponseProtocolOp; import org.opends.server.protocols.ldap.ExtendedResponseProtocolOp; import org.opends.server.protocols.ldap.LDAPMessage; import org.opends.server.protocols.ldap.ModifyDNResponseProtocolOp; import org.opends.server.protocols.ldap.ModifyResponseProtocolOp; import org.opends.server.protocols.ldap.ProtocolOp; import org.opends.server.protocols.ldap.SearchResultDoneProtocolOp; import org.opends.server.protocols.ldap.SearchResultEntryProtocolOp; import org.opends.server.protocols.ldap.SearchResultReferenceProtocolOp; import org.opends.server.types.CancelRequest; import org.opends.server.types.CancelResult; import org.opends.server.types.DN; @@ -59,6 +78,7 @@ import org.opends.server.types.DisconnectReason; import org.opends.server.types.IntermediateResponse; import org.opends.server.types.Operation; import org.opends.server.types.OperationType; import org.opends.server.types.ResultCode; import org.opends.server.types.SearchResultEntry; import org.opends.server.types.SearchResultReference; @@ -76,7 +96,6 @@ // TODO JNR Confirm with Matt that persistent searches are inapplicable to // Rest2LDAP. // TODO JNR Should I override getIdleTime()? // TODO JNR Implement stats /** * Class grouping together an {@link Operation} and its associated @@ -128,6 +147,12 @@ private boolean disconnectRequested; /** * Indicates whether the connection should keep statistics regarding the * operations that it is performing. */ private final boolean keepStats; /** * The Map (messageID => {@link OperationWithFutureResult}) of all operations * currently in progress on this connection. */ @@ -153,6 +178,10 @@ /** The reference to the connection handler that accepted this connection. */ private final HTTPConnectionHandler connectionHandler; /** The statistics tracker associated with this client connection. */ private final HTTPStatistics statTracker; private boolean useNanoTime = false; /** The protocol in use for this client connection. */ private String protocol; @@ -206,6 +235,15 @@ this.securityStrengthFactor = calcSSF(request.getAttribute(SERVLET_SSF_CONSTANT)); this.statTracker = this.connectionHandler.getStatTracker(); this.keepStats = connectionHandler.keepStats(); if (this.keepStats) { this.statTracker.updateConnect(); this.useNanoTime = DirectoryServer.getUseNanoTime(); } this.connectionID = DirectoryServer.newConnectionAccepted(this); } @@ -283,6 +321,21 @@ @Override public void sendResponse(Operation operation) { if (keepStats) { long time; if (useNanoTime) { time = operation.getProcessingNanoTime(); } else { time = operation.getProcessingTime(); } this.statTracker.updateOperationMonitoringData(operation .getOperationType(), time); } OperationWithFutureResult op = this.operationsInProgress.get(operation.getMessageID()); if (op != null) @@ -290,6 +343,12 @@ try { op.futureResult.handleResult(getResponseResult(operation)); if (keepStats) { this.statTracker.updateMessageWritten(new LDAPMessage(operation .getMessageID(), toResponseProtocolOp(operation))); } } catch (ErrorResultException e) { @@ -298,6 +357,44 @@ } } private ProtocolOp toResponseProtocolOp(Operation operation) { final int resultCode = operation.getResultCode().getIntValue(); if (operation instanceof AddOperation) { return new AddResponseProtocolOp(resultCode); } else if (operation instanceof BindOperation) { return new BindResponseProtocolOp(resultCode); } else if (operation instanceof CompareOperation) { return new CompareResponseProtocolOp(resultCode); } else if (operation instanceof DeleteOperation) { return new DeleteResponseProtocolOp(resultCode); } else if (operation instanceof ExtendedOperation) { return new ExtendedResponseProtocolOp(resultCode); } else if (operation instanceof ModifyDNOperation) { return new ModifyDNResponseProtocolOp(resultCode); } else if (operation instanceof ModifyOperation) { return new ModifyResponseProtocolOp(resultCode); } else if (operation instanceof SearchOperation) { return new SearchResultDoneProtocolOp(resultCode); } throw new RuntimeException("Not implemented for operation " + operation); } /** {@inheritDoc} */ @Override public void sendSearchEntry(SearchOperation operation, @@ -309,6 +406,12 @@ { ((SearchResultHandler) op.futureResult.getResultHandler()) .handleEntry(from(searchEntry)); if (keepStats) { this.statTracker.updateMessageWritten(new LDAPMessage(operation .getMessageID(), new SearchResultEntryProtocolOp(searchEntry))); } } } @@ -323,6 +426,13 @@ { ((SearchResultHandler) op.futureResult.getResultHandler()) .handleReference(from(searchReference)); if (keepStats) { this.statTracker.updateMessageWritten(new LDAPMessage(operation .getMessageID(), new SearchResultReferenceProtocolOp( searchReference))); } } return connectionValid; } @@ -332,6 +442,12 @@ protected boolean sendIntermediateResponseMessage( IntermediateResponse intermediateResponse) { // if (keepStats) // { // this.statTracker.updateMessageWritten(new LDAPMessage( // intermediateResponse.getOperation().getMessageID(), // new IntermediateResponseProtocolOp(intermediateResponse.getOID()))); // } throw new RuntimeException("Not implemented"); } @@ -360,11 +476,10 @@ disconnectRequested = true; } // TODO JNR // if (keepStats) // { // statTracker.updateDisconnect(); // } if (keepStats) { statTracker.updateDisconnect(); } if (connectionID >= 0) { @@ -459,6 +574,15 @@ if (previousValue != null) { operationsPerformed.incrementAndGet(); final Operation operation = previousValue.operation; if (operation.getOperationType() == OperationType.ABANDON) { if (keepStats && operation.getResultCode() == ResultCode.CANCELED) { statTracker.updateAbandonedOperation(); } } } return previousValue != null; } @@ -517,6 +641,11 @@ op.futureResult.handleErrorResult(ErrorResultException .newErrorResult(org.forgerock.opendj.ldap.ResultCode.CANCELLED)); op.operation.abort(cancelRequest); if (keepStats) { statTracker.updateAbandonedOperation(); } } catch (Exception e) { // make sure all operations are cancelled, no matter what @@ -613,6 +742,16 @@ buffer.append(getServerAddress()).append(":").append(getServerPort()); } /** * Returns the statTracker for this connection handler. * * @return the statTracker for this connection handler */ public HTTPStatistics getStatTracker() { return statTracker; } /** {@inheritDoc} */ @Override public int getSSF() opends/src/server/org/opends/server/protocols/http/HTTPConnectionHandler.java
@@ -70,9 +70,12 @@ import org.forgerock.opendj.rest2ldap.AuthorizationPolicy; import org.forgerock.opendj.rest2ldap.Rest2LDAP; import org.forgerock.opendj.rest2ldap.servlet.Rest2LDAPContextFactory; import org.glassfish.grizzly.http.HttpProbe; import org.glassfish.grizzly.http.server.HttpServer; import org.glassfish.grizzly.http.server.HttpServerMonitoringConfig; import org.glassfish.grizzly.http.server.NetworkListener; import org.glassfish.grizzly.http.server.ServerConfiguration; import org.glassfish.grizzly.monitoring.MonitoringConfig; import org.glassfish.grizzly.nio.transport.TCPNIOTransport; import org.glassfish.grizzly.servlet.ServletRegistration; import org.glassfish.grizzly.servlet.WebappContext; @@ -94,6 +97,7 @@ import org.opends.server.extensions.NullTrustManagerProvider; import org.opends.server.loggers.HTTPAccessLogger; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.monitors.ClientConnectionMonitorProvider; import org.opends.server.types.ConfigChangeResult; import org.opends.server.types.DN; import org.opends.server.types.DebugLogLevel; @@ -144,6 +148,9 @@ /** The HTTP server embedded in OpenDJ. */ private HttpServer httpServer; /** The HTTP probe that collects stats. */ private HTTPStatsProbe httpProbe; /** * Holds the current client connections. Using {@link ConcurrentHashMap} to * ensure no concurrent reads/writes can happen and adds/removes are fast. We @@ -152,6 +159,15 @@ private Map<ClientConnection, ClientConnection> clientConnections = new ConcurrentHashMap<ClientConnection, ClientConnection>(); /** The set of statistics collected for this connection handler. */ private HTTPStatistics statTracker; /** * The client connection monitor provider associated with this connection * handler. */ private ClientConnectionMonitorProvider connMonitor; /** The unique name assigned to this connection handler. */ private String handlerName; @@ -245,6 +261,22 @@ messages); } if (config.isEnabled() && this.currentConfig.isEnabled() && isListening()) { // server was running and will still be running // if the "enabled" was flipped, leave it to the stop / start server to // handle it if (!this.currentConfig.isKeepStats() && config.isKeepStats()) { // it must now keep stats while it was not previously setHttpStatsProbe(); } else if (this.currentConfig.isKeepStats() && !config.isKeepStats() && this.httpProbe != null) { // it must NOT keep stats anymore getHttpConfig().removeProbes(this.httpProbe); this.httpProbe = null; } } this.initConfig = config; this.currentConfig = config; @@ -324,19 +356,17 @@ // Unregister this as a change listener. currentConfig.removeHTTPChangeListener(this); // TODO JNR // if (connMonitor != null) // { // String lowerName = toLowerCase(connMonitor.getMonitorInstanceName()); // DirectoryServer.deregisterMonitorProvider(lowerName); // } // // if (statTracker != null) // { // String lowerName = toLowerCase(statTracker.getMonitorInstanceName()); // DirectoryServer.deregisterMonitorProvider(lowerName); // } if (connMonitor != null) { String lowerName = toLowerCase(connMonitor.getMonitorInstanceName()); DirectoryServer.deregisterMonitorProvider(lowerName); } if (statTracker != null) { String lowerName = toLowerCase(statTracker.getMonitorInstanceName()); DirectoryServer.deregisterMonitorProvider(lowerName); } } /** {@inheritDoc} */ @@ -451,6 +481,16 @@ return handlerName; } /** * Retrieves the set of statistics maintained by this connection handler. * * @return The set of statistics maintained by this connection handler. */ public HTTPStatistics getStatTracker() { return statTracker; } /** {@inheritDoc} */ @Override public void initializeConnectionHandler(HTTPConnectionHandlerCfg config) @@ -484,14 +524,14 @@ } // TODO JNR // handle ds-cfg-keep-stats // handle ds-cfg-num-request-handlers?? // // Create and register monitors. // statTracker = new LDAPStatistics(handlerName + " Statistics"); // DirectoryServer.registerMonitorProvider(statTracker); // // connMonitor = new ClientConnectionMonitorProvider(this); // DirectoryServer.registerMonitorProvider(connMonitor); // Create and register monitors. statTracker = new HTTPStatistics(handlerName + " Statistics"); DirectoryServer.registerMonitorProvider(statTracker); connMonitor = new ClientConnectionMonitorProvider(this); DirectoryServer.registerMonitorProvider(connMonitor); // Register this as a change listener. config.addHTTPChangeListener(this); @@ -612,6 +652,17 @@ return isConfigurationAcceptable(configuration, unacceptableReasons); } /** * Indicates whether this connection handler should maintain usage statistics. * * @return <CODE>true</CODE> if this connection handler should maintain usage * statistics, or <CODE>false</CODE> if not. */ public boolean keepStats() { return currentConfig.isKeepStats(); } /** {@inheritDoc} */ @Override public void processServerShutdown(Message reason) @@ -715,6 +766,10 @@ this.httpServer.getServerConfiguration(); serverConfig.setMaxBufferedPostSize(requestSize); serverConfig.setMaxFormPostSize(requestSize); if (keepStats()) { setHttpStatsProbe(); } try { @@ -799,6 +854,19 @@ } } private void setHttpStatsProbe() { httpProbe = new HTTPStatsProbe(this.statTracker); getHttpConfig().addProbes(httpProbe); } private MonitoringConfig<HttpProbe> getHttpConfig() { final HttpServerMonitoringConfig monitoringCfg = this.httpServer.getServerConfiguration().getMonitoringConfig(); return monitoringCfg.getHttpConfig(); } private HTTPAuthenticationConfig getAuthenticationConfig( final JsonValue configuration) { @@ -867,6 +935,7 @@ TRACER.debugInfo("Stopping HTTP server..."); this.httpServer.stop(); this.httpServer = null; this.httpProbe = null; TRACER.debugInfo("HTTP server stopped"); logError(NOTE_CONNHANDLER_STOPPED_LISTENING.get(handlerName)); } opends/src/server/org/opends/server/protocols/http/HTTPStatistics.java
New file @@ -0,0 +1,144 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2013 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 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. * <p> * key: HTTP verb => value: number of requests for that verb. * </p> * Not using a ConcurrentMap implementation because the keys are static. The * keys are static because they need to be listed in the schema which is * static. */ private Map<String, AtomicInteger> nbRequests = new HashMap<String, AtomicInteger>(); /** * 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 * verbs. */ private AtomicInteger nbRequestsTotalCount = 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<String> supportedHttpMethods = Arrays.asList("delete", "get", "patch", "post", "put"); for (String method : supportedHttpMethods) { nbRequests.put(method, new AtomicInteger(0)); } } /** {@inheritDoc} */ @Override public void clearStatistics() { this.nbRequests.clear(); super.clearStatistics(); } /** {@inheritDoc} */ @Override public List<Attribute> getMonitorData() { // first take a snapshot of all the data as fast as possible final Map<String, Integer> snapshot = new HashMap<String, Integer>(); for (Entry<String, AtomicInteger> entry : this.nbRequests.entrySet()) { snapshot.put(entry.getKey(), entry.getValue().get()); } // do the same with the underlying data final List<Attribute> results = super.getMonitorData(); // then add the snapshot data to the monitoring data int total = 0; for (Entry<String, Integer> entry : snapshot.entrySet()) { final String httpMethod = entry.getKey(); final Integer nb = entry.getValue(); final String number = nb.toString(); // nb should never be null since we only allow supported HTTP methods total += nb; results.add(createAttribute("ds-mon-http-" + httpMethod + "-requests-total-count", number)); } results.add(createAttribute("ds-mon-http-requests-total-count", Integer .toString(total))); return results; } /** * 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.nbRequests.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.nbRequestsTotalCount.incrementAndGet(); } } opends/src/server/org/opends/server/protocols/http/HTTPStatsProbe.java
New file @@ -0,0 +1,76 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2013 ForgeRock AS */ package org.opends.server.protocols.http; import org.glassfish.grizzly.Buffer; import org.glassfish.grizzly.Connection; import org.glassfish.grizzly.http.HttpProbe; /** * Probe that collect some statistics on the HTTP server: bytes read and bytes * written to the HTTP connection. We are using * {@link #onDataReceivedEvent(Connection, Buffer)} and * {@link #onDataSentEvent(Connection, Buffer)} because they are the only ones * that really output the number of bytes sent on the wire, including data * formatting for the HTTP protocol (chunk size, etc.). * <p> * Use * <code>curl "http://localhost:8080/users?_queryFilter=true&_prettyPrint=true" * --trace-ascii output.txt</code> to trace the client-server communication. * </p> */ @SuppressWarnings("rawtypes") final class HTTPStatsProbe extends HttpProbe.Adapter { private final HTTPStatistics statTracker; /** * Constructs and object from this class. * * @param statTracker * the statistic tracker */ public HTTPStatsProbe(HTTPStatistics statTracker) { this.statTracker = statTracker; } /** {@inheritDoc} */ @Override public void onDataSentEvent(Connection connection, Buffer buffer) { this.statTracker.updateBytesWritten(buffer.limit()); } /** {@inheritDoc} */ @Override public void onDataReceivedEvent(Connection connection, Buffer buffer) { this.statTracker.updateBytesRead(buffer.limit()); } } opends/src/server/org/opends/server/protocols/http/SdkConnectionAdapter.java
@@ -58,20 +58,42 @@ import org.forgerock.opendj.ldap.responses.CompareResult; import org.forgerock.opendj.ldap.responses.ExtendedResult; import org.forgerock.opendj.ldap.responses.Result; import org.opends.server.core.AbandonOperation; import org.opends.server.core.AbandonOperationBasis; import org.opends.server.core.AddOperation; import org.opends.server.core.AddOperationBasis; import org.opends.server.core.BindOperation; import org.opends.server.core.BindOperationBasis; import org.opends.server.core.BoundedWorkQueueStrategy; import org.opends.server.core.CompareOperation; import org.opends.server.core.CompareOperationBasis; import org.opends.server.core.DeleteOperation; import org.opends.server.core.DeleteOperationBasis; import org.opends.server.core.ExtendedOperation; import org.opends.server.core.ExtendedOperationBasis; import org.opends.server.core.ModifyDNOperation; import org.opends.server.core.ModifyDNOperationBasis; import org.opends.server.core.ModifyOperation; import org.opends.server.core.ModifyOperationBasis; import org.opends.server.core.QueueingStrategy; import org.opends.server.core.SearchOperation; import org.opends.server.core.SearchOperationBasis; import org.opends.server.core.UnbindOperation; import org.opends.server.core.UnbindOperationBasis; import org.opends.server.loggers.HTTPRequestInfo; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.protocols.ldap.AbandonRequestProtocolOp; import org.opends.server.protocols.ldap.AddRequestProtocolOp; import org.opends.server.protocols.ldap.BindRequestProtocolOp; import org.opends.server.protocols.ldap.CompareRequestProtocolOp; import org.opends.server.protocols.ldap.DeleteRequestProtocolOp; import org.opends.server.protocols.ldap.ExtendedRequestProtocolOp; import org.opends.server.protocols.ldap.LDAPMessage; import org.opends.server.protocols.ldap.ModifyDNRequestProtocolOp; import org.opends.server.protocols.ldap.ModifyRequestProtocolOp; import org.opends.server.protocols.ldap.ProtocolOp; import org.opends.server.protocols.ldap.SearchRequestProtocolOp; import org.opends.server.protocols.ldap.UnbindRequestProtocolOp; import org.opends.server.types.AuthenticationInfo; import org.opends.server.types.ByteString; import org.opends.server.types.DebugLogLevel; @@ -142,6 +164,15 @@ { operation.setInnerOperation(this.clientConnection.isInnerConnection()); HTTPConnectionHandler connHandler = this.clientConnection.getConnectionHandler(); if (connHandler.keepStats()) { connHandler.getStatTracker().updateMessageRead( new LDAPMessage(operation.getMessageID(), toRequestProtocolOp(operation))); } // need this raw cast here to fool the compiler's generic type safety // Problem here is due to the generic type R on enqueueOperation() clientConnection.addOperationInProgress(operation, @@ -163,6 +194,69 @@ return futureResult; } private ProtocolOp toRequestProtocolOp(Operation operation) { operation.getResultCode().getIntValue(); if (operation instanceof AbandonOperation) { final AbandonOperation op = (AbandonOperation) operation; return new AbandonRequestProtocolOp(op.getIDToAbandon()); } else if (operation instanceof AddOperation) { final AddOperation op = (AddOperation) operation; return new AddRequestProtocolOp(op.getRawEntryDN(), op.getRawAttributes()); } else if (operation instanceof BindOperation) { final BindOperation op = (BindOperation) operation; return new BindRequestProtocolOp(op.getRawBindDN(), op.getSASLMechanism(), op.getSASLCredentials()); } else if (operation instanceof CompareOperation) { final CompareOperation op = (CompareOperation) operation; return new CompareRequestProtocolOp(op.getRawEntryDN(), op .getRawAttributeType(), op.getAssertionValue()); } else if (operation instanceof DeleteOperation) { final DeleteOperation op = (DeleteOperation) operation; return new DeleteRequestProtocolOp(op.getRawEntryDN()); } else if (operation instanceof ExtendedOperation) { final ExtendedOperation op = (ExtendedOperation) operation; return new ExtendedRequestProtocolOp(op.getRequestOID(), op .getRequestValue()); } else if (operation instanceof ModifyDNOperation) { final ModifyDNOperation op = (ModifyDNOperation) operation; return new ModifyDNRequestProtocolOp(op.getRawEntryDN(), op .getRawNewRDN(), op.deleteOldRDN(), op.getRawNewSuperior()); } else if (operation instanceof ModifyOperation) { final ModifyOperation op = (ModifyOperation) operation; return new ModifyRequestProtocolOp(op.getRawEntryDN(), op .getRawModifications()); } else if (operation instanceof SearchOperation) { final SearchOperation op = (SearchOperation) operation; return new SearchRequestProtocolOp(op.getRawBaseDN(), op.getScope(), op .getDerefPolicy(), op.getSizeLimit(), op.getTimeLimit(), op .getTypesOnly(), op.getRawFilter(), op.getAttributes()); } else if (operation instanceof UnbindOperation) { return new UnbindRequestProtocolOp(); } throw new RuntimeException("Not implemented for operation " + operation); } /** {@inheritDoc} */ @Override public FutureResult<Void> abandonAsync(AbandonRequest request) opends/src/server/org/opends/server/protocols/ldap/LDAPStatistics.java
@@ -35,8 +35,9 @@ import static org.opends.server.util.ServerConstants.*; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicLong; import org.opends.messages.Message; import org.opends.server.admin.std.server.MonitorProviderCfg; import org.opends.server.api.MonitorProvider; @@ -198,10 +199,9 @@ * is requested. */ @Override public ArrayList<Attribute> getMonitorData() public List<Attribute> getMonitorData() { ArrayList<Attribute> attrs = new ArrayList<Attribute>(); List<Attribute> attrs = new ArrayList<Attribute>(); long tmpAbandonRequests = abandonRequests.get(); long tmpAddRequests = addRequests.get(); @@ -662,7 +662,7 @@ * The value to use for the attribute. * @return the constructed attribute. */ private Attribute createAttribute(String name, String value) protected Attribute createAttribute(String name, String value) { AttributeType attrType = DirectoryServer.getAttributeType(name.toLowerCase());