Synapse Object

Hello everyone, this wiki gives an overview of what SynapseObject (also referred to as SO) is all about, the reasons why it is being proposed. Changes suggested by Aleksander Slominski, Mukund Balasubramanian and a few other have been incorporated too.

Introduction

Data representation has been a tough job always. But with the advent of XML, representing them has become much easier but still the data handling intelligence is missing (what is that?). Say for instance we have an XML

XML-1

<contacts>
  <contact>
    <name>John</name>	
    <address>360 Morse Ave</address>
    <city>Sunnyvale</city>
    <state>US</state>
    <zip>94086</zip>
  </contact>
  <contact>
    <name>Mary</name>	
    <address>410 Dale Park</address>
    <city>Sunnyvale</city>
    <state>US</state>
    <zip>94086</zip>
  </contact>
</contacts> 

One can say that another way of representing them would be:

XML-2

<contacts>
  <contact name=”John” address=”360 Morse Ave” city=”Sunnyvale” state…></contact>
  <contact name=”Mary” address=”410 Dale Park” city=”Sunnyvale” state…></contact>
</contacts>

Differences Between XML 1 and XML 2

From a generic standpoint both give the notion of a person’s address, XML-1 in this context could be treated as more appropriate as it depicts that a contact has attributes in the form of objects, where each composite object within has an identity of it’s own or each of then can exists even if the contact object is not present but if you think deep, would they meaningfully exist? Not really. At such a granular level it would become a nightmare to maintain them, there could be two people with the same name.
On the other hand XML-2 is more of a wysiwyg (What you see is what you get) but readability wise maybe not be that great. There are different school of thoughts in using XML but then XML has been conceived in a fashion, which allows representation of data in any way users wish to put it.

Unfortunately those examples are too simplistic to be of practical value and non of approaches work well to model more complex data.

However this gets more interesting if address is represented as extensible data structure where street is not mixed with concept of address and a person may have multiple addresses but still we attach only one name to a contact (so attribute is very well fitting):

XML-3

<contacts>
  <contact name="John">
    <address>
      <line1>360 Morse Ave</line1>
      <city>Sunnyvale</city>
      <state>US</state>
      <zip>94086</zip>
    </address>
  </contact>
  <contact name="Mary">
    <address type="home">
      <line1>410 Dale Park</line1>
      <line1>Apt 10</line1>
      <city>Sunnyvale</city>
      <state>US</state>
      <zip>94086</zip>
    <address>
    <address type="work">
      <line1>222 Sunny Blvd</line1>
      <city>Sunnyvale</city>
      <state>US</state>
      <zip>94086</zip>
    <address>
  </contact>
</contacts> 

This of course gives immense control to the person who is writing it but then introduces a whole lot of ambiguity when a different person gets it. The reason being the context is lost in transmission. At one end there is a whole lot of flexibility and on the other end ambiguity.

To resolve this issue, XSDs have been used to validate xmls from either end and provide some control for type validation. Going forward Data-binding mechanisms have provided users to produce classes/jars from an XSD and then using XMLs(conforming to the XSD) generate instances that could be used for performing certain tasks.

Note: it is possible to use XML without any databinding and just with lightweight validation (using XML schema or RELAX NG) 

Take for instance XMLBeans from Apache, which generates java classes from a given XSD and then allows you to get instances by passing an XML, which subscribes to the XSD format.

Note:
For the adventurous few, try out XMLBeans on the above 2 XMLs.
XML 1 - Leads to too many classes to handle
XML 2 - The code is quite cryptic

From a logical perspective (using XMLBeans)

1) You need to generate classes (jars) from the XSD

2) After getting the xml (containing the data), generate instances of those classes

3) Use the instances in some other container/Object to perform certain tasks.

Given the flexibility that the above approach gives one should be more than happy to use it.

_ But consider the following_

Problems with the above approach :

1) You have to maintain the generated classes physically in some location

2) Re-generate them in case the XSD changes

3) Change the underlying logic in the classes which use the generated instances.

4) No in-built search mechanism or features by which complex objects can be recursively traversed to find embedded objects or attributes based on various criteria.

Alternate situation where

1) No generation of classes are required

2) No classes/jars to maintain

3) Get instances directly from the XML based on the XSD

4) Search feature to find attributes

5) Search feature to find embedded objects by giving attribute values

6) Search feature to find embedded objects by giving attribute names

7) And most importantly the object that you get from the XML is generic, so no need of casting it. Just give the XML and get a generic object on which you can perform all the search features as stated above and have the getters and setters too with type information!

This is what SynapseObject is all about. A utility object, that allows manipulation and handling of XML in a generic fashion.

How does it work

It works in two modes

With an XSD (Under progress)

The constructor takes an XML and it’s corresponding XSD and spits out a SynapseObject instance

XML

