/*
 * $RCSfile: DefaultWsInvocationReceiver.java,v $
 * $Date: 2006/01/26 14:48:59 $
 * $Revision: 1.1.2.2 $
 * $Author: andreys $
 */
 
/*
 * Copyright (c) 2002-2003 IST-2004-2006-511731 ModelWare - ModelBus.
 * All rights reserved.
 *
 * This software is published under the terms of the ModelBus Software License
 * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * A copy of ModelBus Software License is provided with this distribution in
 * doc/LICENSE.txt file.
 */
 
/*
 * DefaultWsInvocationReceiver.java 
 * 
 * @author Prawee Sriplakich, Andrey Sadovykh (LIP6)
 * @version $Revision: 1.1.2.2 $ $Date: 2006/01/26 14:48:59 $
 */
package org.eclipse.mddi.modelbus.adapter.infrastructure.transport.server.ws;

import java.util.List;

import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPFault;

import org.apache.log4j.Logger;
import org.eclipse.mddi.modelbus.adapter.infrastructure.LoggerConfigurator;
import org.eclipse.mddi.modelbus.adapter.infrastructure.model_manipulation.DescriptionUtil;
import org.eclipse.mddi.modelbus.adapter.infrastructure.transport.marshal.ws.AbstractMarshaler;
import org.eclipse.mddi.modelbus.adapter.infrastructure.transport.marshal.ws.DefaultMarshaler;
import org.eclipse.mddi.modelbus.adapter.infrastructure.transport.marshal.ws.SoapUtil;
import org.eclipse.mddi.modelbus.adapter.user.AdapterStub;
import org.eclipse.mddi.modelbus.adapter.user.InvalidSession;
import org.eclipse.mddi.modelbus.adapter.user.ModelingServiceError;
import org.eclipse.mddi.modelbus.adapter.user.SessionNeeded;
import org.eclipse.mddi.modelbus.adapter.user.consumer.ModelTypeMismatchException;
import org.eclipse.mddi.modelbus.adapter.user.provider.GenericProvider;
import org.eclipse.mddi.modelbus.description.abstract_.ModelingService;
import org.eclipse.mddi.modelbus.description.abstract_.Parameter;

public class DefaultWsInvocationReceiver extends WsInvocationReceiver {
    AdapterStub adapter;     

    
    SOAPEnvelope reqMsg;
    SOAPEnvelope resMsg;
    ModelingService ms;
    
    // an array of in/inout parameter values
    // if usesScope option is set, it must contain two extra elements: "outScope", "inoutScope"
    Object[] unmarshalledInputs;
    
    // an array of out/inout parameter values
    Object[] unmarshalledOutputs;
    
    private static Logger logger = Logger.getLogger(DefaultWsInvocationReceiver.class);
     

    public DefaultWsInvocationReceiver(AdapterStub adapter) {
         LoggerConfigurator.configure();
         this.adapter = adapter;
         setMarshaler(new DefaultMarshaler(adapter.getProperties()));
    }
    
    

   /* (non-Javadoc)
  * @see org.eclipse.mddi.modelbus.adapter.user.provider.WsInvocationReceiver#process(javax.xml.soap.SOAPMessage, javax.xml.soap.SOAPMessage)
  */
   public void process(SOAPEnvelope reqMsg, SOAPEnvelope resMsg) throws SOAPException  { 
     this.reqMsg = reqMsg;
     this.resMsg = resMsg;
     try {         
       readRequest();
       performService();
       createResponse();
     } catch(Exception e) {
         createSoapFault(resMsg, e);
     }
    }
    
    /**
     * Reads the content in the HTTP request
     * @throws Exception 
  */
   void readRequest() throws Exception {
  
     SOAPBody requestbody = reqMsg.getBody();    
     // the first child in the SOAP body is a input message conforming to WSDL
     SOAPElement reqTopElem = SoapUtil.getFirstChild(requestbody);
     if(reqTopElem==null) {
         logger.error("SERVER: receive empty request");
         logger.debug(reqMsg);
         throw new SOAPException("Empty SOAP request");      
     }
     
     String serviceName = reqTopElem.getLocalName();
     
     ms = DescriptionUtil.getServiceDescription(serviceName, adapter.getToolDescription());
     if(ms==null) {
       throw new SOAPException("Service unknown - " +serviceName);    
     }
         
     List inputParams = DescriptionUtil.get_in_inout_Parameters(ms); 
     
     Parameter [] params = new Parameter [inputParams.size()]; 
     for (int i=0; i<inputParams.size();i++) params[i] = (Parameter)inputParams.get(i);

     unmarshalledInputs =  marshaler.unmarshal(params, reqTopElem); 
    }
    
    
    
   
    void performService() throws SessionNeeded, ModelingServiceError, InvalidSession  { 
      GenericProvider si = adapter.getToolStub().getProvider();
      String serviceName = ms.getName();
      unmarshalledOutputs = si.execute(serviceName, unmarshalledInputs);      
    }
    
    
    
    
    /**
     * Produces the HTTP response
     * @throws Exception 
  */
   void createResponse() throws Exception {
      SOAPBody responsebody = resMsg.getBody();
      AbstractMarshaler.setNamespaces(responsebody);
      
      SOAPElement resTopElem = responsebody.addChildElement( ms.getName() +"Response", "modelbus");
      List outputParams = DescriptionUtil.get_out_inout_Parameters(ms);
      
      if(unmarshalledOutputs.length!= outputParams.size()) {
          throw new ModelTypeMismatchException("Bad number of output parameters, got "
                  + unmarshalledOutputs.length +" expected " +outputParams.size());    
      }     
      
      Parameter [] params = new Parameter [outputParams.size()]; 
      for (int i=0; i<outputParams.size();i++) params[i] = (Parameter)outputParams.get(i);
      marshaler.marshal(params,unmarshalledOutputs,resTopElem);
    }
    

     
     /**
      * Creates a SOAP fault from a cause exception
      * @param resMsg
      * @param cause 
      * @throws SOAPException if the SOAP fault cannot be created
      */
     public static void createSoapFault(SOAPEnvelope resMsg, Exception cause) throws SOAPException {
          SOAPBody responsebody = resMsg.getBody();
          AbstractMarshaler.setNamespaces(responsebody);
          
         SOAPFault f = responsebody.addFault();
          if(cause instanceof ModelingServiceError) {
            ModelingServiceError err = (ModelingServiceError) cause;
            AbstractMarshaler.marshallModelingServiceError(err, f);
          } else {
            f.setFaultString(cause.getClass() +":"+ cause.getMessage());    
            logger.error("Error", cause);
          }
     }
     
     
     /**
      * Creates a SOAP fault from an error message
      * @param resMsg
      * @param errorMessage
      * @throws SOAPException if the SOAP fault cannot be created
      */
     public static void createSoapFault(SOAPEnvelope resMsg, String errMessage) throws SOAPException {
          SOAPBody responsebody = resMsg.getBody();
          AbstractMarshaler.setNamespaces(responsebody);        
          SOAPFault f = responsebody.addFault();
          f.setFaultCode("modelbus:ServerError");
          f.setFaultString(errMessage);
          logger.error("modelbus:ServerError. " + errMessage);
     }
         
     
}
