Superx++ Services Specification

What are Superx++ Services?
Superx++ services are program services that are published on the web that can be executed remotely by sending XML requests or Superx++ objects to the computer exposing the services. These Superx++ services expose methods that are invocable by the XML request or the Superx++ object. The Superx++ object is a courier which can call multiple methods before returning to its sender. This is all a part of the courier messaging model that Superx++ supports. Please note that the sending of an XML request (not wrapped in a Superx++ object) constitutes a simple message.

This may sound quite a bit like typical web services to you. It is similar in essence, however there are obvious implementation differences. Superx++ services do not use XML Schema, SOAP or WSDL. Instead a very simple pair of XML files are used to make things much simpler. In addition, Superx++ services, as currently defined, support the simple messaging model which is not as efficient as courier messaging. So because of these differences, I think it less controversial to define these as Superx++ services rather than web services. However, do keep in mind that this is an XML messaging/services model.

Courier Messaging vs. Simple Messaging
The current methods being used and popularized today for XML messaging require the sending of XML-based messages from a source computer to a destination (service offering) computer. The service is executed on the destination computer and a result is optionally sent back to the source computer. Each message call requires two trips across the network: one to send the data and the other to return the result back to the source. If there are contingencies that need to be handled due to exceptional situations or errors that occur at runtime, then more messages must be sent. This situation can get exacerbated (even without considering errors) in systems that require multiple execution of services. This is what will likely happen in any but the most pedestrian applications. As you can see, this situation produces network clogging due to the back and forth traffic. This is a limiting factor because network bandwidth is still an issue for internet development.

The kind of messaging that I have addressed above is what I call simple messaging. This method is contrasted with the more complex model that I call courier messaging. Courier messaging gets its inspiration from courier services, such as DHL, FedEx or UPS, that deliver packages to homes and businesses all over the world. The sender sends the package via the courier, who delivers the package to the destination. However, if the proper recipient is not immediately available, the typical recourse is for the courier to ask if there is someone else who can sign and receive the package. That sort of logic is the least that customers expect from courier services. That is the sort of logic that is inherent in the courier messaging model. The XML message is sent via a courier (which is a Superx++ object) that delivers it to the destination. However, the courier can determine what else to do while still at the destination based on errors/results reported to it by the destination services. In a typical situation, the courier could perform multiple actions while still at the destination before returning across the network to the source computer. The resulting benefits of this model are that network traffic is dramatically reduced and the messaging transaction has added logic built into it to handle real contingencies. In simple messaging a full business transaction may require multiple messaging transactions, whereas in courier messaging a full business transaction requires only one messaging transaction consisting of a single two-way trip. This is cheaper in terms of network traffic, more advantageous in coding business rules for messaging and more logical in mapping business transactions onto messaging transactions. This is why Superx++ services support courier messaging inherently.

XML Files
There are two XML files that are used to interface between the incoming Superx++ object (sent from the sender machine) and the implementing library executable (currently implemented as .dll files).
The XML files are:
the public interface XML file The file contains all the details of the public interface of the Superx++ services offered on this computer. This document should be viewable across the internet so that it can be queried upon.
the private implementation XML file The file contains all the details associating the Superx++ services with the internal implementing executables (i.e. the .dll files that implement the Superx++ services).

Format of XML Files
Public Interface
<xservices>
   <xservice name="{service name}">
      <method id="{associative method id}" name="{method name}" type="{method type}">
         <parm id="{associative parm id}" type="{parm type}" pass="{val/ref}"
            name="{parm name}">{parm value}</parm>
         .
         .
         .
      </method>
      .
      .
      .
   </xservice>
   .
   .
   .
</xservices>

{service name} The published name of the service by which the Superx++ object (the courier) will refer to the service.
{associative method id} The id value that associates this public method with the function that implements it as specified in the private XML file. The id values of both must match.
{method name} The published name of a method that is part of the service.
{method type} The published return datatype of a method that is part of the service.
{associative parm id} The id value that associates this public parameter for a method with the parameter of the function that implements the method as specified in the private XML file. The id values of both must match.
{parm type} The published datatype of a parameter for a method.
{val/ref} The published passing convention of the parameter:
val means pass by value
ref means pass by reference
{parm name} The published name of a parameter for a method.
{parm value} The default value of a parameter for a method.

