<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<section id="Kernel.RPCService">
  <title>RPC Service</title>

  <para>The <emphasis>RPCService</emphasis> is only needed in a cluser
  environment, it is used to communicate with the other cluster nodes. It
  allows to execute a command on all the cluster nodes or on the coordinator
  i.e. the oldest node in the cluster. The <emphasis>RPCService</emphasis> has
  been designed to rely on JGroups capabilities and should not be used for
  heavy load. It can be used, for example, to notify other nodes that
  something happened or to collect some information from the other
  nodes.</para>

  <para>The <emphasis>RPCService</emphasis> relies on 3 main interfaces which
  are:</para>

  <itemizedlist>
    <listitem>
      <para>The <emphasis>org.exoplatform.services.rpc.RPCService</emphasis>
      that defines the service itslef</para>
    </listitem>

    <listitem>
      <para>The
      <emphasis>org.exoplatform.services.rpc.RemoteCommand</emphasis> that
      defines the command that we can execute on other nodes.</para>
    </listitem>

    <listitem>
      <para>The
      <emphasis>org.exoplatform.services.rpc.TopologyChangeListener</emphasis>
      that defines the listeners that will be notified anytime the topology of
      the cluster changes.</para>
    </listitem>
  </itemizedlist>

  <para>The arguments that will be given to the
  <emphasis>RemoteCommand</emphasis> must be <emphasis>Serializable</emphasis>
  and its return type also in order to prevent any issue due to the
  serialization. To prevent to execute any <emphasis>RemoteCommand</emphasis>
  that could be malicious and to allow to use non
  <emphasis>Serializable</emphasis> command, you need to register the command
  first before using it. Since the service will keep only one instance of
  <emphasis>RemoteCommand</emphasis> per command Id, the implementation of the
  <emphasis>RemoteCommand</emphasis> must be thread safe.</para>

  <para>To be usable, all the <emphasis>RemoteCommand</emphasis>s must be
  registered before being used on all the cluster nodes, which means that the
  command registration must be done in the constructor of your component in
  other words before that the <emphasis>RPCService</emphasis> is started. If
  you try to launch a command that has been registered but the
  <emphasis>RPCService</emphasis> is not yet launched, you will get an
  <emphasis>RPCException</emphasis> due to an illegal state. This has for
  consequences that you will be able to execute a command only once your
  component will be started.</para>

  <para>See an example below:</para>

  <programlisting language="java">public class MyService implements Startable
{
   private RPCService rpcService;
   private RemoteCommand sayHelloCommand;
   
   public MyService(RPCService rpcService)
   {
      this.rpcService = rpcService;
      // Register the command before that the RPCService is started
      sayHelloCommand = rpcService.registerCommand(new RemoteCommand()
      {
         public Serializable execute(Serializable[] args) throws Throwable
         {
            System.out.println("Hello !");
            return null;
         }

         public String getId()
         {
            return "hello-world-command";
         }
      });
   }

   public void start()
   {
      // Since the RPCService is a dependency of RPCService, it will be started before
      // so I can execute my command
      try
      {
         // This will make all the nodes say "Hello !"
         rpcService.executeCommandOnAllNodes(sayHelloCommand, false);
      }
      catch (SecurityException e)
      {
         e.printStackTrace();
      }
      catch (RPCException e)
      {
         e.printStackTrace();
      }
   }

   public void stop()
   {
   }
}</programlisting>

  <para>In the previous example, we register the command
  <emphasis>sayHelloCommand</emphasis> in the constructor of
  <emphasis>MyService</emphasis> and we execute this command in the start
  method.</para>

  <note>
    <para>We expect to have one <emphasis>RPCService</emphasis> instance per
    <emphasis>PortalContainer</emphasis> in a portal mode and only one
    <emphasis>RPCService</emphasis> instance in a standalone mode</para>
  </note>

  <section id="Kernel.RPCService.Configuration">
    <title>Configuration</title>

    <para>The configuration of the <emphasis>RPCService</emphasis> should be
    added only in a cluster environment. See below an example of
    configuration:</para>

    <programlisting language="xml">&lt;configuration&gt;
