Hacia el AjServer

Published on Author lopez2 Comments

Mientras sigo trabajando duro en mi proyecto AjGenesis (estoy generando código, scripts de SQL, y otros artefactos de texto, a partir de un modelo, y ahora, en la nueva versión aún no publicada, hasta alimentándome de la base de datos para generar las entidades), hace ya un tiempo comencé a delinear el AjServer. El año pasado lo había presentado en una charla del Microsoft Users Group de Argentina, y este año ha estado evolucionando.


El AjServer trata de ser un conjunto de librerías que se usan en un cliente y en un servidor. Desde el punto de vista del cliente, permite invocar a lo que podemos llamar una “acción”, identificada por un nombre. Desde el cliente, alguna clase implementa:

Function Execute(ByVal action As String, ByVal ParamArray values As Object()) As Object

es decir, dado el nombre de la acción y los parámetros, el AjServer invoca a algo que se define por configuración. Lo más normal es que esa acción se encuentre en un servidor remoto basado en AjServer, pero también puede ser un método local. Un archivo de configuración de cliente podría incluir

 <AjClient>
  <EndPoints>
   <EndPoint Name=”RemoteServer” Url=”http://localhost:10000/RemoteServer.soap” Type=”AjServer.Common.IServer, AjServer.Common”/>
   <EndPoint Name=”OtherRemoteServer” Url=”http://localhost:10000/OtherRemoteServer.soap” Type=”AjServer.Common.IServer, AjServer.Common”/>
  </EndPoints>
  <Services>
   <Service>
    <Actions>
     <Action Name=”HelloWorld” EndPoint=”RemoteServer”/>
     <Action Name=”OtherHelloWorld” EndPoint=”OtherRemoteServer”/>
     <Action Name=”NewPerson” EndPoint=”RemoteServer”/>
    </Actions>
   </Service>
  </Services>
 </AjClient>

Los “endpoints” pueden corresponder a distintas tecnologías, ya sea remoting, como podría ser un web service especial que exponga algún AjServer remoto. Mientras, un programa servidor que albergue a la librería AjServer, puede exponer esos endpoints como quiera (se puede implementar un nuevo tipo de endpoint, me imagino que implementaré en algún momento uno en Windows Communication Foundation). Un clásico archivo de configuración servidor:

 <AjServer>
  <Channels>
   <Channel Port=”10000″ Protocol=”http”/>
<!–   
   <Channel Port=”10000″/>