An example of the Public Interface
<xservices>
   <xservice name="Calculator">
      <method id="M1" name="Mult" type="int">
         <parm id="P2" type="int" pass="val" name="Parm2">25</parm>
         <parm id="P1" type="int" pass="val" name="Parm1" />
      </method>
      <method id="M2" name="Flip" type="int">
         <parm id="P3" type="string" pass="ref" name="Parm1">Hello World!</parm>
      </method>
   </xservice>
</xservices>

Private Implementation
<ximplementers>
   <func id="{associative method id}" lib="{library executable path}"
         name="{function name}" type="{function type}">
      <parm id="{associative parm id}" type="{parm type}"
         pass="{val/ref}" name="{parm name}">{parm value}</parm>
      .
      .
      .
   </func>
   .
   .
   .
</ximplementers>

{associative method id} The id value that associates this implementing function with the service's public method as specified in the public XML file. The id values of both must match.
{library executable path} The path to the external library executable (e.g. a .dll file) that implements the functions required by the service.
{function name} The name of the function that implements the service method.
{function type} The return datatype of the function that implements the service method.
{associative parm id} The id value that associates this parameter of the implementing function with the parameter of the service's public method as specified in the public XML file. The id values of both must match.
{parm type} The datatype of a parameter for the implementing function.
{val/ref} The passing convention of the parameter:
val means pass by value
ref means pass by reference
{parm name} The name of a parameter for the implementing function.
{parm value} The default value of a parameter for implementing function.

An example of the Private Implementation
<ximplementers>
   <func id="M1" lib="C:\\MyDir\\MyCode.dll" name="GetProduct" type="int">
      <parm id="P1" type="int" pass="val" name="Parm1">7</parm>
      <parm id="P2" type="int" pass="val" name="Parm2">3</parm>
   </func>
   <func id="M2" lib="C:\\MyDir\\MyCode.dll" name="Reverse" type="int">
      <parm id="P3" type="string" pass="ref" name="Parm1">Hamjambo Dunia!</parm>
   </func>
</ximplementers>

You can see from the examples of the public interface and private implementation XML documents how the methods and parameters of the service are associated with the functions and parameters of the library executable. It is important that the id values match since they are the connectors between the two. It is also important that the id values be unique for each method/function and parameter.

Simple Message Superx++ Code
Let us begin with an understanding of the simple messaging that Superx++ services can handle. The following is the Superx++ code that a web client can use to invoke a Superx++ service on a server using simple messaging.

Format of Simple Messaging Superx++ Statement
<xservice name="{service name}" formatresult="{xml/text}">
   <url>{remote Superx++ service listener URL}</url>
   <method name="{method name}">
      <parm name="{parm name}">{parm value}</parm>
      .
      .
      .
   </method>
</xservice>

{service name} The name of the Superx++ service that you want to execute. This must be one of those published in the public interface XML document.
{xml/text} The packaging method for the result(s):
xml means return the result(s) as XML
text means return the result(s) as simple text
{remote Superx++ service listener URL} The URL pointing to the Superx++ ISAPI extension that is the listener for the XML/courier messenger requests.
{method name} The name of the service method to be executed.
{parm name} The name of a parameter of the service method to be executed.
{parm value} The value of a parameter of the service method to be executed.

Example 1 of Simple Messaging
<xpp>
   <xout>The product is </xout>
   <xout>
      <xservice name="Calculator" formatresult="xml">
         <url>http://MyServer/MyDir/XppExt.dll</url>
         <method name="Mult">
            <parm name="Parm1">3</parm>
            <parm name="Parm2">25</parm>
         </method>
      </xservice>
   </xout>
</xpp>

The code above illustrates the use of the <xservice> statement that is new to Superx++. It is part of the Superx++ beta 0.2.2. The <xservice> statement invokes a Superx++ services by posting an XML request to the specified URL. If there is no URL specified then the Superx++ interpreter assumes you wish to access a Superx++ service on the same machine. If no URL is required then you can omit the <url> node.

