Proposal for 'address' functionality in NetRexx

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Proposal for 'address' functionality in NetRexx

Rene Jansen
Administrator
In a NetRexx context, the term 'scripting' is used often to describe the mode in which the translator generates the necessary class and method statements to enable the user to write programs without the overhead of the Java class model notation. In general usage however, the term is often used to indicate a programming style that frequently invoke routines native to the platform. Rexx has the 'address' construct, where the 'environment' that is addressed can be an OS command shell, a facility like ISPF or a specific application like NetView or an editor.

As answered by MFC last year during the symposium interview, it was assumed that all communication external to the JVM - to the native platform - would be handled by Java. This is true and will stay that way.

What I would like to propose here is that because the notation convention in Rexx is better geared towards short interactions with environments, it would be beneficial to 'scripting' applications, but in general to any application that uses external functionality, to adopt that notation. In short, commands that are not recognized in context, like strings enclosed in quotes that are not part of an assignment, are passed to the environment. Platforms have a default environment, which can be changed by the 'address' statement.

Simple interaction can be specified this way, where simple is defined as 'we do not care about the output. If we do care about the results of the external command, it can be trapped in different ways. Under TSO, we have the outtrap function which writes to a stem variable, and on several platforms we can use queuing mechanisms to capture zero or more lines of output. It would be good if NetRexx has a built in equivalent of this.

This is the code of the external library I currently use to simply specify command lines and optionally capture output. It is possible to use it in these ways:

os.exec('sudo shutdown now')

a = os.outtrap('dir \\w')
i = a.iterator
loop while i.hasNext
  line = Rexx i.next
  say line
end

and, as a novel construct, an event based way to use os.exec('curl netrexx.org') with an opportunity to handle every line of output directly without having to wait for the completion of the external command.

[longish code section follows]


/**
 * Class OSProcess implements ways to execute and get output from an OS Process
 */
class OSProcess

  properties indirect
  pid = Process
  returncode
  commandList = ArrayList()
  outList = ArrayList()

  properties private
  listeners = HashSet()
  /**
   * Default constructor
   */
  method OSProcess()
    return

  method outtrap(command_=Rexx) returns ArrayList
    if command_ = '', command_ = null then return null
    a = ArrayList()
    loop until command_ = ''
      parse command_ first command_
      a.add(first.toString())
    end
    return this.outtrap(a)

  method exec(command_=Rexx, wait=1)
    if command_ = '', command_ = null then return
    a = ArrayList()
    loop until command_ = ''
      parse command_ first command_
      a.add(first.toString())
    end
    this.exec(a,wait)

  /**
   * Method run starts an OS process from a command line in an ArrayList
   * @param command is a List that has the command to be executed as elements
   * @return List containing the output of the command
   */
  method outtrap(command_=ArrayList) returns ArrayList
    this.commandList = command_
    do
      pb = ProcessBuilder(command_)
      pb.redirectErrorStream(1)
      this.pid = pb.start()
      in = BufferedReader(InputStreamReader(this.pid.getInputStream()))
      line = Rexx in.readLine()
      loop while line <> null
        this.outList.add(line)
        line = Rexx in.readLine()
      end
      pid.waitFor()
      returncode = pid.exitValue()
      return this.outList
    catch iox=IOException
      say iox.getMessage()
      return ArrayList()
    catch InterruptedException
      say "interrupted"
      return ArrayList()
    end -- do

  /**
   * Method exec starts an OS process from a command line in an ArrayList
   * @param then fires off outputEvent events to every registered listener
   * @return void
   */
  method exec(command_=ArrayList,wait=1)
    this.commandList = command_
    do
      pb = ProcessBuilder(command_)
      pb.redirectErrorStream(1)
      this.pid = pb.start()
      if wait then do
        in = BufferedReader(InputStreamReader(this.pid.getInputStream()))
        line = in.readLine()
        loop while line <> null
          line = in.readLine()
          i = this.listeners.iterator()
          loop while i.hasNext()
            op = OutputEventListener i.next()
          op.outputReceived(OutputLineEvent(this,line,this.pid))
          end
        end
        pid.waitFor()
        returncode = pid.exitValue()
      end
    catch iox=IOException
      say iox.getMessage()
    catch InterruptedException
      say "interrupted"
    end -- do
   
   
  /**
   * Method addOutputEventListener supports registering an event listener
   * @param listener_ is a OutputEventListener
   */
  method addOutputEventListener(listener_=OutputEventListener)
    this.listeners.add(listener_)

  /**
   * Method removeOutputEventListener supports de-registering an event listener
   * @param listener_ is a OutputEventListener
   */
  method removeOutputEventListener(listener_=OutputEventListener)
    this.listeners.remove(listener_)
       

