/* * 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 2006-2009 Sun Microsystems, Inc. * Portions Copyright 2011-2013 ForgeRock AS */ package org.opends.server.protocols.jmx; import java.net.InetAddress; import java.util.*; import java.util.concurrent.atomic.*; import javax.management.Notification; import javax.management.NotificationListener; import javax.management.remote.JMXConnectionNotification; import org.opends.messages.Message; import org.opends.messages.MessageBuilder; import org.opends.server.api.*; import org.opends.server.core.*; import org.opends.server.core.networkgroups.NetworkGroup; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.protocols.internal.InternalSearchListener; import org.opends.server.protocols.internal.InternalSearchOperation; import org.opends.server.protocols.ldap.LDAPFilter; import org.opends.server.types.*; import static org.opends.messages.ProtocolMessages.*; import static org.opends.server.loggers.debug.DebugLogger.*; /** * This class defines the set of methods and structures that must be implemented * by a Directory Server client connection. * */ public class JmxClientConnection extends ClientConnection implements NotificationListener { /** * The tracer object for the debug logger. */ private static final DebugTracer TRACER = getTracer(); /** The message ID counter to use for jmx connections. */ private AtomicInteger nextMessageID; /** The operation ID counter to use for operations on this connection. */ private AtomicLong nextOperationID; /** The empty operation list for this connection. */ private LinkedList<Operation> operationList; /** The connection ID for this client connection. */ private long connectionID; /** * The JMX connection ID for this client connection. */ protected String jmxConnectionID = null; /** * The reference to the connection handler that accepted this connection. */ private JmxConnectionHandler jmxConnectionHandler; /** * Indicate that the disconnect process is started. */ private boolean disconnectStarted = false; /** * Creates a new Jmx client connection that will be authenticated as * as the specified user. * * @param jmxConnectionHandler * The connection handler on which we should be registered * @param authInfo * the User authentication info */ public JmxClientConnection(JmxConnectionHandler jmxConnectionHandler, AuthenticationInfo authInfo) { super(); this.setNetworkGroup(NetworkGroup.getAdminNetworkGroup()); nextMessageID = new AtomicInteger(1); nextOperationID = new AtomicLong(0); this.jmxConnectionHandler = jmxConnectionHandler; jmxConnectionHandler.registerClientConnection(this); setAuthenticationInfo(authInfo); connectionID = DirectoryServer.newConnectionAccepted(this); if (connectionID < 0) { disconnect(DisconnectReason.ADMIN_LIMIT_EXCEEDED, true, ERR_CONNHANDLER_REJECTED_BY_SERVER.get()); } operationList = new LinkedList<Operation>(); // // Register the Jmx Notification listener (this) jmxConnectionHandler.getRMIConnector().jmxRmiConnectorNoClientCertificate .addNotificationListener(this, null, null); } /** * {@inheritDoc} */ @Override public void handleNotification(Notification notif, Object handback) { JMXConnectionNotification jcn ; // // We don't have the expected notification if ( ! (notif instanceof JMXConnectionNotification)) { return ; } else { jcn = (JMXConnectionNotification) notif ; } // // The only handled notifications are CLOSED and FAILED if ((!jcn.getType().equals(JMXConnectionNotification.CLOSED)) && (!jcn.getType().equals(JMXConnectionNotification.FAILED))) { return; } // // Check if the closed connection corresponds to the current connection if (!(jcn.getConnectionId().equals(jmxConnectionID))) { return; } // // Ok, we can perform the unbind: call finalize disconnect(DisconnectReason.CLIENT_DISCONNECT, false, null); } /** * Retrieves the operation ID that should be used for the next Jmx * operation. * * @return The operation ID that should be used for the next Jmx * operation. */ public long nextOperationID() { long opID = nextOperationID.getAndIncrement(); if (opID < 0) { synchronized (nextOperationID) { if (nextOperationID.get() < 0) { nextOperationID.set(1); return 0; } else { return nextOperationID.getAndIncrement(); } } } return opID; } /** * Retrieves the message ID that should be used for the next Jmx * operation. * * @return The message ID that should be used for the next Jmx * operation. */ public int nextMessageID() { int msgID = nextMessageID.getAndIncrement(); if (msgID < 0) { synchronized (nextMessageID) { if (nextMessageID.get() < 0) { nextMessageID.set(2); return 1; } else { return nextMessageID.getAndIncrement(); } } } return msgID; } /** * Retrieves the unique identifier that has been assigned to this connection. * * @return The unique identifier that has been assigned to this connection. */ @Override public long getConnectionID() { return connectionID; } /** * Retrieves the connection handler that accepted this client connection. * * @return The connection handler that accepted this client connection. */ @Override public ConnectionHandler<?> getConnectionHandler() { return jmxConnectionHandler; } /** * Retrieves the protocol that the client is using to communicate with the * Directory Server. * * @return The protocol that the client is using to communicate with the * Directory Server. */ @Override public String getProtocol() { return "jmx"; } /** * Retrieves a string representation of the address of the client. * * @return A string representation of the address of the client. */ @Override public String getClientAddress() { return "jmx"; } /** * Retrieves the port number for this connection on the client system. * * @return The port number for this connection on the client system. */ @Override public int getClientPort() { return -1; } /** * Retrieves a string representation of the address on the server to which the * client connected. * * @return A string representation of the address on the server to which the * client connected. */ @Override public String getServerAddress() { return "jmx"; } /** * Retrieves the port number for this connection on the server * system if available. * * @return The port number for this connection on the server system * or -1 if there is no server port associated with this * connection (e.g. internal client). */ @Override public int getServerPort() { return -1; } /** * Retrieves the <CODE>java.net.InetAddress</CODE> associated with the remote * client system. * * @return The <CODE>java.net.InetAddress</CODE> associated with the remote * client system. It may be <CODE>null</CODE> if the client is not * connected over an IP-based connection. */ @Override public InetAddress getRemoteAddress() { return null; } /** * Retrieves the <CODE>java.net.InetAddress</CODE> for the Directory Server * system to which the client has established the connection. * * @return The <CODE>java.net.InetAddress</CODE> for the Directory Server * system to which the client has established the connection. It may * be <CODE>null</CODE> if the client is not connected over an * IP-based connection. */ @Override public InetAddress getLocalAddress() { return null; } /** {@inheritDoc} */ @Override public boolean isConnectionValid() { return !disconnectStarted; } /** * Indicates whether this client connection is currently using a secure * mechanism to communicate with the server. Note that this may change over * time based on operations performed by the client or server (e.g., it may go * from <CODE>false</CODE> to <CODE>true</CODE> if the client uses the * StartTLS extended operation). * * @return <CODE>true</CODE> if the client connection is currently using a * secure mechanism to communicate with the server, or * <CODE>false</CODE> if not. */ @Override public boolean isSecure() { return false; } /** * Retrieves the human-readable name of the security mechanism that is used to * protect communication with this client. * * @return The human-readable name of the security mechanism that is used to * protect communication with this client, or <CODE>null</CODE> if no * security is in place. */ public String getSecurityMechanism() { return "NULL"; } /** * Sends a response to the client based on the information in the provided * operation. * * @param operation The operation for which to send the response. */ @Override public void sendResponse(Operation operation) { // There will not be any response sent by this method, since there is not an // actual connection. } /** * Processes an Jmx add operation with the provided information. * * @param rawEntryDN The DN to use for the entry to add. * @param rawAttributes The set of attributes to include in the entry to * add. * * @return A reference to the add operation that was processed and contains * information about the result of the processing. */ public AddOperation processAdd(ByteString rawEntryDN, ArrayList<RawAttribute> rawAttributes) { AddOperationBasis addOperation = new AddOperationBasis(this, nextOperationID(), nextMessageID(), new ArrayList<Control>(0), rawEntryDN, rawAttributes); // Check if we have enough privilege if (! hasPrivilege(Privilege.JMX_WRITE, null)) { Message message = ERR_JMX_ADD_INSUFFICIENT_PRIVILEGES.get(); addOperation.setErrorMessage(new MessageBuilder(message)); addOperation.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS) ; } else { addOperation.run(); } return addOperation; } /** * Processes an internal add operation with the provided * information. * * @param entryDN The entry DN for the add * operation. * @param objectClasses The set of objectclasses for the * add operation. * @param userAttributes The set of user attributes for the * add operation. * @param operationalAttributes The set of operational attributes * for the add operation. * * @return A reference to the add operation that was processed and * contains information about the result of the processing. */ public AddOperation processAdd(DN entryDN, Map<ObjectClass,String> objectClasses, Map<AttributeType,List<Attribute>> userAttributes, Map<AttributeType,List<Attribute>> operationalAttributes) { AddOperationBasis addOperation = new AddOperationBasis(this, nextOperationID(), nextMessageID(), new ArrayList<Control>(0), entryDN, objectClasses, userAttributes, operationalAttributes); // Check if we have enough privilege if (! hasPrivilege(Privilege.JMX_WRITE, null)) { Message message = ERR_JMX_ADD_INSUFFICIENT_PRIVILEGES.get(); addOperation.setErrorMessage(new MessageBuilder(message)); addOperation.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS) ; } else { addOperation.run(); } return addOperation; } /** * Processes an internal delete operation with the provided * information. * * @param entryDN The entry DN for the delete operation. * * @return A reference to the delete operation that was processed * and contains information about the result of the * processing. */ public DeleteOperation processDelete(DN entryDN) { DeleteOperationBasis deleteOperation = new DeleteOperationBasis(this, nextOperationID(), nextMessageID(), new ArrayList<Control>(0), entryDN); // Check if we have enough privilege if (! hasPrivilege(Privilege.JMX_WRITE, null)) { Message message = ERR_JMX_DELETE_INSUFFICIENT_PRIVILEGES.get(); deleteOperation.setErrorMessage(new MessageBuilder(message)); deleteOperation.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS) ; } else { deleteOperation.run(); } return deleteOperation; } /** * Processes an Jmx compare operation with the provided information. * * @param rawEntryDN The entry DN for the compare operation. * @param attributeType The attribute type for the compare operation. * @param assertionValue The assertion value for the compare operation. * * @return A reference to the compare operation that was processed and * contains information about the result of the processing. */ public CompareOperation processCompare(ByteString rawEntryDN, String attributeType, ByteString assertionValue) { CompareOperationBasis compareOperation = new CompareOperationBasis(this, nextOperationID(), nextMessageID(), new ArrayList<Control>(0), rawEntryDN, attributeType, assertionValue); // Check if we have enough privilege if (! hasPrivilege(Privilege.JMX_READ, null)) { Message message = ERR_JMX_SEARCH_INSUFFICIENT_PRIVILEGES.get(); compareOperation.setErrorMessage(new MessageBuilder(message)); compareOperation.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS) ; } else { compareOperation.run(); } return compareOperation; } /** * Processes an Jmx delete operation with the provided information. * * @param rawEntryDN The entry DN for the delete operation. * * @return A reference to the delete operation that was processed and * contains information about the result of the processing. */ public DeleteOperation processDelete(ByteString rawEntryDN) { DeleteOperationBasis deleteOperation = new DeleteOperationBasis(this, nextOperationID(), nextMessageID(), new ArrayList<Control>(0), rawEntryDN); // Check if we have enough privilege if (! hasPrivilege(Privilege.JMX_WRITE, null)) { Message message = ERR_JMX_DELETE_INSUFFICIENT_PRIVILEGES.get(); deleteOperation.setErrorMessage(new MessageBuilder(message)); deleteOperation.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS) ; } else { deleteOperation.run(); } return deleteOperation; } /** * Processes an Jmx extended operation with the provided information. * * @param requestOID The OID for the extended request. * @param requestValue The encoded +value for the extended operation, or * <CODE>null</CODE> if there is no value. * * @return A reference to the extended operation that was processed and * contains information about the result of the processing. */ public ExtendedOperation processExtendedOperation(String requestOID, ByteString requestValue) { ExtendedOperationBasis extendedOperation = new ExtendedOperationBasis(this, nextOperationID(), nextMessageID(), new ArrayList<Control>(0), requestOID, requestValue); extendedOperation.run(); return extendedOperation; } /** * Processes an Jmx modify operation with the provided information. * * @param rawEntryDN The raw entry DN for this modify operation. * @param rawModifications The set of modifications for this modify * operation. * * @return A reference to the modify operation that was processed and * contains information about the result of the processing */ public ModifyOperation processModify(ByteString rawEntryDN, ArrayList<RawModification> rawModifications) { ModifyOperationBasis modifyOperation = new ModifyOperationBasis(this, nextOperationID(), nextMessageID(), new ArrayList<Control>(0), rawEntryDN, rawModifications); if (! hasPrivilege(Privilege.JMX_WRITE, null)) { Message message = ERR_JMX_MODIFY_INSUFFICIENT_PRIVILEGES.get(); modifyOperation.setErrorMessage(new MessageBuilder(message)); modifyOperation.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS) ; } else { modifyOperation.run(); } return modifyOperation; } /** * Processes an internal modify operation with the provided * information. * * @param entryDN The entry DN for this modify operation. * @param modifications The set of modifications for this modify * operation. * * @return A reference to the modify operation that was processed * and contains information about the result of the * processing. */ public ModifyOperation processModify(DN entryDN, List<Modification> modifications) { ModifyOperationBasis modifyOperation = new ModifyOperationBasis(this, nextOperationID(), nextMessageID(), new ArrayList<Control>(0), entryDN, modifications); if (! hasPrivilege(Privilege.JMX_WRITE, null)) { Message message = ERR_JMX_MODIFY_INSUFFICIENT_PRIVILEGES.get(); modifyOperation.setErrorMessage(new MessageBuilder(message)); modifyOperation.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS) ; } else { modifyOperation.run(); } return modifyOperation; } /** * Processes an Jmx modify DN operation with the provided information. * * @param rawEntryDN The current DN of the entry to rename. * @param rawNewRDN The new RDN to use for the entry. * @param deleteOldRDN The flag indicating whether the old RDN value is to * be removed from the entry. * * @return A reference to the modify DN operation that was processed and * contains information about the result of the processing. */ public ModifyDNOperation processModifyDN(ByteString rawEntryDN, ByteString rawNewRDN, boolean deleteOldRDN) { return processModifyDN(rawEntryDN, rawNewRDN, deleteOldRDN, null); } /** * Processes an Jmx modify DN operation with the provided information. * * @param rawEntryDN The current DN of the entry to rename. * @param rawNewRDN The new RDN to use for the entry. * @param deleteOldRDN The flag indicating whether the old RDN value is to * be removed from the entry. * @param rawNewSuperior The new superior for the modify DN operation, or * <CODE>null</CODE> if the entry will remain below * the same parent. * * @return A reference to the modify DN operation that was processed and * contains information about the result of the processing. */ public ModifyDNOperation processModifyDN(ByteString rawEntryDN, ByteString rawNewRDN, boolean deleteOldRDN, ByteString rawNewSuperior) { ModifyDNOperationBasis modifyDNOperation = new ModifyDNOperationBasis(this, nextOperationID(), nextMessageID(), new ArrayList<Control>(0), rawEntryDN, rawNewRDN, deleteOldRDN, rawNewSuperior); if (! hasPrivilege(Privilege.JMX_WRITE, null)) { Message message = ERR_JMX_MODDN_INSUFFICIENT_PRIVILEGES.get(); modifyDNOperation.setErrorMessage(new MessageBuilder(message)); modifyDNOperation.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS) ; } else { modifyDNOperation.run(); } return modifyDNOperation; } /** * Processes an internal modify DN operation with the provided * information. * * @param entryDN The current DN of the entry to rename. * @param newRDN The new RDN to use for the entry. * @param deleteOldRDN The flag indicating whether the old RDN * value is to be removed from the entry. * @param newSuperior The new superior for the modify DN * operation, or <CODE>null</CODE> if the * entry will remain below the same parent. * * @return A reference to the modify DN operation that was * processed and contains information about the result of * the processing. */ public ModifyDNOperation processModifyDN(DN entryDN, RDN newRDN, boolean deleteOldRDN, DN newSuperior) { ModifyDNOperationBasis modifyDNOperation = new ModifyDNOperationBasis(this, nextOperationID(), nextMessageID(), new ArrayList<Control>(0), entryDN, newRDN, deleteOldRDN, newSuperior); if (! hasPrivilege(Privilege.JMX_WRITE, null)) { Message message = ERR_JMX_MODDN_INSUFFICIENT_PRIVILEGES.get(); modifyDNOperation.setErrorMessage(new MessageBuilder(message)); modifyDNOperation.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS) ; } else { modifyDNOperation.run(); } return modifyDNOperation; } /** * Processes an Jmx search operation with the provided information. * It will not dereference any aliases, will not request a size or time limit, * and will retrieve all user attributes. * * @param rawBaseDN The base DN for the search. * @param scope The scope for the search. * @param filter The filter for the search. * * @return A reference to the internal search operation that was processed * and contains information about the result of the processing as * well as lists of the matching entries and search references. */ public InternalSearchOperation processSearch(ByteString rawBaseDN, SearchScope scope, LDAPFilter filter) { return processSearch(rawBaseDN, scope, DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, filter, new LinkedHashSet<String>(0)); } /** * Processes an Jmx search operation with the provided information. * * @param rawBaseDN The base DN for the search. * @param scope The scope for the search. * @param derefPolicy The alias dereferencing policy for the search. * @param sizeLimit The size limit for the search. * @param timeLimit The time limit for the search. * @param typesOnly The typesOnly flag for the search. * @param filter The filter for the search. * @param attributes The set of requested attributes for the search. * * @return A reference to the internal search operation that was processed * and contains information about the result of the processing as * well as lists of the matching entries and search references. */ public InternalSearchOperation processSearch(ByteString rawBaseDN, SearchScope scope, DereferencePolicy derefPolicy, int sizeLimit, int timeLimit, boolean typesOnly, LDAPFilter filter, LinkedHashSet<String> attributes) { InternalSearchOperation searchOperation = new InternalSearchOperation(this, nextOperationID(), nextMessageID(), new ArrayList<Control>(0), rawBaseDN, scope, derefPolicy, sizeLimit, timeLimit, typesOnly, filter, attributes, null); if (! hasPrivilege(Privilege.JMX_READ, null)) { Message message = ERR_JMX_SEARCH_INSUFFICIENT_PRIVILEGES.get(); searchOperation.setErrorMessage(new MessageBuilder(message)); searchOperation.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS) ; } else { searchOperation.run(); } return searchOperation; } /** * Processes an Jmx search operation with the provided information. * * @param rawBaseDN The base DN for the search. * @param scope The scope for the search. * @param derefPolicy The alias dereferencing policy for the search. * @param sizeLimit The size limit for the search. * @param timeLimit The time limit for the search. * @param typesOnly The typesOnly flag for the search. * @param filter The filter for the search. * @param attributes The set of requested attributes for the search. * @param searchListener The internal search listener that should be used to * handle the matching entries and references. * * @return A reference to the internal search operation that was processed * and contains information about the result of the processing. */ public InternalSearchOperation processSearch(ByteString rawBaseDN, SearchScope scope, DereferencePolicy derefPolicy, int sizeLimit, int timeLimit, boolean typesOnly, LDAPFilter filter, LinkedHashSet<String> attributes, InternalSearchListener searchListener) { InternalSearchOperation searchOperation = new InternalSearchOperation(this, nextOperationID(), nextMessageID(), new ArrayList<Control>(0), rawBaseDN, scope, derefPolicy, sizeLimit, timeLimit, typesOnly, filter, attributes, searchListener); searchOperation.run(); return searchOperation; } /** * Sends the provided search result entry to the client. * * @param searchOperation The search operation with which the entry is * associated. * @param searchEntry The search result entry to be sent to the client. * * @throws DirectoryException If a problem occurs while attempting to send * the entry to the client and the search should * be terminated. */ @Override public void sendSearchEntry(SearchOperation searchOperation, SearchResultEntry searchEntry) throws DirectoryException { ((InternalSearchOperation) searchOperation).addSearchEntry(searchEntry); } /** * Sends the provided search result reference to the client. * * @param searchOperation The search operation with which the reference is * associated. * @param searchReference The search result reference to be sent to the * client. * * @return <CODE>true</CODE> if the client is able to accept referrals, or * <CODE>false</CODE> if the client cannot handle referrals and no * more attempts should be made to send them for the associated * search operation. * * @throws DirectoryException If a problem occurs while attempting to send * the reference to the client and the search * should be terminated. */ @Override public boolean sendSearchReference(SearchOperation searchOperation, SearchResultReference searchReference) throws DirectoryException { ((InternalSearchOperation) searchOperation).addSearchReference(searchReference); return true; } /** * Sends the provided intermediate response message to the client. * * @param intermediateResponse The intermediate response message to be sent. * * @return <CODE>true</CODE> if processing on the associated operation should * continue, or <CODE>false</CODE> if not. */ @Override protected boolean sendIntermediateResponseMessage( IntermediateResponse intermediateResponse) { // FIXME -- Do we need to support Jmx intermediate responses? If so, // then implement this. return false; } /** * Closes the connection to the client, optionally sending it a message * indicating the reason for the closure. Note that the ability to send a * notice of disconnection may not be available for all protocols or under all * circumstances. * * @param disconnectReason The disconnect reason that provides the generic * cause for the disconnect. * @param sendNotification Indicates whether to try to provide notification * to the client that the connection will be closed. * @param message The message to send to the client. It may be * <CODE>null</CODE> if no notification is to be * sent. */ @Override public void disconnect(DisconnectReason disconnectReason, boolean sendNotification, Message message) { // we are already performing a disconnect if (disconnectStarted) { return; } disconnectStarted = true ; finalizeConnectionInternal(); // unbind the underlying connection try { UnbindOperationBasis unbindOp = new UnbindOperationBasis( this, this.nextOperationID(), this.nextMessageID(), null); unbindOp.run(); } catch (Exception e) { // TODO print a message ? if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } } // Call postDisconnectPlugins try { PluginConfigManager pluginManager = DirectoryServer.getPluginConfigManager(); pluginManager.invokePostDisconnectPlugins(this, disconnectReason, message); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } } } /** * Retrieves the set of operations in progress for this client connection. * This list must not be altered by any caller. * * @return The set of operations in progress for this client connection. */ @Override public Collection<Operation> getOperationsInProgress() { return operationList; } /** * Retrieves the operation in progress with the specified message ID. * * @param messageID The message ID of the operation to retrieve. * * @return The operation in progress with the specified message ID, or * <CODE>null</CODE> if no such operation could be found. */ @Override public Operation getOperationInProgress(int messageID) { // Jmx operations will not be tracked. return null; } /** * Removes the provided operation from the set of operations in progress for * this client connection. Note that this does not make any attempt to * cancel any processing that may already be in progress for the operation. * * @param messageID The message ID of the operation to remove from the set * of operations in progress. * * @return <CODE>true</CODE> if the operation was found and removed from the * set of operations in progress, or <CODE>false</CODE> if not. */ @Override public boolean removeOperationInProgress(int messageID) { // No implementation is required, since Jmx operations will not be // tracked. return false; } /** * Attempts to cancel the specified operation. * * @param messageID The message ID of the operation to cancel. * @param cancelRequest An object providing additional information about how * the cancel should be processed. * * @return A cancel result that either indicates that the cancel was * successful or provides a reason that it was not. */ @Override public CancelResult cancelOperation(int messageID, CancelRequest cancelRequest) { // Jmx operations cannot be cancelled. // TODO: i18n return new CancelResult(ResultCode.CANNOT_CANCEL, Message.raw("Jmx operations cannot be cancelled")); } /** * Attempts to cancel all operations in progress on this connection. * * @param cancelRequest An object providing additional information about how * the cancel should be processed. */ @Override public void cancelAllOperations(CancelRequest cancelRequest) { // No implementation is required since Jmx operations cannot be // cancelled. } /** * Attempts to cancel all operations in progress on this connection except the * operation with the specified message ID. * * @param cancelRequest An object providing additional information about how * the cancel should be processed. * @param messageID The message ID of the operation that should not be * canceled. */ @Override public void cancelAllOperationsExcept(CancelRequest cancelRequest, int messageID) { // No implementation is required since Jmx operations cannot be // cancelled. } /** * {@inheritDoc} */ @Override public String getMonitorSummary() { StringBuilder buffer = new StringBuilder(); buffer.append("connID=\""); buffer.append(connectionID); buffer.append("\" connectTime=\""); buffer.append(getConnectTimeString()); buffer.append("\" jmxConnID=\""); buffer.append(jmxConnectionID); buffer.append("\" authDN=\""); DN authDN = getAuthenticationInfo().getAuthenticationDN(); if (authDN != null) { authDN.toString(buffer); } buffer.append("\""); return buffer.toString(); } /** * Appends a string representation of this client connection to the provided * buffer. * * @param buffer The buffer to which the information should be appended. */ @Override public void toString(StringBuilder buffer) { buffer.append("JmxClientConnection(connID="); buffer.append(connectionID); buffer.append(", authDN=\""); buffer.append(getAuthenticationInfo().getAuthenticationDN()); buffer.append("\")"); } /** * Called by the Gc when the object is garbage collected * Release the cursor in case the iterator was badly used and releaseCursor * was never called. */ @Override protected void finalize() { disconnect(DisconnectReason.OTHER, false, null); } /** * To be implemented. * * @return number of operations performed on this connection */ @Override public long getNumberOfOperations() { // JMX connections will not be limited. return 0; } /** * {@inheritDoc} */ @Override public int getSSF() { return 0; } }