JWT Databinding

From Eclipsepedia

Revision as of 09:15, 19 June 2008 by Mickael.istria.openwide.fr (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Contents

Currently in JWT...

  • We have a DataMapping element which allows to map workflow properties to application input and output.
  • We have complex types (that are DataTypes composed of parameters). However, these complex type have only one level of complexity. (ie you can't put a complexType as a parameter of another complexType)
  • data are not really typed. Everything is String, or JWT-defined type (which are finally aliases for Strings)

Aim

The aim of databinding is to provide to JWT the ability to:

  • Deal with orchestration
  • Deal with complex types
  • Deal with type checking
  • To be continued

Thoughts

  • Is a workflow action equivalent to a (mathematical) function? That means, is it a component that takes some input, and computes some output?
    • What is sure is that Applications are equivalent to functions. So that Application should be fully abstract, with only input and output parameters as attributes
  • We need to be able to know the context (with different scopes?) for any entry of action to make the binding.
    • We know the context on each action with linked data.
  • We need a structured databinding to deal with complex types (classes, records, ...). What we specially require is the ability to browse the context and the variables
    • XPath
    • Expression Language
    • OCL (for EMF models)
    • OpenArchitectureWare
    • Anything else?
    • In fact, JWT already contains some Datamapping between action context and executing application. However, it currently simply maps parameter to parameter, where we would like to be able to map data (ie complex types)
  • We don't need to be able to evaluate complex (mathematical) expressions. Smart dereferencing is what we are looking for. However, it could be interesting to statically evaluate the type of guard conditions. (check whether a comparison is valid...). It could also facilitate the transformation of boolean expressions.
  • We wouldn't like to use BPEL, however we need something that can easily ve transformed into BPEL.
  • It could be good to be able to do static type checking one a binding.
    • May be difficult since the same data type is not the same programmatic type (eg: String for Java, xs:string for XML...)
    • XPath may not be very helpful for this task
    • POJO should be prefered for type checking, since Java is strongly types and native in JWT
  • Iterations may be problematic to define a context. Should we be only able to bind on the latest result of an iterated action, or should we be able to bind with the result of a specific iteration?
  • Is there a bijection between databindings? If yes, it reduces the risk of making a choice.
    • Mickael: I don't think so...
  • It could be cool to integrate a Talend-like UI for mapping:
    • see http://www.talend.com/img/Talend-Open-Studio-v1/tmap.gif
    • Where Left column would be the context, containing all available variables for the current action
    • Database rows would be fields, according to variables' types.
    • Right column would be the set of arguments of the application.
    • The mapping between action context and application should be carried by the reference link between action and application
  • Should action results automatically global variables, or should they stay "under" the action?
    • See DataMapping element in JWT for that. It clearly separates action and application and avoids this kind of question.
  • An application should be able to fill itself input and output parameters.
    • Need introspection (possible with Java and WSDL => ie possible with Java class (SCA) or WSDL location (SAAJ)
    • Requires that Workflow Editor knows the target classpath => A property sheet with the target classpath dor the workflow?
  • Data definition in metamodel should be changed.
    • Need to have a data parameter become a "field", that can be of any type. Need to add basic types to JWT (same basic types set as Java would be cool, easy, and complete)

Concrete issues, remarks

What do we need to use WS?

  • endpoint
  • operation name
  • arguments << this is databinding

What do we have

SAAJ implementation: deals with SOAP and WSDL

Here is the list of remarks that we got when trying to write some code related to web services databinding.

  • Should we really generate a SOAP Request from a WSDL, or just introspect the WSDL enough to know types
  • Where should appear the SOAP Request => Web Service Action in JWT or generated from a transformation from JWT to ...
  • javax.xml.soap and java.wsdl are not really fun to use
  • Could we use an ecore model for WSDL and SOAP?
  • How to make something that works with SOAP, but whom architecture would also fit to REST

We currently have a SAAJ implementation that is only able to build a SOAP request from a WSDL describing a "WorkflowService", for the method listUserActivities (or any method that arguments are called arg0 arg1 or arg2).

Main improvement would be to introspect the WSDL file to check the signature of an operation and to generate a request that match the name and the number of the arguments.

How to pass the arguments ?
  • method 1 (current): pass an array containing all the arguments. This way, we create the message, and each time we have to put an argument, we put the next item from the list.

The problem is that currently, we are only able to pass "simple" types, but not structured ones. This is not easy to solve since a WSDL can contains sone xsd:schema & co, that are not easy to manipulate with Java.

This method also implies that there is no real type checking, since everything is passed as strings.

package javasandboxplugin;
 
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.io.RandomAccessFile;
 
import javax.wsdl.Definition;
import javax.wsdl.WSDLException;
import javax.wsdl.factory.WSDLFactory;
import javax.wsdl.xml.WSDLReader;
import javax.xml.namespace.QName;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPBodyElement;
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPFactory;
import javax.xml.soap.SOAPMessage;
 
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
 
/**
 * Generated code for the test suite <b>TestSoap</b> located at
 * <i>/javaSandboxPlugin/src/TestSoap.testsuite</i>.
 * 
 * @see http://java.sun.com/javaee/5/docs/tutorial/doc/bnbhg.html
 */
public class TestSoap extends TestCase {
 
	private int currentPrefix = 1;
 
	private int currentArg = 0;
	private Object [] arguments = null;
 
	private String getNextArgAsString() {
		Object res = arguments[currentArg];
		currentArg++;
		return res.toString();
	}
 
	private String getPrefix() {
		return "ns" + currentPrefix;
	}
 
	/**
	 * Constructor for TestSoap.
	 * 
	 * @param name
	 */
	public TestSoap(String name) {
		super(name);
	}
 
	/**
	 * Returns the JUnit test suite that implements the <b>TestSoap</b>
	 * definition.
	 */
	public static Test suite() {
		TestSuite testSoap = new TestSuite(TestSoap.class);
		return testSoap;
	}
 
	/**
	 * @see junit.framework.TestCase#setUp()
	 */
	protected void setUp() throws Exception {
	}
 
	/**
	 * @see junit.framework.TestCase#tearDown()
	 */
	protected void tearDown() throws Exception {
	}
 
	public void testSoap() throws WSDLException, SOAPException, IOException {
 
		String endpoint = "http://localhost:8086/BonitaScaService";
		String wsdlURI = endpoint + "?wsdl";
		String methodName = "listUserActivities";
		File outputFile = File.createTempFile("test", "test");
 
		SOAPMessage message = generateRequestSkeletton(wsdlURI, methodName, "true", "true", "bsoa");
		message.writeTo(new PrintStream(outputFile));
		String line;
		RandomAccessFile readableFile = new RandomAccessFile(outputFile, "r");
		while ((line = readableFile.readLine()) != null)
			System.err.println(line);
		readableFile.close();
		outputFile.delete();
 
		System.err.println();
		SOAPMessage res = SOAPConnectionFactory.newInstance().createConnection().call(message, "http://localhost:8086/BonitaScaService");
		res.writeTo(new PrintStream(System.err));
		System.err.println();
	}
 
	/**
	 * @param wsdlURI
	 * @param methodName
	 * @return 
	 * @throws WSDLException
	 * @throws SOAPException
	 * @throws IOException
	 */
	private SOAPMessage generateRequestSkeletton(String wsdlURI, String methodName, Object ... args)
			throws WSDLException, SOAPException, IOException {
		this.arguments = args;
		this.currentArg = 0;
 
		WSDLFactory wsdlFactory = WSDLFactory.newInstance();
		WSDLReader wsdlReader = wsdlFactory.newWSDLReader();
 
		wsdlReader.setFeature("javax.wsdl.verbose",false);
		wsdlReader.setFeature("javax.wsdl.importDocuments",true);
 
		Definition definition = wsdlReader.readWSDL(wsdlURI);
		if (definition == null)
		{
		System.err.println("definition element is null");
		System.exit(1);
		}
 
		/**
		 * Header & footer
		 */
		MessageFactory messageFactory = MessageFactory.newInstance();
		SOAPMessage message = messageFactory.createMessage();
		message.getSOAPHeader().detachNode();
		SOAPBody body = message.getSOAPBody();
		/**
		 * Method
		 */
		QName bodyName = new QName(definition.getTargetNamespace(), methodName, getPrefix());
		SOAPBodyElement bodyElement = body.addBodyElement(bodyName);
		bodyElement.addNamespaceDeclaration("ns1", definition.getTargetNamespace());
 
		/**
		 * Args
		 */
		printArgs(definition, methodName, bodyElement);
 
		return message;
 
	}
 
	private void printArgs(Definition definition, String methodName,
			SOAPBodyElement bodyElement) throws SOAPException {
		/*
		 * Hack!!!
		 */
 
		/**
		 * 1. récupérer args 
		 * 2. for arg:args 
		 *   a. Regarder type
		 *      Si type natif => Go
		 *      sinon Trouver type dans les complexTypes
		 */
 
		SOAPFactory soapFactory = SOAPFactory.newInstance();
		SOAPElement arg0 = bodyElement.addChildElement(soapFactory
				.createElement(new QName(definition.getTargetNamespace(),
						"arg0", "ns1")));
		arg0.setValue(getNextArgAsString());
		SOAPElement arg1 = bodyElement.addChildElement(soapFactory
				.createElement(new QName(definition.getTargetNamespace(),
						"arg1", "ns1")));
		arg1.setValue(getNextArgAsString());
		SOAPElement arg2 = bodyElement.addChildElement(soapFactory
				.createElement(new QName(definition.getTargetNamespace(),
						"arg2", "ns1")));
		arg2.setValue(getNextArgAsString());
 
	}
 
}

SCA implementation: deals with Java

Another possibility is to consider that WS are called by an SCA runtime. This way, we can consider that we have the ability to call any service, with only a few differences (mainly the binding - ws, rmi, ejb...).

SCA Java implementations require one more thing to be able to call a service: the java class of this service. This has to be a parameter to add on the WSApplication. If we don't know this class, we can consider that the workflow engine will be in charge of generating the necessary classes with a WSDL2Java tool.



Web service application

JWT contains a "Web service Application", that represents a call to a web service. This item inherits from application, that is not an abstract application, but a kind of "Java Agilpro Application". Thus, it would be useful to create an Abstract Application, that would be used to define any concrete application (Java, WS, BPEL, SCA, Human...)

See http://dev.eclipse.org/mhonarc/lists/jwt-dev/msg00362.html


I think that the only thing that is common to every application is the fact that it may require argument and return values. That should be shared in the abstract application. Those informations could be stored in something like 2 arrays that would contain descriptions of arguments or return values (which could be a pair name/type-as string or anything else- in a first time).

This way, concrete application would have to implement a way to fill these arrays with descriptions by introspecting Java, WSDL, or anything else (when possible).

Such a strategy would allow us to do some static verification on signatures and types, and will make the edition suppler (one could change his mind and call another method from another service and benefit of verification just by refreshing the application according to its new properties).

M2 : Runtime

Bonita Hook : WSDL/SOAP implementation

TODO

Bonita Hook : SCA implemention

SCA Bonita Hook on SCorWare project (currently close, should be opened one day...)