/*
 * $RCSfile: CopyRestoreFragmentWsInvocationSender.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.
 */
 
/*
 * CopyRestoreFrangmentInvocation.java Add description 
 * 
 * @author Prawee Sriplakich
 * @version $Revision: 1.1.2.2 $ $Date: 2006/01/26 14:48:59 $
 * @see Add references
 *
 * TODO Add description
 * TODO Add references
 */
package org.eclipse.mddi.modelbus.adapter.infrastructure.transport.client.ws;

import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Properties;

import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPFault;
import javax.xml.soap.SOAPMessage;

import org.apache.log4j.Logger;
import org.eclipse.mddi.modelbus.adapter.infrastructure.model_manipulation.DescriptionUtil;
import org.eclipse.mddi.modelbus.adapter.infrastructure.transport.client.AbstractInvocationSender;
import org.eclipse.mddi.modelbus.adapter.infrastructure.transport.marshal.ws.AbstractMarshaler;
import org.eclipse.mddi.modelbus.adapter.infrastructure.transport.marshal.ws.CopyRestoreFragmentMarshaler;
import org.eclipse.mddi.modelbus.adapter.infrastructure.transport.marshal.ws.SoapUtil;
import org.eclipse.mddi.modelbus.adapter.user.ModelingServiceError;
import org.eclipse.mddi.modelbus.adapter.user.consumer.ModelBusCommunicationException;
import org.eclipse.mddi.modelbus.adapter.user.consumer.ModelTypeMismatchException;
import org.eclipse.mddi.modelbus.adapter.user.consumer.NoToolAvailableException;
import org.eclipse.mddi.modelbus.adapter.user.consumer.ServiceUnknownException;
import org.eclipse.mddi.modelbus.description.abstract_.ModelingService;
import org.eclipse.mddi.modelbus.description.abstract_.Parameter;

public class CopyRestoreFragmentWsInvocationSender extends AbstractInvocationSender {

    private static Logger logger = Logger.getLogger(DefaultWsInvocationSender.class);
    
    //AdapterStub adapter;    
    
    SOAPMessage requestMsg;
    SOAPMessage responseMsg;
    String targetUrl;
    
    // an array of in/inout parameter values
    // if usesScope option is set, it must contain two extra elements: "inScope", "inoutScope";
    Object[] unmarshalledInputs;
    
    // an array of out/inout parameter values
    Object[] unmarshalledOutputs;
    
    ModelingService ms;
    
    Collection inScope = null, inoutScope = null;
    
    
    public CopyRestoreFragmentWsInvocationSender(Properties prop) {
        setMarshaler(new CopyRestoreFragmentMarshaler(prop));
    }
    
    
    /* (non-Javadoc)
     * @see org.eclipse.mddi.modelbus.adapter.user.provider.WsInvocationSender#invoke(org.eclipse.mddi.modelbus.description.concrete.Tool, org.eclipse.mddi.modelbus.description.abstract_.ModelingService, java.lang.Object[])
     */
    public Object[] invoke(ModelingService ms, Object[] inputs) 
            throws ServiceUnknownException,
            NoToolAvailableException, ModelTypeMismatchException,
            ModelBusCommunicationException, ModelingServiceError {
        
        this.targetUrl = DescriptionUtil.getProperty(getToolDescription(), "URL")+"."+ms.getName();
        this.ms = ms;
        this.unmarshalledInputs = inputs;

        try {            
            
            createRequestMessage();
            makeConnection();
            readResponseMessage();
            return unmarshalledOutputs;

        } catch (SOAPException e) {
            throw new ModelBusCommunicationException(e.getMessage(), e);
        } catch (IOException e) {
            throw new ModelBusCommunicationException(e.getMessage(), e);            
        }catch (Exception e) {
            throw new ModelBusCommunicationException(e.getMessage(), e);
        }

    }
    

       

    
    