import java.util.EventListener
/**
 * Interface OutputEventListener specifies the one mandatory method for this interface
 */
class OutputEventListener interface implements EventListener
 
  method outputReceived(ob=OutputLineEvent)

import java.util.EventObject
/**
 * Class OutputLineEvent embodies the OutputLineEvent
 */
class OutputLineEvent extends EventObject

  properties indirect
  pid = Process
  line
  /**
   * Default constructor
   */
  method OutputLineEvent(ob=Object,line_, pid_=Process)
    super(ob)
    this.line = line_
    this.pid = pid_
    return

[end of longish code section]

Note that the jvm expects the command in an array, we added fronting methods that take a Rexx string and convert to an array before submitting the command.

If one implements the OutputEventListener interface, the event handler can be registered on the OSProcess instance before calling .exec().

This seems (and has proven) a useful approach, and can be used as such, but the proposal here is to come to an implementation in which we can have programs like:

/* NetRexx suggested, currently hypothetical source code */
"/opt/vc/bin/vcgencmd measure_temp"
say result

[would produce, for example, "temp = 55.6 C" on some computer. 'address bash' would be a default environment on *nix, as would cmd be on windows]

/* NetRexx suggested, currently hypothetical source code */
address bash
a = ask"ls - laF | sort"

[would outtrap the sorted directory list to a]

/* NetRexx suggested, currently hypothetical source code */
address bash to MySource.lineHandler

"tail -f security.log"

class mySource.lineHandler implements OutputEventListener
  method outputReceived(ob=OutputLineEvent)
   if ob.line.pos(".php") >0 then signal alert

Let me know if you think this would be usable, and if we should invest time into implementing this in 3.03

best regards,

René Jansen.

Reply | Threaded
Open this post in threaded view
|

Re: Proposal for 'address' functionality in NetRexx

Chip Davis
Administrator
A cursory glance over your proposal seems reasonable René, but I'm
teaching this week, so I'll take a more thorough look at it this weekend.

I certainly agree with your philosophy of making it easier to drive
external platforms from NetRexx rather than Java.

-Chip-

On 4/25/2013 19:29 Rene Jansen [via Rexx Language Association Forum] said:

