<!-- $Id: openmath.xml 3110 2009-05-26 14:57:43Z alexk $ -->

<Chapter Label="SCSCPmessages">
<Heading>Message exchange by &SCSCP;</Heading>    

To ensure the message exchange as required by &SCSCP; specification, the 
&SCSCP; package extends the global record <C>OMsymRecord</C> from the 
&OpenMath; package with new entries to support &scscp1; and &scscp2; 
content dictionaries (<Cite Key="scscp1cd"/>, <Cite Key="scscp2cd"/>), 
and also service-dependent transient private content dictionaries 
(see <Ref Label="Server" /> for details about transient content 
dictionaries). It also overwrites some &OpenMath; functions by their 
extended (but backwards compatible) versions, and adds some new 
&OpenMath;-related functions to send and receive &SCSCP; messages, 
documented below.
<P/>

Note that functions documented in this chapter belong to the middle-level 
interface, and the user may find it more convenient to use functions 
developed on top of them and explained in next chapters.

<Section Label="SCSCPclient">
<Heading>Communication with the &SCSCP; server</Heading>

<ManSection>
    <Func Name="StartSCSCPsession" 
           Arg="stream"
          Comm="" />
    <Returns>
    string
    </Returns>	 
    <Description>
    Initialises &SCSCP; session and negotiates with the server about the
    version of the protocol. Returns the string with the <C>service_id</C>
    (which may be used later as a part of the call identifier) or causes
    an error message if can not perform these tasks.
<Example>
<![CDATA[
gap> s := InputOutputTCPStream("localhost",26133);
#I  Creating a socket ...
#I  Connecting to a remote socket via TCP/IP ...
< input/output TCP stream to localhost:26133 >
gap> StartSCSCPsession(s);
#I  Got connection initiation message
#I  <?scscp service_name="GAP" service_version="4.dev" service_id="localhost:2\
6133:5541" scscp_versions="1.0 1.1 1.2 1.3" ?>
#I  Requesting version 1.3 from the server ...
#I  Server confirmed version 1.3 to the client ...
"localhost:26133:5541"
]]>
</Example>
After the call to <Ref Func="StartSCSCPsession" /> the &SCSCP; server is
ready to accept procedure calls.
    </Description>
</ManSection>

<ManSection>
   <Func Name="OMPutProcedureCall" 
          Arg="stream proc_name objrec"
         Comm="" />
   <Returns>
     Nothing
   </Returns>	 
   <Description>
      <!-- Document option cd and debuglevel -->
     Takes a stream <A>stream</A>, the string <A>proc&uscore;name</A> and a record 
     <A>objrec</A>, and writes to <A>stream</A> an &OpenMath; object 
     <C>procedure&uscore;call</C> for the procedure <A>proc&uscore;name</A> with
     arguments given by the list <C>objrec.object</C> and procedure call options
     (which should be encoded as &OpenMath; attributes) given in the list <C>objrec.attributes</C>.
     This function accepts the option <C>cd:="cdname"</C> to specify the
     name of the content dictionary if the procedure is actually a standard
     &OpenMath; symbol  note that the server may reject such a call if it
     accepts only calls of procedures from the transient content dictionary,
     see <Ref Func="InstallSCSCPprocedure" /> for explanation). If the <C>cdname</C>
     is not specified, <C>scscp_transient_1</C> content dictionary will be assumed
     by default.
<Example>
<![CDATA[
gap> t:="";; stream:=OutputTextString(t,true);;
gap> OMPutProcedureCall( stream, "WS_Factorial", rec( object:= [ 5 ], 
>      attributes:=[ [ "call_id", "user007" ], 
>                    ["option_runtime",1000],
>                    ["option_min_memory",1024], 
>                    ["option_max_memory",2048],
>                    ["option_debuglevel",1], 
>                    ["option_return_object"] ] ) );;
gap> Print(t);
<?scscp start ?>
<OMOBJ>
	<OMATTR>
		<OMATP>
			<OMS cd="scscp1" name="call_id"/>
			<OMSTR>user007</OMSTR>
			<OMS cd="scscp1" name="option_runtime"/>
			<OMI>1000</OMI>
			<OMS cd="scscp1" name="option_min_memory"/>
			<OMI>1024</OMI>
			<OMS cd="scscp1" name="option_max_memory"/>
			<OMI>2048</OMI>
			<OMS cd="scscp1" name="option_debuglevel"/>
			<OMI>1</OMI>
			<OMS cd="scscp1" name="option_return_object"/>
			<OMSTR></OMSTR>
		</OMATP>
		<OMA>
			<OMS cd="scscp1" name="procedure_call"/>
			<OMA>
				<OMS cd="scscp_transient_1" name="WS_Factorial"/>
				<OMI> 5</OMI>
			</OMA>
		</OMA>
	</OMATTR>
</OMOBJ>
<?scscp end ?>
]]>
</Example>
   </Description>
