Package org.apache.airavata.xbaya.invoker

Source Code of org.apache.airavata.xbaya.invoker.GenericInvoker

/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/

package org.apache.airavata.xbaya.invoker;

import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import javax.xml.namespace.QName;

import org.apache.airavata.common.workflow.execution.context.WorkflowContextHeaderBuilder;
import org.apache.airavata.common.utils.XMLUtil;
import org.apache.airavata.schemas.wec.ContextHeaderDocument;
import org.apache.airavata.workflow.model.exceptions.WorkflowException;
import org.apache.airavata.workflow.model.exceptions.WorkflowRuntimeException;
import org.apache.airavata.xbaya.invoker.factory.InvokerFactory;
import org.apache.airavata.xbaya.jython.lib.ServiceNotifiable;
import org.apache.airavata.xbaya.jython.lib.WorkflowNotifiable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmlpull.v1.builder.XmlElement;

import xsul.wsdl.WsdlDefinitions;
import xsul.wsdl.WsdlException;
import xsul.wsdl.WsdlResolver;
import xsul.wsif.WSIFMessage;
import xsul.xhandler_soap_sticky_header.StickySoapHeaderHandler;
import xsul.xwsif_runtime.WSIFClient;

public class GenericInvoker implements Invoker {

    private static final Logger logger = LoggerFactory.getLogger(GenericInvoker.class);

    private String nodeID;

    private QName portTypeQName;

    private String wsdlLocation;

    private String serviceInformation;

    private String messageBoxURL;

    private String gfacURL;

    private Invoker invoker;

    private Future<Boolean> result;

    private ServiceNotifiable notifier;

    private ContextHeaderDocument.ContextHeader contextHeader;

    private String topic;

    /**
     * used for notification
     */
    private List<Object> inputValues = new ArrayList<Object>();

    /**
     * used for notification
     */
    private List<String> inputNames = new ArrayList<String>();

    boolean failerSent;

    private WsdlDefinitions wsdlDefinitionObject;

    /**
     * Creates an InvokerWithNotification.
     *
     * @param portTypeQName
     *
     * @param wsdlLocation
     *            The URL of WSDL of the service to invoke
     * @param nodeID
     *            The ID of the service
     * @param notifier
     *            The notification sender
     */
    public GenericInvoker(QName portTypeQName, String wsdlLocation, String nodeID, WorkflowNotifiable notifier) {
        this(portTypeQName, wsdlLocation, nodeID, null, notifier);
    }

    /**
     * Creates an InvokerWithNotification.
     *
     * @param portTypeQName
     *
     * @param wsdlLocation
     *            The URL of WSDL of the service to invoke
     * @param nodeID
     *            The ID of the service
     * @param gfacURL
     *            The URL of GFac service.
     * @param notifier
     *            The notification sender
     */
    public GenericInvoker(QName portTypeQName, String wsdlLocation, String nodeID, String gfacURL,
            WorkflowNotifiable notifier) {
        this(portTypeQName, wsdlLocation, nodeID, null, gfacURL, notifier);
    }

    /**
     * Creates an InvokerWithNotification.
     *
     * @param portTypeQName
     *
     * @param wsdlLocation
     *            The URL of WSDL of the service to invoke
     * @param nodeID
     *            The ID of the service
     * @param messageBoxURL
     * @param gfacURL
     *            The URL of GFac service.
     * @param notifier
     *            The notification sender
     */
    public GenericInvoker(QName portTypeQName, String wsdlLocation, String nodeID, String messageBoxURL,
            String gfacURL, WorkflowNotifiable notifier) {
        this.nodeID = nodeID;
        this.portTypeQName = portTypeQName;
        this.wsdlLocation = wsdlLocation;
        this.serviceInformation = wsdlLocation;
        this.messageBoxURL = messageBoxURL;
        this.gfacURL = gfacURL;
        this.notifier = notifier.createServiceNotificationSender(nodeID);
        this.failerSent = false;
        this.contextHeader = WorkflowContextHeaderBuilder.removeOtherSchedulingConfig(nodeID,WorkflowContextHeaderBuilder.getCurrentContextHeader());
        this.topic = notifier.getTopic();
    }