–>   
  </Channels>
  
  <Servers>
  <Server>
  
  <Assembly Name=”TestConsole01″ Prefix=”My”/>
  
  <Queues>
   <Queue Name=”HelloQueue”/>
  </Queues>
  
  <Commands>
   <Command Name=”PrintLine2″>
    <Print Value=”${Value}”/>
    <PrintLine Value=”${Value2}”/>
   </Command>
   <Command Name=”Print” Type=”AjServer.Server.PrintCommand, AjServer.Server”/>
   <Command Name=”PrintLine” Type=”AjServer.Server.PrintLineCommand, AjServer.Server”/>
   <Command Name=”Set” Type=”AjServer.Server.SetCommand, AjServer.Server”/>
  </Commands>
  
  <Actions>
   <Action Name=”HelloWorld”>
    <ProcessStart Name=”HelloProcessA”/>
    <PrintLine Value=”Hello, World”/>
    <PrintLine Value=”${Request.Action}”/>
    <ResponseNew/>
    <Set Var=”Response.Message” Value=”Hello, World”/>
    <PrintLine Value=”${Response.Message}”/>
    <MyPrint Value=”Hello, World again”/>
    <ProcessStart Name=”HelloProcess”/>
    <IfPresent Test=”${Message}”>
     <PrintLine Value=”Message is present”/>
    </IfPresent>
    <IfNotPresent Test=”${Message}”>
     <PrintLine Value=”Message is not present”/>
    </IfNotPresent>
    <If Value=”${Headers}”>
     <PrintLine Value=”There are headers”/>
    </If>
    <Else>
     <PrintLine Value=”No headers”/>
    </Else>
    <ContextNew Var=”NewContext”>
     <Item Key=”ProcessMessage” Value=”${Request.Action}”/>
    </ContextNew>
    <ProcessStart Name=”ContextProcess” Context=”${NewContext}”/>
    <QueueEnqueue Name=”HelloQueue” Value=”${Request.Action}”/>
   </Action>
   <Action Name=”NewPerson”>
    <ObjectNew Var=”Person” Type=”TestConsole01.Person, TestConsole01″/>
    <Set Var=”Person.Name” Value=”Adan”/>
    <PrintLine Value=”${Person.Name}”/>
    <Set Var=”Person.Age” Value=”800″/>
    <PrintLine Value=”${Person.Age}”/>
    <PrintLine2 Value=”Person ” Value2=”${Person.Name}”/>
    <Invoke Object=”${Person}” Method=”Describe”/>
    <Invoke Object=”${Person}” Method=”AddYears”>
     <Parameter Value=”100″ Type=”System.Int32″/>
    </Invoke>
    <Invoke Object=”${Person}” Method=”Describe”/>
    <Try>
     <Invoke Object=”${Person}” Method=”UnknowMethod”/>
    </Try>
    <Catch Var=”Exception”>
     <Print Value=”Exception “/>
     <PrintLine Value=”${Exception.Message}”/>
    </Catch>
    <For Var=”k” From=”1″ To=”10″>
     <ContextClone Var=”Ctx”/>
     <Start Context=”${Ctx}”>
      <Print Value=”Starting “/>
      <Print Value=”${k}”/>
      <PrintLine Value=”…”/>
     </Start>
    </For>
    <Set Var=”k” Value=”10″/>
    <While Test=”${k}”>
     <Print Value=”While”/>
     <Break/>
    </While>
   </Action>
  </Actions>


  <Processes>
   <Process Name=”HelloProcess”>
    <PrintLine Value=”Hello Process”/>
    <QueueEnqueue Name=”HelloQueue” Value=”Message from Process”/>
    <PrintLine Value=”Process ends”/>
   </Process>
   <Process Name=”HelloProcessA”>
    <PrintLine Value=”Hello ProcessA”/>
    <PrintLine Value=”Process begins”/>
   </Process>
   <Process Name=”ContextProcess”>
    <PrintLine Value=”Context Process in action”/>
    <PrintLine Value=”${ProcessMessage}”/>
   </Process>
  </Processes>
  
  <Workers>
   <Worker PoolSize=”10″>
    <Guid Var=”WorkerId”/>
    <Print Value=”Worker activated: “/>
    <PrintLine Value=”${WorkerId}”/>
    <QueueDequeue Var=”Msg” Name=”HelloQueue”/>
    <Print Value=”Worker in action: “/>
    <PrintLine Value=”${WorkerId}”/>
    <PrintLine Value=”${Msg}”/>
   </Worker>
  </Workers>