</ManSection>


<ManSection>
    <Func Name="SCSCPwait" 
           Arg="stream [timeout]"
          Comm="" />
    <Returns>
    nothing
    </Returns>	 
    <Description>
    This function may be used by the &SCSCP; client to wait
    (using <Ref BookName="IO" Func="IO_select" />)
    until the result of the procedure call will be 
    available from <A>stream</A>. By default the timeout is
    one hour, to specify another value give it as the optional
    second argument in seconds. See the end of this chapter 
    for the example.
    </Description>
</ManSection>


<ManSection>
   <Func Name="OMGetObjectWithAttributes" 
          Arg="stream"
         Comm="" />
   <Returns>
     record with components <C>object</C> and <C>attributes</C>, or <K>fail</K>
   </Returns>	 
   <Description>
   <!-- Document option return_tree -->
     This function is similar to the function <C>OMGetObject</C>
     from the &OpenMath; package, and the main difference is that it is 
     able to understand &OpenMath; attribution pairs. It retrieves
     exactly one &OpenMath; object from the stream <A>stream</A>, and
     stores it in the <C>object</C> component of the returned record.
     If the &OpenMath; object has no attributes, the <C>attributes</C> 
     component of the returned record will be an empty list, otherwise
     it will contain pairs <C>[attribute&uscore;name,attribute&uscore;value]</C>,
     where <C>attribute&uscore;name</C> is a string, and 
     <C>attribute&uscore;value</C> is a &GAP; object, whose type is 
     determined by the kind of an attribute. Only attributes, defined by 
     the SCSCP are allowed, otherwise an error message will be displayed.
     <P/>
     If the procedure was not successful, the function returns <K>fail</K>
     instead of an error message like the function 
     <Ref BookName="OpenMath" Func="OMGetObject" /> does. Returning
     <K>fail</K> is useful when <C>OMGetObjectWithAttributes</C> is used
     inside accept-evaluate-return loop.
   </Description>
</ManSection>

As an example, the file <File>scscp/tst/omdemo.om</File> contains some 
&OpenMath; objects, including those from the SCSCP Specification 
<Cite Key="SCSCP"/>. We can retrieve them from this file,
preliminary installing some SCSCP procedures
using the function <Ref Func="InstallSCSCPprocedure"/>:

<Example>
<![CDATA[
gap> InstallSCSCPprocedure("WS_Factorial", Factorial );
gap> InstallSCSCPprocedure("GroupIdentificationService", IdGroup );
gap> InstallSCSCPprocedure("GroupByIdNumber", SmallGroup );
gap> test:=Filename( Directory( Concatenation(
>         GAPInfo.PackagesInfo.("scscp")[1].InstallationPath,"/tst/" ) ), 
>         "omdemo.om" );;
gap> stream:=InputTextFile(test);;
gap> OMGetObjectWithAttributes(stream);     
rec( object := 1, attributes := [  ] )
gap> OMGetObjectWithAttributes(stream);
rec( object := "Primes@localhost:26133", 
  attributes := [ [ "call_id", "call_identifier" ] ] )
gap> OMGetObjectWithAttributes(stream);
rec( object := 120, attributes := [  ] )
gap> OMGetObjectWithAttributes(stream);
rec( object := [ 24, 12 ], 
  attributes := [ [ "call_id", "alexk_9053" ], [ "option_runtime", 300000 ], 
      [ "option_min_memory", 40964 ], [ "option_max_memory", 134217728 ], 
      [ "option_debuglevel", 2 ], [ "option_return_object", "" ] ] )
gap> CloseStream( str );
]]>
</Example>