    /**
     *
     * @param portTypeQName
     * @param wsdl
     * @param nodeID
     * @param messageBoxURL
     * @param gfacURL
     * @param notifier
     */
    public GenericInvoker(QName portTypeQName, WsdlDefinitions wsdl, String nodeID, String messageBoxURL,
            String gfacURL, WorkflowNotifiable notifier) {
        final String wsdlStr = xsul.XmlConstants.BUILDER.serializeToString(wsdl);
        this.nodeID = nodeID;
        this.portTypeQName = portTypeQName;
        this.wsdlDefinitionObject = wsdl;
        this.messageBoxURL = messageBoxURL;
        this.serviceInformation = wsdlStr;
        this.gfacURL = gfacURL;
        this.notifier = notifier.createServiceNotificationSender(nodeID);
        this.failerSent = false;
        this.contextHeader = WorkflowContextHeaderBuilder.removeOtherSchedulingConfig(nodeID,WorkflowContextHeaderBuilder.getCurrentContextHeader());
        this.topic = notifier.getTopic();
    }

    /**
     *
     * @throws WorkflowException
     */
    public void setup() throws WorkflowException {
        try {
            WsdlDefinitions definitions = null;
            if (this.wsdlLocation != null && !this.wsdlLocation.equals("")) {
                WsdlResolver resolver = WsdlResolver.getInstance();
                definitions = resolver.loadWsdl(new File(".").toURI(), new URI(this.wsdlLocation));
            } else {
                definitions = this.wsdlDefinitionObject;
            }

            setup(definitions);

        } catch (WorkflowException e) {
            logger.error(e.getMessage(), e);
            // An appropriate message has been set in the exception.
            this.notifier.invocationFailed(e.getMessage(), e);
            throw e;
        } catch (URISyntaxException e) {
            logger.error(e.getMessage(), e);
            String message = "The location of the WSDL has to be a valid URL or file path: " + this.serviceInformation;
            this.notifier.invocationFailed(message, e);
            throw new WorkflowException(message, e);
        } catch (WsdlException e) {
            logger.error(e.getMessage(), e);
            String message = "Error in processing the WSDL: " + this.serviceInformation;
            this.notifier.invocationFailed(message, e);
            throw new WorkflowException(message, e);
        } catch (RuntimeException e) {
            logger.error(e.getMessage(), e);
            String message = "Error in processing the WSDL: " + this.serviceInformation;
            this.notifier.invocationFailed(message, e);
            throw new WorkflowException(message, e);
        }catch (Error e) {
            logger.error(e.getMessage(), e);
            String message = "Unexpected error: " + this.serviceInformation;
            this.notifier.invocationFailed(message, e);
            throw new WorkflowException(message, e);
        }
    }

    private void setup(WsdlDefinitions definitions) throws WorkflowException {

        // Set LEAD context header.
        WorkflowContextHeaderBuilder builder;
        if(contextHeader == null){
            builder = new WorkflowContextHeaderBuilder(this.notifier.getEventSink()
                .getAddress(), this.gfacURL, null, this.topic,
                "xbaya-experiment", this.messageBoxURL);
        }else{
             builder = new WorkflowContextHeaderBuilder(contextHeader);
        }
        if(builder.getWorkflowMonitoringContext() == null){
            builder.addWorkflowMonitoringContext(this.notifier.getEventSink().getAddress(),
                    this.topic,this.nodeID,this.messageBoxURL);
        } else {
            builder.getWorkflowMonitoringContext().setWorkflowInstanceId(this.notifier.getWorkflowID().toASCIIString());
        }
        builder.getWorkflowMonitoringContext().setWorkflowNodeId(this.nodeID);
        builder.getWorkflowMonitoringContext().setServiceInstanceId(this.nodeID);
        builder.getWorkflowMonitoringContext().setWorkflowTimeStep(1);
        builder.setUserIdentifier("xbaya-user");
        //todo write a UI component to collect this information and pass it through Header
//        builder.setGridMyProxyRepository("myproxy.nersc.gov","$user","$passwd",14000);
        StickySoapHeaderHandler handler = new StickySoapHeaderHandler("use-workflowcontext-header", builder.getXml());
        // Create Invoker
        this.invoker = InvokerFactory.createInvoker(this.portTypeQName, definitions, this.gfacURL, this.messageBoxURL,
                builder, true);
        this.invoker.setup();

        WSIFClient client = this.invoker.getClient();
        client.addHandler(handler);

        WsdlResolver resolver = WsdlResolver.getInstance();
        // Get the concrete WSDL from invoker.setup() and set it to the
        // notifier.

        this.notifier.setServiceID(this.nodeID);
        // if (this.wsdlLocation != null) {
        // this.notifier.setServiceID(this.nodeID);
        // } else {
        // String name = this.portTypeQName.getLocalPart();
        // this.notifier.setServiceID(name);
        // }
    }