<ConsumerIdentification xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://somehost/SO-XML.xsd">
	<consumer>
		<CONSUMER_TYPE>GOLD</CONSUMER_TYPE>
		<IP_ADDRESS_FROM>192.167.6.0</IP_ADDRESS_FROM>
		<IP_ADDRESS_TO>192.168.6.255</IP_ADDRESS_TO>
		<HTTP_AUTH_USERNAME>john</HTTP_AUTH_USERNAME>
		<WS_SEC_USERNAME>john</WS_SEC_USERNAME>
		<assignedService>
			<serviceid>stockQuote1</serviceid>
		</assignedService>
	</consumer>
	<consumer>
		<CONSUMER_TYPE>SILVER</CONSUMER_TYPE>
		<IP_ADDRESS_FROM>192.167.8.0</IP_ADDRESS_FROM>
		<IP_ADDRESS_TO>192.168.8.255</IP_ADDRESS_TO>
		<HTTP_AUTH_USERNAME>Sam</HTTP_AUTH_USERNAME>
		<WS_SEC_USERNAME>Sam</WS_SEC_USERNAME>
		<assignedService>
			<serviceid>stockQuote1</serviceid>
		</assignedService>
	</consumer>
</ConsumerIdentification>

XSD

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
	<xs:element name="CONSUMER_TYPE">
		<xs:simpleType>
			<xs:restriction base="xs:string">
 		</xs:restriction>
		</xs:simpleType>
	</xs:element>
	<xs:element name="ConsumerIdentification">
		<xs:complexType>
			<xs:sequence>
				<xs:element ref="consumer" maxOccurs="unbounded"/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
	<xs:element name="HTTP_AUTH_USERNAME">
		<xs:simpleType>
			<xs:restriction base="xs:string">
		</xs:restriction>
		</xs:simpleType>
	</xs:element>
	<xs:element name="IP_ADDRESS_FROM">
		<xs:simpleType>
			<xs:restriction base="xs:string">
			</xs:restriction>
		</xs:simpleType>
	</xs:element>
	<xs:element name="IP_ADDRESS_TO">
		<xs:simpleType>
			<xs:restriction base="xs:string">
			</xs:restriction>
		</xs:simpleType>
	</xs:element>
	<xs:element name="WS_SEC_USERNAME">
		<xs:simpleType>
			<xs:restriction base="xs:string">
			</xs:restriction>
		</xs:simpleType>
	</xs:element>
	<xs:element name="assignedService">
		<xs:complexType>
			<xs:sequence>
				<xs:element ref="serviceid"/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
	<xs:element name="consumer">
		<xs:complexType>
			<xs:sequence>
				<xs:element ref="CONSUMER_TYPE"/>
				<xs:element ref="IP_ADDRESS_FROM"/>
				<xs:element ref="IP_ADDRESS_TO"/>
				<xs:element ref="HTTP_AUTH_USERNAME"/>
				<xs:element ref="WS_SEC_USERNAME"/>
				<xs:element ref="assignedService"/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
	<xs:element name="serviceid">
		<xs:simpleType>
			<xs:restriction base="xs:string">
			</xs:restriction>
		</xs:simpleType>
	</xs:element>
</xs:schema>

Without an XSD

The constructor takes an XMl and spits out a SynapseObject. The only dependency being the XML should have the type definition for attributes in the XML itself.

XML for SynapseObject

<ConsumerIdentification>
 <consumer>
   <CONSUMER_TYPE type="STRING">GOLD</CONSUMER_TYPE>
   <IP_ADDRESS_FROM type="STRING">192.167.6.0</IP_ADDRESS_FROM>
   <IP_ADDRESS_TO type="STRING">192.168.6.255</IP_ADDRESS_TO>
   <HTTP_AUTH_USERNAME type="STRING">john</HTTP_AUTH_USERNAME>
   <WS_SEC_USERNAME type="STRING">john</WS_SEC_USERNAME>
   <assignedService>
    <serviceid1 type="STRING">stockQuote1</serviceid1>
   </assignedService>
 </consumer>
</ConsumerIdentification>

Features

CLASS-DIAGRAM :

http://svn.apache.org/repos/asf/incubator/synapse/trunk/scratch/infravio/synapse-SO/SO-ClassDiag.JPG

SynapseObject :

Synapse object is the core object, which follows the composite pattern. Each SynapseObject can have one or more SynapseObject embedded within.

Attribute handling :

The setters and getters are type based, example -> so.getString(“foo”) would spit out a string for the attribute name foo.

GenericObject :

For representing attributes a concept of holder object has been used which has the type, value and name information of an attribute

SynapseObjectArray :

Represents an array of SynapseObjects.

Search Handling :

Search is based on

Attribute name (also with added functionality like starts with or ends with) Attribute value (also with added functionality like starts with or ends with) Object name (also with added functionality like starts with or ends with)

Translator :

Translate SynapeObject into any other format by passing a XSLT.

Reasons for using SynapseObject

1) Java Properties class lets you handle name-value pairs in a very good way but when it comes to representing complex objects it becomes very difficult.

2) Using the concept of data binding introduces a very rigid and tight coupling of data and schema. So if the schema changes the underlying data handling mechanism needs to be changed (which includes the beans/classes to hold the complex data structure)

3) Intelligent search features are either driven by xpath/xqueries for pure XML or embedded logic if beans are used, SynapseObject has inbuilt search features by which you can perform complex searches.

