001    /*
002     * CDDL HEADER START
003     *
004     * The contents of this file are subject to the terms of the
005     * Common Development and Distribution License, Version 1.0 only
006     * (the "License").  You may not use this file except in compliance
007     * with the License.
008     *
009     * You can obtain a copy of the license at
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2006-2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.extensions;
028    
029    
030    
031    import org.opends.messages.Message;
032    import org.opends.server.admin.std.server.CancelExtendedOperationHandlerCfg;
033    import org.opends.server.api.ClientConnection;
034    import org.opends.server.api.ExtendedOperationHandler;
035    import org.opends.server.config.ConfigException;
036    import org.opends.server.core.DirectoryServer;
037    import org.opends.server.core.ExtendedOperation;
038    import org.opends.server.loggers.debug.DebugTracer;
039    import org.opends.server.protocols.asn1.ASN1Sequence;
040    import org.opends.server.types.ByteString;
041    import org.opends.server.types.CancelRequest;
042    import org.opends.server.types.CancelResult;
043    import org.opends.server.types.DebugLogLevel;
044    import org.opends.server.types.InitializationException;
045    import org.opends.server.types.ResultCode;
046    
047    import static org.opends.messages.ExtensionMessages.*;
048    import static org.opends.server.loggers.debug.DebugLogger.*;
049    import static org.opends.server.util.ServerConstants.*;
050    import static org.opends.server.util.StaticUtils.*;
051    
052    
053    
054    /**
055     * This class implements the LDAP cancel extended operation defined in RFC 3909.
056     * It is similar to the LDAP abandon operation, with the exception that it
057     * requires a response for both the operation that is cancelled and the cancel
058     * request (whereas an abandon request never has a response, and if it is
059     * successful the abandoned operation won't get one either).
060     */
061    public class CancelExtendedOperation
062           extends ExtendedOperationHandler<CancelExtendedOperationHandlerCfg>
063    {
064      /**
065       * The tracer object for the debug logger.
066       */
067      private static final DebugTracer TRACER = getTracer();
068    
069    
070    
071      /**
072       * Create an instance of this cancel extended operation.  All initialization
073       * should be performed in the <CODE>initializeExtendedOperationHandler</CODE>
074       * method.
075       */
076      public CancelExtendedOperation()
077      {
078        super();
079      }
080    
081    
082      /**
083       * Initializes this extended operation handler based on the information in the
084       * provided configuration entry.  It should also register itself with the
085       * Directory Server for the particular kinds of extended operations that it
086       * will process.
087       *
088       * @param  config       The configuration that contains the information
089       *                      to use to initialize this extended operation handler.
090       *
091       * @throws  ConfigException  If an unrecoverable problem arises in the
092       *                           process of performing the initialization.
093       *
094       * @throws  InitializationException  If a problem occurs during initialization
095       *                                   that is not related to the server
096       *                                   configuration.
097       */
098      public void initializeExtendedOperationHandler(
099                       CancelExtendedOperationHandlerCfg config)
100             throws ConfigException, InitializationException
101      {
102        // No special configuration is required.
103    
104        DirectoryServer.registerSupportedExtension(OID_CANCEL_REQUEST, this);
105    
106        registerControlsAndFeatures();
107      }
108    
109    
110    
111      /**
112       * Performs any finalization that may be necessary for this extended
113       * operation handler.  By default, no finalization is performed.
114       */
115      public void finalizeExtendedOperationHandler()
116      {
117        DirectoryServer.deregisterSupportedExtension(OID_CANCEL_REQUEST);
118    
119        deregisterControlsAndFeatures();
120      }
121    
122    
123    
124      /**
125       * Processes the provided extended operation.
126       *
127       * @param  operation  The extended operation to be processed.
128       */
129      public void processExtendedOperation(ExtendedOperation operation)
130      {
131        // The value of the request must be a sequence containing an integer element
132        // that holds the message ID of the operation to cancel.  If there is no
133        // value or it cannot be decoded, then fail.
134        int idToCancel;
135        ByteString requestValue = operation.getRequestValue();
136        if (requestValue == null)
137        {
138          operation.setResultCode(ResultCode.PROTOCOL_ERROR);
139    
140          operation.appendErrorMessage(ERR_EXTOP_CANCEL_NO_REQUEST_VALUE.get());
141          return;
142        }
143        else
144        {
145          try
146          {
147            ASN1Sequence valueSequence =
148                 ASN1Sequence.decodeAsSequence(requestValue.value());
149            idToCancel =
150                 valueSequence.elements().get(0).decodeAsInteger().intValue();
151          }
152          catch (Exception e)
153          {
154            if (debugEnabled())
155            {
156              TRACER.debugCaught(DebugLogLevel.ERROR, e);
157            }
158    
159            operation.setResultCode(ResultCode.PROTOCOL_ERROR);
160    
161            Message message = ERR_EXTOP_CANCEL_CANNOT_DECODE_REQUEST_VALUE.get(
162                    getExceptionMessage(e));
163            operation.appendErrorMessage(message);
164    
165            return;
166          }
167        }
168    
169    
170        // Create the cancel request for the target operation.
171        Message cancelReason =
172            INFO_EXTOP_CANCEL_REASON.get(operation.getMessageID());
173        CancelRequest cancelRequest = new CancelRequest(true, cancelReason);
174    
175    
176        // Get the client connection and attempt the cancel.
177        ClientConnection clientConnection = operation.getClientConnection();
178        CancelResult cancelResult = clientConnection.cancelOperation(idToCancel,
179                                                                     cancelRequest);
180    
181    
182        // Update the result of the extended operation and return.
183        operation.setResultCode(cancelResult.getResultCode());
184        operation.appendErrorMessage(cancelResult.getResponseMessage());
185      }
186    }
187