From c2beb1994315ebd33bbdd186a3c97d62a194a9ec Mon Sep 17 00:00:00 2001
From: ctissot <ctissot@localhost>
Date: Thu, 20 Dec 2007 09:55:23 +0000
Subject: [PATCH] I use this bug id (138) as an umbrella for a list of  bugfixes/improvements for the DSML gateway.

---
 opends/src/dsml/org/opends/dsml/protocol/DSMLServlet.java |  587 ++++++++++++++++++++++++++++++++++++++-------------------
 1 files changed, 388 insertions(+), 199 deletions(-)

diff --git a/opends/src/dsml/org/opends/dsml/protocol/DSMLServlet.java b/opends/src/dsml/org/opends/dsml/protocol/DSMLServlet.java
index 2e1144f..fc6f661 100644
--- a/opends/src/dsml/org/opends/dsml/protocol/DSMLServlet.java
+++ b/opends/src/dsml/org/opends/dsml/protocol/DSMLServlet.java
@@ -27,7 +27,14 @@
 package org.opends.dsml.protocol;
 
 
+import java.io.BufferedInputStream;
+import java.io.InputStream;
+import java.text.ParseException;
+import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI;
+import javax.xml.bind.JAXBException;
+import org.opends.messages.Message;
 import org.opends.server.core.DirectoryServer;
+import org.opends.server.protocols.ldap.LDAPResultCode;
 import org.opends.server.tools.LDAPConnection;
 import org.opends.server.tools.LDAPConnectionOptions;
 import org.opends.server.util.Base64;
@@ -47,11 +54,21 @@
 import javax.xml.soap.*;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.net.URL;
 import java.util.Enumeration;
 import java.util.Iterator;
 import java.util.List;
 import java.util.StringTokenizer;
 import java.util.concurrent.atomic.AtomicInteger;
+import javax.xml.validation.SchemaFactory;
+import org.opends.server.tools.LDAPConnectionException;
+import org.opends.server.types.LDAPException;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+import org.xml.sax.helpers.XMLReaderFactory;
 
 
 /**
@@ -67,15 +84,33 @@
   private static final long serialVersionUID = -3748022009593442973L;
   private static final AtomicInteger nextMessageID = new AtomicInteger(1);
 
+  // definitions of return error messages
+  private static final String MALFORMED_REQUEST = "malformedRequest";
+  private static final String NOT_ATTEMPTED = "notAttempted";
+  private static final String AUTHENTICATION_FAILED = "authenticationFailed";
+  private static final String COULD_NOT_CONNECT = "couldNotConnect";
+  private static final String GATEWAY_INTERNAL_ERROR = "gatewayInternalError";
+  
+  private static final String UNKNOWN_ERROR = "Unknown error";
+
+  // definitions of onError values
+  private static final String ON_ERROR_RESUME = "resume";
+  private static final String ON_ERROR_EXIT = "exit";
+  
   private Unmarshaller unmarshaller;
   private Marshaller marshaller;
   private ObjectFactory objFactory;
   private MessageFactory messageFactory;
   private DocumentBuilder db;
 
+  // this extends the default handler of SAX parser. It helps to retrieve the
+  // requestID value when the xml request is malformed and thus unparsable
+  // using SOAP or JAXB.
+  private DSMLContentHandler contentHandler;
+  
   private String hostName;
   private Integer port;
-
+  
   /**
    * This method will be called by the Servlet Container when
    * this servlet is being placed into service.
@@ -85,19 +120,22 @@
    * @throws ServletException If an error occurs during processing.
    */
   public void init(ServletConfig config) throws ServletException {
-
+    
     try {
-
       hostName = config.getServletContext().getInitParameter(HOST);
 
       port = new Integer(config.getServletContext().getInitParameter(PORT));
 
       JAXBContext jaxbContext = JAXBContext.newInstance(PKG_NAME);
       unmarshaller = jaxbContext.createUnmarshaller();
+      // assign the DSMLv2 schema for validation
+      URL schema = getClass().getResource("/resources/DSMLv2.xsd");
+      if ( schema != null ) {
+        SchemaFactory sf = SchemaFactory.newInstance(W3C_XML_SCHEMA_NS_URI);
+        unmarshaller.setSchema(sf.newSchema(schema));
+      }
 
       marshaller = jaxbContext.createMarshaller();
-      marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper",
-        new NamespacePrefixMapperImpl());
 
       objFactory = new ObjectFactory();
       messageFactory = MessageFactory.newInstance();
@@ -105,29 +143,15 @@
       dbf.setNamespaceAware(true);
       db = dbf.newDocumentBuilder();
 
-      DirectoryServer.bootstrapClient();
+      this.contentHandler = new DSMLContentHandler();
 
+      DirectoryServer.bootstrapClient();
     } catch (Exception je) {
       je.printStackTrace();
       throw new ServletException(je.getMessage());
     }
   }