> In a NetRexx context, the term 'scripting' is used often to describe
> the mode in which the translator generates the necessary class and
> method statements to enable the user to write programs without the
> overhead of the Java class model notation. In general usage however,
> the term is often used to indicate a programming style that frequently
> invoke routines native to the platform. Rexx has the 'address'
> construct, where the 'environment' that is addressed can be an OS
> command shell, a facility like ISPF or a specific application like
> NetView or an editor.
>
> As answered by MFC last year during the symposium interview, it was
> assumed that all communication external to the JVM - to the native
> platform - would be handled by Java. This is true and will stay that way.
>
> What I would like to propose here is that because the notation
> convention in Rexx is better geared towards short interactions with
> environments, it would be beneficial to 'scripting' applications, but
> in general to any application that uses external functionality, to
> adopt that notation. In short, commands that are not recognized in
> context, like strings enclosed in quotes that are not part of an
> assignment, are passed to the environment. Platforms have a default
> environment, which can be changed by the 'address' statement.
>
> Simple interaction can be specified this way, where simple is defined
> as 'we do not care about the output. If we do care about the results
> of the external command, it can be trapped in different ways. Under
> TSO, we have the outtrap function which writes to a stem variable, and
> on several platforms we can use queuing mechanisms to capture zero or
> more lines of output. It would be good if NetRexx has a built in
> equivalent of this.
>
> This is the code of the external library I currently use to simply
> specify command lines and optionally capture output. It is possible to
> use it in these ways:
>
> os.exec('sudo shutdown now')
>
> a = os.outtrap('dir \\w')
> i = a.iterator
> loop while i.hasNext
>    line = Rexx i.next
>    say line
> end
>
> and, as a novel construct, an event based way to use os.exec('curl
> netrexx.org') with an opportunity to handle every line of output
> directly without having to wait for the completion of the external
> command.
>
> [longish code section follows]
>
>
> /**
>   * Class OSProcess implements ways to execute and get output from an
> OS Process
>   */
> class OSProcess
>
>    properties indirect
>    pid = Process
>    returncode
>    commandList = ArrayList()
>    outList = ArrayList()
>
>    properties private
>    listeners = HashSet()
>    /**
>     * Default constructor
>     */
>    method OSProcess()
>      return
>
>    method outtrap(command_=Rexx) returns ArrayList
>      if command_ = '', command_ = null then return null
>      a = ArrayList()
>      loop until command_ = ''
>        parse command_ first command_
>        a.add(first.toString())
>      end
>      return this.outtrap(a)
>
>    method exec(command_=Rexx, wait=1)
>      if command_ = '', command_ = null then return
>      a = ArrayList()
>      loop until command_ = ''
>        parse command_ first command_
>        a.add(first.toString())
>      end
>      this.exec(a,wait)
>
>    /**
>     * Method run starts an OS process from a command line in an ArrayList
>     * @param command is a List that has the command to be executed as
> elements
>     * @return List containing the output of the command
>     */
>    method outtrap(command_=ArrayList) returns ArrayList
>      this.commandList = command_
>      do
>        pb = ProcessBuilder(command_)
>        pb.redirectErrorStream(1)
>        this.pid = pb.start()
>        in = BufferedReader(InputStreamReader(this.pid.getInputStream()))
>        line = Rexx in.readLine()
>        loop while line <> null
>          this.outList.add(line)
>          line = Rexx in.readLine()
>        end
>        pid.waitFor()
>        returncode = pid.exitValue()
>        return this.outList
>      catch iox=IOException
>        say iox.getMessage()
>        return ArrayList()
>      catch InterruptedException
>        say "interrupted"
>        return ArrayList()
>      end -- do
>
>    /**
>     * Method exec starts an OS process from a command line in an
> ArrayList
>     * @param then fires off outputEvent events to every registered
> listener
>     * @return void
>     */
>    method exec(command_=ArrayList,wait=1)
>      this.commandList = command_
>      do
>        pb = ProcessBuilder(command_)
>        pb.redirectErrorStream(1)
>        this.pid = pb.start()
>        if wait then do
>          in =
> BufferedReader(InputStreamReader(this.pid.getInputStream()))
>          line = in.readLine()
>          loop while line <> null
>            line = in.readLine()
>            i = this.listeners.iterator()
>            loop while i.hasNext()
>              op = OutputEventListener i.next()
>            op.outputReceived(OutputLineEvent(this,line,this.pid))
>            end
>          end
>          pid.waitFor()
>          returncode = pid.exitValue()
>        end
>      catch iox=IOException
>        say iox.getMessage()
>      catch InterruptedException
>        say "interrupted"
>      end -- do
>
>
>    /**
>     * Method addOutputEventListener supports registering an event
> listener
>     * @param listener_ is a OutputEventListener
>     */
>    method addOutputEventListener(listener_=OutputEventListener)
>      this.listeners.add(listener_)
>
>    /**
>     * Method removeOutputEventListener supports de-registering an
> event listener
>     * @param listener_ is a OutputEventListener
>     */
>    method removeOutputEventListener(listener_=OutputEventListener)
>      this.listeners.remove(listener_)
>
>
> import java.util.EventListener
> /**
>   * Interface OutputEventListener specifies the one mandatory method
> for this interface
>   */
> class OutputEventListener interface implements EventListener
>
>    method outputReceived(ob=OutputLineEvent)
>
> import java.util.EventObject
> /**
>   * Class OutputLineEvent embodies the OutputLineEvent
>   */
> class OutputLineEvent extends EventObject
>
>    properties indirect
>    pid = Process
>    line
>    /**
>     * Default constructor
>     */
>    method OutputLineEvent(ob=Object,line_, pid_=Process)
>      super(ob)
>      this.line = line_
>      this.pid = pid_
>      return
>
> [end of longish code section]
>
> Note that the jvm expects the command in an array, we added fronting
> methods that take a Rexx string and convert to an array before
> submitting the command.
>
> If one implements the OutputEventListener interface, the event handler
> can be registered on the OSProcess instance before calling .exec().
>
> This seems (and has proven) a useful approach, and can be used as
> such, but the proposal here is to come to an implementation in which
> we can have programs like:
>
> /* NetRexx suggested, currently hypothetical source code */
> "/opt/vc/bin/vcgencmd measure_temp"
> say result
>
> [would produce, for example, "temp = 55.6 C" on some computer.
> 'address bash' would be a default environment on *nix, as would cmd be
> on windows]
>
> /* NetRexx suggested, currently hypothetical source code */
> address bash
> a = ask"ls - laF | sort"
>
> [would outtrap the sorted directory list to a]
>
> /* NetRexx suggested, currently hypothetical source code */
> address bash to MySource.lineHandler
>
> "tail -f security.log"
>
> class mySource.lineHandler implements OutputEventListener
>    method outputReceived(ob=OutputLineEvent)
>     if ob.line.pos(".php") >0 then signal alert
>
> Let me know if you think this would be usable, and if we should invest
> time into implementing this in 3.03
>
> best regards,
>
> René Jansen.
>
>
>
> ----------------------------------------------------------------------
> If you reply to this email, your message will be added to the
> discussion below:
> http://rexx-language-association-forum.44760.x6.nabble.com/Proposal-for-address-functionality-in-NetRexx-tp321.html
>
> To start a new topic under NetRexx, email
> [hidden email]
> To unsubscribe from NetRexx, click here
> <
> NAML
> <
http://rexx-language-association-forum.44760.x6.nabble.com/template/NamlServlet.jtp?macro=macro_viewer&id=instant_html%21nabble%3Aemail.naml&base=nabble.naml.namespaces.BasicNamespace-nabble.view.web.template.NabbleNamespace-nabble.view.web.template.NodeNamespace&breadcrumbs=notify_subscribers%21nabble%3Aemail.naml-instant_emails%21nabble%3Aemail.naml-send_instant_email%21nabble%3Aemail.naml>
>

Reply | Threaded
Open this post in threaded view
|

Re: Proposal for 'address' functionality in NetRexx

Chip Davis
Administrator
In reply to this post by Rene Jansen
[Apologies for it taking over a month to follow up on this proposal;
this is my busiest time of year.  Am somewhat dismayed that mine is
still the only response it has gotten.]

I like this proposal quite a bit and encourage you to implement it in
3.03 (if you haven't already).  I would not presume to comment on your
suggested implementation code as you are a far better NetRexx
programmer than I.

This is a fundamental characteristic of all Rexx dialects.  It should
be in NetRexx as well.

-Chip-
Reply | Threaded
Open this post in threaded view
|

Re: Proposal for 'address' functionality in NetRexx

Rob Schramm
Did anything ever happen with the 'address' functionality in NetRexx?

I was looking into running NetRexx on z/OS instead of Rexx in batch.

Reply | Threaded
Open this post in threaded view
|

Re: Proposal for 'address' functionality in NetRexx

Rene Jansen
Administrator
Hi Rob,

Be sure to run NetRexx-4.00PRE (build it from source or download it from http://netrexx.org/files/NetRexxF.jar ). This contains the runtime support for ADDRESS shell, which enables you to use:

import org.netrexx.address.  

  command    = ArrayList()
  command.add('cmp')
  command.add('tmpf1')
  command.add('tmpf2’)

  os = OSProcess()
  a  = os.outtrap(command)
  i  = a.iterator()
  loop while i.hasNext()
    line     = Rexx i.next()
    say line
  end


And the other, event-based way to get line-by-line output is also in there. As you might gather, I am still working on the syntax support for this; but this variant I am already using a lot.

I am running NetRexx on a z13 under z/OS 2.1 at work, in ssh, omvs shell, and also in batch. Let me know if you run into trouble or need support for jzos- functionality in NetRexx.

best regards,

René.


On 18 dec. 2015, at 01:47, Rob Schramm [via Rexx Language Association Forum] <[hidden email]> wrote:

Did anything ever happen with the 'address' functionality in NetRexx?

I was looking into running NetRexx on z/OS instead of Rexx in batch.




If you reply to this email, your message will be added to the discussion below:
http://rexx-language-association-forum.44760.x6.nabble.com/Proposal-for-address-functionality-in-NetRexx-tp321p2882.html
To start a new topic under NetRexx, email [hidden email]
To unsubscribe from Rexx Language Association Forum, click here.
NAML