    /**
     *
     * @param operationName
     *            The name of the operation
     * @throws WorkflowException
     */
    public void setOperation(String operationName) throws WorkflowException {
        try {
            this.invoker.setOperation(operationName);
        } catch (WorkflowException e) {
            logger.error(e.getMessage(), e);
            // An appropriate message has been set in the exception.
            this.notifier.invocationFailed(e.getMessage(), e);
            throw e;
        } catch (RuntimeException e) {
            logger.error(e.getMessage(), e);
            String message = "The WSDL does not conform to the invoking service: " + this.serviceInformation;
            this.notifier.invocationFailed(message, e);
            throw new WorkflowException(message, e);
        } catch (Error e) {
            logger.error(e.getMessage(), e);
            String message = "Unexpected error: " + this.serviceInformation;
            this.notifier.invocationFailed(message, e);
            throw new WorkflowException(message, e);
        }
    }

    /**
     *
     * @param name
     *            The name of the input parameter
     * @param value
     *            The value of the input parameter
     * @throws WorkflowException
     */
    public void setInput(String name, Object value) throws WorkflowException {
        try {
            if (value instanceof XmlElement) {
                logger.debug("value: " + XMLUtil.xmlElementToString((XmlElement) value));
            }
            this.inputNames.add(name);
            this.inputValues.add(value);
            this.invoker.setInput(name, value);
        } catch (WorkflowException e) {
            logger.error(e.getMessage(), e);
            // An appropriate message has been set in the exception.
            this.notifier.invocationFailed(e.getMessage(), e);
            throw e;
        } catch (RuntimeException e) {
            logger.error(e.getMessage(), e);
            String message = "Error in setting an input. name: " + name + " value: " + value;
            this.notifier.invocationFailed(message, e);
            throw new WorkflowException(message, e);
        } catch (Error e) {
            logger.error(e.getMessage(), e);
            String message = "Unexpected error: " + this.serviceInformation;
            this.notifier.invocationFailed(message, e);
            throw new WorkflowException(message, e);
        }
    }

    /**
     *
     * @return
     * @throws WorkflowException
     */
    public synchronized boolean invoke() throws WorkflowException {
        try {
            WSIFMessage inputMessage = this.invoker.getInputs();
            logger.debug("inputMessage: " + XMLUtil.xmlElementToString((XmlElement) inputMessage));
            this.notifier.invokingService(inputMessage);

            ExecutorService executor = Executors.newSingleThreadExecutor();
            this.result = executor.submit(new Callable<Boolean>() {
                @SuppressWarnings("boxing")
                public Boolean call() {
                    try {
                        boolean success = GenericInvoker.this.invoker.invoke();
                        if (success) {
                            // Send notification
                            WSIFMessage outputMessage = GenericInvoker.this.invoker.getOutputs();
                            // An implementation of WSIFMessage,
                            // WSIFMessageElement, implements toString(), which
                            // serialize the message XML.
                            logger.debug("outputMessage: " + outputMessage);
                            GenericInvoker.this.notifier.serviceFinished(outputMessage);
                        } else {
                            //if error occurse gfac-axis2 write the error in to output not to the fault
                            WSIFMessage faultMessage = GenericInvoker.this.invoker.getOutputs();
                            // An implementation of WSIFMessage,
                            // WSIFMessageElement, implements toString(), which
                            // serialize the message XML.
                            logger.debug("received fault: " + faultMessage);
                            GenericInvoker.this.notifier.receivedFault(faultMessage);
                            GenericInvoker.this.failerSent = true;
                        }
                        return success;
                    } catch (WorkflowException e) {
                        logger.error(e.getMessage(), e);
                        // An appropriate message has been set in the exception.
                        GenericInvoker.this.notifier.invocationFailed(e.getMessage(), e);
                        GenericInvoker.this.failerSent = true;
                        throw new WorkflowRuntimeException(e);
                    } catch (RuntimeException e) {
                        logger.error(e.getMessage(), e);
                        String message = "Error in invoking a service: " + GenericInvoker.this.serviceInformation;
                        GenericInvoker.this.notifier.invocationFailed(message, e);
                        GenericInvoker.this.failerSent = true;
                        throw e;
                    }
                }
            });

            // Kill the thread inside of executor. This is necessary for Jython
            // script to finish.
            executor.shutdown();

            // Let other threads know that job has been submitted.
            notifyAll();

            // Check if the invocation itself fails. This happens immediately.
            try {
                this.result.get(100, TimeUnit.MILLISECONDS);
            } catch (InterruptedException e) {
                logger.error(e.getMessage(), e);
            } catch (TimeoutException e) {
                // The job is probably running fine.
                // The normal case.
                return true;
            } catch (ExecutionException e) {
                // The service-failed notification should have been sent
                // already.
                logger.error(e.getMessage(), e);
                String message = "Error in invoking a service: " + this.serviceInformation;
                throw new WorkflowException(message, e);
            }
        } catch (RuntimeException e) {
            logger.error(e.getMessage(), e);
            String message = "Error in invoking a service: " + this.serviceInformation;
            this.notifier.invocationFailed(message, e);
            throw new WorkflowException(message, e);
        } catch (Error e) {
            logger.error(e.getMessage(), e);
            String message = "Unexpected error: " + this.serviceInformation;
            this.notifier.invocationFailed(message, e);
            throw new WorkflowException(message, e);
        }
        return true;
    }