-
-
-  /**
-   * The HTTP GET operation.
-   *
-   * @param req Information about the request received from the client.
-   * @param res Information about the response to send to the client.
-   * @throws ServletException If an error occurs during servlet processing.
-   * @throws IOException      If an error occurs while interacting with the client.
-   */
-  public void doGet(HttpServletRequest req, HttpServletResponse res)
-    throws ServletException, IOException {
-    super.doGet(req, res);
-  }
-
-
+  
   /**
    * The HTTP POST operation. This servlet expects a SOAP message
    * with a DSML request payload.
@@ -135,222 +159,370 @@
    * @param req Information about the request received from the client.
    * @param res Information about the response to send to the client.
    * @throws ServletException If an error occurs during servlet processing.
-   * @throws IOException      If an error occurs while interacting with the client.
+   * @throws IOException   If an error occurs while interacting with the client.
    */
   public void doPost(HttpServletRequest req, HttpServletResponse res)
-    throws ServletException, IOException {
-    SOAPMessage reply;
+  throws ServletException, IOException {
     LDAPConnectionOptions connOptions = new LDAPConnectionOptions();
     LDAPConnection connection = null;
+    BatchRequest batchRequest = null;
+    
+    // Keep the Servlet input stream buffered in case the SOAP unmarshalling
+    // fails, the SAX parsing will be able to retrieve the requestID even if
+    // the XML is malmformed by resetting the input stream.
+    BufferedInputStream is = new BufferedInputStream(req.getInputStream(),
+                                                     65536);
+    if ( is.markSupported() ) {
+      is.mark(65536);
+    }
 
-    try {
-      MimeHeaders mimeHeaders = new MimeHeaders();
-      Enumeration en = req.getHeaderNames();
-      String bindDN = "";
-      String bindPassword = "";
-      while (en.hasMoreElements()) {
-        String headerName = (String) en.nextElement();
-        String headerVal = req.getHeader(headerName);
-        if (headerName.equalsIgnoreCase("authorization")) {
-          if (headerVal.startsWith("Basic ")) {
-            String authorization = headerVal.substring(6).trim();
-            // Decode and parse the authorization credentials
-            String unencoded =
-              new String(Base64.decode(authorization));
+    // Create response in the beginning as it might be used if the parsing
+    // failes.
+    BatchResponse batchResponse = objFactory.createBatchResponse();
+    List<JAXBElement<?>> batchResponses = batchResponse.getBatchResponses();
+    Document doc = db.newDocument();
+    
+    SOAPBody soapBody = null;
+    
+    MimeHeaders mimeHeaders = new MimeHeaders();
+    Enumeration en = req.getHeaderNames();
+    String bindDN = null;
+    String bindPassword = null;
+    boolean authorizationInHeader = false;
+    while (en.hasMoreElements()) {
+      String headerName = (String) en.nextElement();
+      String headerVal = req.getHeader(headerName);
+      if (headerName.equalsIgnoreCase("authorization")) {
+        if (headerVal.startsWith("Basic ")) {
+          authorizationInHeader = true;
+          String authorization = headerVal.substring(6).trim();
+          try {
+            String unencoded = new String(Base64.decode(authorization));
             int colon = unencoded.indexOf(':');
-            if (colon < 0)
-              continue;
-            bindDN = unencoded.substring(0, colon).trim();
-            bindPassword = unencoded.substring(colon + 1);
+            if (colon > 0) {
+              bindDN = unencoded.substring(0, colon).trim();
+              bindPassword = unencoded.substring(colon + 1);
+            }
+          } catch (ParseException ex) {
+            // DN:password parsing error
+            batchResponses.add(
+              createErrorResponse(
+                    new LDAPException(LDAPResultCode.INVALID_CREDENTIALS,
+                    Message.raw(ex.getMessage()))));
+            break;
           }
         }
-        StringTokenizer tk = new StringTokenizer(headerVal, ",");
-        while (tk.hasMoreTokens()) {
-          mimeHeaders.addHeader(headerName, tk.nextToken().trim());
-        }
       }
+      StringTokenizer tk = new StringTokenizer(headerVal, ",");
+      while (tk.hasMoreTokens()) {
+        mimeHeaders.addHeader(headerName, tk.nextToken().trim());
+      }
+    }
 
-      SOAPMessage message =
-        messageFactory.createMessage(mimeHeaders, req.getInputStream());
-      message.writeTo(System.out);
+    if ( ! authorizationInHeader ) {
+      // if no authorization, set default user
+      bindDN = "";
+      bindPassword = "";
+    } else {
+      // otherwise if DN or password is null, send back an error
+      if ( (bindDN == null || bindPassword == null)
+         && batchResponses.size()==0) {
+        batchResponses.add(
+              createErrorResponse(
+                    new LDAPException(LDAPResultCode.INVALID_CREDENTIALS,
+                    Message.raw("Unable to retrieve credentials."))));
+      }
+    }
 
-      Document doc = db.newDocument();
-      SOAPBody body = message.getSOAPBody();
+    // if an error already occured, the list is not empty
+    if ( batchResponses.size() == 0 ) {
+      try {
+        SOAPMessage message = messageFactory.createMessage(mimeHeaders, is);
+        soapBody = message.getSOAPBody();
+      } catch (SOAPException ex) {
+        // SOAP was unable to parse XML successfully
+        batchResponses.add(
+          createXMLParsingErrorResponse(is, 
+                                        batchResponse,
+                                        String.valueOf(ex.getCause())));
+      }
+    }
 
-      Iterator it = body.getChildElements();
+    if ( soapBody != null ) {
+      Iterator it = soapBody.getChildElements();
       while (it.hasNext()) {
         Object obj = it.next();
         if (!(obj instanceof SOAPElement)) {
           continue;
         }
         SOAPElement se = (SOAPElement) obj;
-        JAXBElement<BatchRequest> batchRequestElement =
-          unmarshaller.unmarshal(se, BatchRequest.class);
-        BatchRequest batchRequest = batchRequestElement.getValue();
-        BatchResponse batchResponse = objFactory.createBatchResponse();
-
-        List<JAXBElement<?>> batchResponses = batchResponse.getBatchResponses();
-        List<DsmlMessage> list = batchRequest.getBatchRequests();
-
-        for (DsmlMessage nextElement : list) {
-          if (nextElement instanceof SearchRequest) {
-            // Process the search request.
+        JAXBElement<BatchRequest> batchRequestElement = null;
+        try {
+          batchRequestElement = unmarshaller.unmarshal(se, BatchRequest.class);
+        } catch (JAXBException e) {
+          // schema validation failed
+          batchResponses.add(createXMLParsingErrorResponse(is,
+                                                       batchResponse,
+                                                       String.valueOf(e)));
+        }
+        if ( batchRequestElement != null ) {
+          batchRequest = batchRequestElement.getValue();
+          
+          // set requestID in response
+          batchResponse.setRequestID(batchRequest.getRequestID());
+          
+          boolean connected = false;
+          if ( connection == null ) {
             connection = new LDAPConnection(hostName, port, connOptions);
-            connection.connectToHost(bindDN, bindPassword);
-
-            SearchRequest sr = (SearchRequest) nextElement;
-            DSMLSearchOperation ds = new DSMLSearchOperation(connection);
-            SearchResponse searchResponse = ds.doSearch(objFactory, sr);
-
-            JAXBElement<SearchResponse> searchResponseEl =
-              objFactory.createBatchResponseSearchResponse(searchResponse);
-            batchResponses.add(searchResponseEl);
-
-          } else if (nextElement instanceof AddRequest) {
-            // Process the add request.
-            connection = new LDAPConnection(hostName, port, connOptions);
-            connection.connectToHost(bindDN, bindPassword);
-            AddRequest ar = (AddRequest) nextElement;
-            DSMLAddOperation addOp = new DSMLAddOperation(connection);
-            LDAPResult addResponse = addOp.doOperation(objFactory, ar);
-            JAXBElement<LDAPResult> addResponseEl =
-              objFactory.createBatchResponseAddResponse(addResponse);
-            batchResponses.add(addResponseEl);
-          } else if (nextElement instanceof AbandonRequest) {
-            // Process the abandon request.
-            connection = new LDAPConnection(hostName, port, connOptions);
-            connection.connectToHost(bindDN, bindPassword);
-            AbandonRequest ar = (AbandonRequest) nextElement;
-            DSMLAbandonOperation ao = new DSMLAbandonOperation(connection);
-            LDAPResult abandonResponse = ao.doOperation(objFactory, ar);
-          } else if (nextElement instanceof ExtendedRequest) {
-            // Process the extended request.
-            connection = new LDAPConnection(hostName, port, connOptions);
-            connection.connectToHost(bindDN, bindPassword);
-            ExtendedRequest er = (ExtendedRequest) nextElement;
-            DSMLExtendedOperation eo = new DSMLExtendedOperation(connection);
-            ExtendedResponse extendedResponse = eo.doOperation(objFactory, er);
-            JAXBElement<ExtendedResponse> extendedResponseEl =
-              objFactory.createBatchResponseExtendedResponse(extendedResponse);
-            batchResponses.add(extendedResponseEl);
-
-          } else if (nextElement instanceof DelRequest) {
-            // Process the delete request.
-            connection = new LDAPConnection(hostName, port, connOptions);
-            connection.connectToHost(bindDN, bindPassword);
-            DelRequest dr = (DelRequest) nextElement;
-            DSMLDeleteOperation delOp = new DSMLDeleteOperation(connection);
-            LDAPResult delResponse = delOp.doOperation(objFactory, dr);
-            JAXBElement<LDAPResult> delResponseEl =
-              objFactory.createBatchResponseDelResponse(delResponse);
-            batchResponses.add(delResponseEl);
-          } else if (nextElement instanceof CompareRequest) {
-            // Process the compare request.
-            connection = new LDAPConnection(hostName, port, connOptions);
-            connection.connectToHost(bindDN, bindPassword);
-            CompareRequest cr = (CompareRequest) nextElement;
-            DSMLCompareOperation compareOp =
-              new DSMLCompareOperation(connection);
-            LDAPResult compareResponse = compareOp.doOperation(objFactory, cr);
-            JAXBElement<LDAPResult> compareResponseEl =
-              objFactory.createBatchResponseCompareResponse(compareResponse);
-            batchResponses.add(compareResponseEl);
-          } else if (nextElement instanceof ModifyDNRequest) {
-            // Process the Modify DN request.
-            connection = new LDAPConnection(hostName, port, connOptions);
-            connection.connectToHost(bindDN, bindPassword);
-            ModifyDNRequest mr = (ModifyDNRequest) nextElement;
-            DSMLModifyDNOperation moddnOp =
-              new DSMLModifyDNOperation(connection);
-            LDAPResult moddnResponse = moddnOp.doOperation(objFactory, mr);
-            JAXBElement<LDAPResult> moddnResponseEl =
-              objFactory.createBatchResponseModDNResponse(moddnResponse);
-            batchResponses.add(moddnResponseEl);
-          } else if (nextElement instanceof ModifyRequest) {
-            // Process the Modify request.
-            connection = new LDAPConnection(hostName, port, connOptions);
-            connection.connectToHost(bindDN, bindPassword);
-            ModifyRequest modr = (ModifyRequest) nextElement;
-            DSMLModifyOperation modOp = new DSMLModifyOperation(connection);
-            LDAPResult modResponse = modOp.doOperation(objFactory, modr);
-            JAXBElement<LDAPResult> modResponseEl =
-              objFactory.createBatchResponseModifyResponse(modResponse);
-            batchResponses.add(modResponseEl);
-          } else {
-            String msg = "Invalid DSML request:" + nextElement;
-            throw new IOException(msg);
+            try {
+              connection.connectToHost(bindDN, bindPassword);
+              connected = true;
+            } catch (LDAPConnectionException e) {
+              // if connection failed, return appropriate error response
+              batchResponses.add(createErrorResponse(e));
+            }
+          }
+          if ( connected ) {
+            List<DsmlMessage> list = batchRequest.getBatchRequests();
+            
+            for (DsmlMessage request : list) {
+              JAXBElement<?> result = performLDAPRequest(connection, request);
+              if ( result != null ) {
+                batchResponses.add(result);
+              }
+              // evaluate response to check if an error occured
+              Object o = result.getValue();
+              if ( o instanceof ErrorResponse ) {
+                if ( ON_ERROR_EXIT.equals(batchRequest.getOnError()) ) {
+                  break;
+                }
+              } else if ( o instanceof LDAPResult ) {
+                int code = ((LDAPResult)o).getResultCode().getCode();
+                if ( code != LDAPResultCode.SUCCESS
+                  && code != LDAPResultCode.REFERRAL
+                  && code != LDAPResultCode.COMPARE_TRUE
+                  && code != LDAPResultCode.COMPARE_FALSE ) {
+                  if ( ON_ERROR_EXIT.equals(batchRequest.getOnError()) ) {
+                    break;
+                  }
+                }
+              }
+            }
+          }
+          // close connection to LDAP server
+          if ( connection != null ) {
+            connection.close(nextMessageID);
           }
         }
-
-        JAXBElement<BatchResponse> batchResponseElement =
-          objFactory.createBatchResponse(batchResponse);
-
-        marshaller.marshal(batchResponseElement, System.out);
-
-        marshaller.marshal(batchResponseElement, doc);
-      }
-
-      // Send the DSML response back to the client.
-      reply = messageFactory.createMessage();
-      sendResponse(doc, false, reply, res, null);
-
-    } catch (Exception se) {
-      se.printStackTrace();
-      // send SOAP fault
-      try {
-        reply = messageFactory.createMessage();
-        sendResponse(null, true, reply, res, se);
-      } catch (Exception e) {
-      }
-    } finally {
-      if (connection != null) {
-        connection.close(nextMessageID);
       }
     }
+    try {
+      marshaller.marshal(objFactory.createBatchResponse(batchResponse), doc);
+      sendResponse(doc, res);
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+
   }
 
   /**
+   * Returns an error response after a parsing error. The response has the
+   * requestID of the batch request, the error response message of the parsing
+   * exception message and the type 'malformed request'.
+   *
+   * @param is the xml InputStream to parse
+   * @param batchResponse the JAXB object to fill in
+   * @param parserErrorMessage the parsing error message
+   *
+   * @return a JAXBElement that contains an ErrorResponse
+   */
+  private JAXBElement<ErrorResponse> createXMLParsingErrorResponse(
+                                                    InputStream is,
+                                                    BatchResponse batchResponse,
+                                                    String parserErrorMessage) {
+    ErrorResponse errorResponse = objFactory.createErrorResponse();
+    
+    try {
+      // try alternative XML parsing using SAX to retrieve requestID value
+      XMLReader xmlReader = XMLReaderFactory.createXMLReader();
+      // clear previous match
+      this.contentHandler.requestID = null;
+      xmlReader.setContentHandler(this.contentHandler);
+      is.reset();
+      
+      xmlReader.parse(new InputSource(is));
+    } catch (Throwable e) {
+      // document is unparsable so will jump here
+    }
+    if ( parserErrorMessage!= null ) {
+      errorResponse.setMessage(parserErrorMessage);
+    }
+    batchResponse.setRequestID(this.contentHandler.requestID);
+    
+    errorResponse.setType(MALFORMED_REQUEST);
+    
+    return objFactory.createBatchResponseErrorResponse(errorResponse);
+  }
+
+  /**
+   * Returns an error response with attributes set according to the exception
+   * provided as argument.
+   *
+   * @param t the exception that occured
+   *
+   * @return a JAXBElement that contains an ErrorResponse
+   */
+  private JAXBElement<ErrorResponse> createErrorResponse(Throwable t) {
+    // potential exceptions are IOException, LDAPException, ASN1Exception
+    
+    ErrorResponse errorResponse = objFactory.createErrorResponse();
+    errorResponse.setMessage(String.valueOf(t));
+    
+    if ( t instanceof LDAPException ) {
+      switch(((LDAPException)t).getResultCode()) {
+        case LDAPResultCode.AUTHORIZATION_DENIED:
+        case LDAPResultCode.INAPPROPRIATE_AUTHENTICATION:
+        case LDAPResultCode.INVALID_CREDENTIALS:
+        case LDAPResultCode.STRONG_AUTH_REQUIRED:
+          errorResponse.setType(AUTHENTICATION_FAILED);
+          break;
+          
+        case LDAPResultCode.CLIENT_SIDE_CONNECT_ERROR:
+          errorResponse.setType(COULD_NOT_CONNECT);
+          break;
+          
+        case LDAPResultCode.UNWILLING_TO_PERFORM:
+          errorResponse.setType(NOT_ATTEMPTED);
+          break;
+          
+        default:
+          errorResponse.setType(UNKNOWN_ERROR);
+          break;
+      }
+    } else if ( t instanceof LDAPConnectionException ) {
+      errorResponse.setType(COULD_NOT_CONNECT);
+    } else {
+      errorResponse.setType(GATEWAY_INTERNAL_ERROR);
+    }
+    
+    return objFactory.createBatchResponseErrorResponse(errorResponse);
+  }
+
+  /**
+   * Performs the LDAP operation and sends back the result (if any). In case
+   * of error, an error reponse is returned.
+   *
+   * @param connection a connected connection
+   * @param request the JAXB request to perform
+   *
+   * @return null for an abandon request, the expect result for all other
+   *         requests or an error in case of unexpected behaviour.
+   */
+  private JAXBElement<?> performLDAPRequest(LDAPConnection connection,
+                                            DsmlMessage request) {
+    try {
+      if (request instanceof SearchRequest) {
+        // Process the search request.
+        SearchRequest sr = (SearchRequest) request;
+        DSMLSearchOperation ds = new DSMLSearchOperation(connection);
+        SearchResponse searchResponse = ds.doSearch(objFactory, sr);
+        
+        return objFactory.createBatchResponseSearchResponse(searchResponse);
+      } else if (request instanceof AddRequest) {
+        // Process the add request.
+        AddRequest ar = (AddRequest) request;
+        DSMLAddOperation addOp = new DSMLAddOperation(connection);
+        LDAPResult addResponse = addOp.doOperation(objFactory, ar);
+        return objFactory.createBatchResponseAddResponse(addResponse);
+      } else if (request instanceof AbandonRequest) {
+        // Process the abandon request.
+        AbandonRequest ar = (AbandonRequest) request;
+        DSMLAbandonOperation ao = new DSMLAbandonOperation(connection);
+        LDAPResult abandonResponse = ao.doOperation(objFactory, ar);
+        return null;
+      } else if (request instanceof ExtendedRequest) {
+        // Process the extended request.
+        ExtendedRequest er = (ExtendedRequest) request;
+        DSMLExtendedOperation eo = new DSMLExtendedOperation(connection);
+        ExtendedResponse extendedResponse = eo.doOperation(objFactory, er);
+        return objFactory.createBatchResponseExtendedResponse(extendedResponse);
+        
+      } else if (request instanceof DelRequest) {
+        // Process the delete request.
+        DelRequest dr = (DelRequest) request;
+        DSMLDeleteOperation delOp = new DSMLDeleteOperation(connection);
+        LDAPResult delResponse = delOp.doOperation(objFactory, dr);
+        return objFactory.createBatchResponseDelResponse(delResponse);
+      } else if (request instanceof CompareRequest) {
+        // Process the compare request.
+        CompareRequest cr = (CompareRequest) request;
+        DSMLCompareOperation compareOp =
+                new DSMLCompareOperation(connection);
+        LDAPResult compareResponse = compareOp.doOperation(objFactory, cr);
+        return objFactory.createBatchResponseCompareResponse(compareResponse);
+      } else if (request instanceof ModifyDNRequest) {
+        // Process the Modify DN request.
+        ModifyDNRequest mr = (ModifyDNRequest) request;
+        DSMLModifyDNOperation moddnOp =
+                new DSMLModifyDNOperation(connection);
+        LDAPResult moddnResponse = moddnOp.doOperation(objFactory, mr);
+        return objFactory.createBatchResponseModDNResponse(moddnResponse);
+      } else if (request instanceof ModifyRequest) {
+        // Process the Modify request.
+        ModifyRequest modr = (ModifyRequest) request;
+        DSMLModifyOperation modOp = new DSMLModifyOperation(connection);
+        LDAPResult modResponse = modOp.doOperation(objFactory, modr);
+        return objFactory.createBatchResponseModifyResponse(modResponse);
+      } else if (request instanceof AuthRequest) {
+        // Process the Auth request.
+        // Only returns an BatchReponse with an AuthResponse containing the
+        // LDAP result code AUTH_METHOD_NOT_SUPPORTED
+        ResultCode resultCode = objFactory.createResultCode();
+        resultCode.setCode(LDAPResultCode.AUTH_METHOD_NOT_SUPPORTED);
+        
+        LDAPResult ldapResult = objFactory.createLDAPResult();
+        ldapResult.setResultCode(resultCode);
+        
+        return objFactory.createBatchResponseAuthResponse(ldapResult);
+      } 
+    } catch (Throwable t) {
+      return createErrorResponse(t);
+    }
+    // should never happen as the schema was validated
+    return null;
+  }
+
+  
+  /**
    * Send a response back to the client. This could be either a SOAP fault
    * or a correct DSML response.
    *
    * @param doc   The document to include in the response.
-   * @param error Indicates whether an error occurred.
-   * @param reply The reply to send to the client.
    * @param res   Information about the HTTP response to the client.
-   * @param e     Information about any exception that was thrown.
+   *
    * @throws IOException   If an error occurs while interacting with the client.
    * @throws SOAPException If an encoding or decoding error occurs.
    */
-  private void sendResponse(Document doc, boolean error, SOAPMessage reply,
-                            HttpServletResponse res, Exception e)
+  private void sendResponse(Document doc, HttpServletResponse res)
     throws IOException, SOAPException {
+    
+    SOAPMessage reply = messageFactory.createMessage();
     SOAPHeader header = reply.getSOAPHeader();
     header.detachNode();
     SOAPBody replyBody = reply.getSOAPBody();
-
+    
     res.setHeader("Content-Type", "text/xml");
-
-    if (error) {
-      SOAPFault fault = replyBody.addFault();
-      Name faultName = SOAPFactory.newInstance().createName("Server",
-        "", SOAPConstants.URI_NS_SOAP_ENVELOPE);
-      fault.setFaultCode(faultName);
-      fault.setFaultString("Server Error: " + e.getMessage());
-      // FIXME - Set correct fault actor
-      fault.setFaultActor("http://localhost:8080");
-    } else {
-      SOAPElement bodyElement = replyBody.addDocument(doc);
-    }
-
+    
+    SOAPElement bodyElement = replyBody.addDocument(doc);
+    
     reply.saveChanges();
-
+    
     OutputStream os = res.getOutputStream();
     reply.writeTo(os);
     os.flush();
   }
-
-
-
+  
+  
   /**
    * Retrieves a message ID that may be used for the next LDAP message sent to
    * the Directory Server.
@@ -358,15 +530,32 @@
    * @return  A message ID that may be used for the next LDAP message sent to
    *          the Directory Server.
    */
-  public static int nextMessageID()
-  {
+  public static int nextMessageID() {
     int nextID = nextMessageID.getAndIncrement();
-    if (nextID == Integer.MAX_VALUE)
-    {
+    if (nextID == Integer.MAX_VALUE) {
       nextMessageID.set(1);
     }
-
+    
     return nextID;
   }
+
+  /**
+   * This class is used when a xml request is malformed to retrieve the
+   * requestID value using an event xml parser.
+   */
+  private static class DSMLContentHandler extends DefaultHandler {
+    private String requestID;
+    /*
+     * This function fetches the requestID value of the batchRequest xml
+     * element and call the default implementation (super).
+     */
+    public void startElement(String uri, String localName, String qName,
+                             Attributes attributes) throws SAXException {
+      if ( requestID==null && localName.equals("batchRequest") ) {
+        requestID = attributes.getValue("requestID");
+      }
+      super.startElement(uri, localName, qName, attributes);
+    }
+  }
 }
 

--
Gitblit v1.10.0