</Section> 

<Section Label="SCSCPserver">
<Heading>Communication with the &SCSCP; client</Heading>

<ManSection>
   <Func Name="OMPutProcedureCompleted" 
          Arg="stream objrec"
         Comm="" />
   <Returns>
       nothing
   </Returns>	 
   <Description>
     Takes a stream <A>stream</A>, and a record 
     <A>objrec</A>, and writes to <A>stream</A> an &OpenMath; object 
     <C>procedure&uscore;completed</C> 
     with the result being <C>objrec.object</C> and information messages
     (as &OpenMath; attributes) given in the list <C>objrec.attributes</C>.
   </Description>
</ManSection>

<Example>
<![CDATA[
gap> t:="";; stream:=OutputTextString(t,true);;
gap> OMPutProcedureCompleted( stream, 
>      rec(object:=120, 
>      attributes:=[ [ "call_id", "user007" ] ] ));
gap> Print(t);
<?scscp start ?>
<OMOBJ>
	<OMATTR>
		<OMATP>
			<OMS cd="scscp1" name="call_id"/>
			<OMSTR>user007</OMSTR>
		</OMATP>
		<OMA>
			<OMS cd="scscp1" name="procedure_completed"/>
			<OMI> 120</OMI>
		</OMA>
	</OMATTR>
</OMOBJ>
<?scscp end ?>
]]>
</Example>

<ManSection>
   <Func Name="OMPutProcedureTerminated" 
          Arg="stream objrec error_cd error_type"
         Comm="" />
   <Returns>
     nothing
   </Returns>	 
   <Description>
    Takes a stream <A>stream</A>, and a record with an error message <A>objrec</A> (for example
    <C>rec( attributes := [ [ "call_id", "localhost:26133:87643:gcX33cCf" ] ],</C>
    <C>object := "localhost:26133 reports : Rational operations: &lt;divisor> must not be zero")</C>
     and writes to the <A>stream</A> an &OpenMath; object <C>procedure&uscore;terminated</C>
     containing an error determined by the symbol <A>error_type</A> from the content dictionary
     <A>error_cd</A> (for example, <C>error_memory</C>, <C>error_runtime</C> or 
     <C>error_system_specific</C> from the &scscp1; content dictionary (<Cite Key="scscp1cd"/>).
     <P/>
     This is the internal function of the package which is used only in the code for the &SCSCP; server
     to return the error message to the client.
   </Description>
</ManSection>

</Section>


<Section Label="SCSCPsession">
<Heading>Example: &SCSCP; session</Heading>

In the following example we start an &SCSCP; session and perform ten
procedure calls in a loop before closing that session. Note that we
demonstrate the usage of the session ID <C>sid</C> and the function 
<C>RandomString</C> from the &OpenMath; package to produce some unique 
call identifier.
The call ID is a mandatory attribute for any procedure call, however, 
it is not nesessarily random; for example, it may be just a string 
with the number of the procedure call.
<Example>
<![CDATA[
gap> stream:=InputOutputTCPStream( "localhost", 26133 );
#I  Creating a socket ...
#I  Connecting to a remote socket via TCP/IP ...
< input/output TCP stream to localhost:26133 >
gap> sid := StartSCSCPsession( stream );
#I  Got connection initiation message
#I  Requesting version 1.3 from the server ...
#I  Server confirmed version 1.3 to the client ...
"localhost:26133:5541"
gap> res:=[];
[  ]
gap> for i in [1..10] do
>     OMPutProcedureCall( stream, "WS_Factorial", 
>       rec( object := [ i ], 
>        attributes := [ [ "call_id", 
>          Concatenation( sid, ":", RandomString(8) ) ] ] ) );
>     SCSCPwait( stream );
>     res[i]:=OMGetObjectWithAttributes( stream ).object;
> od;
gap> CloseStream(stream);
gap> res;
[ 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800 ]
]]>
</Example>
Also note the usage of <Ref Func="SCSCPwait" /> to wait
until the result of the computation will be available from <C>stream</C>.

</Section>

</Chapter>