Ruby and RPG
talking at last
Aaron BartellDirector of IBM i Innovation
Copyright 2015 Aaron Bartell
● Consulting - Jumpstart your open source pursuit. Small and big projects.
● Free Educational Content on everything open source for IBM i at litmis.com
● spaces.litmis.com provides open source development via browser on IBM i machine in the cloud.
twitter: @litmisteam [email protected]
This session brought to you by...
What are YiPs?
YoungiProfessionals.com - Home siteYoungiProfessionals.com/wiki - Wiki (a lot of content)linkd.in/1iG3oIV - LinkedIn YiPs group
● Began as a group within COMMON USA as a way for young people to find each other at the COMMON USA annual conference.
● Goals: educate, advocate, and get involved!● Wiki is very active● IBM has been using YiPs as a way to share open source that
originates from within their walls (i.e. xmlservice, Ruby gems, PHP code, many tutorials on git, PASE, ssh, FastCGI, etc)
● Top contributor to YiPs wiki is IBM'er Tony Cairns.● "Join" YiPs by via LinkedIn YiPs group: linkd.in/1iG3oIV● Only need to be young at heart! :-)
YiPs = Young i Professionals
What is XMLSERVICE?
YoungiProfessionals.com/wiki/XMLSERVICE - Home siteYoungiProfessionals.com/wiki/index.php/XMLSERVICE/XMLSERVICERuby - Ruby Gem
Make use of all these from Ruby● DB2 for i – SQL and Native● *PGM call● *SRVPGM sub procedure call● Data Area● Data Queue● Message Queue● Commands● System values● Spool files
● Delivered with OS as of IBM i 7.1: TR5 and also included with PowerRuby● Similar to IBM ToolBox for Java, but better in many ways● Great for re-use of existing RPG code from ANY language in your enterprise● Can be invoked via DB2 stored procedure or HTTP REST connection● Author: Tony Cairns, IBM Rochester
… a single library of Open Source RPG code that enables XML scripting calls of IBM i resources using most any language available on your platform.
Flow and 10k foot view
IBM i XMLSERVICE
DB2PGMSRVPGMPASESystem APIUser SpaceWRKACTJOB
XML input from IBMi / Linux /
Windows
Ruby, PHP, Java, etc.
DB2 connection
REST GET/POST
XML
XML
<myscript> <pgm>...</pgm> <cmd>...</cmd> <sh>...</sh> <sql>...</sql></myscript>
Setup xmlservice in Rails app
● RubyGems are a mechanism to wrapper Ruby code for easy sharing (downloading, installing, updating, etc). IBM has developed a RubyGem named 'xmlservice' to wrapper the RPG XMLSERVICE code.
● xmlservice Gem is included with PowerRuby install● First, add gem 'xmlservice' to Gemfile● Second, run bundle install --local
$ cd /www/my_apache/htdocs/rails_app$ bundle install --localResolving dependencies...Using rake (10.1.0)Using i18n (0.6.5)Using minitest (4.7.5)Using multi_json (1.8.0)Using atomic (1.1.14). . .Using xmlservice (1.0.1)Your bundle is complete!Use `bundle show [gemname]` to see where a bundled gem is installed.
source 'https://rubygems.org'
gem 'rails', '4.0.0'gem 'ibm_db'gem 'jquery-rails'gem 'turbolinks'gem 'jbuilder', '~> 1.2'gem 'thin'gem 'xmlservice'
<app_root>/Gemfile
Setup xmlservice in plain Ruby scenario
Simply add require 'xmlservice' to the top of any program. This will search the default paths** for the Gem.
require 'xmlservice'
ActiveXMLService::Base.establish_connection connection: 'ActiveRecord'
. . .
test.rb
**Default IFS paths searched for Gems
/PowerRuby/prV2R1M0/lib/ruby/site_ruby/PowerRuby/prV2R1M0/lib/ruby/vendor_ruby/PowerRuby/prV2R1M0/lib/ruby/gems
*
Call *PGM
MYLIB/PGM1
dcl-pr pgm1 extpgm; char1 char(1); dec1 packed(7:4); end-pr; dcl-pi pgm1; char1 char(1); dec1 packed(7:4); end-pi;
char1 = 'C'; dec1 = 321.1234; return;
Supports much more complex program calls and even go beyond the PCML/Java Toolbox limitations with data structures, sub-procedure return values, and date/time data types.
NOTE: This is 100% free-form RPG, available in IBM i v7.1
*
Invoke via DB2 stored proc
require 'xmlservice'
ActiveXMLService::Base.establish_connection connection: 'ActiveRecord'
pgm1 = XMLService::I_PGM.new("PGM1", 'MYLIB') << XMLService::I_a.new('inchara',1,'a') << XMLService::I_p.new('indec1',7,4,11.1111)
pgm1.call
puts "inchara: #{pgm1.PARM0.inchara}"puts " indec1: #{pgm1.PARM1.indec1}"
● The call to Ruby method establish_connection omits the use of parentheses - another feature of Ruby to lessen the amount of code and make it easier/quicker to visually scan code. The same is true for puts
● Ruby’s left shift operator (i.e. ‘<<’ ) is used to append parameters to the call.● Line pgm1.call makes the call to RPG
$ ruby /ifs/path/xmlservice_rest.rb # inchara: C# indec1: 321.1234
*
Under the covers
<myscript> <pgm error='fast' lib='AARONLIB' name='PGM1'> <parm io='io' var='PARM0'> <data type='1a' var='inchara'><![CDATA[C]]></data> </parm> <parm io='io' var='PARM1'> <data type='7p4' var='indec1'><![CDATA[321.1234]]></data> </parm> <success><![CDATA[+++ success AARONLIB PGM1 ]]></success> </pgm></myscript>
<pgm name='PGM1' lib='AARONLIB' error='fast'> <parm var='PARM0' io='io'> <data var='inchara' type='1a'>a</data> </parm> <parm var='PARM1' io='io'> <data var='indec1' type='7p4'>11.1111</data> </parm></pgm>
XML Request (obtained with pgm1.out_xml)
XML Response (obtained with pgm1.to_xml)
Invoking via HTTP REST
require 'xmlservice'
ActiveXMLService::Base.establish_connection( connection: "http://192.168.168.76:2222/cgi-bin/xmlcgi.pgm", username: 'A2222', password: 'A2222')
pgm1 = XMLService::I_PGM.new("PGM1", 'MYLIB') << XMLService::I_a.new('inchara',1,'a') << XMLService::I_p.new('indec1',7,4,11.1111)
pgm1.call
puts "inchara: #{pgm1.PARM0.inchara}"puts " indec1: #{pgm1.PARM1.indec1}"
Future version will store connection information in xmlservice.yml file with full environment capabilities (i.e. development, test, production, custom)
● The Ruby code could be on another machine or on the same machine.● HTTP REST is less common usage (slower) and more common is DB2 stored proc
approach
Data Types
Create a parameter by invoking new with the parameter name, total length, and initial value.Short vs. long form:
Short Form Long Form ParametersI_a I_String name, len, valueI_a_varying_2 I_VarChar2 name, len, valueI_a_varying_4 I_VarChar4 name, len, valueI_3i0 I_Int8 name, valueI_5i0 I_Int16 name, valueI_10i0 I_Int32 name, valueI_20i0 I_Int64 name, valueI_3u0 I_Uint8 name, valueI_5u0 I_Uint16 name, valueI_10u0 I_Uint32 name, valueI_20u0 I_Uint64 name, valueI_4f I_Float4 or I_Real name, precision, valueI_8f I_Float8 or I_Double name, precision, valueI_b I_Binary name, len, valueI_p I_PackedDecimal name, len, precision, valueI_z I_ZonedDecimal name, len, precision, value
XMLService::I_String.new('last_name', 15, 'Denoncourt')XMLService::I_a.new('last_name', 15, 'Denoncourt')
Call *SRVPGM example
P simple B exportD simple PI 9P 3D my_char 10AD my_int 10i 0 /free
my_char = 'back to you'; my_int = 100; return 123456.789;
/end-freeP E
Note the return parameter. Non-integer return parameters are something the JavaToolbox has struggled with for over a decade.
Invoking *SRVPGM
require 'xmlservice'
ActiveXMLService::Base.establish_connection( connection: "http://192.168.168.76:2222/cgi-bin/xmlcgi.pgm", username: 'A2222', password: 'mypassword')
srvpgm1 = XMLService::I_SRVPGM.new("SRVPGM1","SIMPLE", "MYLIB") << XMLService::I_a.new('my_char', 10, 'a') << XMLService::I_Int32.new('my_int', 200) srvpgm1.setReturn("passback", XMLService::I_p.new('my_out',9,3, 0.0) )
srvpgm1.call
puts " my_out: #{srvpgm1.passback.my_out}"puts "my_char: #{srvpgm1.PARM0.my_char}"puts " my_int: #{srvpgm1.PARM1.my_int}"
# my_out: 123456.789# my_char: back to yo# my_int: 100
Note addition of I_SRVPGM and .setReturn
*
Invoke *CMD from PASE shell
require 'xmlservice'
ActiveXMLService::Base.establish_connection( connection: "http://192.168.168.76:2222/cgi-bin/xmlcgi.pgm", username: 'A2222', password: 'mypassword')
cmd = "system -i 'DSPSYSVAL SYSVAL(QMODEL) OUTPUT(*PRINT)'"dspsysval = XMLService::I_SH.new(cmd)dspsysval.callputs dspsysval.out_xml
Output:<myscript><sh error='fast'><![CDATA[ System Values Page 15770SS1 V7R1M0 100423 RORSERV2 02/11/14 02:39:30 UTC Current Shipped Name value value Description QMODEL 70Y ' ' System model number Note: > means current value is different from the shipped value * * * * * E N D O F L I S T I N G * * * *
Subsequent parsing (i.e regular expression) could obtain the QMODEL number.
Wrap it in Ruby
require 'xmlservice'
module RPG def self.srvpgm1(my_char, my_int) ActiveXMLService::Base.establish_connection( connection: "http://192.168.168.76:2222/cgi-bin/xmlcgi.pgm", username: 'A2222', password: 'mypassword' )
srvpgm1 = XMLService::I_SRVPGM.new("SRVPGM1","SIMPLE", "AARONLIB") << XMLService::I_a.new('my_char', 10, my_char) << XMLService::I_Int32.new('my_int', my_int) srvpgm1.setReturn("passback", XMLService::I_p.new('my_out',9,3, 0.0) )
srvpgm1.call return srvpgm1.passback.my_out endend
puts RPG.srvpgm1('something', 222)
# 123456.789
Encapsulate the call to the RPG program so it is easy to use for other Ruby developers on your staff
Future, "2.0"
class MyPgm1 < ActiveXmlService::Base self.program_name = self.class.name.capitalize self.library = 'MYLIB'
input_parms do char :inchara, 1 dec :indec1, 7.4 ds :inds1,1 do char :dschara, 1 dec :indec1, 7.4 end endend
# How to invokeMyPgm1.call('aa', 222, ['bb', 222])
What we are working towards for syntax…- Have separate class for simple encapsulation and reuse- Have generator to create class (i.e. xmlservice generate <pgm> <lib> <parm1:type> <parm2:type> )
Stateful and Private● Used when IBM i resource will be called many times by the same user profile● Lasting persistent data needed by the IBM i resource (RPG vars, open files, etc.)
Call XMLSERVICE from anywhere
Web apps with Rails - rubyonrails.org
iOS with RubyMotion - rubymotion.com
Android with Ruboto - ruboto.org
Desktop (Mac, Linux, Windows) with Shoes - shoesrb.com
ShoesRB.com
Home site: youngiprofessionals.com/wiki/index.php/XMLService youngiprofessionals.com/wiki/index.php/XMLSERVICE/XMLSERVICERuby
Article by Don Denoncourt which includes XMLSERVICE example: iprodeveloper.com/application-development/discover-power-rails-ibm-i
Article by Jon Paris and Susan Gantner: ibmsystemsmag.com/ibmi/developer/rpg/xmlservice_new_life/ ibmsystemsmag.blogs.com/idevelop/xmlservice/
Blog by Tim Rowe (IBM): iprodeveloper.com/blog/getting-your-data-xml-service
Article by Brian May: iprodeveloper.com/development/unleash-your-ibm-i-xmlservice
On the web
We Have Reached The End!
Now...Get Engaged!1. Visit litmis.com regularly for new content2. Follow @litmisteam on Twitter3. Contact me directly for assistance jump-
starting any open source development projects on IBM i at [email protected]