The XML request that is sent to the Superx++ server (i.e. the machine refered to by the URL or the local machine if there is no URL) looks as follows:
XML Request sent via HTTP by code in Example 1
<xservice name="Calculator" formatresult="xml">
   <method name="Mult">
      <parm name="Parm1">3</parm>
      <parm name="Parm2">25</parm>
   </method>
</xservice>

The XML request above will be HTTP POSTed to the specified URL and processed by the remote machine's Superx++ interpreter. Then the result will be packaged appropriately based on the formatresult attribute's value. If the value is xml then the result is packaged as an XML document. If on the other hand the value is text then the result is passed back as simple text. The result travels back to the sender in the HTTP response.

The Superx++ interpreter handles the XML request. The external library referenced in the private implementation file (i.e. the .dll file) has its function invoked. The result is packaged appropriately and returned in the HTTP response to the client. In the case of the example above, the GetProduct function is invoked (which simply multiples the two operands) and the result is packaged as XML and looks like this:
XML Response sent via HTTP by code in Example 1
<xservice_result name="Calculator">75</xservice_result>

Let us assume that the formatresult attribute's value was text. In that case, the HTTP response would have the following data:
75

The advantage of passing the data back as XML is that you can plug it straight into an XML parser or other component requiring XML (e.g. an XML data island). The advantage of passing the data back as simple text is that you can plug it into any code that requires a string value. If you require the data as an integer or other datatype then you can cast the data to the appropriate type easily enough.

Example 2 of Simple Messaging
<xpp>
   <node name="P1">3</node>
   <node name="P2">25</node>
   <xout>The product is </xout>
   <xout>
      <xservice name="Calculator">
         <url>http://MyServer/MyDir/XppExt.dll</url>
         <method name="Mult">
            <parm name="Parm1"><eval object="P1" /></parm>
            <parm name="Parm2"><eval object="P2" /></parm>
         </method>
      </xservice>
   </xout>
</xpp>

The code above is very similar to that in Example 1. In fact the results are the same for both. The only difference demonstrated in this code is that the values for the Parm1 and Parm2 parameters are derived at runtime in the <eval> statements. The XML request that is sent to the URL is still the same as in the case of Example 1 above.

Courier Messaging Superx++ Code
The code used for courier messaging is not too dissimilar to the code used for simple messaging. However, the benefits of courier messaging far outweigh those of simple messaging when it comes to complex interactions between the concerns of the source and destination.

Format of Courier Messaging Superx++ Statement
<xservice object="{Superx++ courier object}" formatresult="{xml/text}">
   <url>{remote Superx++ service listener URL}</url>
</xservice>

{Superx++ courier object} The name of the Superx++ object that is sent as the courier messenger to the remote machine.
{xml/text} The packaging method for the result(s):
xml means return the result(s) as XML
text means return the result(s) as simple text
{remote Superx++ service listener URL} The URL pointing to the Superx++ ISAPI extension that is the listener for the XML/courier messenger requests.

Example 1 of Courier Messaging
<xpp>
   <!--
   This class must implement the Execute method which returns a string value.
   The Execute method is called by the Superx++ interpreter when it arrives at the remote machine.
   The code in the Execute method is then executed and the result(s) are
   returned via the string in the HTTP response back to the web client.
   -->

   <class name="XMessenger" inherit="">
      <construct />
      <scope type="public">
         <func name="Execute" type="string">
            <body>
               <node name="x" processcode="true">
                  <xservice name="Calculator" formatresult="text">
                     <method name="Mult">
                        <parm name="Parm1">
                           <eval object="this" member="Num1"/>
                        </parm>
                        <parm name="Parm2">
                           <eval object="this" member="Num2"/>
                        </parm>
                     </method>
                  </xservice>
               </node>
               <if>
                  <cond>
                     <eval>
                        <parm type="int" name="a"><eval object="x" /></parm>
                        <expr>a lt; 132</expr>
                     </eval>
                  </cond>
                  <true>
                     <return><eval object="x" /></return>
                  </true>
                  <false>
                     <xservice name="Calculator" formatresult="text">
                        <method name="Flip">
                           <parm name="Parm1">
                              <eval object="this" member="id"/>
                           </parm>
                        </method>
                     </xservice>
                     <return><eval object="this" member="id" /></return>
                  </false>
               </if>
            </body>
         </func>
      </scope>
      <scope type="public">
         <var name="id" type="string">Kimmie</var>
         <var name="Num1" type="int">12</var>
         <var name="Num2" type="int">11</var>
      </scope>
   </class>

   <!-- MyMessenger is the courier messenger object -->
   <node name="MyMessenger" class="XMessenger" />
   <xout>\r\nThe messenger returns </xout>

   <!-- The xservice call HTTP POSTs the MyMessenger object and its -->
   <!-- XMessenger class to the URL -->
   <xout>
      <xservice object="MyMessenger" formatresult="xml">
         <url>http://MyServer/MyDir/XppExt.dll</url>
      </xservice>
   </xout>
