{"comment":{"created_at":"2011-10-17T15:30:54Z","body":"This RFC has now been implemented (a bit different than suggested here).\n\n\n\nfriebe, Wed, 21 Dec 2005 15:28:28 +0100","updated_at":"2011-10-17T15:30:54Z","url":"https://api.github.com/repos/xp-framework/rfc/issues/comments/2430145","id":2430145,"user":{"gravatar_id":"26f07e3b262e9a80436f368cb11bd0c2","avatar_url":"https://secure.gravatar.com/avatar/26f07e3b262e9a80436f368cb11bd0c2?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","url":"https://api.github.com/users/thekid","id":696742,"login":"thekid"}},"action":"created","issue":{"number":12,"created_at":"2011-10-17T15:30:46Z","pull_request":{"diff_url":null,"patch_url":null,"html_url":null},"body":"Scope of Change\n====\nThe RMI collection will be completely overhauled.\n\nRationale\n====\nWe want to be able to create an API that is more similar to the one used\nin Java RMI. This way, we can create a XP -> EJB bridge and talk to our\napplication server in the same way than to that.\n\nFunctionality\n====\nThe functionality tries to be similar to what we know from Java. \n\nClient side\n----\nA simple Java client there looks like this (abbreviated example):\n\n```php\n<?php\n  Properties env = new Properties();\n  env.setProperty(Context.PROVIDER_URL, \"jnp://example.com:1099\");\n\n  InitialContext ctx= new InitialContext(env);\n\n  try {\n    Object ref= ctx.lookup(\"website/Search\");\n    search= (SearchRemoteHome) PortableRemoteObject.narrow(\n      ref, \n      SearchRemoteHome.class\n    );\n  } finally {\n    initialContext.close();\n  }\n  \n  instance = search.create();\n  \n  // Now, we can invoke methods on the instance\n?>\n```\n\nIn PHP, we usually do not have long-running applications (a web page is \nrequested, the script is compiled, then executed, then shut down). \nTherefore, the naming lookup should be made optional for performance\nreasons.\n\nThe interface class used in both client and server:\n\n```php\n<?php\n  class ISearch extends Interface {\n\n    /**\n     * Execute a search\n     *\n     * @access  public\n     * @param   string query\n     * @return  string[] results\n     */\n    function execute($query) { }\n  \n  }\n?>\n```\n\nUsing the PHP access API without naming lookups:\n\n```php\n<?php\n  $search= &Remote::forName('rmi://127.0.0.1:4444/ISearch');\n\n  // Now, we can invoke methods on the instance\n  var_dump($search->execute('Hello'));\n?>\n```\n\nUsing the PHP access API with naming lookup:\n\n```php\n<?php\n  Naming::setProvider(new RemoteNamingProvider('example.com', 1099));\n\n  $search= &Naming::lookup('website/ISearch');\n\n  // Now, we can invoke methods on the instance\n  var_dump($search->execute('Hello'));\n?>\n```\n\nContext\n----\nA context lets you define certain attributes that will be passed \nalongside with invokations. Basically, a context is a Hashmap of\nkeys and values. The context can be accessed by the server \ncomponents.\n\nUsing the PHP access API without naming lookups:\n\n```php\n<?php\n  $context= &new RemoteContext();\n  $context->put('write policy', 'immediate');\n  $search= &Remote::forName('rmi://127.0.0.1:4444/ISearch', $context);\n\n  // Now, we can invoke methods on the instance\n  var_dump($search->execute('Hello'));\n?>\n```\n\nUsing the PHP access API with naming lookup:\n\n```php\n<?php\n  Naming::setProvider(new RemoteNamingProvider('example.com', 1099));\n\n  $context= &new RemoteContext();\n  $context->put('write policy', 'immediate');\n  $search= &Naming::lookup('website/ISearch', $context);\n  \n  // Now, we can invoke methods on the instance\n  var_dump($search->execute('Hello'));\n?>\n```\n\nThink of context like environment variables.\n\nAuthentication\n----\nIf authentication is required, we use the AuthorizedContext class \ninstead of the base class.\n\nUsing the PHP access API without naming lookups:\n\n```php\n<?php\n  $context= &new AuthorizedContext(new PasswordAuth('username', 'password'));\n  $search= &Remote::forName('rmi://127.0.0.1:4444/ISearch', $context);\n\n  // Now, we can invoke methods on the instance\n  var_dump($search->execute('Hello'));\n?>\n```\n\nUsing the PHP access API with naming lookup:\n\n```php\n<?php\n  Naming::setProvider(new RemoteNamingProvider('example.com', 1099));\n\n  $context= &new AuthorizedContext(new PasswordAuth('username', 'password'));\n  $search= &Naming::lookup('website/ISearch', $context);\n  \n  // Now, we can invoke methods on the instance\n  var_dump($search->execute('Hello'));\n?>\n```\n\nServer side\n----\nThe server side is implemented as a JBoss MBean. It provides the following \nmethods:\n\n1) Naming lookups\n\n\n2) Remote method invokation\n\n\n3) Java Messaging\n\n\n4) Discovery API\n\n\nInteraction\n----\n1) Optionally: The client issues a naming lookup and retrieves the fully\n   qualified URI to the remote object (as seen above: \n   rmi://127.0.0.1:4444/ISearch). This remote specification includes:\n   \n   * The protocol (here: rmi)\n   * The host name (here: 127.0.0.1 a.k.a. localhost)\n   * The port (here: 4444)\n   * The interface name (here: ISearch)\n\n   The remote spec is passed to the Remote class which constructs a\n   proxy instance. If you'd like to hardcode all this information, you\n   may use the Remote class directly (first example) - you'll need to\n   live with all the downsides of that, then, but will also save \n   yourself the naming lookup.\n\n2) The client loads the protocol class and passes it the fully qualified\n   URL (as peer.URL object).\n\n3) The client initiates the communication with the server using the\n   protocol class.\n\n4) The client calls a method on the server and reads the results.\n\n5) Repeat 4 if needed\n\n6) The client disconnects. No need to say goodbye.\n\nRMI Protocol\n----\nEach protocol message has a header. It consists of the following elements:\n\n* A magic number, constructed from the crc32 checksum of the string \"xrmi\" \n  (0x3c872747 or 1015490375), packed into 4 bytes using pack(\"N\", $magic).\n  \"N\" stands for 'unsigned long (always 32 bit, big endian byte order)'.\n\n* The protocol major version, as one byte\n\n* The protocol minor version, as one byte\n\n* The message type, as one byte\n\n* If the data is compressed, as one byte (TRUE or FALSE)\n\n* The data length packed into 4 bytes using pack(\"N\", $length)\n\n(=> the header is 12 bytes long).\n\nEncoding the header in PHP:\n\n```php\n<?php\n  $header= pack(\n    'Nc4N', \n    1015490375, \n    $versionMajor,\n    $versionMinor,\n    $messageType,\n    $compressed,\n    $dataLength\n  );\n?>\n```\n\nReading the header in Java:\n\n```php\n<?php\n  java.io.DataInputStream stream = new java.io.DataInputStream(inputStream);\n\n  Header h = new Header(); {\n    h.magicNumber = stream.readInt();\n    h.versionMajor = stream.readByte();\n    h.versionMinor = stream.readByte();\n    h.messageType = stream.readByte();\n    h.compressed = stream.readBoolean();\n    h.dataLength = stream.readInt();\n  }\n?>\n```\n\nThe body of a message is encoded depending on the message type.\n\n\n```\n  Message type    Encoding\n  --------------- --------\n  Initialize      0\n  Request         1\n  Reply           2\n  Ping            3\n  Close           4\n\n```\n\n* Strings in the message body\n  The utf() function creates a string that can be read using the \n  Java method DataInput.readUTF(), see\n  http://java.sun.com/j2se/1.4.2/docs/api/java/io/DataInput.html#readUTF()\n\n  On the PHP side, the com.sun.UTF class is used.\n\n* Body encoding for initialize message (#0)\n\n  The initialize message is ALWAYS the first message in the client/server\n  communication process. It takes care of initialization and authorization.\n  \n  It contains the context (and with that, the authentication data).\n\n  <code>\n    $body= utf($serializedContext);\n  </code>\n  \n  The body contains a serialized representation of the context, serialized\n  according to the rules of object serialization.\n\n* Body encoding for request message (#1)\n\n  The request message issues a request to invoke a remote method.\n\n  It is contained of the following fields:\n  - Object name\n  - Operation name\n  - Mode\n  - Parameters\n\n  Mode is a bit-field of the following values:\n  <pre>\n    Mode                    Encoding\n    ----------------------- ------------\n    Static                  1\n    One-Way (No Reply)      2\n  </pre>\n\n  In PHP:\n  <code>\n    $body= (\n      pack('c', $mode).\n      utf($objectName).\n      utf($operationName).\n      utf($serializedParameters)\n    );\n  </code>\n  \n* Body encoding for reply message (#2)\n\n  This message is the server's reply to a client's request message (see \n  above).\n\n  <pre>\n    Status                  Encoding\n    ----------------------- ------------\n    Success                 0\n    User Exception          1\n    Object does not exist   2\n    Operation non-existant  3\n    Invokation error        4\n    Protocol error          127\n  </pre>\n\n  Success:\n  - Result\n  - Out parameters\n\n  User Exception:\n  - Exception class name\n  - Stacktrace\n  \n  Object does not exist:\n  - Object name\n  \n  Operation non-existant\n  - Operation name\n  \n  Invokation error:\n  - Stacktrace\n\n  Protocol error\n  - Detail message\n  \n  In PHP:\n  <code>\n    $body= pack('ca*', $status, $data);\n  </code>\n\n* Body encoding for ping message (#3)\n\n  This message may be used to keep the connection to the server alive.\n  A server may choose to terminate a socket after a certain timeout\n  to save resources. The ping message does not contain any body.\n\n* Body encoding for close message (#4)\n\n  This message is to be sent when a peer wants to shut down a connection. \n  The body is one bytes in size. This byte contains a reason identifier\n  for shutdown.\n  \n  <pre>\n    Reason             Encoding\n    ------------------ ------------\n    Normal shutdown    0\n    Idle timeout       1\n    Server going down  2\n  </pre>\n    \n  In PHP:\n  <code>\n    $body= pack('c', $reason);\n  </code>\n  \n  The descision to close down a connection can not be vetoed by either\n  side. In case the server issues a timeout message, the client may \n  decide to reconnect on a new connection.\n\n\nDependencies\n====\nBC break in rmi or new package.\n\nRelated documents\n====\n- http://www.javacoffeebreak.com/articles/javarmi/javarmi.html\n  Introduction to Java RMI\n\n- http://java.sun.com/developer/onlineTraining/rmi/RMI.html\n  jGuru: Remote Method Invocation (RMI)\n\n- Naming on JBoss\n  http://docs.jboss.org/jbossas/admindevel326/html/ch3.chapter.html\n  \n","comments":6,"title":"EJB access API","updated_at":"2011-10-17T15:30:55Z","url":"https://api.github.com/repos/xp-framework/rfc/issues/12","id":1929768,"assignee":null,"milestone":null,"closed_at":"2011-10-17T15:30:47Z","user":{"gravatar_id":"26f07e3b262e9a80436f368cb11bd0c2","avatar_url":"https://secure.gravatar.com/avatar/26f07e3b262e9a80436f368cb11bd0c2?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","url":"https://api.github.com/users/thekid","id":696742,"login":"thekid"},"html_url":"https://github.com/xp-framework/rfc/issues/12","labels":[{"name":"framework","url":"https://api.github.com/repos/xp-framework/rfc/labels/framework","color":"118f5b"},{"name":"implemented","url":"https://api.github.com/repos/xp-framework/rfc/labels/implemented","color":"807370"}],"state":"closed"},"legacy":{"issue_id":1929768,"comment_id":2430145}}