    /**
     *
     * @throws WorkflowException
     */
    @SuppressWarnings("boxing")
    public synchronized void waitToFinish() throws WorkflowException {
        try {
            while (this.result == null) {
                // The job is not submitted yet.
                try {
                    wait();
                } catch (InterruptedException e) {
                    logger.error(e.getMessage(), e);
                }
            }
            // Wait for the job to finish.
            Boolean success = this.result.get();
            if (success == false) {
                WSIFMessage faultMessage = this.invoker.getFault();
                String message = "Error in a service: ";
                // An implementation of WSIFMessage,
                // WSIFMessageElement, implements toString(), which
                // serialize the message XML.
                message += faultMessage.toString();
                throw new WorkflowException(message);
            }
        } catch (InterruptedException e) {
            logger.error(e.getMessage(), e);
        } catch (ExecutionException e) {
            // The service-failed notification should have been sent already.
            logger.error(e.getMessage(), e);
            String message = "Error in invoking a service: " + this.serviceInformation;
            throw new WorkflowException(message, e);
        } catch (RuntimeException e) {
            logger.error(e.getMessage(), e);
            String message = "Error while waiting for a service to finish: " + this.serviceInformation;
            this.notifier.invocationFailed(message, e);
            throw new WorkflowException(message, e);
        } catch (Error e) {
            logger.error(e.getMessage(), e);
            String message = "Unexpected error: " + this.serviceInformation;
            this.notifier.invocationFailed(message, e);
            throw new WorkflowException(message, e);
        }
    }

    /**
     *
     * @param name
     *            The name of the output parameter
     * @return
     * @throws WorkflowException
     */
    public Object getOutput(String name) throws WorkflowException {
        try {
            waitToFinish();
            Object output = this.invoker.getOutput(name);
            if (output instanceof XmlElement) {
                logger.debug("output: " + XMLUtil.xmlElementToString((XmlElement) output));
            }
            return output;
        } catch (WorkflowException e) {
            logger.error(e.getMessage(), e);
            // An appropriate message has been set in the exception.
            if (!this.failerSent) {
                this.notifier.invocationFailed(e.getMessage(), e);
            }
            throw e;
        } catch (RuntimeException e) {
            logger.error(e.getMessage(), e);
            String message = "Error while waiting for a output: " + name;
            this.notifier.invocationFailed(message, e);
            throw new WorkflowException(message, e);
        } catch (Error e) {
            logger.error(e.getMessage(), e);
            String message = "Unexpected error: " + this.serviceInformation;
            this.notifier.invocationFailed(message, e);
            throw new WorkflowException(message, e);
        }
    }

    /**
     *
     * @return
     * @throws WorkflowException
     */
    public WSIFMessage getOutputs() throws WorkflowException {
        return this.invoker.getOutputs();
    }

    @Override
    public WSIFClient getClient() {
        return null;
    }

    @Override
    public WSIFMessage getInputs() throws WorkflowException {
        return null;
    }

    @Override
    public WSIFMessage getFault() throws WorkflowException {
        return null;
    }
}
TOP

Related Classes of org.apache.airavata.xbaya.invoker.GenericInvoker

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.