</xpp>

The example code above is interesting to us because it represents the ability to send a program to a remote machine for execution. It is not merely a request for some service to be executed, as is the case with web services or the simple messaging shown previously. Instead, we send code that gets executed at the remote machine. This allows us to place conditional logic in such a program which will handle the runtime contingencies at the remote machine, without needlessly returning to the source. Once the entire mission is accomplished then the result is sent back to the source. The result of this approach is that we can perform multiple actions and service requests with a single two-way trip across the network! This radically reduces network clogging.

Okay, so let me explain this code. The program above is a very simple Superx++ program. It merely defines a class appropriately called XMessenger that contains the Execute method. The Execute method is important because the remote Superx++ interpreter will invoke it in order to make the Superx++ object execute its code. So Execute is the main entry point. Alright, that accounts for the class of the courier object but what about the actual courier object itself? That is the MyMessenger which is defined in the node statement. The xservice statement shown is different from the way we saw it in the simple messaging examples above. It is dramatically smaller in size and has an object attribute.

The object attribute contains the name of the Superx++ object that will be the courier that gets sent to the URL specified in the url attribute. When the xservice statement gets executed like that the request that is sent to the URL looks as follows:
XML Request sent via HTTP by code in Example 1 of Courier Messaging
<xpp>
   <class name="XMessenger" inherit="">
      <construct />
      <scope type="public">
         <func name="Execute" type="string">
            <body>
               <node name="x" processcode="true">
                  <xservice name="Calculator" formatresult="text">
                     <method name="Mult">
                        <parm name="Parm1">
                           <eval object="this" member="Num1"/>
                        </parm>
                        <parm name="Parm2">
                           <eval object="this" member="Num2"/>
                        </parm>
                     </method>
                  </xservice>
               </node>
               <if>
                  <cond>
                     <eval>
                        <parm type="int" name="a"><eval object="x" /></parm>
                        <expr>a lt; 132</expr>
                     </eval>
                  </cond>
                  <true>
                     <return><eval object="x" /></return>
                  </true>
                  <false>
                     <xservice name="Calculator" formatresult="text">
                        <method name="Flip">
                           <parm name="Parm1">
                              <eval object="this" member="id"/>
                           </parm>
                        </method>
                     </xservice>
                     <return><eval object="this" member="id" /></return>
                  </false>
               </if>
            </body>
         </func>
      </scope>
      <scope type="public">
         <var name="id" type="string">Kimmie</var>
         <var name="Num1" type="int">12</var>
         <var name="Num2" type="int">11</var>
      </scope>
   </class>
   <node name="MyMessenger" class="XMessenger" var_string_id="Kimmie"
      var_int_Num1="12" var_int_Num2="11" construct="false" />
   <xout>
      <eval object="MyMessenger" method="Execute" />
   </xout>
</xpp>

From looking at the XML request above, you can see that it is actually Superx++ code! This shows one more use for Superx++: as a language for writing courier messengers. The actual messaging protocol is Superx++. The XML request (or Superx++ program code) above, shows the class of the MyMessenger object, i.e. the XMessenger class that implements the Execute method. When the remote machine receives this program, it will define the XMessenger class and activate the MyMessenger object. Please note that by activation I do not mean instantiation. In normal instantiation, the constructor method of the object's class(es) would be invoked. In activation, the constructor method is not called. The idea behind this is that we want to reactivate an object that was previously instantiated and is now dormant. So what happens is that the object is merely loaded as is into memory. The construct attribute of the <node> statement is set to false. This value of false instructs the remote Superx++ interpreter to activate rather than instantiate the MyMessenger object.

