XNode Framework v1.0
Copyright (c) 2010-2012 James Watts (SOLFENIX)
http://www.solfenix.com
This is FREE software, licensed under the GNU/GPL
http://www.gnu.org/licenses/gpl.html
This software implements the XHTTP protocol
http://www.xhttp.org
The XNode framework is a server and client implementation of the
Extended Hypertext Transfer Protocol (XHTTP).
To use the package it's highly recommended to use a PSR-0 compatible
autoloader for required classes.
You can find a fully compatible autoloader here: https://sourceforge.net/p/php-autoload
Once you've unpacked the files into your include path the package is
ready for use.
To access the XNode server you must first establish a node to connect
to. This is refered to as the "end-point" of the node. To setup an
"end-point" create a new instance of the XNode class and call the
method process( void ). This will make the server listen for XHTTP
requests on the URI to this file, for example:
use Solfenix\XNode\XNode;
$node = new XNode();
$node->process();
Once your "end-point" is available you can now access the node over a
network. The package includes a "test" service to check the status of
the node and run basic unit tests. To test the server call the URI to
your "end-point" with the following XHTTP headers:
HTTP/1.1 GET http://%DOMAIN%/%PATH%/%FILE%
Host: %DOMAIN%
Version: 1.0
Service: Test;*.*
Action: status
Encoding: x-user-defined
Replace the %VARIABLES% with your values and send the request. If the
server is ready and working correctly the following response will be
returned:
HTTP/1.1 200 OK
Date: %DATETIME%
Return: 1
1
If an error occurs a 550 Exception should be returned by the server,
specifying the reason for the failure.
To create an XHTTP service you will first need to define the XHTTP
schema. In this case, we'll create a service called "example" with a
single action, "foo", which expects a required integer argument,
"value".
<?xml version="1.0" encoding="UTF-8"?>
<xhttp xmlns:xhttp="http://www.xhttp.org/schema" version="1.0">
<xhttp:schema version="1.0">
<xhttp:info name="service" value="example"/>
<xhttp:info name="host" value="http://www.solfenix.com/xnode"/>
<xhttp:info name="port" value="80"/>
<xhttp:info name="author" value="James Watts"/>
<xhttp:info name="email" value="contact@jameswatts.info"/>
<xhttp:info name="link" value="http://www.xhttp.org"/>
<xhttp:info name="version" value="1.0"/>
<xhttp:info name="build" value="20120401"/>
<xhttp:action name="foo" function="fooAction">
<xhttp:exception code="99" message="Value must be greater than 10"/>
<xhttp:argument name="value" type="2" use="required"/>
<xhttp:return type="2"/>
</xhttp:action>
</xhttp:schema>
</xhttp>
Now that we have the *XHTTP* schema we can generate the class for
this service.
To define the class simply extend the XService class using the name
of the service in "CamelCase" as the class name, for example, in
this case:
class Example extends XService {
// define your actions here
}
Our schema defines an action called "foo" with a function name
"fooAction", so now we'll define this action in our class.
public function fooAction()
{
// define your logic here
}
When working with XHTTP most of the work is done by the protocol and
handled by the XNode server, such as processing the request,
resolving the API version, validating arguments and generating the
response with the corresponding output. This leaves you to deal with
just the specific logic of each action.
To access the server from the action the XService class provides a
reference through the $this->server property.
From the server we can access the arguments received by the action,
for example:
$value = $this->server->getArgument( 'value' );
When an error occurs within the logic of your action the function
should throw an XException with an error message and code as defined
in the schema for the service, for example:
public function fooAction()
{
$value = $this->server->getArgument( 'value' );
if ( $value < 11 )
{
throw new XException( 'Value must be greater than 10', 99 );
}
echo $value*100;
}
In this case the "foo" action is quite simple, only checking that
the integer specified in the "value" argument is greater than 10, and
if so, multiplying it by 100. However, actions can perform logic as
complex as required, and even call other services and actions.
To create an XHTTP request we'll use the XRequest class. This creates
a request object, using setHost( string $host ) for the node to
connect to, setService( string $service ) for the service to call,
setAction( string $action ) for the action to perform, and
setArguments( array $arguments ) to define the arguments to pass to
the action. For example, if we were to call the service we defined
previously:
$request = new XRequest();
$request->setHost( 'http://www.solfenix.com/xnode?value=33' );
$request->setService( 'example;*.*' );
$request->setAction( 'foo' );
$request->setArguments( array( new XInteger( 'value', 33 ) ) );
When defining the arguments to pass to an action there exist classes
for each data type available, these are:
- **XNull:** Discriminated null value. Defaults to an empty value (no value).
- **XBoolean:** Boolean logical value (1 or 0). Defaults to 0.
- **XInteger:** Whole number. Defaults to 0.
- **XDouble:** Double precision floating point number. Defaults to 0.0.
- **XString:** String of characters. Defaults to an empty value (no value).
- **XArray:** Array of values, storing no keys. Defaults to []. *
- **XStruct:** Associative array or object. Defaults to {}. *
- **XLambda:** Anonymous or named function. Defaults to {}. *
- **XBase64:** Base64-encoded binary data. Defaults to an empty value (no value).
- **XDateTime:** Date and time in ISO-8601 16 format. Defaults to the current date and time.
Each class construct expects 2 arguments, the "name" of the argument,
and the "value".
Creating a request object doesn't send the petition to the server
until you create an XResponse object. The XResponse object can handle
a single XRequest object or an array of multiple XRequest objects.
Each XRequest object has an isReady( void ) method to check that the
request is ready to send and isn't missing require values, such as
the "host" or the "service".
Once processed by the XResponse object, the isComplete( int $index )
method specifies if the response could complete the request
successfully. And finally, the getReturn( int $index ) gets the
value returned by the action, for example:
$response = new XResponse( $request );
if ( $request->isReady() )
{
if ( $response->isComplete() )
{
$result = $response->getReturn();
}
}
In the case of handling multiple requests, each method of the
XResponse object expects the $index of the array of requests to
access the data of the specific request.
Handling requests and responses can be a tedious process. However,
XHTTP provides the functionality of exposing the schema for a
service. This allows implementations to provide the option to build a
remote API. The XNode framework provides this specific functionality
through the XSchema class, for example:
$example = new XSchema( 'http://www.solfenix.com/xnode', 'example', '1.*' );
The $example object is now an API which models the "example" schema,
so we can now call the "foo" action as a method of this object:
$result = $example->foo( new XInteger( 'value', 33 ) );
This overview provides an introduction to the XNode framework. You
can read more about the Extended Hypertext Transfer Protocol (XHTTP)
here: http://www.xhttp.org