<!–
  <Workers>
   <Worker>
    <PrintLine Value=”I’m still working”/>
    <Sleep Value=”1000″/>
   </Worker>
   <Worker>
    <FileWait Var=”File” Path=”..\Dir1″ Pattern=”*.txt”/>
    <Print Value=”Processing 1 “/>
    <PrintLine Value=”${File}”/>
    <FileCombine Var=”FullFile” Path=”..\Dir1″ File=”${File}”/>
    <FileCombine Var=”FullFile2″ Path=”..\Dir2″ File=”${File}”/>
    <FileMove From=”${FullFile}” To=”${FullFile2}”/>
    <Sleep Value=”100″/>
   </Worker>
   <Worker>
    <FileWait Var=”File” Path=”..\Dir2″ Pattern=”*.txt”/>
    <Print Value=”Processing 2 “/>
    <PrintLine Value=”${File}”/>
    <FileCombine Var=”FullFile” Path=”..\Dir2″ File=”${File}”/>
    <FileCombine Var=”FullFile2″ Path=”..\Dir1″ File=”${File}”/>
    <FileMove From=”${FullFile}” To=”${FullFile2}”/>
    <Sleep Value=”200″/>
   </Worker>
   <Worker>
    <FileWait Var=”File” Path=”..\Dir1″ Pattern=”*.xml”/>
    <Print Value=”Processing 1x “/>
    <PrintLine Value=”${File}”/>
    <FileCombine Var=”FullFile” Path=”..\Dir1″ File=”${File}”/>
    <XmlLoad Var=”Document” File=”${FullFile}”/>
    <FileCombine Var=”FullFile2″ Path=”..\Dir2″ File=”${File}”/>
    <XmlSave Value=”${Document}” File=”${FullFile2}”/>
    <FileDelete File=”${FullFile}”/>
    <Sleep Value=”100″/>
   </Worker>
   <Worker>
    <FileWait Var=”File” Path=”..\Dir2″ Pattern=”*.xml”/>
    <Print Value=”Processing 2x “/>
    <PrintLine Value=”${File}”/>
    <FileCombine Var=”FullFile” Path=”..\Dir2″ File=”${File}”/>
    <XmlLoad Var=”Document” File=”${FullFile}”/>
    <FileCombine Var=”FullFile2″ Path=”..\Dir1″ File=”${File}”/>
    <XmlSave Value=”${Document}” File=”${FullFile2}”/>
    <FileDelete File=”${FullFile}”/>
    <Sleep Value=”100″/>
   </Worker>
  </Workers>
–>


  </Server>


  <Server Name=”OtherServer”>
  
  <Assembly Name=”TestConsole01″ Prefix=”My”/>
  
  <Commands>
   <Command Name=”Print” Type=”AjServer.Server.PrintCommand, AjServer.Server”/>
   <Command Name=”PrintLine” Type=”AjServer.Server.PrintLineCommand, AjServer.Server”/>
   <Command Name=”Set” Type=”AjServer.Server.SetCommand, AjServer.Server”/>
  </Commands>
  
  <Actions>
   <Action Name=”OtherHelloWorld”>
    <PrintLine Value=”Hello, World Other Server”/>
    <ResponseNew/>
    <Set Var=”Response.Message” Value=”Hello, Other World”/>
   </Action>
  </Actions>
  </Server>


  </Servers>
  
  <EndPoints>
   <EndPoint Name=”RemoteServer.soap” Type=”TestConsole01.RemoteServer, TestConsole01″/>
   <EndPoint Name=”OtherRemoteServer.soap” Type=”TestConsole01.OtherRemoteServer, TestConsole01″ Server=”OtherServer”/>
<!–   
   <EndPoint Name=”RemoteServer.rem” Type=”TestConsole01.RemoteServer, TestConsole01″/>
–>
  </EndPoints>
 </AjServer>

Noten que aparte de acciones, hay procesos, hilos de ejecución en paralelo, que se lanzan en cualquier momento, desde alguna acción o ante un evento externo al sistema. Contempla luego la existencia de workers: threads de ejecución que se quedan trabajando, esperando trabajo para realizar. Como ven, hay un lenguaje de comandos en XML incluido, y los comandos son predefinidos, o pueden definirse en la configuración, o pueden escribirse e incorporarse a la librería. Siguiendo las ideas de Spring, desde un comando se puede invocar en forma no intrusiva a un método de un objeto nuestro.


Faltan cosas, como un buen Proof of Concept, implementarlo como servicio windows, manejar múltiples AppDomains por configuración, y cuarenta mil etcéteras. Pero me pareció interesante publicarlo algo.


La idea es, luego de tener algún “feedback” en .NET, implementarlo de la misma forma en Java.


Angel “Java” Lopez
http://www.ajlopez.com/

Leave a Reply

Your email address will not be published. Required fields are marked *