After the object is activated, there is a single <xout> statement that will write the result of the Execute method's invocation to the output stream. After the Execute method's result is written to the output stream, the program ends and the Superx++ interpreter places the contents of the output stream into the HTTP response as is. The HTTP response is then sent back to the web client.

When the results are sent back they are packaged according to the formatresult attribute on the <xservice> statement that sent the courier object off on its way. If there is no such formatresult attribute explicitly specified then the default value is xml. Remember, the formatresult attribute is important for specifying how the results of the courier messenger are to be packaged: either xml or text.

In the XML request above, the Execute method invokes the Mult method on the remote machine. Then the <if> statement checks if the result is less than 132. If the comparison is true then the result of the Mult method is returned. If on the other hand the comparison returned false then the Flip method is invoked with a parameter passed in by reference. The id member variable that was passed in by reference. What the Flip method does is to reverse the string that is passed in. So the net effect is to reverse the value in the id member variable. Then the result is returned as the return value of the Execute method.

Okay, if you look at the code in the XML request you will find that the Num1 and Num2 member variables are 12 and 11 respectively. These are passed into the Mult method which returns 132. So the result of the comparison done in the if statement is false. So we know that the Flip method will get invoked. This reverses the contents of the id member variable, which contains Kimmie, to yield a resulting eimmiK which is placed back into the id member variable. Then the resulting value of the id member variable, i.e. eimmiK, is returned in the HTTP response back to the web client.

The above was a very simple XML request but it illustrates the ability to perform multiple actions based on conditional evaluations at runtime on the remote machine. This is the way that web interactions should be done to optimize the use of the web and reduce network traffic. Another benefit of the use of the courier messaging model is that a courier messenger can further HTTP POST itself to other machines in order to accomplish the goals of its original sender.

Calling From Other Languages
The actual implementation of the code that is published as Superx++ services can be written in any language. The resulting executables are packaged as .dll files in the current implementation. However, down the line, I hope to expand this. Okay, that covers the implementation of the Superx++ services; how about the invocation? Well, that is also possible! Since Superx++ is XML and XML is a textual format, then it follows that the XML request can be sent from any language program that can perform an HTTP POST. In order to do this, all you need to do is to POST the XML shown in the XML request examples above to the URL specified for the Superx++ ISAPI extension that acts as the listener for these XML requests. The HTTP response will return to your other language program and you can continue with whatever other processing you are doing as normal.

Required Components
The following are the required components for the Superx++ services:
Superx++ ISAPI extension The Superx++ ISAPI extension is a .dll that is used by the web server and is accessible via the URL specified in the <xservice> statement. Its purpose is to listen for the XML requests and pass them onto the Superx++ interpreter. The name of the currently available Superx++ ISAPI extension is XppExt.dll and you can place it in any appropriate virtual directory of your web server.
Superx++ Hub The Superx++ Hub is a Superx++ interpreter that waits and processes requests via named pipes. The details of the Superx++ Hub can be found at the Superx++ site. Its relevance here is that it communicates with the Superx++ ISAPI extension to service the XML requests. The name of the currently available Superx++ Hub is XppHub.exe and it should be running before any XML requests come in. You can place it in a startup directory and let it run in the background.
XML request The XML request can contain an explicit service method call or a Superx++ courier object.
Public Interface XML The Superx++ services are published on the internet via the public interface XML. Each organization would publish at least one such file. This file can be queried upon using Superx++ or other XML technologies so as to discover what services are published.
Private Implementation XML The Superx++ services are implemented by executables which are specified in the private implementation XML. The reason for this abstraction is to allow different executables to be swapped in to implement the same public services without service interruption.
ISAPI-compliant Web Server The Superx++ ISAPI extension is executed by the web server when an HTTP request comes to the web server for the URL which points to the Superx++ ISAPI extension. So the web server acts as the middle man here.
Web Client Any web client that can HTTP POST the XML requests shown above will suffice as the web client.