thekid/rfc — Issue #12: RFC 0012: EJB access API
Author: thekid
Created: 2011-10-09 14:09:12+00:00
State: open
Labels: rfc

Scope of Change
====
The RMI collection will be completely overhauled.

Rationale
====
We want to be able to create an API that is more similar to the one used
in Java RMI. This way, we can create a XP -> EJB bridge and talk to our
application server in the same way than to that.

Functionality
====
The functionality tries to be similar to what we know from Java.

Client side
----
A simple Java client there looks like this (abbreviated example):

```php

```

In PHP, we usually do not have long-running applications (a web page is
requested, the script is compiled, then executed, then shut down).
Therefore, the naming lookup should be made optional for performance
reasons.

The interface class used in both client and server:

```php

```

Using the PHP access API without naming lookups:

```php
execute('Hello'));
?>
```

Using the PHP access API with naming lookup:

```php
execute('Hello'));
?>
```

Context
----
A context lets you define certain attributes that will be passed
alongside with invokations. Basically, a context is a Hashmap of
keys and values. The context can be accessed by the server
components.

Using the PHP access API without naming lookups:

```php
put('write policy', 'immediate');
$search= &Remote::forName('rmi://127.0.0.1:4444/ISearch', $context);

// Now, we can invoke methods on the instance
var_dump($search->execute('Hello'));
?>
```

Using the PHP access API with naming lookup:

```php
put('write policy', 'immediate');
$search= &Naming::lookup('website/ISearch', $context);

// Now, we can invoke methods on the instance
var_dump($search->execute('Hello'));
?>
```

Think of context like environment variables.

Authentication
----
If authentication is required, we use the AuthorizedContext class
instead of the base class.

Using the PHP access API without naming lookups:

```php
execute('Hello'));
?>
```

Using the PHP access API with naming lookup:

```php
execute('Hello'));
?>
```

Server side
----
The server side is implemented as a JBoss MBean. It provides the following
methods:

1) Naming lookups

2) Remote method invokation

3) Java Messaging

4) Discovery API

Interaction
----
1) Optionally: The client issues a naming lookup and retrieves the fully
qualified URI to the remote object (as seen above:
rmi://127.0.0.1:4444/ISearch). This remote specification includes:

* The protocol (here: rmi)
* The host name (here: 127.0.0.1 a.k.a. localhost)
* The port (here: 4444)
* The interface name (here: ISearch)

The remote spec is passed to the Remote class which constructs a
proxy instance. If you'd like to hardcode all this information, you
may use the Remote class directly (first example) - you'll need to
live with all the downsides of that, then, but will also save
yourself the naming lookup.

2) The client loads the protocol class and passes it the fully qualified
URL (as peer.URL object).

3) The client initiates the communication with the server using the
protocol class.

4) The client calls a method on the server and reads the results.

5) Repeat 4 if needed

6) The client disconnects. No need to say goodbye.

RMI Protocol
----
Each protocol message has a header. It consists of the following elements:

* A magic number, constructed from the crc32 checksum of the string "xrmi"
(0x3c872747 or 1015490375), packed into 4 bytes using pack("N", $magic).
"N" stands for 'unsigned long (always 32 bit, big endian byte order)'.

* The protocol major version, as one byte

* The protocol minor version, as one byte

* The message type, as one byte

* If the data is compressed, as one byte (TRUE or FALSE)

* The data length packed into 4 bytes using pack("N", $length)

(=> the header is 12 bytes long).

Encoding the header in PHP:

```php

```

Reading the header in Java:

```php

```

The body of a message is encoded depending on the message type.

```
Message type Encoding
--------------- --------
Initialize 0
Request 1
Reply 2
Ping 3
Close 4

```

* Strings in the message body
The utf() function creates a string that can be read using the
Java method DataInput.readUTF(), see
http://java.sun.com/j2se/1.4.2/docs/api/java/io/DataInput.html#readUTF()

On the PHP side, the com.sun.UTF class is used.

* Body encoding for initialize message (#0)

The initialize message is ALWAYS the first message in the client/server
communication process. It takes care of initialization and authorization.

It contains the context (and with that, the authentication data).

$body= utf($serializedContext);

The body contains a serialized representation of the context, serialized
according to the rules of object serialization.

* Body encoding for request message (#1)

The request message issues a request to invoke a remote method.

It is contained of the following fields:
- Object name
- Operation name
- Mode
- Parameters

Mode is a bit-field of the following values:

Mode Encoding
----------------------- ------------
Static 1
One-Way (No Reply) 2

In PHP:

$body= (
pack('c', $mode).
utf($objectName).
utf($operationName).
utf($serializedParameters)
);

* Body encoding for reply message (#2)

This message is the server's reply to a client's request message (see
above).

Status Encoding
----------------------- ------------
Success 0
User Exception 1
Object does not exist 2
Operation non-existant 3
Invokation error 4
Protocol error 127

Success:
- Result
- Out parameters

User Exception:
- Exception class name
- Stacktrace

Object does not exist:
- Object name

Operation non-existant
- Operation name

Invokation error:
- Stacktrace

Protocol error
- Detail message

In PHP:

$body= pack('ca*', $status, $data);

* Body encoding for ping message (#3)

This message may be used to keep the connection to the server alive.
A server may choose to terminate a socket after a certain timeout
to save resources. The ping message does not contain any body.

* Body encoding for close message (#4)

This message is to be sent when a peer wants to shut down a connection.
The body is one bytes in size. This byte contains a reason identifier
for shutdown.

Reason Encoding
------------------ ------------
Normal shutdown 0
Idle timeout 1
Server going down 2

In PHP:

$body= pack('c', $reason);

The descision to close down a connection can not be vetoed by either
side. In case the server issues a timeout message, the client may
decide to reconnect on a new connection.

Dependencies
====
BC break in rmi or new package.

Related documents
====
- http://www.javacoffeebreak.com/articles/javarmi/javarmi.html
Introduction to Java RMI

- http://java.sun.com/developer/onlineTraining/rmi/RMI.html
jGuru: Remote Method Invocation (RMI)

- Naming on JBoss
http://docs.jboss.org/jbossas/admindevel326/html/ch3.chapter.html

Comments
====
- friebe, Tue Jan 4 11:35:38 CET 2005
Maybe also look at ICE (http://zeroc.com/)

- friebe, Wed Jan 19 11:44:56 CET 2005
First idea on authentication

- friebe, Wed Jan 19 12:51:36 CET 2005
Second idea on authentication

- friebe, Wed Jan 19 13:05:23 CET 2005
We should have a base context class and could then derive the
AuthorizedContext from it.

- friebe, Mon Mar 14 11:26:01 CET 2005
The "compressed" field is reserved for future use. At the moment, it will
always contain 0.

- friebe, Wed Dec 21 15:28:28 CET 2005
This RFC has now been implemented (a bit different than suggested here).