4) The reason people use Java Properties class is because name-value pairs can be shared by other class without any dependency. SynapseObject is more like a Properties Class with added features to handle Complex Objects and also allow search features.

Uses Case

A) Data-Sharing between mediators: Consumers need to be identified, once it's identified the information could be shared by the SLA mediator which depending on a consumer will set the priority. Below is the pseudo code of how this can be achieved using SynapseObject and how datasharing would become easy.

Background Info

ConsumerIdentification mediator needs to identify a client by the following ways:

1) IP {eg. 192.168.5.10}

2) IP Range {eg. 192.168.5.20- 192.168.5.30}

3) WS-SEC auth token

4) HTTP auth token

5) certificate (Other factors that need to be considered whether the incoming message was first encrypted and then signed or was it signed and then encrypted).

Let's consider 1) IP

Using SynapseObject

ConsumerIdentification XML fragment:
------------------------------------
 
<?xml version='1.0' encoding='windows-1252'?>
		<Consumer_Identification>
                 <Consumer>
                   <CONSUMER_TYPE type=\"xsd:String\">GOLD</CONSUMER_TYPE>
                   <IP_ADDRESS_FROM type=\"xsd:String\">192.167.6.0</IP_ADDRESS_FROM>
                   <IP_ADDRESS_TO type=\"xsd:String\">192.168.6.255</IP_ADDRESS_TO>
                   <HTTP_AUTH_USERNAME type=\"xsd:String\">john</HTTP_AUTH_USERNAME>
                   <WS_SEC_USERNAME type=\"xsd:String\">john</WS_SEC_USERNAME>
                   <Assigned_Service>
                    <Service_ID type=\"xsd:String\">stockQuote1</Service_ID>
                   </Assigned_Service>
                 </Consumer>
                 <Consumer>
                   <CONSUMER_TYPE type=\"xsd:String\">SILVER</CONSUMER_TYPE>
                   <IP_ADDRESS_FROM type=\"xsd:String\">192.168.6.255</IP_ADDRESS_FROM>
                   <IP_ADDRESS_TO type=\"xsd:String\">192.168.6.255</IP_ADDRESS_TO>
                   <HTTP_AUTH_USERNAME type=\"xsd:String\">mary</HTTP_AUTH_USERNAME>
                   <WS_SEC_USERNAME type=\"xsd:String\">mary</WS_SEC_USERNAME>
                   <Assigned_Service>
                    <Service_ID type=\"xsd:String\">stockQuote1</Service_ID>
                   </Assigned_Service>
                 </Consumer>
                </Consumer_Identification>

In the ci mediator code fragment

 
// the the requester ip 
ip = {get the remote ip from the messageContext/SynapseContext }
 
//Identify if the consumer is there and get appropriate details and store the consumer related details in the messageContext, one more things to note is that storing shared data is by the mediator name itself eg. ci 
SynapseObject obj = consumerIdentification.findSynapseObjectByAttributeValueStartingWith(ip);
messageContext.setProperty(consumerIdentification.getName(),obj);
obj will contain all the required values if identified!
 
SLA xml Fragment:
------------------
<sla>
    <consumer>
        < service>
            < epr type="String">http://www.webservicex.net/stockquote.asmx</epr>
            < priority type="Integer">0</priority>
        </service>
        < service>
            <epr type="String">http://www.webservicex.net/findZIPCode.asmx</epr>
            < priority type="Integer">1</priority>
        </service>
    </consumer>
</sla>

In the SLA Mediator code fragment

 
//As there is a dependency between the SLA mediator and CI the SLA mediator will pick information for its dependency(Note: we also proposed a concept 
//of MediatorContext which will have dependency and other information for a particular mediator)
 
//Get the identified consumer from the messagecontext
SynapseObject consumerIdentification = (SynapseObject)messageContext.getProperty("ci");
 
// get the consumer name and consumer type
String consumerName = consumerIdentification.getName();
String consumerType = consumerIdentification.getString("CONSUMER_TYPE");
 
//find the sla details for the identified consumer
SynapseObject consumer = sla.findSynapseObjectByAttributeValue(consumerName);
String fromAddress = (String)synapseMessageContext.getTo();
SynapseObject service = consumer.findSynapseObjectByAttributeValue(fromAddress );
 
// The priority value would be used by the SLA mediator to forward the request to the provider depending on the priority. 
String priority = service.getString("priority");

Simplified XML (XML-N)

It uses XML attributes for SynapseObject Attribute and simple convention to represent type "{type}value" ex. "{int}10" and it should be possible to write XML schema to validate such values if there was ever need (break string into type "{int}" and valudate rest against XML schemas xsd:int)

<ConsumerIdentification>
 <consumer consumer-type="GOLD" ip-address-from="192.167.6.0" ip-address-to="192.167.6.255"
   http-auth-username="john" ws-sec-username="john"
 >
   <assignedService>stockQuote1</assignedService>
   <assignedService>waterMeter</assignedService>
 </consumer>
</ConsumerIdentification>

It is both short and can be validated. And cvan be automatically processed to provide functionality of SynapseObject API

  • No labels