....  
  &lt;component&gt;
    &lt;key&gt;org.exoplatform.services.rpc.RPCService&lt;/key&gt;
    &lt;type&gt;org.exoplatform.services.rpc.jgv3.RPCServiceImpl&lt;/type&gt;
    &lt;init-params&gt;
      &lt;value-param&gt;
        &lt;name&gt;jgroups-configuration&lt;/name&gt;
        &lt;value&gt;classpath:/udp.xml&lt;/value&gt;
      &lt;/value-param&gt;
      &lt;value-param&gt;
        &lt;name&gt;jgroups-cluster-name&lt;/name&gt;
        &lt;value&gt;RPCService-Cluster&lt;/value&gt;
      &lt;/value-param&gt;
      &lt;value-param&gt;
        &lt;name&gt;jgroups-default-timeout&lt;/name&gt;
        &lt;value&gt;0&lt;/value&gt;
      &lt;/value-param&gt;
      &lt;value-param&gt;
        &lt;name&gt;allow-failover&lt;/name&gt;
        &lt;value&gt;true&lt;/value&gt;
      &lt;/value-param&gt;
      &lt;value-param&gt;
        &lt;name&gt;retry-timeout&lt;/name&gt;
        &lt;value&gt;20000&lt;/value&gt;
      &lt;/value-param&gt;
    &lt;/init-params&gt;
  &lt;/component&gt;   
...
&lt;/configuration&gt;</programlisting>

    <table>
      <title>Fields description</title>

      <tgroup cols="2">
        <tbody>
          <row>
            <entry><emphasis>jgroups-configuration</emphasis></entry>

            <entry>This is the location of the configuration of jgroups. This
            parameter is mandatory.</entry>
          </row>

          <row>
            <entry><emphasis>jgroups-cluster-name</emphasis></entry>

            <entry>This is the name of the cluster. This parameter is optional
            and its default value is <emphasis>RPCService-Cluster</emphasis>.
            Since we could have several instances of the
            <emphasis>RPCService</emphasis>, the final name will be
            "${jgroups-cluster-name}-${container-name}"</entry>
          </row>

          <row>
            <entry><emphasis>jgroups-default-timeout</emphasis></entry>

            <entry>This is the default timeout to use if the timeout is not
            given, if no response could be get after this timeout an exception
            will be thrown. This parameter is optional and its default value
            is 0 which means that we don't use any timeout by default. This
            parameter is expressed in milliseconds.</entry>
          </row>

          <row>
            <entry><emphasis>allow-failover</emphasis></entry>

            <entry>This is parameter indicates whether a command on the
            coordinator needs to be relaunched or not if the coordintator
            seems to have left the cluster. This parameter only affects the
            behavior of the methods
            <emphasis>executeCommandOnCoordinator</emphasis>. This parameter
            is optional and its default value is true.</entry>
          </row>

          <row>
            <entry><emphasis>retry-timeout</emphasis></entry>

            <entry>This parameter is the maximum amount of time to wait until
            the new coordinator is elected. This parameter is linked to the
            parameter <emphasis>allow-failover</emphasis>, and thus used in
            the exact same conditions. This parameter is optional and its
            default value is 20000. This parameter is expressed in
            milliseconds.</entry>
          </row>
        </tbody>
      </tgroup>
    </table>
  </section>

  <section id="Kernel.RPCService.SingleMethodCallCommand">
    <title>The SingleMethodCallCommand</title>

    <para>Most of the time we only need to call a method on a given object,
    this can be done thanks to the
    <emphasis>org.exoplatform.services.rpc.SingleMethodCallCommand</emphasis>
    which is the implementation of a <emphasis>RemoteCommand</emphasis>
    proposed by default. This command will dynamically execute a method on a
    given object.</para>

    <programlisting language="java">// Register the command first (to be done before that the RPCService has been started)
RemoteCommand commandGetName = rpcService.registerCommand(new SingleMethodCallCommand(myService, "getName"));
...
// Execute the command on the coordinator (can be done only after having started the RPCService)
String name = rpcService.executeCommandOnCoordinator(commandGetName, true);
// Print the name
System.out.println("Name : " + name);</programlisting>

    <para>This example:</para>

    <orderedlist>
      <listitem>
        <para>Register a <emphasis>SingleMethodCallCommand</emphasis> that
        will call <emphasis>getName()</emphasis> on the Object
        <emphasis>myService</emphasis> anytime the command will be
        executed.</para>
      </listitem>

      <listitem>
        <para>Execute the command synchronously on the coordinator, assuming
        that the same command (with the same id) has already been registered
        on the coordinator</para>
      </listitem>

      <listitem>
        <para>Print the name got from the coordinator</para>
      </listitem>
    </orderedlist>

    <note>
      <para>As any <emphasis>RemoteCommand</emphasis>, it has to be registered
      before being executed and before the <emphasis>RPCService</emphasis> is
      launched.</para>
    </note>

    <note>
      <para>As any <emphasis>RemoteCommand</emphasis>, the command can be
      executed only once the <emphasis>RPCService</emphasis> is
      launched.</para>
    </note>

    <note>
      <para>The <emphasis>SingleMethodCallCommand</emphasis> only allow public
      methods, if you try to register a non public method an
      <emphasis>RPCException</emphasis> will be thrown at creation
      level.</para>
    </note>
  </section>
</section>