    void createRequestMessage() throws Exception {
        requestMsg = SoapUtil.messageFactory.createMessage();
        SOAPBody requestbody = requestMsg.getSOAPBody();
        AbstractMarshaler.setNamespaces(requestbody);            
        SOAPElement reqTopElem = requestbody.addChildElement(ms.getName(), "modelbus");
        List inputParams = DescriptionUtil.get_in_inout_Parameters(ms);
        //check the number of parameters
        if(getCopyRestoreFragmentModelMarshaler().isUseScope()) {
            if(unmarshalledInputs.length!= inputParams.size() +2 )
                throw new ModelTypeMismatchException("Bad number of input parameters, got "
                     + unmarshalledInputs.length +" expected " +inputParams.size() + " + inScope, outScope");               
            // marshal Scope
            inScope = (Collection) unmarshalledInputs[inputParams.size()]; 
            if(inScope!=null) {   
                getCopyRestoreFragmentModelMarshaler().marshallScope( 
                        CopyRestoreFragmentMarshaler.IN_SCOPE, inScope, reqTopElem);
            } 
            inoutScope = (Collection) unmarshalledInputs[inputParams.size() +1];
            if(inoutScope!=null) {
                getCopyRestoreFragmentModelMarshaler().marshallScope( 
                        CopyRestoreFragmentMarshaler.INOUT_SCOPE, inoutScope, reqTopElem);            
            }        
        } else {
          if(unmarshalledInputs.length!= inputParams.size())
             throw new ModelTypeMismatchException("Bad number of input parameters, got "
                  + unmarshalledInputs.length +" expected " +inputParams.size());    
        }
        
        // marshal parameters
        for (int i = 0; i < inputParams.size(); i++) {
            Parameter p = (Parameter) inputParams.get(i);
            getMarshaler().marshal(p, unmarshalledInputs[i], reqTopElem);
        }
                         
    }
    
    private void makeConnection() throws SOAPException {      
    
        logger.debug("Call URL: "+targetUrl);

        SOAPConnection con = SoapUtil.connectionFactory.createConnection();
        
        logger.debug("Call with Message: "+requestMsg.getSOAPBody().toString());
          
        responseMsg =  con.call(requestMsg, targetUrl); 
        con.close();        
        logger.debug("Response Message: "+responseMsg.getSOAPBody().toString());
        
    }
    
    
    // unmarshall response message    
    void readResponseMessage() throws Exception {

      SOAPBody responsebody = responseMsg.getSOAPBody();
      if (responsebody.hasFault()) {
         SOAPFault f = responsebody.getFault(); 
         if(AbstractMarshaler.isModelingServiceError(f)) {
            ModelingServiceError err = AbstractMarshaler.unmarshallModelingServiceError(f);
            throw err;   
         } else {
           throw new ModelBusCommunicationException(f.toString());
         }
         
      } else {
          SOAPElement resTopElem = SoapUtil.getFirstChild(responsebody);
          if(resTopElem==null) {
                logger.error("Empty SOAP response");
                logger.debug(responsebody.toString());
            throw new ModelBusCommunicationException("Empty SOAP response");                    
          }
          //unmarshall Scope
          if(getCopyRestoreFragmentModelMarshaler().isUseScope()) {
            getCopyRestoreFragmentModelMarshaler().unmarshallScope(resTopElem);      
            
            // inform the tool about changes (added/deleted model elements).
            if(inoutScope!=null) {
               inoutScope.clear();
               inoutScope.addAll(getCopyRestoreFragmentModelMarshaler().getInoutScope());          
            }
          }
          
          List outputParams = DescriptionUtil.get_out_inout_Parameters(ms);
          unmarshalledOutputs = new Object[outputParams.size()];
          for (int i = 0; i < outputParams.size(); i++) {
              Parameter p = (Parameter) outputParams.get(i);
              unmarshalledOutputs[i] = getMarshaler().unmarshal(p, resTopElem);
          }
                    
      }
    }
    
    public CopyRestoreFragmentMarshaler getCopyRestoreFragmentModelMarshaler() {
        return (CopyRestoreFragmentMarshaler) getMarshaler();        
    }   
    
    

}
