Icebreak Programmers Guide

User Manual:

Open the PDF directly: View PDF PDF.
Page Count: 240

DownloadIcebreak-programmers-guide
Open PDF In BrowserView PDF
IceBreak
Programmers Guide
Copyright © 2013 System & Method A/S

Programmers Guide
Creating server applications
by Niels Liisberg

.

This book applies to IceBreak version: V4R04BLD0395 and above.

IceBreak
System & Method A/S
All rights reserved. No parts of this work may be reproduced in any form or by any means - graphic, electronic, or
mechanical, including photocopying, recording, taping, or information storage and retrieval systems - without the
written permission of the publisher.
Products that are referred to in this document may be either trademarks and/or registered trademarks of the
respective owners. The publisher and the author make no claim to these trademarks.
While every precaution has been taken in the preparation of this document, the publisher and the author assume no
responsibility for errors or omissions, or for damages resulting from the use of information contained in this document
or from the use of programs and source code that may accompany it. In no event shall the publisher and the author be
liable for any loss of profit or any other commercial damage caused or alleged to have been caused directly or
indirectly by this document.
Printed: januar 2013 in Copenhagen

Special thanks to all the dedicated IceBreak contributors:
Publisher
Comprendo.dk
Managing Editor
Kaj Vang Jensen
Technical Editors
Niels Liisberg
Bent Ronne
Cover Designer
Kenneth Riber Andersen
Team Coordinator
Martin Hect Olsen
Production
Comprendo.dk

Tom Grønkjær Nielsen
Jens Berg Churchill
Anders Thostrup-Clemmensen
Bjarke Aronso
John Foldager
Syd Nicholson
Dan Foldager
Peder Zacho
Jim Cooper
Tracy Eastwood
Edward Wright
Milan Zdimal
Frank Doherty
Per Rahr
Oran Paul
Lars Erik Brodersen
Jens Erik Mejlsbye
John Quarentello
Jørgen Wisbech
Erik Rex
Bent Ronne
Jeppe Klinge Bundgaard
Claus Rytter Larsen
Henning Orensoe

4

IceBreak

Table of Contents
Foreword

2

Part I Getting started

1 First Step ................................................................................................................................... 2
2 Prerequisites
...................................................................................................................................
for installation
11
3 Introducing
...................................................................................................................................
IceBreak
11

16

Part II Basic Features

1 Response
...................................................................................................................................
object
16
Placing runtime
.........................................................................................................................................................
data in a HTML document
Placing runtime
.........................................................................................................................................................
data using "Markers"
Dynamically
.........................................................................................................................................................
including stream files
Sending the
.........................................................................................................................................................
response back to the client
Trimming.........................................................................................................................................................
the response object

16
17
18
21
23

2 Request ...................................................................................................................................
object
24
The "Form"
.........................................................................................................................................................
function
Using the..................................................................................................................................................
"FormNum()" function
Using the.........................................................................................................................................................
"QryStr" function to parse parameters along the URL
The "QryStrNum"
..................................................................................................................................................
Function

24
25
26
28

3 Server object
................................................................................................................................... 28
Controlling
.........................................................................................................................................................
the HTTP Header
Retrieving.........................................................................................................................................................
Server Information
System Global
.........................................................................................................................................................
Variables

28
30
32

4 Session object
................................................................................................................................... 34
Session management
.........................................................................................................................................................
Log on to.........................................................................................................................................................
an icebreak session

34
35

5 Server behaviour
................................................................................................................................... 39
Setting up.........................................................................................................................................................
HTTPS
Use the pre-request
.........................................................................................................................................................
exit program

39
40

44

Part III Building applications

1 Debugging
...................................................................................................................................
IceBreak applications
44
2 Using compiler
...................................................................................................................................
directives
51
3 How to include
...................................................................................................................................
external resources
52
4 A simple ...................................................................................................................................
database application
55
5 Database...................................................................................................................................
maintenance application
57
6 Split your...................................................................................................................................
program logic and design into separated files
61
7 Writing and
...................................................................................................................................
reading stream files
62
8 AJAX Async
...................................................................................................................................
JavaSript and XML
64
9 Creating ...................................................................................................................................
XML files Dynamically
66
10 Inter process
...................................................................................................................................
communication
72
11 Uploading
...................................................................................................................................
files to a IceBreak server
74

System & Method A/S

Contents

5

12 Controlling
...................................................................................................................................
the state of a "CheckBox"
77
13 Mixing Jave-Script
...................................................................................................................................
and RPG
78
14 VB-Scripting.
...................................................................................................................................
Merge i5/OS data into a MS-Word document
81
15 Using keyCodes
...................................................................................................................................
(SPAM Prevention)
84
16 Using COBOL
...................................................................................................................................
as ASPX programming language
85
17 Using Legacy
...................................................................................................................................
RPG fixed form code
88

90

Part IV Internal Large Objects - ILOB's

1 ILOB's - Internal
...................................................................................................................................
Large Objects
90
2 ILOB's and
...................................................................................................................................
SQL
93
3 ILOB's with
...................................................................................................................................
IBM supplied API's
96
4 ILOB's, httpRequest
...................................................................................................................................
and XML
97
5 ILOB's secures
...................................................................................................................................
your streamfile upload to your IceBreak server
101
6 ILOB's in
...................................................................................................................................
WebServices
103

Part V SQL

106

1 Using embedded
...................................................................................................................................
SQL
106
2 SQL - Producing
...................................................................................................................................
a list using a cursor
107
3 SQL to the
...................................................................................................................................
ResponseObject
110

Part VI XML, Webservices and proxies

121

1 WebServices
...................................................................................................................................
- the easy way
121
Using arrays
.........................................................................................................................................................
in webservices
Using external
.........................................................................................................................................................
described datastructures in webservices

126
127

2 Using Proxy.
...................................................................................................................................
Making HTTP request to web servers
133
3 Using the
...................................................................................................................................
built-in XML Parser on the request object
136
4 Using the
...................................................................................................................................
built-in XML Parser on a string or stream file
140
5 ILOB's, ...................................................................................................................................
httpRequest and XML (SOA components)
142

Part VII OEM, Bundle IceBreak

148

1 Ship IceBreak
...................................................................................................................................
allong with your product (COPY)
148

Part VIII Using JAVA

153

1 Java as ...................................................................................................................................
the host language
153
2 Accesing
...................................................................................................................................
remote data bases with JDBC
159

Part IX Utilities

165

1 Introduction
................................................................................................................................... 165
Bind to IceUtility
.........................................................................................................................................................
Prototyping
.........................................................................................................................................................

165
165

2 Functions
................................................................................................................................... 165
Administrator();
.........................................................................................................................................................
Disabled(disable);
.........................................................................................................................................................

System & Method A/S

165
166

6

IceBreak
DropDown(TagName:
.........................................................................................................................................................
SqlCmd {:SelectedValue} {: HtmlExtend});
exists(varying);
.........................................................................................................................................................
FieldListOpen(Library:
.........................................................................................................................................................
File);
FieldListRead();
.........................................................................................................................................................
LowerCase(varying);
.........................................................................................................................................................
MemberListOpen(Library:
.........................................................................................................................................................
File: Member {:Format} {:OverrideProcessing});
MemberListRead();
.........................................................................................................................................................
ObjectExists(Library:
.........................................................................................................................................................
Object: ObjectType);
ObjectListOpen(Library:
.........................................................................................................................................................
Object: Type {: Format});
ObjectListRead();
.........................................................................................................................................................
ReverseDNSlookup(IP
.........................................................................................................................................................
address);
UpperCase(varying);
.........................................................................................................................................................
UserExists(UserProfile);
.........................................................................................................................................................

166
167
167
167
167
168
168
169
169
169
170
170
170

3 Samples................................................................................................................................... 170
DropDown
.........................................................................................................................................................
sample
HTML code
..................................................................................................................................................
RPGLE ..................................................................................................................................................
code

Part X Administration menu

170
171
172

176

1 Work with
...................................................................................................................................
servers
176
2 SQL prompt
................................................................................................................................... 181
3 Application
...................................................................................................................................
wizard
182
4 Component
...................................................................................................................................
wizard
182
5 Sencha ...................................................................................................................................
Touch Component Wizard
182
6 Source file
...................................................................................................................................
browser
184
7 Services................................................................................................................................... 184
Web TAPI
.........................................................................................................................................................
Web printers
.........................................................................................................................................................

184
184

8 Frameworks
................................................................................................................................... 184
9 Display ...................................................................................................................................
current server
189
10 Display ...................................................................................................................................
current header info
189
11 Display ...................................................................................................................................
all servers
189
12 Display ...................................................................................................................................
joblog
189
13 Display ...................................................................................................................................
job
189
14 Display ...................................................................................................................................
trace
190
15 Authorization
................................................................................................................................... 190
16 Subsystem
...................................................................................................................................
configuration
190
17 Your information
................................................................................................................................... 190
18 License...................................................................................................................................
information
190
19 Build history
...................................................................................................................................
log
190
20 Open projects
...................................................................................................................................
log
191

Part XI Appendix

193

1 Intergration
...................................................................................................................................
to BlueSeries
193
2 Internal ...................................................................................................................................
relation between CCSID and encoding schemes
194

System & Method A/S

Contents

7

3 Manual ...................................................................................................................................
Installation
197
4 Technical
...................................................................................................................................
decumentations
199
What is IceBreak
.........................................................................................................................................................
Application
.........................................................................................................................................................
Server Programs as a concept
The Object
.........................................................................................................................................................
model
The Request
..................................................................................................................................................
Object:
The Form
..................................................................................................................................................
Parser:
The Session
..................................................................................................................................................
Object
The XML
..................................................................................................................................................
parser:
The Server
..................................................................................................................................................
Object:
The Application
..................................................................................................................................................
Object:
The Response
..................................................................................................................................................
Object:
Other function
..................................................................................................................................................
Internal ..................................................................................................................................................
Large Objects - ILOB's
Creating.........................................................................................................................................................
Application Server Programs (ASPX):
Compile..................................................................................................................................................
and run
ASPX program
..................................................................................................................................................
files - Normal web application programs
ASMX program
..................................................................................................................................................
files - WebServices
Program..................................................................................................................................................
activation group
Dispatcher
.........................................................................................................................................................
methods
Session..................................................................................................................................................
persistent process
Application
..................................................................................................................................................
pooling
Multi Process
..................................................................................................................................................
Single Session
..................................................................................................................................................
Programming
.........................................................................................................................................................
ASPX File
..................................................................................................................................................
Identification
ASPX File
..................................................................................................................................................
parsing
How to place
..................................................................................................................................................
dynamic data at runtime
Remarks
..................................................................................................................................................
IceBreak..................................................................................................................................................
language enhancements
I18N - internationalization
..................................................................................................................................................
AJAX ..................................................................................................................................................
IceBreak.........................................................................................................................................................
Macros
Using the
..................................................................................................................................................
simple macros
Using script
..................................................................................................................................................
macros
Macro list
..................................................................................................................................................
Security.........................................................................................................................................................
Considerations in IceBreak
Direct Access
..................................................................................................................................................
Apache ..................................................................................................................................................
Server
Secure Web
..................................................................................................................................................
Server
Secure Sockets
..................................................................................................................................................
Layer (SSL)

Part XII Acknowledgements
Index

System & Method A/S

199
200
201
202
202
202
203
203
203
204
204
205
205
206
206
206
207
208
208
209
210
211
212
212
212
213
213
214
214
215
216
217
217
218
220
220
221
222
222

228
229

IceBreak

if (Problem());
exsr FixIt;
else;
NOP();
endif;

System & Method A/S

Part

I

2

IceBreak

1

Getting started

1.1

First Step
Getting Started:
When the IceBreak server is installed an running you can
used the administration menu. Here you need to create
your own applications server instance where you can run
your own applications. Also - you can visit the
ApplicationStore on the web from where you can
download application, frameworks, plugins and tools...
Now let's get started:

Create my own server instance.
The server instance is a combined webserver and
applications server for ILE programs. You can serve plain
html, text and image files directly from the IFS AND you
can run ILE RPG, COBOL programs from IBMi libraries
and JAVA classes. You need to define a root path on the
IFS where streamfiles are placed. You also need to
define a library name where you application is placed.
Logon to the
·
·
·
·

Logon to the "Administration menu"
Click "Administration"
Click "Work with Servers"
Click the green + or press F6 for "Create a new
server":

Now fill in the form - let's call our first server ICETEST
· Enter "icetest" in the server id and give it a good

System & Method A/S

Getting started
description.
· The application library is automatically set to ICETEST
· The "HTTP IFS path" (or the root path) is
automatically set to "/www/ICETEST"
· Now set the port number to 7777. ( You can ensure it
is available if it not used in the NETSTAT *CNN list)
· Ensure it is in "development mode" which will cause
the compilers to be available.
· Finally press the "Create" button.

Now you have created you server. Now lets start it:

·
·
·
·

Right click on the row "ICETEST" in the grid.
On the drop down menu select "Start"
Press the "Refresh button"
The server will now switch from red to green.

Congratulation !! Now you have an running server you
can work with.
If you open a green-screen you can see it has created:
1. Directory /www/ICETEST
2. Library ICETEST
3. Job description ICETEST in ICETEST
4. Source file QASPSRC in ICETEST - This is where the
IceBreak pre-compiler will place the program source
5. Source file QSOAPHDR in ICETEST - this is where the
IceBreak pre-compiler will place prototypes for SOAP
WebServices
6. IceBreak also creates a datashare named ICETEST so
you can access the Root path directly. We will need
that in a moment.

System & Method A/S

3

4

IceBreak

My First application
Any good programming tool can make a "hello world" in
a couple of lines. Now lets do exactly that in IceBreak:
First you need to have access to the application Root
path. If you open your file explorer you should be able
to work with it just bu typing the name of your IBMi and
the share name. In my case my IBMi is called DKEXP05
so I enter the address:
\\dkexp05\ICETEST
Which looks like:

You will see that IceBreak has created two file folders "Intermediate" which is a working sandbox and
"System" where you will find a lot of common
components like images, styles, scripts complete
frameworks. Do not delete any of these folders or their
contents.
Now lets create a new program file:

· Right click and select "New"
· Select "New Text document"
· Now right click and rename "New Text Document.txt"
to hello.aspx

System & Method A/S

Getting started
· Open "hello.aspx" with an editor of you choice. I'll use
"notepad" in this case.
· Now enter the source code:

<%/free%>

Hello world!! time in IceBreak land is : <%= %
char(%timestamp) %>

<% *inlr = *on; %>

Let's look at the code before you save and run it.
The first thing you will notice is the code is surrounded
by <% and %> Every thing that is not enclosed in this
escape sequence will be sent to the browser ( the
client). Next - character strings can be set to the
browser if you include the "=" equal sign. So in this case
we are converting a timestamp to a character string and
sending a dynamic value to the browser. There are
several ways to do tat trick in IceBreak, but for now we
will just use this monolithic design :)
Yeps - it time to save the source. Ensure your folder now
contains hello.aspx ( If you have hidden suffixes ensure
it is not "hello.aspx.txt" it will not work)

It is time to fire up the baby - and see if it works.

· Open your browser
· In the URL - enter http:// the name of your IBMi : the
port / hello.aspx
Since my IBMi is called DKEXP05 the URL looks like:
http://dkexp05:7777/hello.aspx
Notice the name of the server is not shown here - it is
only referred to by the port number.
If you have copied and pasted correctly your browser
will show something like this:

System & Method A/S

5

6

IceBreak

Congratulation !! Now you have an running application in
your server.
What happens under the hood is what is called a JIT Just In Time compilation. If IceBreak can see the hello.
aspx source but the HELLO program object in ICETEST is
missing or outdated, the JIT compiler kicks in and (re)
compiles the source and creates the program object.
Even though this sample only contains a few lines of
code it illustrates how easy you can bring your IBMi ILE
code to the web. How advanced is up to you.

Using the component wizard
It is nice to be creative and write applications fast.
However some times a little help from the toolbox is
required to speed up the process. In IceBreak we have a
couple of tools to assist you in this process.
The component wizard is by far the most easy generator
to use. It comes in two flavours: vanilla and strawberry or rather web 1.0 and web 2.0.
Web 1.0 is clean html and has the flavour of the web.
web 2.0 is more javascript and dynamic html and has
the flavour of an windows/mac/linux desktop application
which requires some kine of frame work to look nice and
behave correctly. IceBreak ships with the ExtJS
framework which also makes up the administration
application.
But first things first - lets have a look at the web 1.0
component wizard and create a simple html based
report.

·
·
·
·
·

Open the administration console
Open "Tools"
Open "Component wizard"
In the "library" field enter *LIBL
In the "file" file enter product

System & Method A/S

Getting started
· In the "view" select As Simple List Program
· Now click "display the file" button

Your browser now shows this:

The complete text area will contain the final program:

System & Method A/S

7

8

IceBreak

<%
H*' -------------------------------------------------------------------------------H*' List of product
H*' -------------------------------------------------------------------------------F*Filename+IPEASF.....L.....A.Device+.Keywords+++++++++++++++++++++++++++++Comments
Fproduct
IF A E
K disk
D*Name++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++++Comments
D i
s
4B 0
C/free
*inlr = *ON;
//' first the html header and the table to put the data into
//' -------------------------------------------------------%>





Product master

<% //' Now reload the list, e.g. Set lower limit with *loval is the first record //' then repeat reading until end-of-file or counter exhausted //' ------------------------------------------------------------------------setll *loval PRODUCTR; read PRODUCTR; i = 0; dow (not %eof(product) and i < 200) ; i = i + 1; %> <% read PRODUCTR; EndDo; = %char(PRODKEY) %> = %char(PRICE) %> = %char(STOCKCNT) %> = %char(STOCKDATE) %> %>
Product Key Product ID Description Manufacturer ID Price Stock Count Stock Date
<% <% = PRODID %> <% = DESC %> <% = MANUID %> <% <% <%
Now this looks more like a program - with SETLL and READ and ENDDO - I like that. Lets create a new file in our server called list1.aspx Just follow that same procedure as with the hello.aspx. System & Method A/S Getting started · Right click and select "New" · Select "New Text document" · Now right click and rename "New Text Document.txt" to list1.aspx · Open "list1.aspx" with an editor of you choice. I'll use "notepad" in this case. · Go back to the Component wizard. · Click in the code-area and press Ctrl-A and Ctrl-C which is select all and copy to clipboard. · Go back to notepad · Now press Ctrl-V for paste · ... your code has arrived Your notepad will look like this: When you save it and run it it produces a rather basic report: System & Method A/S 9 10 IceBreak Explore the Application Store Some tools a not installed in the same go as when you install the IceBreak core. A nice (free) tool is Snow flake which installs as a companion tool on your windows desktop and contains program snippets you can cut and past into your own work. RPG specs rulers for fixed format - just copy from snowflake and paste. · · · · · Open the administration console Open "Resources on the internet" Click "Application store" Locate "Snowflake" Click "Download" This will bring you through the windows installation process and soon you will have Snowflake installed on your desktop tray When installing applications that requires to run on the System & Method A/S Getting started 11 IBM, you first click the download, which will place the installation files on your desktop - THEN Click Install application on server. These two step allows you to not have access to the internet while accessing the IBMi which sometimes are required for security reasons. 1.2 Prerequisites for installation Getting Started: Before installing please check that you have the following information ready: · First write down the TCP/IP address for your IBMi · You will need a user profile and password with *SECADM class for installing IceBreak · Also your FTP-server must be started on your IBMi Now let's install the IceBreak server system: · · · · · · · · · Open your internet browser and find http://icebreak.org Select the "download" option Fill in your name, company name and e-mail address. Click the "Start download" Now you will have a IceBreakSetupxxxx.exe (xxxx indecate the build) which will start the installation on your IBMi / iSeries/ i5 / AS/400. Enter the TCP/IP address for your IBMi Enter the user profile and password with *SECADM class. Now you can see the blue progress bar working while IceBreak is being unpacked and installed Finally you will be prompted using the "black/green" environment or the browser based environment .. Just click on the URL Congratulation!! - The IceBreak server is now up and running. Change the administration server to prompt for a user profile and password: · · · · · 1.3 Open the "Work with server" Select the ADMIN server and click "Edit server settings" In the "General" tab, Find "logon required" and change it to YES Click "Save settings" Select the ADMIN server and click "Restart" Introducing IceBreak Getting Started: IceBreak is a native HTTP-application server for IBMi, iSeries, i5 and AS/400. This server brings the power of the Internet right into the heart of ILE environment on the IBMi so you can create modern web applicatins with you RPG skils and bring legacy applications to the web. The IceBreak Server is an advanced, user-friendly server technology, enabling you to build web applications on the IBM i5/ IBMi/ AS/400 server platform. Yes - You can reuse your RPG coding skills and legacy code. IceBreak saves source files on the IFS. This gives you the freedom to use any text editor to produce System & Method A/S 12 IceBreak your applications. From low cost or free web designing tools like NotePad, pspPad, HTML-kit and NotePad ++ to professional tools like WDSc, Microsoft Visual Web Development, FrontPage or DreamWeaver you make the choice depending on your needs and experience. You can even create IceBreak programs using tools on a Mac like iWeb. You are able to create very efficient web applications running directly under the i5/OS OS/400 / IBM I operating system as native compiled program objects. Thanks to the IceBreak native server your applications are protected against subtle activity on the Internet. The key to a simple web-development approach is ".aspx", Compiled Active Server Pages. This technology has been used in .NET on Microsoft web servers for a quite some time. Now we are bringing ASPX to the IBMi "Application Server Program eXtension". The syntax is similar and the performance is faster with i5/OS OS/400 / IBM I program objects executing directly from the IceBreak server. The Object model The host languages in IceBreak are all the ILE languages: RPG, COBOL or CLP. However, these languages don't have an object model known in the Object Oriented programming world (OOP). IceBreak introduces an interface, so you are able to access the object model directly from RPG, COBOL and CLP. The object model is hidden from your application-layer, however IceBreak allows the user via an API interface to communicate directly with all objects instantiated by the IceBreak server in RPG, COBOL or CLP. Take a look at the communication flow between the IceBreak server and client web browsers: 1. The client places a request at the IceBreak server which creates a request object 2. The Request object is processed: Dependent on the content type either the form-parser for HTML or the XML-parser is executed for XML input. 3. ASPX Program initiates- You can retrieve data from the request object(2) and render the response object (5) 4. You can use imbedded SQL to make database I/O, call legacy code, use IBM API's or call IceBreak API's etc. 5. The Response object is prepared to the clients codepage and encoding scheme 6. IceBreak sends the response back to the client System & Method A/S Getting started 13 The Objects used in the IceBreak server When the client (the Browser) requests a HTML document from a web server, it will send a request to the server. The server then receives the response and render the result in the browser canvas. Let's follow each of these objects involved in the process from the request to the response: The Request Object: The Request object contains all data sent from the client. In the HTTP protocol that is the header and content. The header describes the content which can be either a "Form Object" or an "XML-Object". The Form Parser: The Form Parser initiates automatically when it is a HTML Form-object. The following functions are available in your ASPX-program: · Myvar=Form('FormVar'); · MyNumvar=FormNum('FormNumVar'); · MyVar=QryStr('URLParameter') · MyVarNum=QryStr('NumericURLParameter') · GetHeader(KeyWord) · GetHeaderList(Name:Value:'*FIRST' | '*NEXT') The XML parser: The XML parser is invoked automatically when the content in the request is a XML-document. That is System & Method A/S 14 IceBreak when the content-type is set to "text/xml". Example: · Myvar=XmlGetValue('/element1/element2/element[elementnumber]@anattribute' : 'Defaultvalue'); The Session Object: Fact: The Internet is "stateless" - your program must be designed to process input and produce output and then terminate. You cannot have open files or static memory between panels. A Break-through: The IceBreak server is maintaining a session with the client by creating a "session cookie". Even if the client browser is blocking "cookies" a session cookie is normally allowed. Sometimes you have to change the "allow session cookies" flag in the browser for the applications to work correctly. Sessions are maintained as long as you want, and you can configure the duration of a session using the WRKICESVR or WRKXSVR command. A session has a very small "footprint" and uses little system resources. Session object functions: · · · · MyVar = SessGetVar('MyVariable'); MyVarNum = SessGetVarNum('MyNumericVariable'); SessSetVar(''MyVariable'); SessSetVarNum(''MyNumericVariable'); The Server Object: The server object contains static server information like the configuration parameters, but also dynamic information from the client. Server object functions: · MyVar = GetServerVar('AserverVariable'); · PointerToMyVar = GetServerVarPtr('AserverVariable'); The Response Object: The Response object contains all data sent from the server to the client. In HTTP protocol that is the header and content. The header describes the content which can be of any type HTML, XML, GIF, TIF, PDF, etc. This is the place where you render your dynamic output data with the ASPX syntax. When your program quits IceBreak will the send the response to the client. Response object functions: · · · · · · · · · · · · ResponseWrite(Value) ResponseWriteNL(Value) ResponseNLWrite(Value) ResponseEncTrim(Value) SetContentType(MimeType) SetCharset(CharSet) AddHeader('Name' : 'Value') SetHeader('Name' : 'Value') Redirect('ToUrl') SetStatus(Code) SetCacheTimeout(Minutes) SetEncodingType(*HTML (default) | *XML | *NONE ) Follow the rest of the tutorial so you can master ASPX and IceBreak. Enjoy! System & Method A/S Part II 16 IceBreak 2 Basic Features 2.1 Response object 2.1.1 Placing runtime data in a HTML document Basic Functions: The Basic Syntax Rule An IceBreak-ASPX file normally contains HTML tags, just like an HTML file. However, an ASPX file can also contain server scripts/code, surrounded by the delimiters <% and %>. Server scripts/code are executed on the server, and can contain any expressions, statements, procedures, or operators valid for the scripting language you prefer to use. In the following tutorial we will use Free-RPG. ASPX uses an escape sequence between the HTML document and the code portion. To start the code escape insert <% To end the code insert %> To place variables from the code insert <%= pgmvar %> A small sample "Hello world" written in Free-RPG might look like: <%/free%> Hello world!! time in IceBreak land is : <%= %char(%time) %> <% *inlr = *on; %> Line1: · First we insert <% to switch into "script code-mode". · The RPG-compiler is then set to use "free format-mode". · Switch back to HTML using %> . Line 2,3,4: · In HTML-mode you are able to write any valid HTML text. · Place the value of a function call to retrieve the time value by inserting <%=. · All response is in text format: Convert the result of the %time -function with the %char-function. · Switch back to HTML with %> . Line 5: · Again insert <% to switch into "code-mode". · Insert *INLR to terminate the program by setting this switch to *ON. · Finally we switch back to HTML with %> . You cannot view the ASPX source code by selecting "View source" in a browser. You will only see the output from the ASPX file which is plain HTML. This is because the scripts are executed on the server before the result is sent back to the browser. System & Method A/S Basic Features 17 In our ASPX tutorial, every example displays the hidden ASPX source code. This will make it easier for you to understand how it works. 2.1.2 Placing runtime data using "Markers" Basic Functions: Using "Markers" "Markers" are used to place data in the response object just like using <% = variable %>. A marker value is inserted into the the response object just before data is sent back to the browser. Markers data will be encoded according the current value set by SetEncodingType('*html' (default) | '*xml' | '*none'); So it can contain any kind of data: HTML, Scripts etc. but has a limit of 32766 bytes in RPG There are two steps in using a marker: · Insert the the marker in the response object. The syntax is: <%$ Mymarker %> · Then assign the marker to a value. This is done by calling the build in function: SetMarker ('MyMarker' : 'this is the value for my marker'); A small sample "hello world" written in Free-RPG might look like: <%/free%> The marker value is: <%$ MyMarker %> ... <% SetMarker('MyMarker': 'hello world!!'); *inlr= *ON; %> Separating business logic and presentation layer Markers also make it possible to separate .aspx code and HTML or XML documents. Here are the two steps: 1. Place all your HTML or XML code in a separate document which can be designed and validated by any HTML or XML editor. 2. Make a .aspx program which refers to a specific tag in the HTML / XML document at runtime. Your connection with variables in the final response is through markers. The syntax is the same as for static include in the presentation layer: Next you referfollowing to that tag from the program by setting markers and finally render the result by: ResponseWriteTag('filename' : 'tagname'); Filename: The file name and path can be absolute or relative for the ResponseWriteTag(Filename : TagName) according to the following System & Method A/S 18 IceBreak · /path/filename.ext · ./Filename.ext · Filename.ext This absolute from the IFS root This is relative to the Server instance root path This is relative to the browser relative "refer location" Tagname: The tag name is the location in the file - until next tag or end of file (which comes first) The special values *FIRST can be used as tag name to refer to the first protion of the file prior to any tags. This is useful when dealing with XML-response files since they can be validated. An XML file can not start with a comment, which the tag looks like from a XML file editor’s perspective. Example: The HTML document (let's call it ex01marker1.htm) will contain the following:

Dynamic placing data using markers

<%$ MyCounter %> <%$ MyTime %>
The ASPX program is HTML free and only use the SetMarker(variable : value); and the ResponseWriteTag(Filename : TagName); build-in function. <% d i s 10i 0 /free ResponseWriteTag('./tutorials/ex01marker1.htm' : '*FIRST'); for i = 1 to 1000; SetMarker('MyCounter': %char(i)); SetMarker('MyTime' : %char(%timestamp)); ResponseWriteTag('./tutorials/ex01marker1.htm' : 'detail'); endfor; ResponseWriteTag('./tutorials/ex01marker1.htm' : 'end'); return; %> 2.1.3 Dynamically including stream files Basic Functions: The IceBreak ASPX-compiler has the powerful "include" function which dynamically enables you to System & Method A/S Basic Features 19 include any stream file object in the response. You can import Microsoft Word documents, PDF files, Excel spread sheets, HTML, XML etc. The Include-function loads files according to the http path entered in the IceBreak server configuration. The file path can be absolute or relative according to the folowing · /path/filename.ext This absolute from the IFS root · ./Filename.ext This is relative to the Server instance root path · Filename.ext This is relative to the browser relative "refer location" How to let the Browser open the XLS-sheet, not asking for downloading the file. Run an IceBreak ASPX-program creating the file contents. Then let the browser open the associated file type. For that purpose we use double suffix. IceBreak detects the first suffix, and the browser detects the following suffix. The file name might be: MyApp.aspx.XLS The contents type however has to be set so the browser can open the resulting file. Otherwise a dialog box will appear asking you to download the file. The following code include a simple sheet: <% D*'Name+++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ D errstr s 512 varying /free // We will place Excel in the response object // the "setContentType" must be executed before placing data in the response object SetContentType('application/x-msexcel'); SetCacheTimeOut(240); // Load the stream file into the response object errstr = Include('./tutorials/sheet1.xls'); if ( errstr > '') ; SetContentType('text/html'); SetCacheTimeOut(0); %><%= errstr %><% endif; return; %> Please note: The use of SetCacheTimeOut(240) is required. Otherwise the message "404 document not found" is issued because the browser first places the file into the cache - and then opens it with the associated application, in this case Microsoft Excel. The dialog box is avoided by setting the contents type: SetContentType('application/x-msexcel'); System & Method A/S 20 IceBreak How to let the Browser open the DOC with Microsoft Word, not asking for downloading the file Word documents can also be created in the same way. Now you have to change the contents type to Word document and the application suffix to DOC: 1) SetContentType('application/msword'); 2) MyApp.aspx.DOC The following code include a simple Word-document <% D*'Name+++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ D errstr s 512 varying /free // We will place a word-document in the response object // the "setContentType" must be executed before placing data in the response object SetContentType('application/msword'); SetCacheTimeOut(240); // Load the stream file into the response object errstr = Include('./tutorials/testword.doc'); if ( errstr > '') ; SetContentType('text/html'); SetCacheTimeOut(0); %><%= errstr %><% endif; return; %> Can I do that for any file type? Yes! As long you know the SetContentType and the FileSuffix. Maybe you need to search the Internet to find the right Content type, also called the MIME type but here is a popular list: Application to start Microsoft Word Microsoft Excel Adobe Acrobat Kodak imaging Microsoft Power Point Rich Text Application programs File Suffix DOC XLS PDF TIF PPT RTF EXE .. Others SetContentType / MIME type application/msword application/x-msexcel application/pdf image/tiff application/vnd.ms-powerpoint application/rtf application/octet-stream Hint: The "ShowSample.aspx" used in this tutorial includes an example displaying the source by wrapping the APS/HTML content in tags. IceBreak includes a DB/2 table called MIM00 which controls the default MIME-type for different file extensions. You can modify this table but first backup this file. You can replace the contents with your own version. This table indicates which extensions ASPX-programs are using. The default default MIME type for an filename or attribute can be retrieved by: MyMimetype = GetMimeType('FilenameOrAttribute.ext') System & Method A/S Basic Features 21 The following code is including a PDF file and find the content type using the GetMimeType function: <% D*'Name+++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ D errstr s 512 varying /free // We will place PDF file in the response object // the "setContentType" must be executed before placing data in the response object SetContentType(GetMimeType('./tutorials/sample.pdf')); SetCacheTimeOut(240); // Load the stream file into the response object errstr = Include('./tutorials/sample.pdf'); if ( errstr > '') ; SetContentType('text/html'); SetCacheTimeOut(0); %><%= errstr %><% endif; return; %> 2.1.4 Sending the response back to the client Basic Functions: The response is by default build up in a response buffer, which will be transferred back to the client (the browser) in one go - when your applications programs returns. In some cases you might find it convenient to send the buffer back in smaller pieces. Some situations might be: · Your application runs for a long time and produces output occasionally. · You program produces more that 16MB which is the maximum size of the response buffer · You are creating a "Web Push technology" applications. In the above situations you might to exploit the "chunked" transfer encoding. Chunked. IceBreak automatically used the chunked transfer encoding after you call the setChunked(); IceBreak procedure. The header will immediately be sent back to the client (the browser) so it is important that you setup all headers (if any) before calling setChunked();Likewise you must set the chunked before you send any data to the response object. The setChunked() procedure also takes minimum size of a chunk buffer you want to sent. Don't make it to small since it will have a performance impact - a good approximation might be around 4K. Each time this threshold is exceeded the output buffer will be flushed and sent back to the client. If you want to control when the buffer is actually sent back to the client, you can call the responseFlush (); which sending the buffer and afterwards clear it. It only works in Chunked mode. When used in "normal" mode the output buffer only gets cleared. Syntax: setChunked(BufferSize); BufferSize: System & Method A/S 22 IceBreak · The buffer threshold value in bytes for automatically flushing the response to the client ( browser) · CHUNK_AUTO_FLUSH used it your application uses markers. Syntax: responseFlush(); Sample: <% d i s 10i 0 /free setChunked(4096); %><% for i = 1 to 1000; %>Sending chunked data at :<% = %char(%TimeStamp()) %>
<% endfor; *inlr= *ON; %> Also use this feature if you having a processes bar or for long running task as status information purposes: <% d i s 10i 0 /include qasphdr,posix /free setChunked(1024); %><% for i = 1 to 10; %>Running step <%= %char(i) %> of 10
<% // An extra new-line is required before the browser displays the line responseFlush(); // Here the response is being sent back to the client sleep(1); // This is a C-library function you can access if you include the POSIX member from QASPHDR endfor; *inlr= *ON; %> Markers and Chunks When you are using markers you have to bare in mind that your static response and the dynamic marker values are rendered when you send the response back to the client. You have to synchronize that behaviour with the chunks being sent. System & Method A/S Basic Features 23 The easiest way is to set the chunk minimum size to CHUNK_AUTO_FLUSH. That causes the response to be rendered and flushed in one go when you use the responseWriteTag(); procedure. Otherwise you can use the combination parseMarker() / responseFlush(); Sample: <% d i s 10i 0 /free setChunked(CHUNK_AUTO_FLUSH); responseWriteTag('./tutorials/ex01mark1.htm' : '*FIRST'); for i = 1 to 1000; setMarker('MyCounter': %char(i)); setMarker('MyTime' : %char(%timestamp)); responseWriteTag('./tutorials/ex01mark1.htm' : 'detail'); endfor; responseWriteTag('./tutorials/ex01mark1.htm' : 'end'); return; %> The following sample is if you want to control the flow 100% by you self. This has actually a better performance since the buffer is only sent to client for each 100 resulting rows. <% d i s 10i 0 /free setChunked(1000000); responseWriteTag('./tutorials/ex01mark1.htm' : '*FIRST'); for i = 1 to 1000; setMarker('MyCounter': %char(i)); setMarker('MyTime' : %char(%timestamp)); responseWriteTag('./tutorials/ex01mark1.htm' : 'detail'); if (%rem(i : 100) = 0); responseFlush(); endif; endfor; responseWriteTag('./tutorials/ex01mark1.htm' : 'end'); return; %> 2.1.5 Trimming the response object Basic Functions: Depending on the nature of your application you can set up how the response is trimmed before returning to the client. The default trimming option is set on the server with CHGICESVR and the keyword DFTTRIM The DFTTRIM can have 4 values: System & Method A/S 24 IceBreak · · · · *NONE - The field value goes as it is to the client *LEFT - All leading blanks from left is removed before sending the result to the client *RIGHT - All trailing blanks from right is removed before sending the result to the client *BOTH - Both leading and trailing blanks are removed before sending the result to the client You can override this value at runtime by calling the build-in setTrim(); setTrim() can process 4 values: · setTrim(TRIM_NONE) The field value goes as it is to the client · setTrim(TRIM_LEFT) All leading blanks from left is removed before sending the result to the client · setTrim(TRIM_RIGHT) All trailing blanks from right is removed before sending the result to the client · setTrim(TRIM_BOTH) Both leading and trailing blanks are removed before sending the result to the client If you want to remove white space from the source stream you can use the compiler directive trimoutput='YES' 2.2 Request object 2.2.1 The "Form" function Request object: When you use input fields in an IceBreak-ASPX page - you make a "form" in HTML. Input field surrounded with the "form" can be "posted" back into the IceBreak Server: When you want to use the content of the posted form use the "Form" Icebreak-ASPX function to retrieve the posted value from the request object. The following example is IceBreak ASPX code in Free-RPG: <% d myName /free s 256 varying // Take the "myName" attribute from the form object an place it // into a program variable // ----------------------------------------------------------myName = form('myName'); %>
Enter your name, and press enter :
When I come back to this page my name is: <%= myName %> <% *inlr = *on; %> Note the relation between "
<% GetFormList (Field: value : '*FIRST'); dow (Field > '') ; %> <% GetFormList (Field: value : '*NEXT'); Enddo; *inlr = *on; %>
Field Value
<%= Field %> <%= Value %>
2.2.1.1 Using the "FormNum()" function Request object: Just like the "Form()" ASPX function you can use the "FormNum()" function to retrieve numeric values from a form. The "FormNum()" function returns the numeric value from a "form" field Into a RPG variable or use the value in an expression. The value returned is always a "packed decimal(30,15)" To allow a wide range of numeric data sizes. The conversion in respect to number of digits and decimal position is done by the RPG-runtime. All formatting chars like -,;$ etc. are striped out. Therefore is this function is also useful to converting date field, since date formatting is striped out. The decimal sign , or . is used in respect to the underlying System & Method A/S 26 IceBreak IceBreak server job description. ex: eval Number = FormNum('MyFormField'); or: if (FormNum('MyFormField') <= 0) then; %> My Form Field has to be a valid number <% endif; <% d myNumber /free s 9 5 myNumber = FormNum('myNumber'); %>

The value of "myNumber" is : " <%= %char(myNumber) %>

Enter a number. Use decimal points and signs as you please:
<% *inlr = *on; %> 2.2.2 Using the "QryStr" function to parse parameters along the URL Request object: The "QryStr" Function. The "QryStr" takes the value from a parameter parsed along with the URL. There are (at least) two ways to build the URL in a HTML document: · Passing the variable name and value along the System & Method A/S Basic Features 27

Enter your name, and press enter :

When I come back to this page my name is: <%= QryStr('myname') %>

This link takes the value "ABC" along the URL back to the application
<% *inlr = *on; %> Listing all fields in the query string You can also list both values and field names parsed on the query string returned to the IceBreak application like: <% *' -------------------------------------------------------------------------- * *' Demo : Show all query string fields received from the browser-client *' -------------------------------------------------------------------------- * d Field s 256 varying d Value s 4096 varying c/free %>
<% GetQryStrList (Field: value : '*FIRST'); dow (Field > '') ; %> <% GetQryStrList (Field: value : '*NEXT'); Enddo; *inlr = *on; %>
Field Value
<%= Field %> <%= Value %>
System & Method A/S 28 2.2.2.1 IceBreak The "QryStrNum" Function Request object: The "QryStrNum" takes the numeric value from a parameter parsed along with the URL To retrieve input fields from an ASPX page you use the "form" tag in HTML. Input field surrounded with the "form" can be sent along the URL by the "GET" function back into the IceBreak Server: The following example is IceBreak ASPX code in Free-RPG <% D*'Name+++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ D MyNumber s 15 5 /free MyNumber = QryStrNum('MyNumber'); %>

Enter a number or a date and press enter :

When I come back to this page the number is: <%= %char(MyNumber) %>

This link takes the value "1234,56" along the URL back to the application
<% *inlr = *on; %> 2.3 Server object 2.3.1 Controlling the HTTP Header Server Behaviour: The HTTP header is the way you control the Browser behavior. Here are the functions available: Function name SetHeader Redirect SetCharset SetContentType SetContentType SetStatus Description Sample Set a header attribute in the SetHeader('Location':'http://www. response agentdata.com'); Force the browser to reload a Redirect('http://www.agentdata. page from another URL com'); Set the character set used for the SetCharset('windows-1252'); resulting document Set the MIME type on the resulting SetContentType('text/html'); document Set the MIME type and character SetContentType('text/html; set used for the resulting charset=windows-1252'); document Changes the HTTP status code for SetStatus('401 Access denied'); System & Method A/S Basic Features 29 the response. See the complete list here GetHeader Returns the value of a given header keyword in this case the full URL val= GetHeader('Referer'); GetHeaderList Returns all headers one by one GetHeaderList(Keyword , Value, '*FIRST' | '*NEXT'); Here is a sample <% *' -------------------------------------------------------------------------- * *' Demo : How to make a redirect *' -------------------------------------------------------------------------- * /free //' One way to make a "redirect" Redirect('http://www.google.com'); //' The same thing made "by hand" // SetStatus('302 Redirect'); // SetHeader('Location' : 'http://www.google.com'); %> Never say Hello world - i'll be redirected to google before that ....<% *inlr = *on; %> Run the sample Show the sample This sample shows all headers received from the browser-client <% *' -------------------------------------------------------------------------- * *' Demo : Show all headers received from the browser-client *' -------------------------------------------------------------------------- * D Keyword S 256 varying D Value S 4096 varying /free %>

Get a header value direct: Host = <%= GetHeader('host') %>

<% GetHeaderList (Keyword: value : '*FIRST'); System & Method A/S 30 IceBreak <% dow (Keyword > '') ; %> GetHeaderList (Keyword: value : '*NEXT'); Enddo; *inlr = *on; %>
Keyword Value
<%= Keyword %> <%= Value %>
Run the sample 2.3.2 Show the sample Retrieving Server Information Server Behaviour: The server has many configuration parameters and runtime information which are available to you ASPXprogram. Call the the GetServerVar() function to place values in your program variable. Example: MyServerId = GetServerVar('SERVER_ID'); The complete list with actual run-time values: Server variable Description SERVER_SOFTWA The name and version of the running server RE SERVER_ID Name of current server instance SERVER_TOKEN The enumerated number of the server instance SERVER_DESCRIP Description of the server instance TION SERVER_LOCAL_P The TCP/IP portnumer (from 1 to 65535) where the server is polling for requests ORT SERVER_INTERFA The TCP/IP interface where the server is polling for requests. (Interface created by CE i5/OS command ADDTCPIFC) SERVER_JOB_NAM The underlaying i5/OS job name E SERVER_JOB_USE The underlaying i5/OS job user name (not the active user) R SERVER_JOB_NUM The underlaying i5/OS job internal job number BER SERVER_JOB_MOD The state of the server: "*PROD" or "*DEVELOP" E SERVER_LOGON_ An authenticaton prompt is automatically displayed when the user request the page REQUIRED and are "unknown" (Not available yet) SERVER_STARTUP Whether the server should start when the subsystem is activated or must be started _TYPE by STRICESVR or STRXSVR SERVER_DEFAULT The user profile used when starting a server instance process _USERPROFILE SERVER_ROOT_PA The IFS path used for web document. This can not be relative but is fixed to the IFS- System & Method A/S Basic Features 31 Server variable Description TH root The web document displayed when no specific document is requsted. This is relative SERVER_DFT_DOC to the SERVER_ROOT_PATH Number of seconds before a document expires. 0=immediately. SERVER_CACHE_T Servers in *DEVELOP mode always overrides this value to 0 so the cache always is IMEOUT refreshed SERVER_INPUT_B Number of bytes in the input buffer (the Request Object). UFFER_SIZE When zero a default of 1Mbytes is used SERVER_OUTPUT_ Number of bytes in the output buffer (the Response Object). BUFFER_SIZE When zero a default of 1Mbytes is used SERVER_COOKIE_ Number of bytes in the output buffer (the Response Object). BUFFER_SIZE When zero a default of 64Kbytes is used Name of program to set extra libray list etc. It is called when the server instance is SERVER_INITIAL_ initiate - Not each time a new client connects PGM_NAME or *NONE SERVER_INITIAL_ Name of library where the initial program exists PGM_LIB SERVER_JOBQ_NA The jobqueue from where the server process is started ME SERVER_JOBQ_LI Name of library where the jobqueue exists" B This is where all your APS-programs are placed when they are compiled. SERVER_APPLICAT This is where the QASPSRC file is created with your precompiled ASPX-program ION_LIB sources SERVER_TGTRLS The default target i5/OS release for programs created on this server instance SERVER_TRACE_F The name of the trace file created when TRACE=*ON When blank, the file name ILE defaults to Trace.txt in the SERVER_ROOT_PATH SERVER_SYSTEM_ The system name from the network attribute NAME SERVER_OS_VER The current version and relase of i5/OS SERVER_CCSID The current CCSID or *AUTO if the CCSID is dynamic seletected SESSION_TIMEOU Number of seconds before the session automatically is terminated T Default is 1440 seconds SESSION_ID The Unique Session Timestamp-id; also it is the time when the session was started The Unique Session number; Also it is the job number of the first lightwaight job that SESSION_NUMBER initiated the session SESSION_USERID The i5/OS userprofile logged on. When no logon was issued it returns *DEFAULT REMOTE_ADDR The remote TCP/IP address of the client web browser REMOTE_PORT The remote TCP/IP port number negotiated by the TCP/IP layer REQUEST_HOST_N The TCP/IP address or name for the requested server AME The method the document was requested: REQUEST_METHO GET parameters is parsed along the URL D POST Parameters are parsed in the form object The complete URL. E.g. the resource filename with path and extension and REQUEST_URL parameters REQUEST_FULL_P The resource filename with path and extension ATH REQUEST_REF_PA The refered path from the http header if given. Otherwise the reffence path where TH the resource were requested REQUEST_PATH The path portion only of the request REQUEST_FILE The filename and extension only REQUEST_RESOU The resource (filename only) portion only of the request in uppercase RCE REQUEST_FIRST_ The first extension for the resource of the request in uppercase. If only one extension EXTENSION exist this will be the same value REQUEST_EXTENS The extension for the resource of the request in uppercase ION REQUEST_HEADER The complete header string REQUEST_RAW The complete request, excluding the content System & Method A/S 32 IceBreak Server variable Description REQUEST_CONTEN The content string T Parameters sent along the GET or POST request after the document. The URL in the QUERY_STRING browser HIVE_NAME If running i a hive this is the virtual path name (the hive name). Otherwise blank HIVE_PATH If running i a hive this is the physical path to the IFS. Otherwise blank HIVE_LIB If running i a hive this is the application library for the current . Otherwise blank All i5/OS system values are also available by prefixing the system value with "SYSVAL_". like: DayOfWeek = GetServerVar('SYSVAL_QDAYOFWEEK'); The complete list of system values can be found in the i5/OS command WRKSYSVAL Here are samples values Server variable SYSVAL_QDAYOFWEEK SYSVAL_QTIME Run the sample 2.3.3 Sysval QDAYOFWEEK QTIME Description The day of week The current time Show the sample System Global Variables Basic Functions: System Global Variables are persistent between sessions and servers. I.e. if you create a system global variable in one session on one server it will be visible in all other servers and session. So be carful especially when you clear system global variables - it has an impact on the entire system. Functions: globalSetVar ( variableName : value ); myVar = globalGetVar( variableName : [defaulrValue] ); globalSetVarNum ( variableName : numeric value ); myNumVar = globalGetVarNum( variableName : [default Numeric Value] ); globalClrVar ( qualified name ); Variable Name: You can use any name for the global variable, however we suggest that you qualify you names according to X-path naming, since you will be able to import and export using XML in releases to come. Also for the reason that the name you use is system wide. At least provide some kind of name space - for instance the current server name. System & Method A/S Basic Features 33 Value: Any string expression - up to 32K bytes Default value: Any string expression - up to 32K bytes. Applied when the variable does not exists in the System Global domain. When the variables exists, the default value is ignored. Numeric value: Numeric expression that can be stored in a 31.15 decimal variable Qualified name: Any string expression. You can apply the * to give a generic value to clear - up to 32K bytes. Applied when the variable does not exists in the System Global domain. When the variables exists, the default value is ignored. Example: <% d*Name++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++++Comments++++++++++++ d myName s 256 varying d counter s 10i 0 d si s 12 varying /free // String sample using x-path globalSetVar('/myprops/cust@name' : 'John'); myname = globalGetVar('/myprops/cust@name' : 'N/A'); %>My Name: <% = myName %>
<% // Default to N/A if not set // Number sample - using x-path: counter = globalGetVarNum ('/myprops/cust@counter' : -1) +1; globalSetVarNum ('/myprops/cust@counter' : counter); %>Counter is now: <% = %char(counter) %>
<% // Default to -1 if not set // Cleanup sample: Delete all variables under "cust1" ( still x-path globalClrVar ('/myprops/cust1*'); // Simple name - yet qualified: si = '/' + getServerVar('SERVER_ID') + '/'; globalSetVar(si +'now' : %char(%timestamp())); %>time is:<%= globalGetVar(si + 'now') %><% globalClrVar (si + 'now'); *inlr= *ON; %> Note: The data is stored in the DB/2 table SGV00 - and you can manipulate it directly by i.e. SQL, but be aware that this might change from release to release. Also, if you need to mirror IceBreak between and use System global variables - you need to mirror this System & Method A/S 34 IceBreak DB/2 table SGV00. 2.4 Session object 2.4.1 Session management Basic Functions: The internet has no session mechanism - the internet is stateless. However, state information is required to track data from one page to another in a modern web application. IceBreak support two different ways to keep track of sessions namely by session cookies and by URL Rewriting. Both methods have some pros and cons. What you choose to use depends on your application. Session cookie By default all session in iceBreak is maintained by a session cookie. The session ID is automatically placed in the http header and sendt back and forth between the browser and the IceBreak server. However, browsers may disable the use of cookies - even harmless session cookies. Also, some browsers have difficulties with serving the right session cookie to the right application in a multi-frame environment. I.e. when the outer frame is served by one server - let's say an IIS and the inner frame is served by IceBreak. In both cases you need to use the URL rewriting method. URL Rewriting (session stability by URL redirection) URL Rewriting is one of the popular session tracking methods used for Non-cookie browsers to save session information. URL Rewriting tracks the user's session by including the session ID in the URL (to carry information from one HTML page to another). The information is stored inside the URL, as an additional parameter where all the links on a page are re-written so that the server side program receives the old as well as new data. Thus a session (or a connection is maintained between multiple pages) for every user. Since the session ID is exposed to the user it might be changed. In that case IceBreak just creates a new session. Some pitfalls/considerations: · Beware that you only use relative redirection. · Ensure that Ajax calls refer to the same session URL. · Sessions might be bookmarked and even transferred to other clients Accessing the session object You can put data into the session object and retrieve data back by some simple IceBreak functions: · MyVar = SesGetVar('MyVariable'); · MyVarNum = SesGetVarNum('MyNumericVariable'); · SesSetVar('MyVariable' : MyValue); · SesSetVarNum('MyNumericVariable': 1234567.89); Also ILOB's are in maintained by the session object. More on that later in the ILOB chapter. System & Method A/S Basic Features 2.4.2 35 Log on to an icebreak session Basic Functions: In IceBreak you can use either the native i5/OS user profile login or you can use an LDAP server or Windows server running active directory to authticate a IceBreak session. Log on using an I5/OS user profile In many cases you will build applications that requires running authenticated under another user profile than the default profile that was used when the server instance was started. For that purpose the IceBreak-ASPX has the following build-in functions: LogOn Syntax: Message = LogOn ( Userprofile : Password ); Field Name Data type UserProfile CHAR(10) Password CHAR(128) Description The i5/OS User profile The associated password for the above user profile Returns Message If blank the logon attempt was successful; otherwise it contains a descriptive message VARCHAR(512) When the "LogOn" executes successfully the underlying job for the IceBreak will change the session profile and all successive jobs associated with that session will use same profile handle. Ex: <% d msg s /free msg = LogOn(Userid:Password); if (msg <= ''); Initpage(); return; else; exsr ShowLogon; endif; ... %> Run the sample System & Method A/S Show the sample 512 varying 36 IceBreak Log on using an LDAP server or Windows server running Active Directory This is a simple way to authenticate the user profile and password against LDAP or Windows server. However, since there is no connection between the user profile on i5/OS and LDAP/Windows this will only be an authentication vailidation, but no credentials are given. For that purpose the IceBreak-ASPX has the following building functions: LDAP_Logon Syntax: flag = LDAP_Logon ( Server : Userprofile : Password ); Field Name Server URL Data type VARCHAR(128) UserProfile VARCHAR(128) Password CHAR(128) flag BOOL (indicator) Description Server name or TCP/IP adrress. Explicit host list. The User profile on LDAP / Windows Active Directory The associated password for the above user profile Returns When *ON an error occured and you can examin that error by calling GetLastError(); Explicit Host List Specifies the name of the host on which the LDAP server is running. The host parameter may contain a blank-separated list of hosts to try to connect to, and each host may optionally be of the form host:port . The following are typical examples: error = error = error = LDAP_Logon('server1' : MyUser : MyPwd); LDAP_Logon('server2:1200':MyUser : MyPwd); LDAP_Logon('server1:800server2:2000 server3' :MyUser : MyPwd); You can also use a default host. i.e when the host parameter is set to ("ldap://") the LDAP library will attempt to locate one or more default LDAP servers, with non-SSL ports, using the SecureWay error = LDAP_Logon ('ldap://' : MyUser : MyPwd); If more than one default server is located, the list is processed in sequence, until an active server is found. The "Server URL" can include a Distinguished Name (DN), used as a filter for selecting candidate LDAP servers based on the server's suffix (or suffixes). If the most significant portion of the DN is an exact match with a server's suffix (after normalizing for case), the server is added to the list of candidate servers. For example, the following will only return default LDAP servers that have a suffix that supports the specified DN: error = LDAP_Logon ('ldap:///cn=niels, dc=cph, dc=agentdata, dc=com' :MyUser: MyPwd); In this case, a server that has a suffix of "dc=austin, dc=ibm, dc=com" would match. If more than one default server is located, the list is processed in sequence, until an active server is found. If the "Server URL" contains a host name and optional port, the host is used to create the connection. No attempt is made to locate the default server(s), and the DN, if present, is ignored. For example, the following two are equivalent: error = LDAP_Logon('ldap://myserver' : MyUser : MyPwd); error = LDAP_Logon('myserver':MyUser : MyPwd); System & Method A/S Basic Features 37 In general you will always test the result of the log on by retrieving the messages from the GetLastError() function. Ex: <% .... error = LDAP_Logon(Server:Userid:Password); if (error); <% = GetLastError() %> return; else; exsr ReadyToGo; endif; ... %> Show the sample LoggedOn Syntax: Flag = LoggedOn (); Field Name Flag Data type Indicator/ Logical / boolean Description Returns *ON if a session is logged on. The "LoggedOn()" function can be used to redirect the user to the correct logon ASPX page where the user id/password can be entered. Or it can be used to determine whether or not the session is run as Anonymous session. Ex: <% .... if (not LoggedOn()); exsr doLogon; return; endif; ... %> batchLogin You can also create an IceBreak session from a batch or interactive job. This is useful when you run IceBreak in mixed environments with CGIDEV2, PHP or java from the same IBMi box. From you within a (no-IceBreak) RPG program you issue a "bachLogin" which in turn gives you a session handle to an IceBreak session. Notice that you need to provide a userid and password - This is native IBMi profile information. Also your RPG program has to bind to the ICEBREAK bin directory so you need ICEBREAK on your library System & Method A/S 38 IceBreak list to compile and run it. You can now concatenate the session id into an URL to your icebreak application and application will run with the credentials specified: h bnddir('ICEBREAK') /include qasphdr,icebreak d session s 22 varying /free session = batchLogon('SYSTEST ' : 'DEMO' : 'DEMO'); url = 'http://myIBMI:1234/' + session + '/myProgram.aspx'; // now provide the url to the client .... *inlr = *ON; When you are done with the session you can explicitly terminate the session if needed with a batchLogoff: h bnddir('ICEBREAK') /include qasphdr,icebreak d session s 22 varying /free ... batchLogoff ( 'SYSTEST ' : session); *inlr = *ON; .... System & Method A/S Basic Features 2.5 Server behaviour 2.5.1 Setting up HTTPS 39 Server Behaviour: See the videocast on from the Internet HTTPS is the secure version of the HTTP protocol. It is the same but uses the Secure Socket Layer - SSL as the transportations. You need a certificate to run IceBreak with HTTPS. This certificate can be issued by Verisign (tm) among others - or you can build one your self. In this tutorial we will step through the configuration of the IceBreak server instance and build a certificate using the buld-in "Digital Certificate Manager" that ships with i5/OS - OS/400. Step 1: Create a certificate. · · · · · · · · · · · · · · · · · · Open the "IBMi task": Click on the following link http://MySystemI:2001 Logon as QSECOFR Click on "Digital Certificate Manager" Click on "Select a Certificate store" Select "*SYSTEM" Now it shows the path to the certificate - it might be "/QIBM/USERDATA/ICSS/CERT/SERVER/ DEFAULT.KDB". Write the file path down - it must be entered into the IceBreak configuration later. Enter the password for the certificate - the password is case-sensitive. If you don't know what it is the click on "reset password" Write the password down - it must be entered into the IceBreak configuration later. Create a new Certificate: 1: Select "Server / client certificate" [Continue] 2: Select "Local Certificate Authority" [Continue]. 3: Fill in required values. [Continue] 4: Don't select anything. [Continue] Assign the Certificate to the certificate store: 1: Select "manage certificate Store". 2: Select "Set default certificate" [Continue]. 3: Select the certificate you just made [Continue]. Step 2: Configure the IceBreak server instance. · · · · · · · · Go to the iceBreak administration menu. Click on work with servers Stop the server you want to run with HTTPS Select and edit the server you want to run with HTTPS Click on the advanced button Set the protocol type to "HTTPS" Set the certificate file path and password to what you wrote down in step 1. Restart the server. You don't have to make any changes in your application to utilize HTTPS. System & Method A/S 40 2.5.2 IceBreak Use the pre-request exit program Server Behaviour: The pre-request program is an .aspx program that is executed before each and every "normal" request is processed in IceBreak. It can be used for custom designed security, URL overriding, generic heading handling etc. How to configure The .aspx program you want to use must be compiled by referring to it from a normal browser URL. Due to performance reasons the normal JIT compilation is bypassed for the pre-request exit program. Now - change the server instance to refer to the exit program. Use either CHGICESVR command or use the "ADMIN" page "work with server instances" and change the pre-request exit program parameter to the name of your program. Also you can set the library name if you want to let more server instances point to the same exit program. Use the exit program for Internet / Intranet security When you are making web applications you will face that some resources might be public available where the user is anonymous. Also you might want to build your own internet user account which has nothing to do with i5/OS security at all. Now you can put your security logic into the pre-request exit program and secure all your resources. You can control whether or not IceBreak will server a specified resource with the build in function SetBreak. If you use SetBreak(*ON) the normal http serving is bypassed and only the response object from your pre-request exit program is sent back to the client (the browser) Syntax: SetBreak ( *ON | *OFF ); This example let IceBreak serve anything but .PDF files: <% ... extention = GetServerVar('REQUEST_FIRST_EXTENSION'); if (extention = 'PDF'); SetContentType('text/html; charset=windows-1252'); %>You can not view PDF files - sorry <% SetStatus('401 Access denied'); SetBreak (*ON); endif; return; %> Performance considerations Since this program is called each and every time a request is made to the icebreak server instance you have to design it to use very little resources and keep the program on the "stack" (e.g. don't seton *INLR). Also keep files open if any. System & Method A/S Basic Features Advanced login Then next sample show how to make a basic authentication using a pre-request exit program. Thanks to Jens Berg Churchil - KTP, Denmark: <% D*ame+++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++ D pos s 5U 0 D Flag s 1S 0 INZ(0) D lo c 'abcdefghijklmnopqrstuvwxyzæøå' D up c 'ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ' D Auth64 s 1024A VARYING D Auth s 1024A VARYING D Username s 128A VARYING D Password s 128A VARYING D Status s 128A VARYING D Message s 512A VARYING /free // Only if the user is not logged on yet if not LoggedOn(); Auth64 = GetHeader('Authorization'); pos = %Scan(' ' : %Trim(Auth64)); if (pos = 6); // Expect 'Basic BASE64_ENCODED_STR' Auth64 = %Subst(Auth64 : pos + 1); Auth64 = xlateStr(Auth64 : 0 : 1250); Auth = Base64DecodeStr(Auth64); Auth = xlateStr(Auth : 1250 : 0); pos = %Scan(':' : Auth); if (pos > 1); Username = %Subst(Auth : 1 : pos - 1); Password = %Subst(Auth : pos + 1); Username = %Xlate(lo : up : Username); Message = Logon(Username:Password); if LoggedOn(); SesSetVar('USERNAME' : Username); endif; if (%Scan('deaktiveret' : Message) > 0); Flag = 2; endif; else; Flag = 1; Message = 'Invalid Authorization header'; endif; endif; if not LoggedOn(); if (Flag = 1); Status = '400 Bad Request'; elseif (Flag = 2); Status = '403 Forbidden'; else; Status = '401 Unauthorized'; SetHeader('WWW-Authenticate':'Basic realm="My Webserver name"'); endif; SetContentType('text/html; charset=windows-1252'); SetStatus(Status); System & Method A/S 41 42 IceBreak SetHeader('x-login-message' : Message); SetMarker('Message' : Message); SetMarker('Status' : Status); %> <%$ Status %>

<%$ Status %>.

<%$ Message %>

<% SesEnd(); SetBreak (*ON); endif; endif; return; /end-free %> System & Method A/S Part III 44 IceBreak 3 Building applications 3.1 Debugging IceBreak applications Programming: Debugging a web application can be very difficult, IceBreak has some build in features which make life a lot more easy. You can use the 5250 debugger, the GUI debugger or simply use the console to log data values. Use what ever fits your needs. Using the "Console": The simplest ways to debug it just to send values of variables directly to the console. This can me achieved by the adding the following code to your RPGLE program: <% /free consoleLog('Any text can go to the console'); *inlr = *ON; %> This text will now occur in the browser debugger console along with other consol log notifications: System & Method A/S Building applications 45 Pleas notice, that the consoleLog uses a protocol called "WildFire" whitch requires a pluging like FirePHP to be installed in you Chrome of FireFox browser. When you are building XML or JSON based applications you can log objets and arrays from the IceBreak XML and JSON parser directly. The following code is using both simple strings and complex JSON objects: <% // Example: // Using the "consoleLog" on Json objects // -----------------------------------------------------------------d pJson d subobj s s * * /include qasphdr,jsonparser /free *inlr = *ON; consoleLog('Demo of JSON objects. First parse a string'); consoleLog('{ "manuid":"CASIO", "price" :123.45 }'); + + + pJson = json_ParseString ('{ "manuid":"CASIO", + "price" :123.45, + "subobj": { + "a": 1, + "b": 2, + "c": 3 + } + }'); + if json_Error(pJson) ; consoleLog('Json error:' + json_Message(pJson)); json_Close(pJson); return; endif; consoleLog('Json parser ran ok, now show the contents'); consoleLogJson(pJson); consoleLog('Now only show the "subobj" object:'); subobj = json_locate(pJson : 'subobj'); consoleLogJson(subobj); json_Close(pJson); Which will result in the following output in firebug / chrome console: System & Method A/S 46 IceBreak Using traditional server side debuggers: IceBreak also provides support for both GUI and basic 5250 debugging. Please ensure to put the server into *MULTITHREAD mode before starting any of the debugging approaches. Otherwise it can be rather difficult to find which jog is actually service you application. But in *MULTITHREAD you have one IBMi job for each "WebJob" so You can use both System I debuggers: The GUI debugger and the 5250 service job debugger. The GUI debugger If you have IBMi Navigator installed, you have already installed the system debugger. Otherwise read the chapter installing the system debugger. You need some settings before you can use the debugger: · You browser must allow Active-X components · The debug server must run: STRDBGSVR and STRTCPSVR SERVER(*DBG) (or CALL QSYS/ QTESSTRSVR for V5R1) · The IceBreak server must be in development mode · The IceBreak server must be running in *MULITHREAD ( or *SINGLE) mode From the URL where you application you want to debug type: /system/strdbg.aspx E.g if you have a server instance running on port 60001 it will look like: System & Method A/S Building applications 47 http://mysystem:60001/system/strdbg.aspx An Active-X warning might pup up now. please continue. Short after the system debugger will appear. You will have to fill in the name and library of the program to debug: System & Method A/S 48 IceBreak Now press OK and the intermediate source of your program will appear. Place a break-point and press the green "Run" button. Go back to the browser and run the program by entering the name at the URL like: http://mySystemi:60001/hello.aspx Application now runs to the breakpoint line. You can not step through the source by F11. Use the build in help to investigate the debugger functionalities: System & Method A/S Building applications 49 Using the 5250 debugger. If You prefer the green-screen debugger, you can still use that. · Navigate to the IceBreak menu with GO ICEBREAK · Enter command WRKICESVR · Enter option 17 at the server you want to debug which will prompt the STRICEDBG command System & Method A/S 50 IceBreak Enter the name of the program you want to debug. Now the service debugger will appear. If you will be absolutely sure that you hit the right session then use /system/dspsvrinf.aspx from browser URL and find the session timestamp for the session you are debugging. The value *LAST refer to the most reason session that was started in the IceBreak subsystem http://MySystemi.org:60000/system/dspsvrinf.aspx Installing the GUI debugger. You can install this and it work equaly well on Windows, Linux and Mac: If you are running I5/OS V5R1 or V5R2 you need a few PTF's V5R1 : · Server PTF SI09825 · Client PTF SI06031 V5R2: · Server PTF SI09834, SI08512 · Client PTF SI09844 Java 1.3 (or later) run-time environment must be installed on your IBMi. This is product 5722-JC1 option 5. You will also need a recent JRE on your client PC. You must copy 3 “.jar” (Java Archive) files to your PC. Locate or create a directory and copy from the IBMi: · /QIBM/ProdData/HTTP/public/jt400/lib/jt400.jar · /QIBM/ProdData/HTTP/public/jt400/lib/tes.jar · jhall.jar from http://java.sun.com/products/javahelp System & Method A/S Building applications 51 Place them in C:\i5debug Change the CLASSPATH to refer to C:\i5debug. If you're debugging from “outside” the office firewall, you will need port 4026 open which is the “single point of contact” for the user interface. Note that port 4026 is registered in the IBMi service table as “asdebug”. 3.2 Using compiler directives Precompiler: When the IceBreak compiles a program it uses a Just-In-Time technology. The JIT compiler is invoked only if the server instance is in *DEVELOP mode and if the source files has been modified since the last compilation. That means - if you change a program it will be re-compiled when you open it from the browser next time. The IceBreak compiler has 4 stages: · · · · IceBreak pre-compiled IBM SQL pre-compiled [Optional] IBM ILE compiler [RPG/COBOL/C++/CLP] IBM Binding [CRTPGM or CRTSRVPGM] All steps can be controlled by compiler directives within the source file starting the source file with a <% @ and terminated by %> like: <%@ language="SQLRPGLE" sqlopt="COMMIT(*NONE)" modopt="text('demo')" pgmopt="BNDDIR (UTIL)" %> For each step that utilize IBM commands you can override the default values with sqlopt, modopt and pgmopt Directive Value language RPGLE CBLLE CPP CLLE SQLRPGLE SQLCBLLE SQLCPP pgmtype System & Method A/S Default * Source Source Source Source Source Source Source PGM * SRVPGM NOASPMOD NOASPSRVP GM WEBSERVIC E code code code code code code code is is is is is is is in in in in in in in Description ILE-RPG format ILE-COBOL format ILE-C++ format ILE-CL ILE-RPG format with SQL ILE-COBOL format with SQL ILE-C++ format with SQL Bound program with access to the IceBreak Object model Service program with access to the IceBreak Object model Program Module. No access to the IceBreak Object model Service program. No access to the IceBreak Object model Service program. With access to the IceBreak Object model and all procedures exposed as WebServices 52 IceBreak Directive Value trimoutput NO Default * YES srcstyle FREE * WDSC 3.3 Description The response object is rendered as is White space are removed from the response object, reducing the final output RPG columns are aligned automatically, Block comment /* */, and free SQL syntax are allowed RPG syntax is strict according to columns, comments and SQL sqlopt Any parameters for CRTSQLxxx command modopt Any parameters for CRTRPGMOD/CRTCBLMOD/CRTCPPMOD/CRTCLMOD command pgmopt Any parameters for CRTPGM/CRTSRVPG command How to include external resources Programming: Dynamic include When you include data into your ASPX-program it can be done in to different ways - either static or dynamic. Dynamic include is done by the IceBreak server at run time by the ResponseObject, which are covered in : Placing runtime data using "Markers" Dynamically including stream files Static include Static include is done by the IceBreak pre compiler or by the host language compiler. Host language include If you use RPG as the host language you might be familiar with the /COPY or /INCLUDE or if you use COBOL it looks like "copy MemberName in SourceFile". With these copy function you can place only code into source physical file. IceBreak, however also has a include feature in the pre compiler which allows you to both include code as well as XML and HTML into source physical file from where the IBM compiler is running. The include can be placed anywhere in your source allowing you to initialize constants from included stream files, program code, and for the response object both HTML, XML, JSON etc. This is also very convenient if you still like to use the PDM as you preferred source editor, because you can make one very small ASPX-program in the IFS that only includes the complete source from a source file in a library. System & Method A/S Building applications 53 IceBreak pre-compiler include In a IceBreak ASPX program we use the ASPX notation for including resources. the syntax is: The "FileToInclude.htm" above is any stream file relative to the current resource where you issued the include statement. Of cause you can address any stream file in the IFS. But then you have to prefix the name with at "/" like: You can also include relative to the server root path by prefixing the file name with a "." like: You can put this include anywhere in your source, so now you are able to include both HTML and ASPXcode, initialize constants with values from the include file etc. Include can be done recursively with a max level to 200 files... IceBreak extension to the ASPX-include We have made an extension to the ASPX-include syntax. we have introduced Tags. Tags can be used to include a fragment from the include file. The syntax is: The include file can now contain tags that will be included. Like: The pre compiler will now include all data just after the tag until it finds a new tag or the end of file. This technique can be used to externally describe HTML files - just like a normal DDS-displayfile. This is a way to separate code and HTML into two or more different files. Consider the following ASPX program ex01IncApp.aspx: System & Method A/S 54 IceBreak <%/free %><% select; when Form('Screen') = 'Screen03'; %><% when Form('Screen') = 'Screen02'; %><% Other; %><% endsl; %><% *INLR = *ON; %> Now its counter part - the html file ex01IncApp.htm : This shows the use of externally described HTML files

This is screen 01

This is screen 02

This is screen 03

This technique is very important when you migrate legacy programs into new ASPX programs - but also when you design new applications. With this approach you can let a web designer handle just the html file. Because the tag is only a HTML comment and is accepted by all web-design tools Run the sample Show the sample Reference to the current file. If you have separated your application into a .ASPX file and a .HTML file which shares the same name excluding the extension - then you can refer to the include file with a # The syntax is: System & Method A/S Building applications 55 Reference to XML / XHTML include files. When you are dealing with XML and XHTML you might know that "doctype ..." must be the first in the file. There for you can not give this part of the file a tag name. For that purpose you can use the pseudo tag name *FIRST, which includes until the next tag in the include file: A simple database application Programming: The most powerful feature in IceBreak is the ability to integrate the i5/OS or OS/400 DB-2 database using ILE-programs. This is why IceBreak has such outstandingly fast file access. Let's take a look at a simple program that displays the first 200 records from a database file. First, we need to declare the file we are using. In this case it is a product file with some digital cameras. We also need a counter 'i' for the counting record occurrences later. We use the <% escape sequence to go into RPG-code mode. Declare and switch back to HTML using the %> sequence. <% f*Filename+IPEASF.....L.....A.Device+.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ fProduct IF A E K disk d*Name++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ d i s 10U 0 /free %> Build a valid HTML-document where the header and the body are written in plain HTML. System & Method A/S 56 IceBreak After the table header we are ready to put in real data from the database. So we use <% escape to go into FREE-RPG, set the file pointer to the first record, and read that. If we have a valid record, then we enter a DO-loop that repeats reading until end-of-file or the number of records is reached. <% setll *loval ProductR; read ProductR; i = 0; dow (not % eof(Product) and i < 200) ; i = i + 1; %> Place the record data into the HTML-table row. This is done in plain HTML, but with the <%= syntax. If we had some numeric values here we might want to convert them with %char or %edit functions: <% read ProductR; EndDo; %> We finish up by terminating the program so the result can be shown:
Product IDDescription Manufacturer ID Price StockCount StockDate
<% = PRODID %> <% = DESC %> <% = MANUID %> <% = %char(PRICE) %> <% = %char(STOCKCNT) %> <% = %char(STOCKDATE) %>
<% return;%> The final program looks like: System & Method A/S Building applications 57 <% //' Now reload the list, e.g. Set lower limit with *loval is the first record //' then repeat reading until end-of-file or counter exhausted //' ------------------------------------------------------------------------setll *loval ProductR; read ProductR; i = 0; dow (not %eof(Product) and i < 200) ; i = i + 1; %> <% read ProductR; EndDo; %>
Product ID Description Manufacturer ID Price Stock Count Stock Date
<% = PRODID %> <% = DESC %> <% = MANUID %> <% = %char(PRICE) %> <% = %char(STOCKCNT) %> <% = %char(STOCKDATE) %>
<% return; %> Run the sample 3.5 Show the sample Database maintenance application Programming: Let's go one step further, and expand the simple "List" application so the database can update/delete and write. This sample combines the Form() and QryStr() functions from the first tutorials . Also we use the "File Field Descriptor" tool which can produce the components of the application we a building. To simplify the program we have put the logic into separate subroutines: 1.Init: The initial settings from the HTML document, references to style sheets and j-scripts. 2.Main logic This part determines the functions based on previous incarnations of the ASPX-page state. 3.Load List Similar to database application, tutorial 5, this reads the database and builds the html table 4.Edit This Shows a form with the selected database occurrence, and buttons for update, delete and new System & Method A/S 58 IceBreak 5.Exit This cleans up, closes, and terminates the program We also have traditional RPG for file and data declarations F-spec and D-spec etc. The "init" has nearly the same layout as the previous sample, but all initialization should be placed here in the future: <% //' -------------------------------------------------------------------------------//' Init; setsup the HTML header and stylesheet / (evt. the script links) //' -------------------------------------------------------------------------------Begsr Init; %>

Work with Products

<% Endsr; %> Now to the core applications - the "Main" logic The Form('Option') used in the multi way if (select) is the result of any prior buttons "clicks" on the "edit" form The state can be extracted from that. The QryStr('Key') returns the unique key from the Query String in the request object i.e. the URL //' -------------------------------------------------------------------------------//' The Main logic controlling the state from previous incarnations //' -------------------------------------------------------------------------------Begsr Main; //' Previous function parses update or add parameter //' -----------------------------------------------select; //' The "New" button is clicked in the edit form when Form('Option') = 'New' ; reset ProductR; Exsr Edit; //' The "Update" button is clicked in the edit form when Form('Option') = 'Update'; prodKey = FormNum('product.prodKey'); chain prodKey ProductR; if (%found); exsr Form2db; update ProductR; else; reset ProductR; setll *hival ProductR; readp ProductR; MaxKey = ProdKey + 1; exsr Form2db; ProdKey = MaxKey; write ProductR; endif; Exsr LoadList; System & Method A/S Building applications 59 //' The "Delete" button is clicked - and a prodKey exists; now delete that record when Form('Option') = 'Delete'; prodKey = FormNum('product.prodKey'); chain prodKey ProductR; if (%found); delete ProductR; endif; Exsr LoadList; //' The "Return" button is clicked when Form('Option') = 'Return'; Exsr LoadList; //' When Clicking on a row in the table the " 0; prodKey = QryStrNum('prodKey'); chain prodKey ProductR; unlock Product; Exsr Edit; other; Exsr LoadList; endsl; Exsr Exit; EndSr; Load list reads all records from the database file and puts them into a HTML table. Real data from the database is ready to be placed under the table header. Use <% escape to go into FREE-RPG and the set the file pointer to the first record and read that. If a valid record is shown, enter a DO-loop that repeats reading until end-of-file or the number of records is reached. Note: Here a Form is used in conjunction with the "POST" method and a "New" button. This causes the same ASPX page to be redisplayed, but with the "Option" Form-Field set to the value "New". The main logic will respond to that by clearing input fields and running the "Edit" routine for the new record. The list table is created by the "Component Wizard (File Field Description tool)" found on the administration menu under "tools" . This produces the HTML structure for any database file: <% //' -------------------------------------------------------------------------------//' loadList; is much like a "load subfile". All records are placed into a html table //' -------------------------------------------------------------------------------Begsr LoadList; %>
<% // Now reload the list // ------------------Count = 0; setll *loval ProductR; System & Method A/S 60 IceBreak read(n) ProductR; dow (not %eof(Product) and Count < 2000) ; Count = Count + 1; %> <% read(n) ProductR; EndDo; %>
Product ID Description Manufacturer ID Price Stock Count Stock Date
<% = PRODID %> <% = DESC %> <% = MANUID %> <% = %editc(PRICE:'J') %> <% = %editc(STOCKCNT:'J') %> <% = %char(STOCKDATE) %>
<% EndSr; %> The Edit routine features all the record fields into form fields in detail level. Note: the Form in conjunction with the Post method causes the ASPX page to be redisplayed, but with the "Form" decorated with all data from this routine. Also, the "Option" contains either "Update" "Delete" or "Return" depending on which button is pressed. The input form "Component Wizard (File Field Description tool)" found on the administration menu under "tools" . This produces the HTML structure for any database file: <% //' -------------------------------------------------------------------------------//' Edit; Is just showing a form which is being posted back with all input fields //' Filled //' -------------------------------------------------------------------------------Begsr Edit; %>
Product ID
Description
Manufacturer ID
Price
Stock Count
Stock Date
<% EndSr; %> Finally we finish up by terminating the HTML (table, body and document) and terminate the program so the result can be shown: <% //' -------------------------------------------------------------------------------//' Exit Finish up the the complete HTML and quits the program //' -------------------------------------------------------------------------------Begsr Exit; %> <% return; Endsr; /end-free%> Run the sample 3.6 Show the sample Split your program logic and design into separated files Programming: In this sample we will split the logic and the design into to files (.ASPX and .HTML). We are using the " Pre-compile time Include with tags" technique in the sample. This will make the ASPX source code much easier to understand and the HTML include file will only hold the presentation. List program The following list program “Tutorials/ex19WrkPrd.aspx” is written in RPGLE and it loops through a file called Product. All records are putted into a HTML table described in the included file “Tutorials/ ex19WrkPrd.htm”. System & Method A/S 62 IceBreak Show the RPGLE source: Show the sample RPGLE-fixed Show the sample RPGLE /free So the user interface, the presentation layer is only in this HTML files: Show HTML presentation layer Record maintenance program From the list program you can maintain products by use of maintain program “Tutorials/ex19EdtPrd. aspx” and the included “Tutorials/ex19EdtPrd.htm”. Show the RPGLE source: Show the sample RPGLE-fixed Show the sample RPGLE /free Try the sample 3.7 Writing and reading stream files Build in functions : A handy feature in IceBreak is the ability to write and read stream files directly from strings. What it does It retrieves a string buffer and writes the contents to a stream file in the IFS according to the server directory. If you need to locate the file in the root of the IFS, then start the file name with an "/". e.g. "/ MyFile.text". Optionally, you can convert the data from EBCDIC to ASCII by setting *ON in the conversion option. Subdirectories must exists but files are created. Write Stream files from strings Use the built-in function "putStreamString(...)" to write a text file from a string. Syntax: System & Method A/S Building applications 63 error = putStreamString ( FileName:FileOptions: StringtoWrite: xLate); Field Name FileName Data type Description Default VARCHAR(256) path and name of the stream file to be created/appended to These are the options from the STDIO.H FileOptions VARCHAR(256) w=write, a=append, b=binary, t=text codepage=1252 is windows codepage StringToWr VARCHAR Any data to put into the file ite (32768) xLate BOOL Convert from EBCDIC to ASCII *OFF Note: if you need to write new lines use the x'0D25' sequence, or sequence in EBCDIC. Reading Stream files into strings Use the built-in function "getStreamString(...)" to read a text file from a string. Syntax: error = getStreamString ( FileName: String : Offset : MaxLength : xLate); Field Name FileName Data type Description Default VARCHAR(256) Path and name of the stream file to be read This is where the file contents is placed. The Contents is truncated VARCHAR(1 to String if the file contains more that 32768 or MaxLength number of 32768) bytes. Offset LONGINT Starting position in the file where 1=the first byte Maximum number of bytes to place into the result. no padding is done if the file is shorter. MaxLength LONGINT Use %size(String)-2 since the result is a varying string (-2 to omit the length) xLate BOOL Convert from ASCII to EBCDIC *OFF Here is an example. The file now contains: Note: if you need to write new lines use the x'0D25' sequence, or sequence in EBCDIC. <%@ language="RPGLE" %> <% D*Name++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ D Error s N D CRLF s 2A inz(x'0d25') D str s 32760 varying /free // This appends a string to a ascii stream file - converting the input text string to ascii Error = PutStreamString( 'test.txt': 'ab,codepage=1252': binary codepage=1252 is windows System & Method A/S // The output file name // w:write a:append, b: 64 IceBreak 'My log file at: ' + %char(%timestamp) + CRLF: *ON); // The text string to write // Conversion from EBCDIC to ASCII // Now read the complete test log file back into "str" - converting the input file to EBCDIC Error = GetStreamString( 'test.txt': // The input file name str: // where to place the contents 1: // Starting position in the file; 1=first byte %size(str)-2: // Maximum number of bytes to read *ON); // Conversion from ASCII to EBCDIC %>The file now contains:
<%= str %>
<%
return;
%>

Run the sample

3.8

Show the sample

AJAX Async JavaSript and XML
Programming:
When you want to create application based on components - AJAX is an excellent choice.
AJAX lets you handle "onClick" round-trips to the server, so you don't need to reload a complete page but rather load fragments.
IceBreak has a small, yet powerful implementation of AJAX, which allows you to replace any DIV /
SPAN / P tag with data of your choice - on the fly
Look at the following static HTML page, and see how we can make it alive with an AJAX call

<%@ language="RPGLE" %>







· The first AJAX relatet line is 5: This refer to the script containing all the AJAX implementation. AJAX is always a client technology · Next is line 8: "adAjaxCall" is the round trip to the server. The first parameter is WHERE you want to place data. The second parameter is HOW you want it. This is an URL to a resource - in this System & Method A/S Building applications 65 case an ASPX program that creates a table ... more on that later. · Last - line 9: A
tag where I want to put my data when the call is complete. The "id" attribute is the key here. The next step is to make the server side application. It only have to return the table element - not a complete html document. Otherwise it is pretty straight forward - making a table based on a result set: <% F*Filename+IPEASFRlen+LKlen+AIDevice+.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ Fproduct1 if e k disk d pmanuid s like(manuid) /free *inlr = *on; pmanuid = qrystr('manuid'); %> <% chain pmanuid productr; dow not %eof(product1) and manuid = pmanuid; %> <% read productr; enddo; %>
<% = prodid %> <% = desc %>
As you can see it only create the "raw" table. It have no idea in what context it is used - it just create the list/table. The formatting is provided by the client document we just saw before. It looks easy - and it is. The only problem with AJAX in the real world is: · Debugging: It might sometimes be difficult to find the right component doing what. · Caching: The browser might in some cases be confused about resources in the inner HTML and will therefore not cache it. · JavaScript might not be available in the target browser. Run the sample Now lets change the first HTML to an ASPX with a drop-down list so you can feel the real power of AJAX: <% F*Filename+IPEASFRlen+LKlen+AIDevice+.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ FMANUFACT IF E K DISK /free *inlr = *on; %> <%//' For using Ajax - just include the Ajax script in the system folder %> System & Method A/S 66 IceBreak
Select a manufacturer: <% //' The adAjaxcall takes two parameters: //' 1) the id name for an div or paragraph to hold the result. In this case a table //' 2) The url to the APS program to produce the result. in this case we build up the QueryString with parameters - the key to our database lookup %>
Product info will be listed here.
Run the sample 3.9 Creating XML files Dynamically Programming: Until now we have only studied IceBreak ASPX creating HTML files dynamically. In other cases you might need to produce XML files dynamically, which can be done very easily with the IceBreak ASPX. We learned in "Tutorial 4" how to include Word or Excel sheets dynamically. You will now expand that knowledge and let IceBreak ASPX create the XML contents. Again we use a double suffix. IceBreak detects the first suffix, and the browser detects only the last. The resulting file name might be: a MyApp.aspx.XML The contents type, should be set for the browser to open the resulting file. Otherwise it will ask you to download the file (which may be the purpose in another case). The following case creates a simple XML file for a Web shop. Step 1 - The legacy code that reads the data First lets take a look at an classic program that read all manufactures of digital cameras and produces a list of all available cameras for each manufacturer: System & Method A/S Building applications 67 <%@ language="RPGLE" %> <% *' -------------------------------------------------------------------------- * *' Program ex07XmlA.asp *' *' Reads all manufacturers of digital cameraes and coresponding products *' *' -------------------------------------------------------------------------- * F*Filename+IPEASFRlen+LKlen+AIDevice+.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ FMANUFACT IF E K DISK prefix('MANU_') FPRODUCT1 IF E K DISK prefix('PROD_') *' Read manufacturer C *LOVAL C C *IN80 SETLL MANUFACTR READ MANUFACTR DOWEQ *OFF 8080 *' Read all products for that manufacturer C MANU_MANUID CHAIN PRODUCTR C *IN80 DOWEQ *OFF C MANU_MANUID READE PRODUCTR 8080 MANUFACTR 8080 C ENDDO C C C %> READ ENDDO SETON 80 LR Step 2 - Building the XML Now we let the ASPX features extend the code to produce the XML data. First we need to tell the browser that we are dealing with XML. That is done with the SetContentType which takes a MIME type as parameter ... this is done in FREE-RPG mode. /free SetContentType('application/xml; charset=utf-8'); /end-free Second we need a XML header and a root tag that wraps all the XML stuff: Then we need a Manufacture tag with the following data from the file: System & Method A/S 68 IceBreak And the the Product tag with the following data from the file: The program logic must insert the end tags of cause. Now The Program looks like: <% *' -------------------------------------------------------------------------- * *' Program ex07XmlA.asp *' *' Reads all manufacturers of digital cameraes and coresponding products *' *' -------------------------------------------------------------------------- * F*Filename+IPEASFRlen+LKlen+AIDevice+.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ FMANUFACT IF E K DISK prefix('MANU_') FPRODUCT1 IF E K DISK prefix('PROD_') *' This program deals with XML. UTF-8 is the prefered charset for that /free SetContentType('application/xml; charset=utf-8'); /end-free *' XML data is mostly in UTF-8 format %> <% *' Read manufacturer C *LOVAL C C *IN80 SETLL MANUFACTR READ MANUFACTR DOWEQ *OFF 8080 *' Now put the manufacturer informations into the response object %> <% *' Read all products for that manufacturer C MANU_MANUID CHAIN PRODUCTR 80 System & Method A/S Building applications C *IN80 DOWEQ *OFF *' Now put the product informations into the response object %> <% C MANU_MANUID READE PRODUCTR C ENDDO %> <% C C C %> READ ENDDO SETON 69 MANUFACTR 8080 8080 LR Thats all you need. If you run this sample you browser will format the data as a XML document. You can collapse and expand each node in the XML-tree Run the sample Show the sample Step 3 - Using the XML data If you have installed Microsoft Office 2003 or greater - then you can use the XML data right away. In the browser window right-click on the mouse and select "Export to Microsoft Office Excel". You will be prompted for where to put the data into sheet. And last - you go a Pivot table. System & Method A/S 70 IceBreak It's really useful!!! Step 4 - Formating the XML data Browsers are able to reformat the XML data to be more readable to humans. It uses a transformation style sheet, a XSL file. We have made a small XSL file called Product.XSL which reformats the XML you just created. System & Method A/S Building applications 71 Show the XSL file Now you have to refer to the transformation style sheet from within the XML file before the transformation occurs. It is done in the XML header with The final ASPX program now looks like: <% *' -------------------------------------------------------------------------- * *' Program ex07XmlB.asp *' *' Reads all manufacturers of digital cameraes and coresponding products *' *' -------------------------------------------------------------------------- * F*Filename+IPEASFRlen+LKlen+AIDevice+.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ FMANUFACT IF E K DISK prefix('MANU_') FPRODUCT1 IF E K DISK prefix('PROD_') *' This program deals with XML. UTF-8 is the prefered charset for that /free SetContentType('application/xml; charset=utf-8'); /end-free *' Here we use the transformations stylesheet "Product.xsl" %> <% *' Read manufacturer C *LOVAL C C *IN80 SETLL MANUFACTR READ MANUFACTR DOWEQ *OFF 8080 *' Now put the manufacturer informations into the response object %> <% *' Read all products for that manufacturer C MANU_MANUID CHAIN PRODUCTR C *IN80 DOWEQ *OFF *' Now put the product informations into the response object %> <% C C MANU_MANUID %> <% C C C %> READE ENDDO PRODUCTR 8080 READ ENDDO SETON MANUFACTR 8080 LR When you try to run the program your browser will reformat the XML document into a nice HTML document. The point here is - that is it the same data provided for both the human and for the application. Run the final sample 3.10 Inter process communication Programming: If you want to send messages across the internet i.e. if you are building a chat-room you will need a method to communicate between processes - hence the name inter process communication. If you are familiar with data queues on the IBMi you will be happy to know that you can use data queues right out of the box in IceBreak. Data queues will not interrupt the normal HTTP request/response flow but rather run in a separated thread in the IceBreak core. Sending and receiving data to a data queue from the browser: In the "system" hive there is two IceBreak build in functions that sends data to the data queue and receives data from the data queue. Normally you will wrap these functions in AJAX calls from a web framework like ExtJs, DOJO or jQuery. However, you can try the functionality directly from the browser URL First let us create a queue to work with. On the command line - enter: CRTDTAQ DTAQ(QGPL/JOHN) MAXLEN(1024) Like this: System & Method A/S Building applications 73 Now start a browser and let it wait for an event on that queue. This is done by the /system/rcvdtaq command. Notice it will just "spin" the waiting symbol until data arrives in the data queue, and notice you'll need to write the data queue name and library in uppercase: Next: Let's send the text "Hello world" into the messages queue JOHN in QGPL. This is done by the / system/snddtaq command Now: As soon you press the Enter and send the request, immediately after the waiting process will wake up and show the text "Hello world" You can control the following parameters: Parameter Description dtaq Name of the data queue. This values has to be in uppercase The name of the library containing the dataqueue. This values must be in uppercase. The lib special values *LIBL and *CURLIB can be used String data representation of the data snddtaq will place in the data queue. This will be data converted between UTF-8 and EBCDIC according to the current CCSID of the server job Number of seconds rcvdtaq will wait before returning an empty response. Don't set this timeout value longer than the AJAX call timeout value, it might fill up you communication stack key If a keyed dataqueue, this is the char presentation of the key number of bytes in the total keylen ( the key will be padded with blanks to fit this length). keylen Defaults to the string length of the key System & Method A/S 74 IceBreak keytype The type of entry to wait for: EQ, GE, LE, GT, GT. Defaults to EQ - has to be in uppercase Normally you will place the rcvdtaq and snddtaq in some AJAX call. You will notice that no application server job is started. The dataqueues are handled by the multithreaded core, and will not interrupt your normal program call flow. Also notice. It does not matter which server port you are sending or receiving at - all queues are available on all server instances despite the server port number. Just notice that if the server requires you to logon - then you can't send or receive on data queues before the logon process is completed normally. 3.11 Uploading files to a IceBreak server Programming: In this tutorial we will create a simple IceBreak program which uploads files - either to the IFS or to an internal large object (ILOB). Basically this program is just a simple HTML form. The magic however is in the combination of the form encoding type set to multipart/form-data and the special input fields of type "file". Configure the allowed destination: When you upload files they will be placed with a temporary name in the /tmp folder on the IFS - from here it is your responsibility to move them into your designated folder. You can, however restrict/allow the client to upload into one or more dedicated folders. You simply place a configuration file in Your server root path called webConfig.xml The configuration file has a upload element which again can contain a map of valid directories an the corresponding alias as the client refer to it. Finally You can give a generic folder path for any invalid upload filenames. This is indicated by an * as the alias name. By default that would be the /tmp folder on the IFS. The webConfig.xml file is hidden from the client. It is only available in the physical path, not in the virtual counterpart. The webConfig.xml contains (among other stuff) the following. The configuration above says: · Any uploaded files designated to virtual folder "frameworks" will be placed in the sub-folder "framework" in the server root path. System & Method A/S Building applications 75 · Any uploaded files designated to virtual folder "upload" will be placed in the absolute path "/www/ anyplace/docs" · The final "*" alias is a "catch all" - so all other virtual folder references will be placed into the "/tmp" folder The code: Next we will take a look at the file type, how it is used to upload files to your IceBreak server and how you can control the uploaded file. The combination of the form encoding type set to multipart/form-data and the special input fields of type "file" makes it work. Two components are needed,
and tags: The tag type has a special feature called "ENCTYPE". This is the encoding type for file-uploading to "multipart/form-data". It informs the browser to include all form elements like attachments in an email instead of passing the data in the form object. Also notice that IceBreak only supports the UTF-8 charset when you have inputs fields on you upload form. You always need to specify accept-charset="utf-8" if you also submits input fields. Input fields can be retrieved by the form() api for IFS stream files The NAME paramter must contain a valid virtual path and file. the path must be a name found in the webConfig.xml file in the upload element. The name must conform to any valid file name for the IFS. The name can be set to the special value "*" if you want IceBreak to create a unique name and place the file into the /tmp IFS folder. for ILOB's (Internal Large Objects) The tag type is set to "file". This informs the browser to attach a file in form attachment. The System & Method A/S 76 IceBreak browser automatically places a Browse-button next to the file name. The "NAME" is the destination name of an ILOB, but you have to prefix it by *ILOB: Now you have some objects in the resulting ASPX request object which you can retrieve by the Form('') or FormNum('') functions. Field Name Returns upload Returns field Returns IFS Returns client Returns FormNum('file.count') Form('file.n.uploadname') Form('file.n.localname') Form('file.n.remotename') form('file.n.size') Description the number of attachments in the file the intended name from the form "name" the name of the uploaded filename on the the name of the selected filename on the the size of the file in bytes Where 'n' is the file number in the attachment between 1 and "FormNum('file.count')" The final sample: <% //' D-specs var var var var I use the "var" icebreak macro to declare my variables- they will expand to i FilesOnForm oldName newName like(int) like(int) like(String) like(String) /include qasphdr,ifs /free %>

Files uploads on the form was: <%= form('file.count') %>

.
<% //' the first uses the default file name and will be placed temporary in /tmp/xxxxx.upload //' the second uses the "UPLOAD" which is mapped to location: /www/anyplace/docs on the IFS via the webConfig.xml file placed in the server root path //' the last is trying to hack into a invalid path, so it will fallback to the default /tmp path %>
File to upload :
File to upload :
File to upload :
Aditional text :

<% = Form('text1') %>

<% //'The table header %> System & Method A/S Building applications <% //' Now build a simple table with info //' we iterate through each file-field FilesOnForm = FormNum('file.count'); for i = 1 to FilesOnForm; %><% endfor; %>
Filenumber Name on the upload form Uploaded to Uploaded from Size in Bytes
<%= %char(i)%> <%= form('file.' + %char(i) <%= form('file.' + %char(i) <%= form('file.' + %char(i) <%= form('file.' + %char(i)
77 about the uploaded files on the request form + + + + '.uploadname') %> '.localname') %> '.remotename') %> '.size') %> <% //' Finally - if we use the method with temporary filename //' we rename and move the temporary file to the decided finally location //' Note we include the prototype IFS from qasphdr to utilize the IFS api "rename" if form('file.1.remotename') > ''; oldName = form('file.1.localname'); // This is the teporary name newName = '/www/anyPlace/docs/upload1.dat'; // this is the resulting name if rename( oldName :newName) = 0; %>File was moved from: <% = oldName %> to: <% = newName %><% else; %>Not able to moved from: <% = oldName %> to: <% = newName %><% endIf; endIf; return; %> 3.12 Controlling the state of a "CheckBox" Programming: Check boxes are used for logical states ON/OFF .. TRUE/FALSE. This is done by the "checked" attribute in the HTML. The following code builds a HTML-form containing a check box
By using the value "checked" it is very easy to transfer the logical state from the ASPX: System & Method A/S 78 IceBreak
>
RPG has logical variables and indicators which can be used for direct control of these check boxes. <% D*Name++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ D IsItOk s N /free IsItOk = form('IsItOk') > *blanks; if (IsItOk); %>This Checkbox is Checked<% else; %>This Checkbox is not Checked<% endif; %> When the value is retrieved from the checkbox, it will contain "checked" or blank. Now take the check state into logical variables and control the check box. Run the sample 3.13 Show the sample Mixing Jave-Script and RPG Programing: With HTML you are able to use scripts in your ASPX code in IceBreak. This can be data from a DB2 database which contain the options in a menu structure. Here is a small sample. How to put the system time into an "alert" popup message: This is done by the following code: <%/free *inlr = *ON; %>

Script sample

System & Method A/S Building applications 79 When the value is retrieved from the checkbox, it will contain "checked" or blank. Now take the check state into logical variables and control the check box. Script sample It does not look like much, but these few lines do quite a lot of work: · When the ASPX program is executed the %time() value is placed into the script · The total HTML file is the sent to the browser · The browser displays the HTML "Script sample" · Then it interprets the script showing the alert prompt with the time Run the sample Show the sample Tip: When you want to include JavaScript into your project you can find free snippets and complete components on the Internet. The following example shows how to build a menu. The first part only declares some of the RPG variables. <% D*Name++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++++Comments+++++ ++++++ D url s 256 varying /free %> Now we make reference to style sheets and JavaScripts. The following code makes up the menu items in Java Script The complete page is built by a table with the Java script menu on the left side and the contents on the right made by an IFRAME (Inline frame). System & Method A/S Building applications 81 <% url = QryStr('func'); if url = *blanks; url = 'default.htm'; endif; %>
<%return;%> You can take this navigator menu and load the item from a DB2 database to make a user dependent menu. 3.14 VB-Scripting. Merge i5/OS data into a MS-Word document Programming: The power of building script using an IceBreak ASPX-program is relay amazing. Here we will start MSword as an Active-X component and then build a document based on data from an DB2-table. The first step is to bring up MS-word and just fill in some data: System & Method A/S 82 IceBreak When You click on the "Word" button the VB-Script is started. The construction getObject followed by CreateObject is used to reuse word is it is already started. The hole magic is to use the "TypeText" method on the word object: Run the sample Show the sample Next step is to bring live data into the document with an IceBreak ASPX Program. Now we can iterate through a database table and build the script dynamically. <% *' -------------------------------------------------------------------------- * *' Program ex17Word2.asp *' *' Reads all manufacturers of digital cameraes and coresponding products *' *' This demonstrates the interaction with Microsoft Word scriptiong capabilities *' You need to allow "active-X" to run from your icebreak server - otherwise it will not work *' System & Method A/S Building applications 83 *' -------------------------------------------------------------------------- * F*Filename+IPEASFRlen+LKlen+AIDevice+.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ FMANUFACT IF E K DISK prefix('MANU_') FPRODUCT1 IF E K DISK prefix('PROD_') //' --------------------------------------------------------------------------------------------%>

The report is ready press OK to open it in word

As you can see - the structure is the same, but the RPG-logic i reading the entire file and inserting data in the document with "TypeText" method. Hint: Use word macro recording tool to show you all you need to do to produce, print and save (etc.) a document. Hint2: You can use the same technique to produce Excel spreadsheets. Run the sample Show the sample . 3.15 Using keyCodes (SPAM Prevention) Programming: Use "KeyCodes" to prevent a spammer from creating unwanted accounts from your web-application. What it does It prompts the user for a sequence of random numbers presented in a graphic format which is not easy for OCR-software to recognize. Also the information behind "KeyCodes" can not be exposed neither the "query string" or the "form" object. How it is done The key-code is generated as a random number using a timestamp as the base. Here we use four digits. //' Create a new key code: //' Get a pseudo random number .. that is the current timestamp sec cat milli sec part //' Time is in format: 2005-05-05-12.34.56.123456 rand = Num(%subst(%char(%timestamp()):21:2) + %subst(%char(%timestamp()):18:2)); rand = %rem(rand : 10000); //' Limit it to between 0 and 9999 System & Method A/S Building applications KeyCode = %subst(%char(rand + 10000) : 2: 4); prefix zeros SesSetVar('KeyCode' : KeyCode); 85 //' convert it to 4-char string with //' Store it into session A .GIF file for each digit is created with an almost unreadable font i.e. the "Curlz" font. Each digit from the keyCode is returned to the response object not exposing the original name, as .GIF image data. Here we use an ASPX that includes the .GIF data, and sets the contents type to "image/gif". Remember to set the cache time out to zero, otherwise the browser will just get the first image and then reuse that from the cache. You are creating the image contents dynamically! <% //' Return the "Curlz" image for the KeyCode position in the query string KeyPos = QryStrNum('KeyPos'); // The Key Digit position .. First 1 then 2 and last 4.. if (KeyPos >= 1); KeyCode = SesGetVar('KeyCode'); KeyPicture = %subst(KeyCode : KeyPos : 1); errstr = include('image/curlz' + KeyPicture + '.gif'); if (errstr = ''); SetContentType('image/gif'); SetCacheTimeout(0); else; %><%= errstr %><% endif; return; endif; %> Run the sample 3.16 then 3 Show the sample Using COBOL as ASPX programming language Programming: By migrating a COBOL program to IceBreak ASPX, you have a good opportunity to move legacy code towards the Internet. This release supports the basic features of the "form" object and the "response" object. These features are sufficient for writing COBOL-ASPX for the IceBreak server. Let's look into the souce code: First, set the precompiler to COBOL (CBLLE). <%@ language="CBLLE" %> In the "Environment division" you will need some special linkage features for the IceBreak server. This is done by including the member "httpxlink" in file "qasphdr". System & Method A/S 86 IceBreak Environment division. Configuration section. Special-names. copy httpxlink in qasphdr. In the "Data division" you need to include IceBreak-internal work variables using the member "httpxdata" in file "qasphdr". Data Division. Working-Storage Section. copy httpxdata in qasphdr. In the "procedure division" you are now able to utilize the "request" and the "response" object within the IceBreak server. When placing data in the response object you call on one of the following procedures and macros. Syntax <%= MyVariable %> "Response_Write" "Response_Write_NL" "Response_NL_Write" Description URL-Encodes and blank-trims a variable into the response object Writes the parameter/literal to the response object as it is Writes the parameter to the response object. Then appends a new line characters Writes a new line of characters into the response and appends the parameter/literal The final sample might look like this using basic COBOL paragraphing. <%@ language="CBLLE"%><% *' ------------------------------------------------------------- '* Environment division. Configuration section. Special-names. copy httpxlink in qasphdr. *' ------------------------------------------------------------- '* Data Division. Working-Storage Section. copy httpxdata in qasphdr. Procedure Division. *' ------------------------------------------------------------- '* Main section. *' Insert the html heading text %>

This is a test from a COBOL.ASP program Run the sample

Show the sample System & Method A/S Building applications 87 Use the following macros when you want to retrieve data from form input fields. Syntax MyVariable = Request.Form("MyFormField"); MyVariable = Request.FormNum("MyFormField"); MyVariable = Request.QueryString("FormField"); MyVariable = Request.QueryStringNum ("FormField"); Description Retrieve a char field from the input form Retrieve a number field from the input form Retrieve a char field from the URL Retrieve a number from the URL Please Note: 1) Macros in IceBreak-COBOL are terminated by ";" and they look likefunction calls in "Visual-Basic". 2) The first parameter (the left side of the =) is the name of the variable in your COBOL program to receive the content. 3) The second parameter is the form field name. The name of any HTML tag. Show the complete list of macros Let's extend the sample above placing a form field and showing what was typed into that field This sample might look like this: <%@ language="CBLLE"%><% *' ------------------------------------------------------------- '* Environment division. Configuration section. Special-names. copy httpxlink in qasphdr. Input-output section. File-Control. *' ------------------------------------------------------------- '* Data Division. Working-Storage Section. copy httpxdata in qasphdr. 01 Globals. 05 MyField pic x(30). Procedure Division. *' ------------------------------------------------------------- '* Main section. Main01. *' Insert the html heading text %>

This is a test from a COBOL.ASP program

Enter a string: <% MyField = Request.Form("MyField"); %>
The string was: <%= MyField %>
<% MainEnd. exit. %> System & Method A/S 88 IceBreak Run the sample Finally let's look at a COBOL-ASPX application producing a list of data using the DB2-database Show the sample Run the sample When using the procedure interface, it might look like this: call procedure "Response_Write" using content " call procedure "Response_Write" using content "

This is a test from a COBOL.ASP program

" end-call Use the "using content" calling convention when placing text literals, or "using reference" as the calling convention. Remember that text literals have a maximum length of 255 characters. 3.17 Using Legacy RPG fixed form code Programming: You can even use old style "input primary files" and the old-style "cycle", however, you have to migrate old RPG-III programs to IceBreak which can be done with the following guide-lines: · · · · · Convert the RPG-III to RPG-ILE using the CVTRPGSRC command Move the source to the IFS using "Source File Browser" tool found in the Adminitration menu Isolate the business logic from display files into routines Rewrite the user interface into HTML Use the "File Field Descriptor" tool to create HTML tables and HTML forms The fixed form business logic might be used with little or no change at all: <%@ language="RPGLE" %> <% FPRODUCT IP E DISK %><% = prodid %><%= Desc %>
Run the sample System & Method A/S Part IV 90 IceBreak 4 Internal Large Objects - ILOB's 4.1 ILOB's - Internal Large Objects ILOB's: Host languages like RPG and COBOL have a limit in program variable size. IceBreak breaks that limit by utilizing userspaces and associates them to a session. The transfer of data back and forth between Request object or Response object can be done with help from ILOB's. Also SQL CLOB's and BLOB's can be mapped to ILOB’s. See ILOB's and SQL Consider a file upload application. When the user hits the “upload” button on a form this data can be placed in an ILOB up to 2Gbytes. This ILOB can now save itself as a stream file. The XML parser can parse it or it can be placed into DB/2 CLOB field. ILOB's is by default session maintained, but can also be persistent so it is ideal to share data between server instances and session instances with ILOB's. ILOB's contains a body and a header which maps directly to the HTTP protocol. Therefore ILOB is used for IceBreak webservices. i5/OS userspaces are used to implement ILOB's. They are wrapped in an easy-to-use IceBreak-API's. However, you can use IBM supplied API's for manipulating userspaces if you create the basic type ILOB. see the API sample. The access to IOB functions is available by including: /include qasphdr,ilob ILOB Functions: · · · · · · · · · · · · · · · · · · · · IlobPtr = ILOB_OpenPersistant(Library : Name); Ok = ILOB_DeletePersistant(IlobPtr); Ok = ILOB_Read(IlobPtr: String: Offset : Length); Ok = ILOB_ReadNext(IlobPtr: String :Length); Ok = ILOB_Write(IlobPtr : String :Offset); Ok = ILOB_LoadFromBinaryStream (IlobPtr: FileName); Ok = ILOB_LoadFromTextStream (IlobPtr: FileName); Ok = ILOB_SaveToBinaryStream (IlobPtr: FileName); Ok = ILOB_SaveToTextStream(IlobPtr: FileName); OK = ILOB_Xlate(IlobPtr: fromCCSID : toCCSID); Ok = ILOB_Append(IlobPtr : String); Ok = ILOB_Clear (IlobPtr); DataPtr= ILOB_GetDataPtr(IlobPtr); // Obsolete - now the IlobPointer is the same as the data p Len = ILOB_GetLength(IlobPtr); ILOB_SetData (IlobPtr : Length : Data | *NULL); ILOB_SetWriteBinary(IlobPtr; *ON|*OFF); ILOB_Close(IlobPtr); ILOB_Ilob2Clob( ClobLocator : IlobPtr : Offset : Length ); ILOB_Clob2Ilob( IlobPtr : ClobLocator : Offset : Length ); ILOB_SubIlob (OutIlobPtr: InIlobPtr : FromPos : Length | ILOB_ALL : ToPos | ILOB_END); // Pos Also functions directly accessible from the response, request, session object and the XML parser: · Form2ILOB(IlobPtr: FormFieldName); · ResponseWriteILOB(IlobPtr); · SetResponseObject(IlobPtr | *NULL); System & Method A/S Internal Large Objects - ILOB's · · · · 91 IlobPtr = SesGetILOB(IlobName : [Defultsize=8192] : [HeaderSize=4096] ); IlobPtr = SesGetUsrSpc(usrspcname: IlobName : [Defultsize = 8192] ); XmlPtr = Xml_ParseILOB ( IlobPtr : Options: InputCcsid : OutputCcsid); error = Xml_GetIlobValue (IlobPtr: XmlPtr : xPathNode); ILOB’s are also used for response and request objects in some application server session dispatcher modes. First let's play with a ILOB as a way to preserve session variables for an application. A good practice might be to prefix the ILOB name with the name of the program for program global session variables, and "globals." for cross program variables. Simply base all variables you want to preserve in a session on a pointer served by an ILOB. If the name does not exists - it will automatically be created: <%@ language="RPGLE"%> <% /include qasphdr,ilob D*Name++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ d MyIlob s * d MySession ds based(MyIlob) d Counter 10I 0 d first 1A C/free *inrt = *on; MyIlob = SesGetILOB('Thispgm.MyIlob'); "MyIlob" session ILOB if ( first <> *ON); Counter = 0; First = *ON; endif; Counter = Counter + 1; %><% = %char(Counter) %><% %> Show the sample // break the cycle // All ILOB's in the following is based on // Initialize the ilob fields // Increment the counter in the ilob Run the sample You can manipulate ILOB's with ILOB_SubIlob, where you can take a fraction or all data from an ILOB and insert it or append it to another ILOB <%@ language="RPGLE" modopt="DBGVIEW(*LIST)" %> <% D*Name++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ d firsttime s n INZ(*ON) d ilob1 s * System & Method A/S 92 IceBreak d ilob2 s * /include qasphdr,ilob C/free // Get two pointers to some session ILOB's ilob1 = SesGetILOB('ilob1'); ilob2 = SesGetILOB('ilob2'); // Clear Ilobs. The second only the first time Ilob_Clear(ilob1); if (firsttime); Ilob_Clear(ilob2); firsttime = *OFF; endif; // Put data in the first ilob, so we redirect the response to the first ilob SetResponseObject(ilob1); // Use the normal ASPX syntax to produce data, this time however it ends up in "ilob1" %> <%= %char(%timestamp()) %> <% // Switch back to default reposnse object SetResponseObject(*NULL); // Now append that data to the second ilob Ilob_SubIlob(ilob2 : ilob1 : 1 : ILOB_ALL : ILOB_END); // Build the result %>

ILOB Demo - Press refresh to append to the list

<% // take the final ilob which contains all table rows and put it into the table ILOB_SetWriteBinary(ilob2 : *ON); // This is already in ASCII ResponseWriteIlob(ilob2); %>
<% return ; %> Show the sample Run the sample System & Method A/S Internal Large Objects - ILOB's 4.2 93 ILOB's and SQL ILOB's can map CLOB and BLOB coloumns in a SQL table. It requires, however, that the SQL tables a journal'ed and commit are allowed. In this sample we are using SQL and maps fields to SQL CLOB fields, it requires a "locator", but with that you are able to save and restore SQL data in a session. <%@ <% *' *' *' language="SQLRPGLE" options="COMMIT(*ALL)" modopt="DBGVIEW(*LIST)" %> -------------------------------------------------------------------------------Use CLOB Fields directly from input form and the response object -------------------------------------------------------------------------------- /include qasphdr,ilob D*Name++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ d MyIlob s * d MyClob s sqltype(CLOB_LOCATOR) d lobind s 5i 0 d ALL s 10I 0 inz(-1) *' -------------------------------------------------------------------*' Main logic *' -------------------------------------------------------------------/Exec sql Set Option Optlob=*YES, Commit=*ALL, Closqlcsr=*ENDACTGRP /End-exec C/free *inrt = *on; // break the cycle MyIlob = SesGetILOB('MyIlob'); // All ILOB's in the following is based on "MyIlob" session ILOB %>

CLOB/ILOB Demo


<% if Form('form2clob') > ''; Form2Clob(myClob : 'lob'); Exsr Sql_Insert; %>
<% responseWriteCLOB(MyClob); %>
<% ILOB_Clob2Ilob(MyIlob:MyClob:1:ALL); System & Method A/S 94 IceBreak endif; if Form('Ilob2clob') > ''; ILOB_Ilob2Clob(MyClob:MyIlob:1:ALL); Exsr Sql_Insert; %>
<% responseWriteCLOB(MyClob); %>
<% endif; if Form('showilob') > ''; %>
<% responseWriteILOB(MyILOB); %>
<% endif; if Form('loadfromstream') > ''; ILOB_LoadFromStream(MyIlob :'/www/systest/space.txt':'r'); %>
<% responseWriteILOB(MyILOB); %>
<% endif; if Form('savetostream') > ''; Form2ILOB(myIlob : 'lob'); ILOB_SaveToStream(MyIlob :'/www/systest/space.txt':'w,ccsid=277'); endif; if Form('Delete') > ''; Exsr Sql_Delete; endif; %> <% // Now reload the list // ------------------Exsr Sql_Open; // Declare and Open the SQL cursor Exsr Sql_Fetch; // Get the first row from the result set Dow (SqlCod = 0) ; // repeat until max number of rows found or EOF %> <% Exsr Sql_Fetch; // Get the next row from the result set EndDo; Exsr Sql_Close; // Always remember to close cursors after use %>
Clob
<% responseWriteCLOB(MyClob); %>
<% return; //' -------------------------------------------------------------------------------//' Open is declaring And opening the SQL Cursor //' Actually the declare ends up as a comment in the final object //' -------------------------------------------------------------------------------Begsr Sql_Open; /Exec SQL Declare List cursor for Select yclob from y for update of yclob /End-exec System & Method A/S Internal Large Objects - ILOB's /Exec SQL Open List /End-Exec Exsr Sql_Monitor; Endsr; //' -------------------------------------------------------------------------------//' Fetch - is retrieving the newt row from the result set //' -------------------------------------------------------------------------------Begsr Sql_Fetch; /Exec SQL Fetch list into :MyClob :lobind /End-Exec Exsr Sql_Monitor; Endsr; //' -------------------------------------------------------------------------------//' Close - Just close the cursor //' -------------------------------------------------------------------------------Begsr Sql_Close; /Exec SQL Commit hold /End-Exec Exsr Sql_Monitor; /Exec SQL Close list /End-Exec Exsr Sql_Monitor; Endsr; //' -------------------------------------------------------------------------------//' Insert a new row //' -------------------------------------------------------------------------------Begsr Sql_Insert; /Exec SQL Insert into y values :MyClob /End-Exec Exsr Sql_Monitor; Endsr; //' -------------------------------------------------------------------------------//' delete all rows //' -------------------------------------------------------------------------------Begsr Sql_Delete; /Exec SQL Delete from y /End-Exec Exsr Sql_Monitor; Endsr; //' -------------------------------------------------------------------------------//' Sql_Monitor is the global monitor for sql-errors //' The SQL_SetError sends the message back to the IceBreak server. //' Then use 'GetLastError' to display the formatted error message //' -------------------------------------------------------------------------------Begsr Sql_Monitor; select; when SqlCod = 0; when SqlCod = 100; other; SQL_SetError(SqlCod:SqlErm); %> System & Method A/S 95 96 IceBreak <% Endsl; EndSr; %> 4.3 ILOB's with IBM supplied API's If you want to use traditional userspaces with in a session and let IceBreak handle the memory management, you can use a special userspace ILOB which has no ILOB's features except for the plain userspace and the fact it will be connected to your session and reclaimed when the session ends. Syntax: IlobPtr = SesGetUsrSpc(UsrSpcName: IlobName : [Defultsize=8192] ); Field Name Usage Data type UsrSpcName OUTPUT CHAR(20) Name INPUT VARCHAR(256) Name INPUT - optional INT4 IlobPtr OUTPUT Return value POINTER Description Automatically generated name of the resulting qualified output name and library for the user space Your session global wide alias name for the ILOB userspace managed for your session. (Not case sensitive) The optional initial size for the userspace in bytes. Default i 8K if omitted Pointer to userspace Sample: <%@ <% *' *' *' language="RPGLE" %> -------------------------------------------------------------------------------Demo: userspace managed by ilobs -------------------------------------------------------------------------------- /include qasphdr,ilob d d d d MyIlob pObj ReadCount lstobj s s s s * * 5u 0 20 * ------------------------------------------------------------- * D gh ds Based(MyIlob) D LikeDs(QUSH0100) System & Method A/S Internal Large Objects - ILOB's 97 * ------------------------------------------------------------- * D ol ds Based(pObj) d likeds(QUSL010003) * ------------------------------------------------------------- * D quslobj pr extpgm('QUSLOBJ') D SpaceName 20 D Format 8 const D ObjQual 20 const D ObjType 10 const /Include QSysInc/qRpgleSrc,QUSGEN /Include qasphdr,QUSLOBJ *' -------------------------------------------------------------------*' Main logic *' -------------------------------------------------------------------C/free %>

Tutorials

Using Userspace like an ilob.

<% *inlr = *on; MyIlob = SesGetUsrSpc(lstobj : 'ListOfmyObjects' : 4096 ); quslobj ( : : : lstobj 'OBJL0100' '*ALL QGPL '*ALL '); ' pObj = myilob + gh.QUSOLD; // Position to Record format for ReadCount = 1 to gh.QUSNBRLE; // ReadCount < Number List Entries %><% %><% %><% %><% %><% pObj = pObj + gh.QUSSEE; // Size Each Entry endfor; %>
<% = ol.QUSOLNU %><% = ol.QUSOBJNU %><% = ol.QUSOBJTU %>
4.4 ILOB's, httpRequest and XML ILOB's: In a Service Oriented Architecture world (SOA) the ability to intercommunicate huge data streams is essential. As we saw earlier ILOB's is a way deal with large data from within an ILE program. System & Method A/S 98 IceBreak This tutorial will show how to use ILOB's and make HTTP request with XML based data stream. Basically we want to send a XML request to a server program and in return receives the XML response. By using ILOB's we are able to break the 32K limit that RPG normally has. The Server program <%@ language="RPGLE" %> <% *' ------------------------------------------------------------------------------------------*' Runs an SQL query for the XML request received *' ------------------------------------------------------------------------------------------D*Name++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ d manufactid s 16 varying D Error s N D SqlCmd s 1024 varying D MaxRows s 10i 0 /free //' The first thing is always to set charset and content type SetContentType ('application/xml; charset=windows-1252'); //' Take the parameter from the XML request manufactid = reqXmlGetValue('/request/manufactid' : ''); //' Build the SQL command sqlcmd = 'select * from product where manuid = ''' +manufactid+ ''''; MaxRows = 10000; //' Now run the SQL query %><% Error = SQL_Execute_XML(sqlcmd : maxrows); if (Error); %><% endif; return; %> System & Method A/S Internal Large Objects - ILOB's 99 1. The SetContentType() to "application/xml" is essential. We both sends ad receives data in XML format. if IceBreak "see" the /XML in the content type it will automatically run the XML-parser. 2. The xml request is already parsed so we have access to an XML object that IceBreak maintains. Now we can use the X-path syntax to refer to the value of the element "manufactid" in the " request" elemet. 3. The SQL statement is constructed. Just adding the "where" clause and we are ready to run the SQL. 4. Finally the surroundings for the XML is set up. Note that the encoding tag in the XML header has to be the same as we used in "SetContentType()" 5. SQL_Execute_XML() simply returns the SQL result set as an XML document, which is placed directly in the response object. You can see the number of variables in a program like this i kept to a minimum. All the data manipulation is done behind the scenes in the request and response object. The Client program The client program is a little more sophisticated the the client. It is dealing with the access to the ILOB's and parser directly: <%@ language="RPGLE" %> <% d*' Include the ILOB and xml parser prototypes /include qasphdr,ilob /include qasphdr,xmlparser d*Name++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ d manufactid s 16 varying d path s 64 varying d Error s N d reqILOB s * d respILOB s * d xmlPtr s * d i s 10i 0 d rows s 10i 0 /free //' Bacically this program just toggle between the manufactures manufactid = form('manufactid'); //' The first thing is always to set charset and content type SetContentType ('text/html; charset=windows-1252'); //' First I crerate my work ILOB's reqILOB = SesGetILOB('request'); request respILOB = SesGetILOB('response'); response from the server // get a pointer to a session ILOB used as my // get a pointer to a session ILOB used for the //' Reset my ilob ILOB_Clear(reqILOB); ILOB_Clear(respILOB); //' Now i want to populate a simple XML request. - my ILOB header need a content type XML //' All httpRequest are routet to the same default job hench the cookie ILOB_SetHeaderBuf( reqILOB : 'Content-Type: application/XML; charset=windows-1252' ); //' I reroute my response object to the request ILOB, so I can use the ASP sysnax for System & Method A/S 100 IceBreak creating the XML SetResponseObject(reqILOB); %> <% = manufactid %> <% //' Now i redirect my response back to the default responce objet ( what my browser receives > SetResponseObject(*NULL); //' My request is now ready to to to the server, so i call the httpRequest for ILOB's Error = ILOB_httpRequest( '/tutorials/ex24ilobsvr.asp': // The URL in form:"http://server:port/resource" 30: // Number of seconds before timing out 'POST': // The "POST" method reqILOB: // pointer to my Request ILOB RespILOB // pointer to my Response ILOB ); //' Check for errors if error; %><% = GetlastError('*MSGTXT') %><% return; endif; //' My data has arrived - I'll fire up the XML parser xmlPtr = XML_ParseILOB ( //' Returns XML-object tree from an ILOB RespILOB: //' Pointer to an ILOB object 'syntax=loose': //' Parsing options 1252: //' The ccsid of the input ilob (0=current job) 0 //' The ccsid of the XML tree (0=current job) ); //' Check for errors if XML_Error(xmlPtr); %><%= XML_Message(xmlPtr) %><% XML_Close(xmlPtr); return; endif; //' The Result will be a table %>

Products by: <% = manufactid %>

<% System & Method A/S Internal Large Objects - ILOB's //' now print the report rows = num(XML_GetValue(xmlPtr: '/resultset/row[ubound]' for i = 0 to rows -1; path = '/resultset/row[' + %char(i) + ']@'; %><% endfor; %>
Product id Product Desciption Product Price
<% = XML_GetValue(xmlPtr: path + 'prodid' :'N/A') <% = XML_GetValue(xmlPtr: path + 'desc' :'N/A') <% = XML_GetValue(xmlPtr: path + 'price' :'N/A')
<% 101 :'0')); %> %> %> //' Always release the memory used XML_Close(xmlPtr); return; %> Show the sample Run the sample 1. Like the server program we need to set up the contents type. It need to map to the same values as the server. 2. The we create two ILOB's used for request and response 3. The clear of the the Request ilob is essential. Otherwise data will just append to the ILOB. 4. The ILOB has a header which is used for HTTP communication. You have access to that header by the "ILOB_SetHeaderBuf()". Note that you replaces the complete header by using the method. 5. The "SetResponseObject()" is used to reroute the response data to an ILOB so the data goes to the ILOB and not the normal response object. When you want to switch back, the just call "SetResponseObject()" with a *NULL parameter and you have your normal response object back which goes to your browser. This method can also be applied to creating XML files on the fly by building up the ILOB and the save the ILOB to stream file. 6. Now with the request XML in the "request" ILOB we just runs the "ILOB_httpRequest()" method and receives the "response" ILOB. 7. All the data in the ILOB is in ASCII, so when we fire up the XML parser we have to tell it which ccsid the ILOB is sored in. In this case "windows-1252" maps to "ccsid 1252". 8. Now are finished with the ILOB's the rest of the program just formats the XML tree to the response object that goes to the end-users browser. Here again - like in the server - we are extracting data using the X-Path syntax. 9. Finally always remember to use XML_Close() to free up the memory used by the XML parser. 4.5 ILOB's secures your streamfile upload to your IceBreak server Next Lets upload data to an ILOB and save it to a stream file. Note the *ILOB: in the input field. The name just after is the ILOB field. This is a good way to protect files in an upload until you decide where to save the uploaded file (see tutorial 3 on uploads) On the form you set the "enctype" to "multipart/form-data". This ensure that the browser uploads the attached file:
System & Method A/S 102 IceBreak Set the input type to file and the name prefixed by *ILOB: to ensure the up loaded stream is placed in the ILOB. From there you can manipulatet it in any way you like with the ILOB build in functions. Now the final program: <%@ language="RPGLE" %> <% /include qasphdr,ilob D*Name++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ d MyUploadIlob s * C/free *inrt = *on; // break the cycle MyUploadIlob = SesGetILOB('MyUploadIlob'); %>

ILOB upload Demo


File to upload :
<% if Form('file.1.RemoteName') > ''; %>

The Remote file name is: <%= form('file.1.Remotename') %>

It was uploaded to an ILOB : <%= form('file.1.Localname') %>

The size of the received file was: <%= form('file.1.size') %>

<% // Now save it to disk ILOB_SaveToBinaryStream(MyUploadIlob : 'MyUploadIlob.txt'); endif; %> Show the sample Run the sample System & Method A/S Internal Large Objects - ILOB's 4.6 103 ILOB's in WebServices ILOB's ILOB's or Internal Large Objects is heavily used in IceBreak to store large chunks of data. In this example I’ll show you how to run a SQL query based on a request in a WebService. The XML result is placed in an ILOB and returned to the WebService client as a string. <%@ language="RPGLE" pgmtype="webservice" %><% h NOMAIN /include qasphdr,ilob p*name++++++++++..b...................keywords++++++++++++++++++++++++++comments+++++++++ +++ p GetProductList... p B export d d SqlCmd d xmlout PI 1024 * input varying output d*Name++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ d Error s N d i s 10i 0 /free xmlout = SesGetILOB('sqllist'); in the response setResponseObject ( xmlout ); the ILOB ILOB_SetWriteBinary(xmlout : *ON); //' The SQL result set will go directly to the ILOB //' Redirect all output to the response object to //' This is in ASCII so don't x-late it later. %><% //' Now run the SQL query and put all data into the response object MaxRows = 10000; Error = SQL_Execute_XML(sqlcmd : maxrows); if (Error); %><% endif; setResponseObject (*NULL); here //' Go back to use the normal response object from /end-free P GetProductList... P E %> As you can see - it is pretty much a normal service program - except for the input/output keywords. It is a service program with no mainline. It simply exports a procedure. However, You are not restricted to only one. The trick here is that xmlout is defined as as pointer. When IceBreak recognize a pointer in th WebService declaration it will assume it is a ILOB'pointer. In this example I have used the System & Method A/S 104 IceBreak SQL_Execute_XML() to produce the SQL result set XML by redirecting the ResponseObject to the xmlout ILOB. Now IceBreak is tranfering the resultset in the WebService interface. System & Method A/S Part V 106 IceBreak 5 SQL 5.1 Using embedded SQL SQL: SQL programs can have another subtype besides RPGLE, the other is called SQLRPGLE. All you have to do is tell the precompiler that another programming language is being used, and override how the commitment control is being used. The first line of ASPX code does that, it is called Compiler-directives: <%@ language="SQLRPGLE" sqlopt="COMMIT(*NONE)" %> The "sqlopt" parameter can override any additional parameters on the CRTBNDRPG and CRTSQLRPGI. Host variables are needed to hold the result of the SQL-query. This is a standard RPG d-spec definition. <% D*Name++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ D MyCounter s 10U 0 D Now s Z /free %> The last thing is the actual SQL-statement. This is: <% Exec SQL Select count(*) , Current Timestamp into :MyCounter, :Now from Product; %> Or if you prefer the classic style syntax - enclosed by /exec and /end-exec: <% /Exec SQL Select count(*) , Current Timestamp into :MyCounter, :Now from Product /End-Exec %> Both syntaxes above are supportet both within fixed or free format from i5/OS ver. 5R1 with help from the IceBreak pre-compiler. Note, that colon in :MyCounter and :now is the method to describe an RPG host variable when you are writing SQL-statements. Finally, you are able to present the result in HTML like this. System & Method A/S SQL 107

The number of rows in table "Product" is <%= %char(MyCounter) %> and time is: <% = %char (now) %>

The complete example looks like this. <%@ language="SQLRPGLE" sqlopt="COMMIT(*NONE)" %> <% D*Name++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ D MyCounter s 10U 0 D Now s Z /free %>

Using SQL

<% Exec SQL Select count(*) , Current Timestamp into :MyCounter , :Now from product; %>

The number of rows in table "product" is <%= %char(MyCounter) %> and time is: <% = % char(now) %>

<% return; %> Show the sample 5.2 Run the sample SQL - Producing a list using a cursor SQL: If you want to use SQL to create result sets and read rows into a HTML table, then you need a "cursor". Take a look at the following example which is a embedded-SQL version of a List application. Here we place all SQL-statements into subroutines, so it doesn't interfere with the main logic. Also notice the use of SQLMonitor which is a method to determine if SQL-statements have completed normally. <%@ <% H*' H*' H*' language="SQLRPGLE" options="COMMIT(*NONE)" %> -------------------------------------------------------------------------------A List using embedded SQL -------------------------------------------------------------------------------- D*Name++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ D Rows s 10i 0 D MsgId s 7 D MsgFile s 10 D Sql_Cmd s 1024 Varying *' -------------------------------------------------------------------- System & Method A/S 108 IceBreak *' The SQL host variables are included as an external data-structure *' -------------------------------------------------------------------D Product E ds *' -------------------------------------------------------------------*' Main logic *' -------------------------------------------------------------------/free Exsr Init; Exsr LoadList; Exsr Exit; //' -------------------------------------------------------------------------------//' Init; sets up the HTML header and stylesheet / (evt. the script links) //' -------------------------------------------------------------------------------Begsr Init; %> <% Endsr; //' -------------------------------------------------------------------------------//' loadList; is much like a "load subfile". All records are placed into a html table //' -------------------------------------------------------------------------------Begsr LoadList; // First build the table header // ---------------------------%> <% // Now reload the list // ------------------Rows = 0; // reset the row counter Exsr Sql_Open; // Exsr Sql_Fetch; // Dow (SqlCod = 0 and Rows < 2000) ; // Rows = Rows + 1; // Declare and Open the SQL cursor Get the first row from the result set Repeat until max number of rows found or EOF Count number of rows so fare %> <% Exsr Sql_Fetch; EndDo; Exsr Sql_Close; // Get the next row from the result set // Always remember to close cursors after use %>
Product ID Description Manufacturer ID Price Stock Count Stock Date
<% = PRODID %> <% = DESC %> <% = MANUID %> <% = %editc(PRICE:'J') %> <% = %editc(STOCKCNT:'1') %> <% = %char(STOCKDATE) %>
<% EndSr; //' -------------------------------------------------------------------------------- System & Method A/S SQL 109 //' Exit Finish up the the Final html and quits the program //' -------------------------------------------------------------------------------Begsr Exit; %> <% return; Endsr; //' -------------------------------------------------------------------------------//' Open is declaring And opening the SQL Cursor //' Actually the declare ends up as a comment in the final object //' -------------------------------------------------------------------------------Begsr Sql_Open; Sql_Cmd = 'Select * from Product ' + 'Where prodId > '' '' ' + 'Order by ManuId'; Exec SQL Prepare pList from :Sql_Cmd; Exsr Sql_Monitor; Exec SQL Declare List cursor for pList; Exsr Sql_Monitor; Exec SQL Open List; Exsr Sql_Monitor; Endsr; //' -------------------------------------------------------------------------------//' Fetch - is retrieving the newt row from the result set //' -------------------------------------------------------------------------------Begsr Sql_Fetch; Exec SQL Fetch list into :product; Exsr Sql_Monitor; Endsr; //' -------------------------------------------------------------------------------//' Close - Just close the cursor //' -------------------------------------------------------------------------------Begsr Sql_Close; Exec SQL Close list; Exsr Sql_Monitor; Endsr; //' -------------------------------------------------------------------------------//' Sql_Monitor is the global monitor for sql-errors //' The SQL_SetError sends the message back to the IceBreak server. //' Then use 'GetLastError' to display the formatted error message //' -------------------------------------------------------------------------------Begsr Sql_Monitor; select; when SqlCode = 0; when SqlCode = 100; other; SQL_SetError(SqlCode:SqlErm); %> <% Endsl; EndSr; Show the sample System & Method A/S Run the sample 110 5.3 IceBreak SQL to the ResponseObject SQL: You can use the Structured Query Language - SQL in several ways in IceBreak. The classic way is to incorporate embedded-SQL into your code with Embedded SQL. But IceBreak also lets you use SQL-result sets directly in your application. IceBreak has two build-in functions that return either a HTML-table or a complete XML document directly into your response object. SQL to a HTML-table If you just want to list the content of a SQL select statement (the result set) , then the SQL_Execute_HTML build-in function is the easiest way to incorporate database information into your application. This function formats the data values in respect to the data types in the result set. The result is placed directly in the response-object just where the function is executed: <% D*Name++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ D Error s N D SqlCmd s 1024 varying D MaxRows s 10i 0 /free %> <% *inlr SqlCmd MaxRows Error = = = = *on; 'Select * from product'; 1000; SQL_Execute_HTML(sqlcmd : maxrows); if (Error); %> <% = getLastError('*MSGTXT') %>
<% = getLastError('*HELP') %><% endif; %> Show the sample Run the sample The SQL_Execute_HTML build-in function returns logical *ON if an error occurs, which sets the "LastError" property. You can then retrieve the last error with GetLastError('*MSGTXT | *HELP | *MSGID') which returns the last error in a string. The SqlCmd parameter can be any SQL select statement up to 32760 bytes long. The MaxRows parameter determines the maximum number of rows allowed in the result set. System & Method A/S SQL 111 SQL to a XML-document The SQL_Execute_XML build-in function returns the root element of an XML-document called . Each row of the result set is called and has an attribute named after the SQL column name. However, you have to fill in the XML header with the version 1.0 and the encoding type of your choice - i. e. combine this function with SetContentType() . And ofcause you can append a formatting style sheet that reformats the XML into a XHTML document or what ever. The result is placed directly in the response-object just where the function is executed: <% D*Name++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ D Error s N D SqlCmd s 1024 varying D MaxRows s 10i 0 /free SetContentType ('application/xml; charset=windows-1252'); %> <% *inlr = *on; SqlCmd = 'Select * from product'; MaxRows = 10000; Error = SQL_Execute_XML(sqlcmd : maxrows); if (Error); %><% endif; %> Show the sample Run the sample The SQL_Execute_XML build-in function returns logical *ON if an error occurs, which sets the "LastError" property. You can then retrieve the last error with GetLastError('*MSGTXT | *HELP | *MSGID') which returns the last error in a string. The SqlCmd parameter can be any SQL select statement up to 32760 bytes long. The MaxRows parameter determines the maximum number of rows allowed in the result set. SQL to any custom format The SQL_Execute_Callback build-in function calls your own custom function which makes you able to build any kind of output; from JSON to CSV etc. Basically it works as the above but you parse it your own function which is called for each cell in the result set -including the header. The following sample creates a simple HTML list: System & Method A/S 112 IceBreak <% /include qasphdr,sqlvar d*Name++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ d Error s N d SqlCmd s 1024 varying d FromRow s 10i 0 d MaxRows s 10i 0 d RenderCell d CellValue d Row d OfRows d Col d OfCols d SqlVar pr 10i 4096 10i 10i 10i 10i 0 0 0 0 0 varying value value value value likeds(I_sqlvar) /free %> <% SqlCmd = 'Select * ' + 'from product ' + 'order by MANUID'; FromRow = 1; maxRows = 10000; SQL_Execute_CallBack( SqlCmd: FromRow: MaxRows: %paddr(RenderCell) ); //' //' //' //' The Select * from ... From row number in the result set where 1 is the first Maximum number of rows returned in the resultset Custom Cell rendering call-back function *inrt = *on; %> <% /end-free //' -----------------------------------------------------------------------------------------//' The "RenderCell" is called for each cell in the result set //' -----------------------------------------------------------------------------------------p*name++++++++++..b...................keywords+++++++++++++++++++++++++++++comments++++++ ++++++ p RenderCell B d PI 10i 0 d CellValue 4096 varying d Row 10i 0 value d Rows 10i 0 value d Col 10i 0 value d Cols 10i 0 value d SqlVar likeds(I_sqlvar) /free Select; System & Method A/S SQL 113 //' Row zero i the header only When ( row = 0); if (col = 1); %>

Number of rows in the result set: <%= %char(Rows) %>

<% endif; %><% if (col = cols); %><% endif; //' Row one and abowe is cell data from the result set When ( row >= 1); if (col = 1); //' First coloumn %><% endif; %><% if (col = cols); //' Last coloumn %><% endif; //' Row -1 indicates that is an EOF indications - no data is returned. This event always comes once as the last event When ( row = -1); %>
<% = sqlVar.SqlName %>
<% = CellValue %>
<% Endsl; //' Return I_CONTINUE as long a you want to iterate. If you want to break the loop then return I_BREAK return I_CONTINUE; /end-free p RenderCell %> Show the sample e Run the sample The SQL_Execute_Callback build-in function returns logical *ON if an error occurs, which sets the "LastError" property. You can then retrieve the last error with GetLastError('*MSGTXT | *HELP | *MSGID') which returns the last error in a string. The SqlCmd parameter can be any SQL select statement up to 32760 bytes long. The FromRow parameter is the starting row you want to retrieve from the result set. This makes it perfect to scroll through a dataset with a paging logic. The MaxRows parameter determines the maximum number of rows you will have returned on each subsequent call. The Callback is the procedure address of your cell function. Initially it is call with just the header with the row value of zero. Each subsequent call returns the relative row number in the sub-result-set. Finally you receive a value of -1 which is the EOF indication that allows you to mach up the final response. System & Method A/S 114 IceBreak The SQLVAR template structure is defined in the QASPHDR file and is received with appropriate value for the actual cell. The cell value is formatted to a default string, but you have access to the binary data from with in the SQLVAR structure along with the database data type. Advanced use of the SQL_Execute_Callback() Suppose you want to produce an Excel spread sheet on the fly base on XML and all data is loaded using SQL. In that case SQL_Execute_Callback() build-in function is perfect. This solution has two components: · A XML template file · The ASPX source using SQL_Execute_Callback() First let's take a look at the XML template. This template is produced by saving a spreadsheet from Excel in XML format. Then we have modified all dynamic data to be referred to by static include and tag names. 11.8132 10995 21360 0 645 False False 11 System & Method A/S SQL 115 %>!R1C1:R<%= %char <% = sqlHdr(i).sqlColName %>< NamedCell ss:Name="_FilterDatabase"/> <% = CellValue %>
1 R1C1:R<%= %char(Rows+1) %>C<%= %char(Cols) %> False False
System & Method A/S 116 IceBreak <%= SheetName %>!R2C1:R<%= %char(Rows+1) %>C<%= %char(Cols) %> R1C1 True /resultset/row RC[<%= %char(i-1) %>] @<% = sqlHdr(i).SqlColName %> <% = type %> None
This is a bit long, however that is required to make a XML list in Excel. Please note that the template is prepared for static include so RPG variables and buldings are used in the template Now let's have a look at the ASPX code. <% /include qasphdr,sqlvar d*Name++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ d Sql_Cmd s 1024 varying D D d d d d D D d start limit sheetname style type q i len SqlHdr s s s s s s s s ds 10i 10i 32 16 32 1 10i 10i d RenderCell d CellValue d Row d Rows d Col d Cols d SqlVar pr n 4096 10i 10i 10i 10i d CallbackHead d Cols d SqlHdr pr 0 0 varying varying varying inz('''') 0 0 dim(200) likeds(I_sqlHdr) 0 0 0 0 varying value value value value likeds(I_sqlvar) 10i 0 value dim(200) likeds(I_sqlHdr) /free //' -----------------------------------------------------------------------------------------//' Mainline //' ------------------------------------------------------------------------------------------ System & Method A/S SQL 117 //' These 3 lines causes: //' 1) Excel to open it //' 2) prompt for a download //' 3) Keep the temporary file to stay in the cache until excell has it open SetContentType('application/vnd.ms-excel; charset=utf-8'); SetHeader ('content-disposition' : 'attachment; filename=AnXMLexcelList.xls'); SetCacheTimeout(10); sheetname = 'Sheet1'; start = 1; limit = 99999; //' allways all !!! Sql_Cmd = 'Select * ' + 'from product '; SQL_Execute_Header( sql_cmd: %paddr(CallbackHead) ); SQL_Execute_CallBack( sql_cmd: Start: Limit: %paddr(RenderCell) ); *inrt = *on; //' //' //' //' The Select * from ... From row number in the result set where 1 is the first Maximum number of rows returned in the resultset Custom Cell rendering call-back function /end-free //' -----------------------------------------------------------------------------------------//' This is called once when the coloumn names are ready //' we only copy the header array to a global array for later use //' -----------------------------------------------------------------------------------------p*name++++++++++..b...................keywords+++++++++++++++++++++++++++++comments++++++ ++++++ p CallbackHead B d PI d Cols 10i 0 value d Sql_Hdr dim(200) likeds(I_sqlHdr) d i s 10i 0 d comma s 1 varying /free SqlHdr = Sql_Hdr; /end-free p CallbackHead E //' -----------------------------------------------------------------------------------------//' The renderCell is called for each cell in the result set. here we produce the complete XML //' -----------------------------------------------------------------------------------------p*name++++++++++..b...................keywords+++++++++++++++++++++++++++++comments++++++ ++++++ p RenderCell B d PI N d CellValue 4096 varying d Row 10i 0 value d Rows 10i 0 value d Col 10i 0 value d Cols 10i 0 value d SqlVar likeds(I_sqlvar) System & Method A/S 118 IceBreak /free //' Row zero is the header only. from row = 1 etc it also contains data //' So we build the initial XML stuff when the first column is detected if (row = 0 and col = 1); %><% for i = 1 to cols; len = %len(%trim(sqlHdr(i).sqlColName)) * 4; if ( sqlHdr(i).SqlLen > len) ; len = sqlHdr(i).SqlLen; endif; %><% endfor; %><% for i = 1 to cols; %><% endfor; %><% //' from row = 1 and forward it also contains data from the resultset //' we build each data cell here elseif (row > 0); if (col = 1); %><% endif; select; when sqlHdr(col).SqlType >= 480 and sqlHdr(col).SqlType <= 490; type = 'Number'; style = 's22'; when sqlHdr(col).SqlType >= 491 and sqlHdr(col).SqlType <= 501; type = 'Number'; style = 's22'; other; type = 'String'; style = 's23'; endsl; %><% if (col = cols); %><% //' row -1 is the EOF indication. This event always comes once at last //' here we finalize the XML with all the xPath stuff elseif (row = -1 ); %><% for i = 1 to cols; select; when sqlHdr(i).SqlType >= 480 and sqlHdr(i).SqlType <= 490; type = 'double'; when sqlHdr(i).SqlType >= 491 and sqlHdr(i).SqlType <= 501; type = 'integer'; other; type = 'string'; endsl; %><% endfor; %><% for i = 1 to cols; select; when sqlHdr(i).SqlType >= 480 and sqlHdr(i).SqlType <= 490; type = 'double'; when sqlHdr(i).SqlType >= 491 and sqlHdr(i).SqlType <= 501; type = 'integer'; System & Method A/S SQL 119 other; type = 'string'; endsl; %><% endfor; %><% %><% //' Return *ON as long a you want to itterate. If you want to break the loop then return *OFF return *ON; /end-free p RenderCell Note that the CallbackHead() is using array data structures as parameters. This data type was introduced in i5/OS R5V2M0. This Admin pages can run back to R5V1M0 so you have to copy the source to your own server instance with a target release ar R5V2M0 or above - to try it out. System & Method A/S Part VI XML, Webservices and proxies 6 XML, Webservices and proxies 6.1 WebServices - the easy way 121 WebServices: WebServices is the backbone in Service Oriented Architecture - SOA. IceBreak lets you create SOA complaint WebServices from any RPG service program in few easy steps. · Set the compiler directive type="webservice". · Set the "export" keyword on the function you want to populate. · Use the IceBreak keyword extentions Input, Output or InOut on the parameter list. · Suffix your source file with the .asmx extension. When you refers to the WebService from the Browser URL IceBreak will: · Compile the RPG program into a service program · Create a source file QSOAPHDR with prototypes for your functions, so you can reuse them in a non SOAP environment. · Build the SOAP wrapper functions for your exported functions (They have the same name suffixed by an "_") · Build a WSDL file that describes how to invoke the webservice What is SOAP and WSDL Soap is an XML document that is sent back and forth between the WebService consumer and the WebService provider with the parameters and which function to invoke. The WSDL describes the invocation, functions names and their parameters and types. Now lets se how to create the WebService - step by step.a Create a webservice source Open your favorite editor and paste the following in System & Method A/S 122 IceBreak <%@ language="RPGLE" pgmtype="webservice" %> <% h nomain p*name++++++++++..b...................keywords++++++++++++++++++++++++++comments+++++++++ +++ p Calculator B export d Calculator d x d y d z pi 10i 0 Input 10i 0 Input 10i 0 Output /free z = x + y; /end-free p Calculator %> E This sample takes x and y as input parameters and calculates the sum z. As you can see - it is pretty much a normal service program except for the input/output keywords in the D-Spec. basically it is a normal service program with no mainline. It simply exports a number of procedures. You are not restricted to only one. The following data types are supported: i5/OS type char packed zoned integers float time date timestamp pointer to ILOB WebService type s:string s:decimal s:decimal s:decimal s:decimal s:time s:date s:datetime s:string You can pass "atomic" parameters and arrays. Also, you can pass external described data structures as complex types. Even arrays of externally described structures which becomes arrays of complextypes If you want to pass arrays or data structures, then click here to see howto use arrays in webservices You can use ILOB's to pass large data chunks (12MB) from and to the WebService. Click here to see how to use ILOB's in WebServices Save the WebService System & Method A/S XML, Webservices and proxies 123 Now save the webservice as WebService.asmx in your development server directory. The suffix ASMX is very important, since it causes IceBreak to load the service program and locate the requested WebService functions within. Compile the WebService Simply Refer to the WebService.asmx?WSDL from a browser ... and that's it. The ?WSDL causes the WebService to return its own definition to the rest of the world. If you had made any typos you will see the compilation post list as usual. You are done !! The WebService is ready to use. Use the WebService You can use the WebService from WebSphere or .NET or any other SOA complaint architecture. One easy place is to integrate it into Microsoft office Word or Excel. Here is an Excel example: · · · · Open Excel Click Tools Click Macro Click "Visual Basic Editor" · Click "Tools" · Click "Web Service References" (If it don't show - then download webservices for office tools from System & Method A/S 124 IceBreak Microsoft, it is free) · · · · · · Now click in "WebService URL" Enter the URL to your IceBreak server and the name of the WebService Click "Search" In the right panel your webservice is shown "Check" the "WebService" Click "add" System & Method A/S XML, Webservices and proxies 125 Now all the code needed is created for you now just enter the following macro and you are ready: Sub Calc() Dim Calculator As New clsws_WebService Worksheets(1).Range("C1").Value = _ Calculator.wsm_Calculator( _ Worksheets(1).Range("A1").Value, _ Worksheets(1).Range("B1").Value _ ) End Sub The macro above takes cell A1 and B1 and call the WebService which in turn calculates the sum and place it in cell C1 System & Method A/S 126 6.1.1 IceBreak Using arrays in webservices On the service procedure you can specify the RPG keyword dim() to give an array a dimension. However it is not necessary all elements that is transmitted. To determine the number of elements that is received or sent by the SOAP service, you can call the IceBreak build in function soap_ArrayElements(). Beware that you need to pass the address of the array. if you want to detect the number of elements received: NumberOfReceivedElements = soap_ArrayElements(%addr(InputArray)); if you want to set the number of array element that is returned to the soap client: soap_ArrayElements(%addr(InputArray) : NumberOfElementeToSend); This sample code receives an array of keys. For each key it returns the value fetched from the database in a corresponding output element to the client: <%@ language="RPGLE" pgmtype="webservice" %> <% h nomain fproduct if e k disk p*name++++++++++..b...................keywords++++++++++++++++++++++++++comments++++++++++++ p Products B export d Products d iKeys d oDesc d oPrice d oStockDate pi d i d activeElements /free s s 10i 0 Input dim(1000) 256 Output dim(1000) varying 11 2 Output dim(1000) D Output dim(1000) 10i 0 10i 0 // Store number of elements received activeElements = soap_ArrayElements(%addr(ikeys)); // read each product from the input array of active elements for i = 1 to activeElements; ProdKey = ikeys(i); chain ProdKey ProductR; if %found; oDesc(i) = Desc; oPrice(i) = Price; oStockDate(i) = stockDate; else; oDesc(i) = 'N/A'; oPrice(i) = 0; oStockDate(i) = %date(); endif; endFor; // Set the size of theh output array soap_ArrayElements(%addr(oDesc) soap_ArrayElements(%addr(oPrice) soap_ArrayElements(%addr(oStockDate) /end-free p Products %> to return to the client : activeElements); : activeElements); : activeElements); e System & Method A/S XML, Webservices and proxies 6.1.2 127 Using external described datastructures in webservices SOAP services supports "complext types" which is a collection of atomic fields. This concept maps quite well the the data-structure concept in RPG. However, datastructures in RPG support overlaps, pointers, sub-definitions and other tweaks which are not good pratice in a service oriented architecture. So IceBreak uses the best form the two worlds. By introducing external described data-structures as complex types you will have two fishes in the same catch: Dynamic defined data based on DDS or SQL together with the possibility to expose these structures in WebServices. And you can even make arrays of comples types. Lets have an example: <%@ language="SQLRPGLE" pgmtype="webservice" %><% <% h nomain debug d Product E DS based(prototype_only) qualified /* ----------------------------------------------------------------------------------Get product by a key number and return a complex type ----------------------------------------------------------------------------------- */ p getProductByKey... p b export d pi d iKey 10i 0 input d oProduct output likeds(Product) // Work fields d prodRec ds likeds(Product) /free prodRec.prodKey = iKey; exec sql select * into :prodRec from product where prodKey = :prodRec.prodKey; oProduct = prodRec; /end-free p e The magic begins at : d Product E DS based(prototype_only) qualified This line of code will go to the library and import the definition of "Product" . The "based(prototype_only) " instructs the compiler to not assign any memory to that definition, but rather use the definition as a template. The next magical line is the: d oProduct output likeds(Product) The oProduct output parameter with will have the same fields as the "product E DS" template form above. The "output" instructs the IceBreak pre-compiler to create a SOAP wrapper and build a WSDL definition for all the fields in that data-structure and, as well, include the structure as a "complext type" in the WSDL Now we can use a simple SQL to fetch all the columns in one go. Take a look of the beauty - actually we have no real internal hard-coded definition of data in this little sample. System & Method A/S 128 IceBreak Now lets try this WebService: 1. Save the above code as wscomplex1.asmx on the IFS for any test IceBreak server. 2. Open your browser and refer to the WSDL definition of this service so it compiles - like: http://myIBMi:60000/wscomplex1.asmx?WSDL Now you can see that the externally described structure is expanded in to a complex type in the WSDL. The complex type "product" are used as a return parameter on the SOAP call "getProductByKeyResponse " System & Method A/S XML, Webservices and proxies Let's test the SOAP service: System & Method A/S 129 130 IceBreak Open your SoapUI - if you don't have a copy, then you can download and install it from here: http://sourceforge.net/projects/soapui/ or purchase it from http://www.soapui.org/ Now create an new project: Lets call it "complex" and enter the location of you webservice's WSDL, which is the name of youe service with the amsx extension and WSDL as the URL parameter (query string): Press the "OK" and let Soap-UI build the SOAP interfaces for you. In the "projects" 1. Expand the "getProductByKey". 2. Fill in "100" in the iKey parameter. 3. Now press the green > run button. Now you should see something similar to this: System & Method A/S XML, Webservices and proxies 131 List of complex types Now lets add a new webservice method that returns a list product from a manufacturer. Basically we want to return an array of complex types. And all we need to do is to create a loop on the SQL select statement, so we need a SQL cusrsor. From the webservice perspective, we now need to define the array and this is done by a "dim" option on out output. Add the following getProductForManufact to you code: System & Method A/S 132 IceBreak <%@ language="SQLRPGLE" pgmtype="webservice" %><% <% h nomain debug d Product E DS based(prototype_only) qualified /* ----------------------------------------------------------------------------------Get product by a key number and return a complex type ----------------------------------------------------------------------------------- */ p getProductByKey... p b export d pi d iKey 10i 0 input d oProduct output likeds(Product) // Work fields d prodRec ds likeds(Product) /free prodRec.prodKey = iKey; exec sql select * into :prodRec from product where prodKey = :prodRec.prodKey; oProduct = prodRec; /end-free p e /* ----------------------------------------------------------------------------------Get products by manufacturer and return a list complex type ----------------------------------------------------------------------------------- */ p getProductForManufact... p b d pi d iManuId d oProduct export 20 input varying output likeds(Product) dim(512) colhdg // Work fields d prodList ds likeds(Product) d rows s 10i 0 inz(0) /free exec sql declare c1 cursor for select * from product where manuid = :iManuid; exec sql open c1; exec sql fetch c1 into :prodList; dow sqlcode = 0 and rows < 512; rows = rows +1; oProduct(rows) = prodList; exec sql fetch c1 into :prodList; enddo; exec sql close c1; // This is how many we want to send back to the client soap_ArrayElements(%addr(oProduct): rows); /end-free p e System & Method A/S XML, Webservices and proxies 133 Let's re-create the Soap-UI project and run it: Now we have an array of 512 elements we can return to the client; eact row is produced by a SQL fetch the oProduct is the list we are returning so we finally use the soap_ArrayElements to set the number of active elements in the array - this is managed by the "row" counter. Also notice we want some more advanced names in our SOAP service. So in the "likeds" you provide the "colhdg" IceBreak keyword on your output or input structures. IceBreak will convert the column heading from the externally described file/data-structure to the complex type field names. Internally in you RPG source you just work with the field names of externally described data structure, but from the SOAP service / the clients point of view we are use the coloumnheadings as names. Therefor: Beware the column heading can confirm to valid SOAP-field names, otherwise you client will not be able to consume the WSDL and therefore the SOAP service you are providing. Final note: This sample illustrate how easy you can provide a SOAP web-service using IceBreak and RPGLE. Your WSDL is automatically created, and in this sample you basically have no internal described data. Everything is provided by IBMi data management. In this sample we are only dealing with list of complex types send back to the client, you can however, as easy consume arrays of complex types by replacing the "output" with the "input" or "inout" keyword. 6.2 Using Proxy. Making HTTP request to web servers httpRequest: A proxy is a technique to execute a web-request on another web server. System & Method A/S 134 IceBreak What it does IceBreak has a built-in "virtual browser" so you are able to perform "GET" and "POST" functions in your ASPX program. This allows you to send parameters along the URL and build dynamic form data in the request. It even allows you to include XML data in a SOAP envelope creating web-service applications. How it is done Use the built-in function "httpRequest(..)" to exchange data between your IceBreak ASPX-program and another web server. httpRequest supports both HTTP and HTTPS. When you use HTTPS you will net to set up the certificate store as described in: Setting up HTTPS httpRequest Syntax: error = httpRequest ( ReqUrl: ReqTimeOut: ReqMethod: reqData: reqContentsType: reqXlate: respXlate: respHeader: respBody); Field Name Data type Description The URLinform:"http:// server:port/Resource? parm1=value1&parm2=v alue2" Default You can use both http and https. reqUrl VARCHAR(32768) reqTimeOut INT(5) reqMethod VARCHAR(10) reqData VARCHAR(32768) reqContentsType VARCHAR(256) reqHeader VARCHAR(32768) reqXlate CHAR(15) respXlate CHAR(15) respHeader VARCHAR(32768) respBody VARCHAR(32768) Error boolean If you skip "http://server: port" and use/Resource? parm1=value1&parm2=v alue2 the request with be executed on the current server instance. I.e. "loopback" port. Number of seconds 15 before timing out "POST" or "GET" GET Data in the "form" when none using "POST" The MIME type of the text/html request Additional headers none The Request charset:utf-8 | iso-8859-1 | windows- windows-1252 1252 The Response charset: windows-1252 utf-8 | iso-8859-1 | windows-1252 Output: the http header none from the remote web server response Output: the http body Response object from the remote web server response Returns If an error occurs, this System & Method A/S XML, Webservices and proxies Field Name Data type Description will be set to "TRUE" and you can retrieve the reason with msg = GetLastError() 135 Default Example 1. Include a entire web page directly into your response object: <%@ language="RPGLE" %> <% D Error s N /free // This simply places the result in the response object // using all default parameters Error = httpRequest( 'www.ibm.com/us/' : 30 : 'GET' :*OMIT:*OMIT:*OMIT:*OMIT:*OMIT:*OMIT:*OMIT); if error; %> <% = GetLastError('*MSGID') %> <% = GetLastError('*MSGTXT') %> <% = GetLastError('*HELP') %> <% endif; %> Example 2. This is an equivalent example but sets up all parameters. <%@ language="RPGLE" %> <% D*Name++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ D ReqUrl s 32767 varying The URL in form:"http://server:port/file" D ReqTimeOut s 5I 0 Number of seconds before timing out D ReqType s 10 varying "POST" or "GET" D ReqData s 32767 varying The form data when using "POST" D ReqContentType s 256 varying The MIME type of the request D ReqHeader s 32767 varying Aditional Headers D ReqXlate s 15 The target charset (valid: utf-8 | iso-8859-1 | windows-1252 ) D RespXlate s 15 The charset for the response (valid:utf-8 | iso-8859-1 | windows-1252) D RespHeader s 32767 varying Out: Response Header D RespData s 32767 varying Out: Response Body D Error s N /free // This uses all parameters and returns both the header and body in separate variables System & Method A/S 136 IceBreak Error = httpRequest( 'www.ibm.com/us/': resource" 30: 'GET': '': 'text/html; charset=utf-8': '': 'UTF-8': iso-8859-1 | windows-1252 ) 'UTF-8': (valid:utf-8 | iso-8859-1 | windows-1252) RespHeader: RespData); if error; %> <% = GetLastError('*MSGID') %> <% = GetLastError('*MSGTXT') %> <% = GetLastError('*HELP') %> <% else; responseWrite(RespData); into my response object endif; return; %> Show the sample 6.3 // The URL in form:"http://server:port/ // // // // // // Number of seconds before timing out "POST" or "GET" The formdata when using "POST" The MIME type of the request Extra headers UTF-8 is the target charset (valid: utf-8 | // UTF-8 is the charset for the response // Out: Response Header // Out: Response Body // Just put the response from "www.ibm.com/us/" Run the sample Using the built-in XML Parser on the request object Sample 15: XML contents in a HTTP request is the core of Web-Services used in SOAP. XML is the perfect transportation method of almost any information on the internet. What it does When a client is creating a XML-request object it will always set the content-type header attribute to manage XML, i.e. "text/xml" or "application/xml" or "ms-office/XML". IceBreak will automatically parse the input. How it is done You simply use the built-in function reqXmlGetValue(...) to retrieve data. This function is using the XPath syntax to navigate into the XML-object tree. MyVar = reqXmlGetValue(Path : Defaultvalue); Field Name Data type MyVar VARCHAR(32760) Path CHAR(*) Default CHAR(*) Description The return value of the XML-object This is the path to the XML element or attribute in XPath format Default Any default value if the "path" was not found in System & Method A/S XML, Webservices and proxies Field Name Data type Description the XML-object tree 137 Default XPath XPath is a language for finding information in an XML document. XPath is used to navigate through elements and attributes in an XML document. XPath is a major element in the W3C's XSLT standard. XQuery and XPointer are both built on XPath expressions. Understanding XPath is crucial for working with advanced XML. The XPath is a syntax to navigate into the XML object tree: Path Expression / @ [ubound] [n] Description Location from the root in the XML object tree An attribute value Upper boundary for elemet Subscripting the index of 'n' 0=First, 1=next ... Consider the following XML request:
will give the following result: Path Expression example /Order/Header@Orderno /Order/Header@CustName /Order/Detail/Line[ubound] /Order/Detail/Line[1]@qty Description Returns the attribute "Orderno" in the element "Header" in element 436533 "Order" Returns the attribute "Custname" in the element "Header" in John Doe element "Order" Returns the number of "line" ´s 2 in "detail" in "Order" Returns the attribute "qty" in the second element "line" in "Detail" in 50 "Order" Now let us create a small server: 1. It receives a XML-request ( the layout as above) in charset UTF-8 format System & Method A/S Result 138 IceBreak 2. Parse the XML request 3. Build a HTML response using the values found in the XML request 4. Finaly it sends the response back to the client Let's take a closer look: <%@ language="RPGLE" %> <% *' ------------------------------------------------------------------------------------------*' Web Service server: Parse the XML and return a HTML document *' ------------------------------------------------------------------------------------------- D*Name++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ D path s 1024 varying D NumberOfLines s 5 0 D i s 5 0 /free // Always set the charset before putting data into the response object SetCharset('utf-8'); %>

The XML request was:

<% = GetServerVar('REQUEST_CONTENT') %>

List the Order

Order Number : <% = reqXmlGetValue('/Order/Header@Orderno' : 'No number was given') %>
Customer name: <% = reqXmlGetValue('/Order/Header@CustName' : 'Customer name was not given') %>
Order date : <% = reqXmlGetValue('/Order/Header@Date' : 'No date was not given') %>

<% NumberOfLines = num(reqXmlGetValue('/Order/Detail/Line[ubound]' : '0')); for i = 0 to NumberOfLines - 1; Path = '/Order/Detail/line[' + %char(i) + ']'; %> <% endfor; %>
Line No Item No Description Qty
<% = reqXmlGetValue(Path + '@LineNo' : '0') %> <% = reqXmlGetValue(Path + '@ItemNo' : 'N/A') %> <% = reqXmlGetValue(Path + '@Description' : 'N/A') %> <% = reqXmlGetValue(Path + '@Qty' : '0') %>
<% System & Method A/S XML, Webservices and proxies 139 return; %> But how do you produce a request with a XML content for that server? You might reuse the HTTP-proxy we made in Tutorial 13. It is able to make a HTTP-request with any kind of content, including XML. What the client must do: 1. Set up charset UTF-8 - the default when dealing with XML and webservices. 2. Build a request XML structure. 3. Put it into the request content. 4. Ensure that the "content type" containing xml and charset e.g. "text/xml; charset=utf-8". 5. Execute the HTTP-request. 6. Present the result in the browser. <%@ language="RPGLE" %> <% * ------------------------------------------------------------------------------------------* Send a XML request to the server and then just display the response data * ------------------------------------------------------------------------------------------D*Name++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ D xml s 32767 varying *ON=Convert to response to ebcdic D RespHeader s 32767 varying Out: Response Header D RespData s 32767 varying Out: Response Body D ServerURL s 255 varying The URL to the web service D Error D crlf s c N x'0d25' /free // When dealing with XML and webservices; the preferred charset is UTF-8 // Also - the charset must be selected before anything is placed in the responseobject SetCharset('utf-8'); // Then we build the request XML xml = '' + CRLF + '
' + CRLF + ' ' + CRLF + ' ' + CRLF + ' ' + CRLF + ' ' + CRLF + ''; System & Method A/S 140 IceBreak // I'll run the service on the same IceBreak server instance so we skip the "http:// server:port" // and just go with the resource ServerURL = '/tutorials/ex15Server.asp'; // post the HTTP-request to the server ASP and return both the header and body in separate variables Error = httpRequest( ServerURL: // The URL in form:"http://server:port/ resource" 30: // Number of seconds before timing out 'POST': // "POST" or "GET" xml: // The formdata or xml when using "POST" 'text/xml, charset=utf-8': '': 'utf-8': ISO-8859-1 | windows-1252 ) 'utf-8': (valid: UTF-8 | ISO-8859-1 | windows-1252 RespHeader: RespData); // The MIME type of the request // Extra headers // UTF-8 is the target charset (valid: UTF-8 | // UTF-8 is the charset for the response ) // Out: Response Header // Out: Response Body // Take all the response and send it back to the browser responseWrite(RespData); return;%> Show the sample 6.4 Run the sample Using the built-in XML Parser on a string or stream file XML: Using the built-in XML Parser on stream files or strings The XML parser is also convenient for stream files and strings containing XML-structures. What it does You can parse a stream file or a string containing XML structures by adding an extra prototype to your ASP program, module or service program. The XML parser is a small and fast parser that use the XPath syntax to retrieve XML elements or attributes. How it is done · · · · · First you have to Include the XML-parser portotype into your ASP-source. Then declare a pointer to he XML-tree. Then use the function xml_ParseFile() or xml_ParseString() to process the stream filen or string. Now you can retrieve data in the XML-tree by xml_Getvalue(...). Finally you must reclaim the storage used by the parser with xml_Close(). Let us have a look at an example: <%@ language="RPGLE" %><% System & Method A/S XML, Webservices and proxies 141 /include qasphdr,xmlparser D*Name++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ D xmlPtr s * Pointer to the XML tree D xmlString s 1024 varying XML string to parse D val s 1024 varying temp. value D node s 256 varying temp. value D crlf c x'0d25' the sequence /free %> <% // First build the request XML xmlString = '' + CRLF + '
' + CRLF + ' ' + CRLF + ' ' + CRLF + ' ' + CRLF + ' ' + CRLF + ''; // Just show the XML %>

The XML structrure

<%=xmlString%>

The Result when parsing the XML and finding the values with X-Path

<% // Then Parser the string xmlPtr = XML_ParseString(xmlString:'syntax=LOOSE'); // If the parser is not able to parse the string; then display the error if XML_Error(xmlPtr); %><%= XML_Message(xmlPtr) %><% // Otherwise - the parser ran ok, so we pick the second line description atribute // remember that x-path use [0] as the first index [1] as the next etc... // the 'N/A' is the default value if i can not be found in the XML tree else; node = '/Order/Detail/Line[1]@description'; val = XML_GetValue(xmlPtr:node:'N/A'); %>Node:<%=Node%> has the value of: <%= val %><% endif; XML_Close(xmlPtr); %> <% return; System & Method A/S 142 IceBreak %> Show the sample 6.5 Run the sample ILOB's, httpRequest and XML (SOA components) SOA:: In a Service Oriented Architecture world (SOA) the ability to intercommunicate huge data streams is essential. ILOB's as we saw earlier is a way deal with large data from within a ILE program. This tutorial will show how to use ILOB's and make HTTP request with XML based data stream. Basically we want to send a XML request to a server program and in return receives the XML response. By using ILOB's we are able to break the 32K limit that RPG normally has. The Server program <%@ language="RPGLE" %> <% *' ------------------------------------------------------------------------------------------*' Runs an SQL query for the XML request received *' ------------------------------------------------------------------------------------------D*Name++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ d manufactid s 16 varying D Error s N D SqlCmd s 1024 varying D MaxRows s 10i 0 /free //' The first thing is always to set charset and content type System & Method A/S XML, Webservices and proxies 143 SetContentType ('application/xml; charset=windows-1252'); //' Take the parameter from the XML request manufactid = reqXmlGetValue('/request/manufactid' : ''); //' Build the SQL command sqlcmd = 'select * from product where manuid = ''' +manufactid+ ''''; MaxRows = 10000; //' Now run the SQL query %><% Error = SQL_Execute_XML(sqlcmd : maxrows); if (Error); %><% endif; return; %> 1. The SetContentType() to "application/xml" is essential. We both sends ad receives data in XML format. if IceBreak "see" the /XML in the content type it will automatically run the XML-parser. 2. The xml request is already parsed so we have access to an XML object that IceBreak maintains. Now we can use the X-path syntax to refer to the value of the element "manufactid" in the "request" element. 3. The SQL statement is constructed. Just adding the "where" clause and we are ready to run the SQL. 4. Finally the surroundings for the XML is set up. Note that the encoding tag in the XML header has to be the same as we used in "SetContentType()" 5. SQL_Execute_XML() simply returns the SQL result set as an XML document, which is placed directly in the response object. You can see the number of variables in a program like this i kept to a minimum. All the data manipulation is done behind the scenes in the request and response object. The Client program The client program is a little more sophisticated than the client. It is dealing with the access to the ILOB's and parser directly: <%@ language="RPGLE" %> <% d*' Include the ILOB and xml parser prototypes /include qasphdr,ilob /include qasphdr,xmlparser d*Name++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++++Comments++++++ ++++++ d manufactid s 16 varying d path s 64 varying d Error s N d reqILOB s * d respILOB s * d xmlPtr s * d i s 10i 0 d rows s 10i 0 /free //' Basically this program just toggle between the manufactures manufactid = form('manufactid'); System & Method A/S 144 IceBreak //' The first thing is always to set charset and content type SetContentType ('text/html; charset=windows-1252'); //' First I create my work ILOB's reqILOB = SesGetILOB('request'); request respILOB = SesGetILOB('response'); response from the server // get a pointer to a session ILOB used as my // get a pointer to a session ILOB used for the //' Reset my ilob ILOB_Clear(reqILOB); ILOB_Clear(respILOB); //' Now i want to populate a simple XML request. - my ILOB header need a content type XML //' All httpRequest are routed to the same default job hence the cookie ILOB_SetHeaderBuf( reqILOB : 'Content-Type: application/XML; charset=windows-1252' ); //' I reroute my response object to the request ILOB, so I can use the ASP syntax for creating the XML SetResponseObject(reqILOB); %> <% = manufactid %> <% //' Now i redirect my response back to the default response objet ( what my browser receives > SetResponseObject(*NULL); //' My request is now ready to to to the server, so i call the httpRequest for ILOB's Error = ILOB_httpRequest( '/tutorials/ex24ilobsvr.asp': // The URL in form:"http://server:port/resource" 30: // Number of seconds before timing out 'POST': // The "POST" method reqILOB: // pointer to my Request ILOB RespILOB // pointer to my Response ILOB ); //' Check for errors if error; %><% = GetlastError('*MSGTXT') %><% return; endif; //' My data has arrived - I'll fire up the XML parser xmlPtr = XML_ParseILOB ( //' Returns XML-object tree from an ILOB RespILOB: //' Pointer to an ILOB object 'syntax=loose': //' Parsing options 1252: //' The ccsid of the input ilob (0=current job) 0 //' The ccsid of the XML tree (0=current job) ); //' Check for errors if XML_Error(xmlPtr); %><%= XML_Message(xmlPtr) %><% XML_Close(xmlPtr); return; endif; //' The Result will be a table %>

Products by: <% = manufactid %>

System & Method A/S XML, Webservices and proxies 145
<% //' now print the report rows = num(XML_GetValue(xmlPtr: '/resultset/row[ubound]' for i = 0 to rows -1; path = '/resultset/row[' + %char(i) + ']@'; %><% endfor; %>
Product id Product Description Product Price
<% = XML_GetValue(xmlPtr: path + 'prodid' :'N/A') <% = XML_GetValue(xmlPtr: path + 'desc' :'N/A') <% = XML_GetValue(xmlPtr: path + 'price' :'N/A')
<% :'0')); %> %> %> //' Always release the memory used XML_Close(xmlPtr); return; %> 1. Like the server program we need to set up the contents type. It need to map to the same values as the server. 2. The we create two ILOB's used for request and response 3. The clear of the the Request ILOB is essential. Otherwise data will just append to the ILOB. 4. The ILOB has a header which is used for HTTP communication. You have access to that header by the "ILOB_SetHeaderBuf()". Note that you replaces the complete header by using the method. 5. The "SetResponseObject()" is used to reroute the response data to an ILOB so the data goes to the ILOB and not the normal response object. When you want to switch back, the just call "SetResponseObject()" with a *NULL parameter and you have your normal response object back which goes to your browser. This method can also be applied to creating XML files on the fly by building up the ILOB and the save the ILOB to stream file. 6. Now with the request XML in the "request" ILOB we just runs the "ILOB_httpRequest()" method and receives the "response" ILOB. 7. All the data in the ILOB is in ASCII, so when we fire up the XML parser we have to tell it which ccsid the ILOB is stored in. In this case "windows-1252" maps to "ccsid 1252". 8. Now are finished with the ILOB's the rest of the program just formats the XML tree to the response object that goes to the end-users browser. Here again - like in the server - we are extracting data using the X-Path syntax. 9. Finally always remember to use XML_Close() to free up the memory used by the XML parser. Run the sample System & Method A/S 146 IceBreak System & Method A/S Part VII 148 IceBreak 7 OEM, Bundle IceBreak 7.1 Ship IceBreak allong with your product (COPY) OEM - (Original equipment manufacturer) means the original manufacturer of a component for a product, which may be resold by another company. In the case of IceBreak it means you can put all the IceBreak features into you own software package and ship your package and IceBreak in one go. As an alternative, you can let your customers install IceBreak from the web, and just configure you OEM server ( or servers) once and let your application have control over license authorization. In both cases you have the option to run IceBreak servers in you own subsystem as a part of you own product. Obtain a OEM licence key Before you can make an OEM version of IceBreak you need to contact the IceBreak support team at mailto:support@system-method.com to get a OEM licence key. An OEM licence key let you create a server instance, and run that server from your own subsystem OEM Licence Exit Program You need a OEM licence exit program in you application library that returns your OEM key (or keys) to the IceBreak core. The name of this program is by default SVCOEMEXIT. This can be a simple RPG program or even a CLP as in the following example Pgm Parm(&licXml) /* Simply return the Licence XML string for your product ----------------------------------------------------- */ Dcl &licXml *Char (2048) chgvar &licXml (' ADDICESVR SVRID(MYICEOEM) TEXT('My icebreak oem server') SVRPORT(60006) JOBQ (QSYS/QSYSNOMAX) Now you need to start the servers with STRICEJOBS, this must be done from at batch job either in you own subsystem by a call from a CL-program in i.e. the auto-start-job or you can submit it from the command line - again you can use QSYS/QSYSNOMAX job queue. ===> SBMJOB CMD(STRICEJOBS) JOB(STRMYJOB) JOBQ(QSYS/QSYSNOMAX) Note: Do not try to start the server from with in the WRKICESVR option 12 or the STRICESVR command. Your OEM servers are detached from the normal IceBreak subsystem, so the normal start features does not work as in a plain IceBreak installation. You can however use option 13=End server or ENDICESVR command. Always use the STRICEJOBS for OEM servers. ( This, however, might change in future releases). Now the server is up a running - you can test it by one of the build in servies like SVCLOGON: 1. Open your browser: 2. Enter the URL http://mysystemI:60006/svclogon.aspx Now the default logon icebreak prompt is shown - note: system styiling is not in the default OEM build: System & Method A/S OEM, Bundle IceBreak 151 Finally you can now deploy you application library with IceBreak build in. That is all there is to it. Use Your product with a plain IceBreak installation Your application can coexist with any "nomal" plain IceBreak installation. Even demo and community edition, depending on which OEM licence code for your product you obtain. Normally; if your application just require the IceBreak Runtime, it will be sufficient to just install the newest version from the icebreak download site and configure your server ( which can be done automatically by a CL program in you application package, and the finally start the IceBreak subsystem. You will not need to provide any licence codes for the IceBreak server it self System & Method A/S Part VIII Using JAVA 8 Using JAVA 8.1 Java as the host language 153 If you want to build java web applications then you can choose from many server technologies: Tomcat, WebSphere Glassfish - just to name a few. IceBreak also supports java. But where Tomcat and WebSphere only support java, IceBreak on the other hand runs Java and ILE in the same session. So when do You need to use Java in IceBreak? · If you have mixed environments of ILE and Java. · if you want to use some features that does not exists in ILE / RPG like JDBC to acces SQL databases on remote systems. · If you need high JAVA performance · If you are running on a small system where i.e. WebSphere can not run. · If you want to use open-source java libraries like iText to produce PDF-files, xmlSec to sign XML files etc. How does java work in IceBreak Java for IceBreak is not a "standard" servlet container like Tomcat or websphere, but rather a way to let java use the IceBreak server object model. The layer between your java code and the IceBreak is extremely thin, so you will not have the same performance penalty in IceBreak that you have in a "standard" servlet container on the IBMi. When you establish an IceBreak session it becomes equally available for ILE and java so you can refer to a RPG resource in one httprequest and a java resource in the next with no performance overhead. Your java and RPG session shares the following: · · · · The request object The response object The session with session variables and ILOB's Globals and server-vars. Now lets get stated: Create a java "hello World" in IceBreak 1) Fire up you Java environment of choice: eclipse, NetBeans, WDSc, RDi, IntelliJ - any will do. 2) Now create a new java project. Let's call it "IceBreakTest". Don't create a "Java Web project", since it will be for servlet containers which IceBreak is not. 3) Set environment: The version of java you are using are important.The version you compile to, need to be the same on the target IBMi system. In this sample I will used JDK 1.5. So ensure the you right click on the project the select project properties. Select i.e. JDK 1.5 or JDK 1.6 - just ensure you have the same JDK installed on the IBMi that you are compiling against. But for now select JDK 1.5 System & Method A/S 154 IceBreak 4) Copy and paste the version of IceBreak core integrations classes that matches you environment into your project. You find it on the IFS in the IceBreak core path, where x-x is the java JDK version you are using.. Typically copy it from here: \\myIBMi\IceBreak\java\IceBreak-x-x.jar In eclipse you simply: a) go the the project properties b) click on the "java build path" c) click on "add external JAR" d) Enter the share name to the icebreak-x-x.jar as described above. This jar file contains all the access to the IceBreak core you need. Also you will find the documentation for IceBreak.jar in the IceBreak admin at the "Programmers guide" -> java documentation. Or you can open it from here: \\myIBMi\IceBreak\java\javadoc\index.html Write you java code Now having the IceBreak jar in place you can start using it: 1) Add a package to you project, just callit IceBreakTest like the project. 3) Add a package to you project. Packages means you can have several classes with several methods in one package. IceBreak supports packages. It is a nice way to sperate logic into dedicated source files. 2) Add a class to the package - let's call it "simple". this will produce a source file called simple.java 3) In the source "simple.java" you can add the following code: a) You need to give the name of the package it belongs to: IceBreakTest - was the name b) Now import all the core classes from the IceBreak core: This is done by import icebreak.core.*; c) Add the class body for the simple class like public class simple - it need to be public so the IceBreak core can access is at runtime d) Add a method to the simple class - let call it "sayHey" which will use the request object to get the name and the response object to reply back: package IceBreakTest; import icebreak.core.*; public class simple { public static void sayHey () { String s = qrystr.get("name"); response.write("Hey " + s); System & Method A/S Using JAVA 155 } } ... Not much code required to make a Web applicaitons with Java in IceBreak... :) Compile and deploy "icebreaktest". Click on "make project" and if you had success we are ready to deploy it to the IceBreak server: On the IFS, in the application server "Http root path" you can make a directory called "java", where you can put your applications. For my "systest" server it will be: //myIbmi/www/systest/java In Netbeans you simply copy the complete contents of the "dist" folder from the "NetBeansProject" folder and paste it to the "java" directory described above. In eclipse/WSDc /RDi you export the jar file: 1) 2) 3) 4) 5) 6) Click on properties on the project. click on "export" Select "java"->"JAR file" Click "Next" Select the "export destination" to be the IFS application server path selected in IceBreak Click "Finish" My IFS folder now looks like this: System & Method A/S 156 IceBreak In the application server you need to setup the callspath for your JAVA. The classpath is where IceBreak java searches for your application .JAR file(s): You will have to open the webConfig.xml in your application server "Http root path" - if it does not exists, simply create it, and add the java element: Set the classpath to the complete location of where you did place you application jar file. This is from the IBMi perspective so if you afterwards use the "WRKLNK" command to verify the existence of the file. Note: the classpath can be a list of files. Simply separate the jar files by a : as you will see in the next tutorial. Version: In this sample we use JDK version 1.5 - again this have to match the compiled version from your IDE and you must have this version installed on your IBMi Now save your webConfig.xml. For each time you deploy/recompile you application or change the webConfig.xml you have to reload the IceBreak JVM. Simply restart the IceBreak server from a command line to accomplish this task. ENDICESVR SVRID(SYSTEST) RESTART(*YES) System & Method A/S Using JAVA 157 Run your "Hello world" application. Now You should be good to go. Open you browser. And enter the URL of your application: First: the name or IP-address and the port-number of you IBMi: In my case it is : http://myIBMi:60000/ Next: The package name slash the class name: In my case that is IceBreakTest/simple Now you can access all "public void .. (void)" methods in that class with colon and the method name. Here it is :sayHey Finally - all java need to be suffixed by .java to route the request to the IceBreak JVM So finally my URL looks like: http://myibmi:60000/IceBreakTest/simple:sayHey.java NOTE !! NOTE !!: Beware - Java is case sensitive so now the URL are case sensitive. Everything from the package name and forward need to be in the right upper or lower-case. Let's try the it: Take a look at the code again: We actually supplied the query string as well: so if we give the parameter name=John it will be echoed back. Lets take it for a spin: System & Method A/S 158 IceBreak Nice!! Now we receive a parameter from the URL, parse it into our Java-code and place that in our response. We are golden!! It is important that you always keep the structure of the "Package" / "Class" : "Method" and ensure that you use the same case in all levels. If you fail to do so, you will receive a class not found message: System & Method A/S Using JAVA 8.2 159 Accesing remote data bases with JDBC The main reason for you to use Java in IceBreak is to benefit from all the java libraries you can find out there on the internet. In this tutorial I'll show you how to access a MS SQL server from an IceBreak program. This sample also illustrates the use of properties in the webConfig.xml, classpath lists and more. Creating a JDBC application A Java Data Base Connection can be run against almost any SQL server. From MySql , Oracle, MS SQL to DB/2 on any platform. From tiny devices to mainframes. So lets extend the "IceBreakTest" package from previous tutorial to exploit the benefit of JDBC. Open your IDE of choice, open the previous tutorial and add the following listHtml method to you code: import icebreak.core.*; import java.sql.* ; public class simple { public static void sayHey () { String s = qrystr.get("name"); response.write("Hey " + s); } public static void listHtml() { try { // Load the database driver String driver = System.getProperty("driver"); String connect = "jdbc:sqlserver://DKSRV01;databaseName=Northwind;user=xx;"; String sqlcmd = "Select * from customers"; // Load the database driver and get connection to the database Class.forName(driver) ; Connection conn = DriverManager.getConnection(connect); // Print all warnings for( SQLWarning warn = conn.getWarnings(); warn != null; warn = warn.getNextWarning() ) { response.writeln( "SQL Warning:" ) ; response.writeln( "State : " + warn.getSQLState() ) ; response.writeln( "Message: " + warn.getMessage() ) ; response.writeln( "Error : " + warn.getErrorCode() ) ; } // Get a statement from the connection Statement stmt = conn.createStatement() ; // Execute the query ResultSet rs = stmt.executeQuery( sqlcmd) ; // Loop through the result set response.writeln(""); response.writeln(""); while( rs.next() ) { response.writeln(""); for (int i = 1 ; i <5; i++) { response.write(""); } response.writeln(""); } response.writeln("
"); System & Method A/S 160 IceBreak response.write(rs.getString(i)); response.write("
"); response.writeln(""); // Close the result set, statement and the connection rs.close() ; stmt.close() ; conn.close() ; } catch( SQLException se ) { // Loop through the SQL Exceptions response.writeln( "SQL Exception:" ) ; while( se != null ) { response.writeln( "State : " + se.getSQLState() ) ; response.writeln( "Message: " + se.getMessage() ) ; response.writeln( "Error : " + se.getErrorCode() ) ; se = se.getNextException() ; } } catch( Exception e ) { response.writeln( e.toString() ) ; } } } All the new code is in the listHtml method. Let me go through it step by step: a) The first initialization of the string driver, connect and sqlcmd are simply string constants; // Load the database driver String driver = System.getProperty("driver"); String connect = "jdbc:sqlserver://DKSRV01;databaseName=Northwind;user=xx;"; String sqlcmd = "Select * from customers"; - The driver is the name that implements the JDBC in out case a driver supplied by Micosoft which you can find in the IceBreak core IFS path under /java/lib. The JAR files are discussed later when we talk about the classpath. The name is supplied by the driver attribute from "webConfig.xml", where you also have the classpath. so System.getProperty() returns values from your webConfig.xml, feel free to use that feature. - Connect is the "connection string" where you have the URL to the SQL database server, the name of the database to connect to, and a user name/password. - sqlcmd is just a simple select which resurens alle the rows in the customers database table. b) class.forName loads the implementation of the JDBC, in this case it is the Microsoft driver, which must be found in the class-path, getConnection returns a handle to a logged on database connection ( this might take a little while the first time) // Load the database driver and get connection to the database Class.forName(driver) ; Connection conn = DriverManager.getConnection( connect); c) If an error occurs, we can trap that and print it to the browser screen; Note this is a list and we use the IceBreak response.write to send the response back to the client // Print all warnings for( SQLWarning warn = conn.getWarnings(); warn != null; warn = warn.getNextWarning() ) { response.writeln( "SQL Warning:" ) ; response.writeln( "State : " + warn.getSQLState() ) ; response.writeln( "Message: " + warn.getMessage() ) ; System & Method A/S Using JAVA response.writeln( "Error 161 : " + warn.getErrorCode() ) ; } d) Now we can run the SQL query; and return a resultset into "rs" // Execute the query ResultSet rs = stmt.executeQuery( sqlcmd) ; e) For each row in the resultset we produce at HTML-table row using the icebreak response.write this tutorial just list the five first columns. // Loop through the result set response.writeln(""); response.writeln(""); while( rs.next() ) { response.writeln(""); for (int i = 1 ; i <5; i++) { response.write(""); } response.writeln(""); } response.writeln("
"); response.write(rs.getString(i)); response.write("
"); response.writeln(""); f) After the last row, we do a little cleanup; Close the result set, close the statement and finally close the connection. // Close the result set, statement and the connection rs.close() ; stmt.close() ; conn.close() ; g) Exceptions - First we listen to SQL exceptions; if any occurs we simply list them to the browser screen. } catch( SQLException se ) { // Loop through the SQL Exceptions response.writeln( "SQL Exception:" ) ; while( se != null ) { response.writeln( "State : " + se.getSQLState() ) ; response.writeln( "Message: " + se.getMessage() ) ; response.writeln( "Error : " + se.getErrorCode() ) ; se = se.getNextException() ; } h) More Exceptions - Finally we listen to generic exceptions, if any occurs we simply list them to the browser screen }catch( Exception e ) { response.writeln( e.toString() ) ; } } Now compile the IceBreakTest package again, and re-deploy it to the IBMi - However, we just need to tweak the classpath a bit to let the JVM load the database driver: reopen the webConfig.xml: - Add the MS SQL driver JAR til the classpath: System & Method A/S 162 IceBreak - Add the property driver with the values of "com.microsoft.sqlserver.jdbc.SQLServerDriver", which is used by the Microsoft implementation And remember: For each time you deploy/recompile you application or change the webConfig.xml you have to reload the IceBreak JVM. Simply restart the IceBreak server from a command line to accomplish this task. ENDICESVR SVRID(SYSTEST) RESTART(*YES) Run the report application: Now we need to setup the URL in the browser - First: the name or IP-address and the port-number of you IBMi: In my case it is : http://myIBMi:60000 Next: The package name slash the class name: In my case that is IceBreakTest/simple Now the method prefixed by a colon in this case :listHtml Finally - all java need to be suffixed by .java to route the request to the IceBreak JVM So the URL looks like: http://myibmi:60000/IceBreakTest/simple:listHtml.java Again !! NOTE !! NOTE !!: Beware - Java is case sensitive so part of the URL are case sensitive. Everything from the package name and forward need to be in the right upper or lower-case. If you have done it right, and configured a server in your network to allow JDBC and change the code above accordingly - it will produce the following report: System & Method A/S Using JAVA Amazing ... :) System & Method A/S 163 Part IX Utilities 9 Utilities 9.1 Introduction 165 Utilities: Included in the standard IceBreak installation you will find IceBreak Utility (Services program). The IceBreak Utility (IceUtility) is constantly increased with function useful for IceBreak programmers. This document describe how to use the IceUtility functions and how to bind from you own IceBreak program to the IceUtility service program. All samples in this document are written in IceBreak RPGLE. Why are these utilities not part of the IceBreak core? All functions in the IceUtility is "stand alone" and does not requires the IceBreak core. hence, you can use it to other the web based applications. All functions in the iceBreak core relies on a server instance and the object model around that. 9.1.1 Bind to IceUtility Every time you need to use one or more functions from the IceUtility you must refer to a Bind directory call ICEUTILITY like: H BndDir('ICEUTILITY') 9.1.2 Prototyping You must include member “ICEUTILITY” placed in file “QASPHDR” placed in the IceBreak library for the right prototyping of the functions use by the IceUtility like: /Include qAspHdr,IceUTILITY 9.2 Functions In the following I describe function by function how to use them – normally with a little sample. Legend: · bool => Indicator variable · varying => Variable-Length Character field · * => pointer 9.2.1 Administrator(); Returns *ON if the user has Administrator rights. Sample: If Administrator(); // Do some Administrator stuff Else; System & Method A/S 166 IceBreak // The user is Not an Administrator endif; 9.2.2 Disabled(disable); Returns “disabled=disabled” if disable is *ON Use this function to make it easier to disable input for users depending on RPG fields directly. Sample: If field “MyBool” contains *ON the input field name “MyName” will be disabled and the user will NOT be able to enter data into it. Type="text" name="MyName" value ="<%=MyName %>" 9.2.3 > DropDown(TagName: SqlCmd {:SelectedValue} {: HtmlExtend}); Writes a formatted HTML “select” back to the response object formatted with output from a SQL select command. Parameters: FormName: Form name that can be read with the standard IceBreak Form function. e.g.: Manuid = Form('PRODUCT.MANUID'); Sql command: Enter a Sql command. The Sql output will be placed in the select dropdown list. If you select two or more fields in the select, the first one will be returned as the "key" field eg. System & Method A/S Utilities 167 Check out “/icebreak/Tutorials/ex19.htm” for a demo of the function. 9.2.4 exists(varying); Check IFS and return *ON if found Sample: if (exists('/path/file.ext')); // do some stuff for the STMF endif; 9.2.5 FieldListOpen(Library: File); Open and prepare a list of fields for a database file. Together with FieldListRead() you can generate a list of fields within the first record format for a file. The first parameter must be the library name where the file name from the second parameter is located. Sample: FieldListOpen('MYLIB' : 'MYFILE'); For more samples check out FieldListRead(); 9.2.6 FieldListRead(); Reads a row of data prepared with FieldListOpen(); The function returns its data into a data structure defined as a pointer to it. Sample: This sample opens a file in a library and loops through the “File Field Description” for the file and set the field “myField” to the name of the field name (ffd.fieldName) just read. D pFFD D FFD s ds * likeds(FLDL0100) based(pFFD) if (FieldListOpen(UpperCase(Lib) : UpperCase(File))); pFFD = FieldListRead(); dow (pFFD <> *NULL); myField = ffd.fieldName; pFFD = FieldListRead(); enddo; endif; 9.2.7 LowerCase(varying); Convert and return a string in lowercase. Sample: System & Method A/S 168 IceBreak UserID = LowerCase(UserID); 9.2.8 MemberListOpen(Library: File: Member {:Format} {:OverrideProcessing}); Together with function MemberListRead() it lets you generate a list of member names and descriptive information based on specified selection parameters. The first parameter must be the library name where the file name from the second parameter is located. “Format” is an optional parameter with default set to QUSL0200 “OverrideProcessing” is an optional parameter with default set to *OFF Sample: MemberListOpen('MYLIB': 'MYFILE': 'MYMEMBER); For more samples check out MemberListRead(); For more information see OS/400 API QUSLMBR (http://publib.boulder.ibm.com/IBMi/v5r2/ic2924/index. htm?info/apis/quslmbr.htm) 9.2.9 MemberListRead(); Reads a row of data prepared with MemberListOpen() The function returns its data into a data structure defined as a pointer to it. You must select a structure that fits the chosen format in the MemberListOpen – that is: MBRL0100 Member name use data structure QUSL010000 MBRL0200 Member name and source information use data structure QUSL0200 (Default) For MBRL0310, MBRL0320, MBRL0330 check the description @: http://publib.boulder.ibm.com/IBMi/ v5r2/ic2924/index.htm?info/apis/quslmbr.htm Sample: This sample open and prepare a list of members to be read and sets the field “MyMember” to the member name just read. H BNDDIR('ICEUTILITY') D pML s D ML ds * likeds(QUSL0200) based(pOL) /Include qAspHdr,IceUtility if (MemberListOpen(UpperCase(Lib): UpperCase(File): UpperCase(Member))); pML = MemberListRead(); dow (pML <> *NULL); MyMember = ml.QUSMN01; pML = MemberListRead(); enddo; endif; System & Method A/S Utilities 169 9.2.10 ObjectExists(Library: Object: ObjectType); This function checks object existence and verifies the user's authority to the object before trying to access it. Sample: if (NOT ObjectExists('QSYS': 'MyLib': '*LIB')); // Library MyLib was not found endif; 9.2.11 ObjectListOpen(Library: Object: Type {: Format}); Together with function ObjectListRead() it lets you generate a list of object names and descriptive information based on specified selection parameters. The third optional parameter "Format" may either be a specific object type, or a special value of *ALL. For a complete list of the available object types, see the OS/400 API QUSLOBJ manual. Sample: ObjectListOpen('MYLIB': 'MYFILE': '*FILE')); This sample check for the existing of file MYFILE placed in library MYLIB For more information see OS/400 API QUSLOBJ (http://publib.boulder.ibm.com/IBMi/v5r2/ic2924/index. htm?info/apis/quslobj.htm) “Format” is an optional parameter with default set to OBJL0200 9.2.12 ObjectListRead(); Reads a row of data prepared with ObjectListOpen(); The function returns its data into a data structure defined as a pointer to it. You must select a structure that fits the chosen format in the ObjectListOpen – that is: OBJL0100 OBJL0200 OBJL0300 OBJL0400 OBJL0500 OBJL0600 OBJL0700 Object names (fastest) use data structure QUSL010003 Text description and extended attribute use data structure QUSL020002 (Default) Basic object information use data structure QUSL030000 Creation information use data structure QUSL0400 Save and restore information; journal information use data structure QUSL0500 Usage information use data structure QUSL0600 All object information (slowest) use data structure QUSL0700 Sample: This sample open and prepare a list of objects to be read and sets the field “MyObject” to the object name just read. H BNDDIR(' ICEUTILITY') D pOL s D OL ds * likeds(QUSL020002) based(pOL) /Include qAspHdr,IceUTILITY if (ObjectListOpen(UpperCase(Lib): UpperCase(Obj): UpperCase(Type))); pOL = ObjectListRead(); dow (pOL <> *NULL); MyObject = ol.QUSOBJNU00; pOL = ObjectListRead(); System & Method A/S 170 IceBreak enddo; endif; 9.2.13 ReverseDNSlookup(IP address); Reverse DNS lookup. This function returns the host name for an IP address. Sample: HostName = ReverseDNSlookup ('129.42.16.103'); This HostName will hold 'www.ibm.com' 9.2.14 UpperCase(varying); Convert and return a string in UPPERCASE. Sample: UserID = UpperCase(UserID); 9.2.15 UserExists(UserProfile); Check OS/400 User profile and return *ON if found. Sample 1: bool = UserExists('JOHN'); Sample 2: if UserExists(User); // The User exists else; // The User does not exists endif; 9.3 Samples 9.3.1 DropDown sample This sample shows how to use the DropDown function in an IceBreak RPGLE program. The code is separated in a RPGLE part and a HTML part. The IceBreak pre-compiler collects the needed code into one source code and compile the program (for more information see tutorials/ex01Include. htm). System & Method A/S Utilities 9.3.1.1 171 HTML code System & Method A/S 172 IceBreak 9.3.1.2 RPGLE code <% H DecEdit(*JOBRUN) H BNDDIR('ICEUTILITY') Use correct decimal p F*Filename+IPEASFRlen+LKlen+AIDevice+.Keywords+++++++++++++++++++++++++++++Comments++++++++++++ FPRODUCT uf A E K disk The file beeing maint /Include qAspHdr,IceUtils D*Name++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++++Comments++++++++++++ D Func S 10 Will contian 'OK' whe D Mode S 10 ChangeMode or AddMode D Error S n Error indicator D AlertText S 64 The Alert text to be D showCount S 5 0 Number of times this D ModeText D ChangeMode D AddMode S c c 64 D Class_Key S 64 D System D Program const('UPDATE') const('ADD') The displayed text fo Define constant for C Define constant for A Special behaviour for SDS *PROC The program name /free exsr init; // Select type of logic, when no function then assum get record select; when func = 'OK'; exsr valInput; if Error; exsr InputForm; else; exsr updateDB; endif; other; exsr getRecord; exsr inputForm; // Validate input, if error then return // Show the input form again // update the record // Get the record from the QryStr // Put the input form endsl; exsr exit; // return to the web server and apply the response object // -----------------------------------------------------------------------// get the record. If not exists Jump into create mode... // -----------------------------------------------------------------------//LN01Factor1+++++++Opcode&ExtFactor2+++++++Result++++++++Len++D+HiLoEq....Comments++++++++++++ Begsr getRecord; ProdKey = QryStrNum('PRODKEY'); // Read the key from the URL (e.g. http://myServer/MyPgm?Key= chain(n) ProdKey PRODUCTR; *IN80 = NOT %FOUND; if *in80 = *on; Mode = AddMode; clear PRODUCTR; // Mark for ADD mode // Clear the record format when creating a new record System & Method A/S Utilities else; Mode = ChangeMode; 173 // Mark for UPDATE mode endif; Endsr; // -----------------------------------------------------------------------// Validate input from the form // -----------------------------------------------------------------------Begsr valInput; Error = *off; // No errors yet exsr form2DB; // Move from form to internal fields // Validate input if Mode = AddMode AND ProdKey = 0; SesSetVar('PRODUCT.PRODKEY.error': 'Must be > 0 when creating a record'); Error = *on; endif; // Set error text for the form field in error // Mark for at least one error if ProdID = *blank; SesSetVar('PRODUCT.PRODID.error': 'Required field!'); Error = *on; endif; if Desc = *blank; SesSetVar('PRODUCT.DESC.error': 'Required field!'); Error = *on; endif; endsr; // -----------------------------------------------------------------------// Now add or updates the record // -----------------------------------------------------------------------BegSr updateDB; select; when Mode = ChangeMode; chain ProdKey PRODUCTR; *IN80 = NOT %FOUND; if *in80 = *off; exsr Form2DB; update PRODUCTR; endif; when Mode = AddMode; write PRODUCTR; endsl; // Chain to the record for update // Update fields from form fields into the records fields // Update the record // When add mode // Just write the record, // Include the HTML code for the "GoBack" tag here at compile time */ // %><% showCount = 0; EndSr; // Next show will be the first // -----------------------------------------------------------------------// Form to database for the record // -----------------------------------------------------------------------BegSr Form2db; monitor; PRODKEY PRODID DESC MANUID System & Method A/S = = = = FormNum('PRODUCT.PRODKEY'); Form('PRODUCT.PRODID'); Form('PRODUCT.DESC'); Form('PRODUCT.MANUID'); // Copy numeric data from the form into the // Copy character data from the form into th 174 IceBreak PRICE = FormNum('PRODUCT.PRICE'); STOCKCNT = FormNum('PRODUCT.STOCKCNT'); STOCKDATE = %date(Form('PRODUCT.STOCKDATE')); on-error *all; Error = *on; exsr InputForm; AlertText = 'Error in the form, check ' + 'numeric or date values entered!'; // Include the Alert tag %><% // Error in the form, prepare for re-display exsr Exit; endmon; EndSr; // -----------------------------------------------------------------------// Init set up the HTML header incl. stylesheets and scripts // -----------------------------------------------------------------------Begsr Init; SesClrVar('PRODUCT.*'); // Clear all session vars used as error texts Func = Form('Func'); // The last function used by the user (e.g. pressed OK Mode = Form('Mode'); // AddMode og ChangeMode showCount = FormNum('showCount') + 1; // Count number of times this panel was showed (e.g. w // Include the init tag %><% endsr; // -----------------------------------------------------------------------// Write the input form // -----------------------------------------------------------------------BegSr InputForm; Class_Key = *blank; if Mode = AddMode; ModeText = 'Add a new record'; else; Class_Key = 'PROTECT'; ModeText = 'Change a record'; endif; %><% EndSr; // -----------------------------------------------------------------------// Done // -----------------------------------------------------------------------Begsr exit; // Include the exit part of the HTML code here at compile time */ %><% return; // Return to the browser with the response object build in this program EndSr; // ------------------------------------------------------------------------ System & Method A/S Part X 176 IceBreak 10 Administration menu 10.1 Work with servers This is where you maintain and configure the list of servers instances in your IceBreak sub system. Creating a new server At least you will need to give it a name. By default this name is used as description, rootpath and application library for your new server - more on that later. The server name also is an eye catcher when you look in the iceBreak subsystem. Here you can see two jobs for each server when it is active. Once active job and one spare job (the backup job) which in status lock wait until it is needed - when the application pool is full or if anything happens to the the primary job. Port IceBreak server are listening on one specific port number in the TCP/IP protocol. When you assign port numbers it is recommended that you check the port number and see if it is available. Use the NETSTAT *CNN command and see if your desired port is free for use. One port can only serve one server at the time. You can reuse the port number; however, you have to stop the server on that particular port before you start another. Interface address By default the value *ANY which of cause means that this IceBreak server is listening on all available interfaces. You can see the complete list of interfaces with the command NETSTAT *IFC. If you want to share the same port number between two or more IceBreak server - the just add a dedicated interface giving it a new IP address Mode Where the server is in development mode it will check if the source for each particular application is changed compared to the running compiled version. If so the JIT ( Just-in-time ) compiler will kick in; compile the application and run it. If any kind of types or syntax error was found, the you will be presented the post list of the application. The development mode is only available for Enterprise versions of IceBreak. In "production" mode the JIT process is bypassed and the application will always be executed. The IceBreak PRO server version only allows the production mode, which also ensures the no application hacking can occur - according to SOX. Target release When compile programs the target release of the compiler can be selected with with option. Root path This is the IFS location where all your resources for your applications and web sites "lives". By default the root path will be a subdirectory to the "/www" path also used by the Apache server. This allows you to share resources like .css . gif .html files between IceBreak applications and Apache Web server. Referring to the root path with in applications: The file name and path can be absolute or relative when you build applications i.e. using the ResponseWriteTag(Filename : TagName); This reference is according to the following rule: · /path/filename.ext · ./Filename.ext This absolute from the IFS root This is relative to the Server instance root path System & Method A/S Administration menu · Filename.ext 177 This is relative to the browser relative "refer location" The above applies to application only. From the url to top level root is always the this root path for security reasons. If you want to make applications that serves other directories which is above the root, then make an application that includes this resource. then you have programmatic control over the security. Application library When the JIT compiler kicks in the output will be a genuine I5/OS program object. This program is placed in the application library. Since that is the case and the max length of a object in I5/OS i 10 char. you must ensure that the final object name is unique despite your IFS source is longer or is placed in subdirectories. Default document This is the document or application that is show if the URL to the server is blank. This document or application is also available even if the logon required parameter is set to *YES. Which allows you to build your own log on screen, and secure all resources with in the IceBreak server instance. Default profile Initially when a server instance is running it will run under this particular user profile - this can be overridden at runtime by the logon() build in function. Protocol The protocols available is HTTP and the secure version counterpart HTTPS. By default the more lightweight HTTP is selected, however if you want to make secure solutions like banking software HTTPS is the way to go. Click here to see how to configure HTTPS over SSL. Library list All ILE applications runs with a library list. This tab lets you set up the default library list for your job and the server instance which eventually is the same as you applications. Trace The trace tab gives you the possibility to enter a file name where Incoming requests and out going responses are logged. *NO - no trace is made. *YES will trace the headers. *ALL will trace headers and contents. This generates a huge amount of data so be careful. The TLOG00 database file also contains Trace for header but works as a round robin Certificates When you use the HTTPS protocol as described above , you will need a certificate. Click here to see how to configure HTTPS over SSL. Advanced tab You should normally only change the parameter on the advanced tab after you has consulted an IceBreak service representative. System & Method A/S 178 IceBreak Initial program When the server instance is starting up ( not the job carnation), this optional program is being called. This is convenient to set additional library list here. Job queue By default bot server instance and server job carnation is submitted accordingly to a job description placed with the server name in the application library. However, you can override the value from the job description with this value. Cache timeout This value is placed in all HTTP headers for static contents. When you are in development mode you might want to change this value to zero to avoid any client side caching. This value can be overridden programmatically with the setCacheTimeout(sec); in your application. Value is in seconds. Session timeout The number of minutes a session is maintained after it was detected inactive. ( That is - no server round trips). When this timer expires the ICECORE will remove session related state information, variables, ILOB's. For session stable servers also the session job is terminated causing files being closed, QTEMP library deleted, SQL cursors closed etc. Value is in minutes. Connection timeout The number of seconds IceBreak is maintaining a TCP/IP connection after it was detected inactive. ( That is - no server round trips). When this timer expires the server instance thread that is directly communicating with the client is terminated and resources is released back to the i5/OS. The connection timeout has no impact on the session which will remain "alive" despite the connection is terminated. If the client reconnects, a new server instance thread will be created and reconnected to the session. Value is in seconds. Buffer size The input, output and cookie buffer are only used when the server runs in multi processed mode. Buffers in that particular mode are allocated using teraspaces . The larger buffer the larger foot print. The buffers in other server modes are allocated by ILOB's which again are based on userspaces. Value in in bytes Coded character set ID The CCSID is used when converting back and forth between client codepage and server side codepage which can be ascii, unicode and utf-8 for the client and any EBCDIC for the server side. Also the result from the IceBreak pre-compiler places the code in QASPSRC in the application library. This source file will be created with this CCSID. Default response trimming System & Method A/S Administration menu 179 When IceBreak places dynamic data in the response it will be blank trimmed accordingly to this parameter. See the tutorial. Shared application library Default NO. The application library might also contain additional programs which may not be accessible from the URL. in that case you can change this value to YES, which in turn causes an extra validation of the object - it must reside as a row in the DB/2 table DIR00 within IceBreak core library usually called ICEBREAK. When you use this feature you must provide a deployment feature to update the DIR00 table on the target IceBreak server. This feature is basically used for OEM version of IceBreak. We suggest you keep this value to NO and place your additionally programs in an sperate library which is accessible using the library list. The URL reference will always be calling the application in the application library. Pre-request exit program You can define your own security algorithms for any resource within IceBreak. This optional ASPXprogram is called prior to any content is returned to the client. See the tutorial. Add File Server Share When you select yes, a share to the server root path on the IFS is automatically created. Now you can map this share as a network drive in you Windows (or using SAMBA on Mac and Linux) to edit the source stream file files that eventually makes the website or application. WebService URI When you build webservices, it need to define a URI for you reaource. This is the name that will be statically bound to the web-service. See the tutorial. Days to keep transmission log Each request / response is logged in the DB/2 table TLOG00 in the icebreak core library. Compared to the trace the TLOG00 is in tabular form, which makes it suitable for any network statistics, such as turnaround time and debugging because you can query it with e.g. SQL. Rows from the TLOG00 table will be removed when they are older that this parameter. Session type A session can be maintained either by a cookie - a small token the browser will return to the server for each subsequent request. Or it can be maintained by redirection to a session unique virtual sub-path. pros/cons: · Cookies can be disabled - but session cookies are normally not; · URL session can be bookmarked - but this might not cause a problem for you application. · Cookie-2 is only supported by new (Microsoft) browsers, but can not be disabled. System & Method A/S 180 IceBreak Dispatcher method IceBreak has several modes to dispatch the serving job. Each which has their own benefits - See technical documentation. The short version: · Use MULTITHREAD with pool size set to zero for intranet solutions. · Use MULTITHREAD with pool size arround 5 jobs for internet solution. Multi thread server options The following option are only available for server running with the multi threaded IceBreak core. Heartbeats If you will assure that the IceBreak server core is running you can enter the TCP/IP address of the interface and the frequency you want to ping with a heartbeat. If the heartbeat is not responded - IceBreak will launch a new carnation of the server job, and kill any server job that were suppose to serve. Leave that blank if you have a monitoring system or don't want to take up bandwidth with network pings. Max Sessions per Server job This is the part of IceBreak load balancing. After around 250 concurrent network connections TCP/IP jobs start degrade the performance since the job will be overloaded. If you exceed this parameter value a new instance of the server job will be started, which again is ready for up to 250 concurrent network connections. You can set til value to a lower value on smaller system to gain overall performance for the IceBreak applications on the cost of the total system performance. The math is simple - ex. 2500 concurrent users with the limit set to 250: 2500 / 250 = 10 IceBreak server jobs Max transactions per Server job You can renew the server instance job after a number of transactions to clean up heap/stack - to release memory. 0=No max; the server instance job in never renewed. Max Sockets per Server job Related to max session per server job, this is the actual number of physical connections to clients. if you keep these two values the same then any of the values that is exceed first will cause the new instance to start. Server job run priority The i5/OS job priority for the server instance - the job that is connected to the client. Session job run priority The i5/OS job priority for the session job - the job that is runs the application. System & Method A/S Administration menu 181 Job Pool Size The pool size has only effect for multithreaded job dispatching. This value set equal to zero disables the pool which again runs the server in session stable mode / job persistent mode. This is recommended for intranet applications, since you have a physical job for each client; just like 5250 application. When you change this value to a value above zero this again reflect the number of physical jobs that serve application requests. You can never be assure that any subsequent request from a client will hit the same server instance except when you set the value to on - since there will only one job to serve all request. This can be valuable knowledge when making data-queue like application / web-service like applications. see technical documentation for dispatcher methods. 10.2 SQL prompt Administration Menu: You can can enter any select SQL select statement from this prompt. Other SQL statements like "update" or "delete" are however not allowed for security reasons. Try the prompt In the Administration Menu under the Tool menu you will find the SQL prompt. Try the following SQL statement produces a report over some digital cameras from a demo table: Select * from product order by 1 You can select the output format to be in HTML or XML from the drop down box. Using the output XML in Excel If you right on the XML output, you will find that you can open the result set with Microsoft Excel: Right click and select import. External references to the SQL query You can copy the final URL from the statement to you clip board so you can run the query from out side the the administration menu. System & Method A/S 182 10.3 IceBreak Application wizard The application wizard builds a skeleton program that you can use as a foundation for your own programs You can build your own templates for this application generator if you like. Just save your templates in the IFS path where IceBreak is in stalled. Locate the sub-folder for your programming language: RPG: \IceBreak\Wizards\Templates\RPG COBOL: \IceBreak\Wizards\Templates\COBOL Remember to save your templates before you upgrade IceBreak to a new version. 10.4 Component wizard Like the application wizard, the component wizard generates code. However, it ranges from code snippets to complete programs you can use as foundation for your own application. The component wizard uses a database file or a SQL table / view and generate the code corresponding to you selection it in the dropdown box. The code or code snippet are shown in the text box where from you can select it by clicking the text box and press the key combination
Then you can paste it into you source for your application. 10.5 Sencha Touch Component Wizard The IceBreak Sencha Thouch code generator / component wizard is quite straight forward. After you fire it up, you simply fill in generation parameters and it will produce a directory with j a number of sub directories containing the iPhone / iPad / android application. Basically the application is a HTML5 based web application, however i utilize all the features in HTML5 and / or the web-kit environment allowing a web application to have the same look and feel as a native application, but can be installed and run from the internet directly from your IceBreak Server. The directory also it contains compilation parameter required if you want to create a native handheld application that can be downloaded and installed from Apple AppStore or android market and run totally offline. Prerequsits Before you start you need to download a version of the Senche Touch frame work . The application generator is designed to work with Sencha touch version 2. This however will change over time. For copyrights reason the IceBreak server is not distributed with the Sencha touch frame work, the installation on the other hand i quite easy: 1. Download Sencha touch from http://www.sencha.com/products/touch/download/ 2. Unpack the zip file 3. Place the Sencha Touch directory under the /System/Plugins directory of your IceBreak application server. 4. The "/System/Plugins" directory: Please note that the /System/Plugins directory is a symbolic link and is therefore available in all server instances via the system hive. Also /System/Plugins are left unchanged when you update IceBreak to the next version. The /System/Plugins directory are not changed, deleted or updated by IceBreak, System & Method A/S Administration menu 183 you, however, must have in mind that any changes you apply to /System/Plugins will be propagated to all server instances of IceBreak server on your system. Therefore: Do not delete it!! Also the /System/Plugins directory is perfect for shared resources between IceBreak servers – just to name a few that might interest you: · · · · · · jQuery ExtJs Sencha Touch jQuery Touch DoJo Capuchino Create My First App Now lets fire up the code generator and build out first application: · · · · · Open the IceBreak Adminstration Open the "tool" menu Click on the "Sencha Touch generor" Now you will se the generator wizard: Now lets fill in the wizard form: 1. First the fille in the library and file: Lets use the simple PRODUCT database table which is default available in *LIBL of you IceBreak installation. 2. Select the component type: Now just select the List and edit for application. 3. Select the server where it will be installed and run from: The server need to be in development mode before the wizard successfully can compile the RPGLE-REST service it will create. 4. Enter the name of the "app" this will also be the name of the directory created for you app, so don't enter a name so overwriting existing stuff will occur. Also avoid spaces and hyphens. 5. Enter a a description of the app: This will be the name you see on the iPhone/iPad/Androide desktop menu when you attaché the app tou you home screen – So give it at proper description but not to long – the phone desktop has limited space. Now you are good to go!! Press the "generate" and let the magic begin - it might run for a while. Run my first App Open your iPhone/iPad/androide and open the browser: Enter the url of the application you just made: http://myIBMI:1234/myapp/index.html myIBMI is the ip address or name of you IBM 1234 denotes the port number you already have configured for you IceBreakserver Myappis the exact name of you app you entered in the above opt 4 Index.html is The default document – just use that name for now Now you will see an application similar to this: It has the following features: · It only loads 25 rows from the sever at the time to reduce net workload – this can of cause be changed. But when you page through it loads the 25 etc. · It makes a generic search on all columns in the basing table – this can be modified later · When you click on a row, it brings up a form where you can change the row contents, and update the contents. · You can create new rows in the table · When you swipe down on the first page it will reload the list contents. System & Method A/S 184 IceBreak The application will in all cases be based on the access to a DB/2 database file. So the application generator will build the following components for you: · The Ajax based client code · The REST service – which btw also contains a full-blown web 2.0 CRUD web-desktop application · And IFS folder as a subfolder in you application server root that contains the source to the above. 10.6 Source file browser Since IceBreak applications source is based on IFS stream files you need at too to migrate your legacy code from source physical files. The "source file browser" lets cut and paste from a source physical file member and trim the first six left characters off if you like - not recommended if you are using WDSc, but is useful if you are using i.e. Microsoft Visual Web Developer tool. 10.7 Services Services is a collection of features that enhance the IceBreak server core. Services can be installed as add-on products via framework deployment. 10.7.1 Web TAPI Web TAPI is a service that brings the "telephony API" on the client available for IceBreak applications on system i. This is excellent when you want to build web based call center applications or extend a CRM solution with a "dial customer button". You need to download the "web TAPI client service" to each PC that will be using the feature. You will find the "web TAPI client service" for download at http://icebreak.org/tools.htm 10.7.2 Web printers Web printer is a service that brings clients printers available as output queues on the system i. On the client you have to install the "Web printer client service" which will expose the client connected printers over HTTP. The transmission of data is 128 bit encrypted over a plain HTTP protocol. You will find the "Web printer client service" for download at http://icebreak.org/tools.htm 10.8 Frameworks In IceBreak you can deploy applications as "Frameworks". A framework is a generic for Applications , services, plug-ins and complete solutions. IceBreak frameworks were introduced to help developers deploying their applications and plug-ins to other IceBreak installations. You can use IceBreak frameworks to deploy you own applications or installing IceBreak applications and Plug-ins from the IceBreak community and software vendors. To find new software from the IceBreak community you can System & Method A/S Administration menu 185 visit http://icebreak.org or select “Work with IceBreak Frameworks, Applications and Plug-ins.” from the main IceBreak menu. When you have a server instance with all your own applications, then you can export all its contents both program objects from the application library - along with IFS objects .html, .gif's etc. directly to a stream file on the IFS. Framework files has the extension of .IFW (IceBreak FrameWork). Export a framework: 1. Logon to your IceBreak admin page 2. Click on work with servers 3. Select the server that contains what you want to export 4. Click "Edit server settings" 5. Click "Export as framework" Fill in to export form and press "Export" The Export Server panel are use to prepare and the export of a server as a framework. Product information Indicate the product information's of the server on the target system. Description The default description shown when the end user installs the framework. Vendor The name of the vendor of this framework. Vendor URL Enter a URL to the vendors homepage. Later when the end user are going to install the framework on the target system this link will be active. URL Enter a URL to the products homepage. Later when the end user are going to install the framework on the target system this link will be active. Version The version of the framework can be entered here. You will see that the "file name" will altered automatically including the version entered. IceBreak Server ID This Server ID will be the server ID that the end user will be shown as the default server ID. Port number Use this parameter to specify the default TCP/IP port used for this IceBreak server exported. Application library The default application library name for the target system. Http Root Path The IFS default root path for this framework on the target system. User exit programs on the target installation You can define user exit programs to be called on the target system before and after the installation has occurred. The "before" exit program will be executed as the first process on the target system. The program will be restored into QTEMP and executed from their. The post exit program will be called as the finale step in the installation process. The library QTEMP holds a data area called NEWSERVER with a logical value = '1' if the server was new and was created during System & Method A/S 186 IceBreak the installation process. Sample post exit CL program: /* Post Framework install exit program */ pgm Dcl &NewServer *lgl RtvDtaara Qtemp/NewServer &NewServer if (&NewServer) then(Do) clrpfm GROUP00 monmsg cpf0000 clrpfm QUERY00 monmsg cpf0000 RUNSQL SQLCMD('Insert into GROUP00 ("GROUP", TEXT, + DESC) VALUES(''MYFIRST'', ''My first + group in Inspire'', ''This is My first + group in IceBreak Inspire'')') monmsg cpf0000 enddo else do /* Upgrade */ RunSQL SqlCmd('update query00 set qrytk = rrn(query00) where qrytk = 0') monmsg (sql0000 cpf0000) enddo endpgm Hint! You can retrieve information of the framework just installed by use of the command RTVICESVRA *RECENT. Sample: If you need to know the name of the application library entered by the user under the installation process you can use the following line: RtvIceSvrA SvrId(*Recent) AppLib(&AppLib) The field &Applib will hold the name of the application library just installed into. You can retrieve the following information: Returned SVRID Tcp/Ip Port Tcp/Ip Interface Description Server type Startup type Http Root Path www Default Document Initial Program Initial Program Library Job queue Job queue Library Application Library Shared Application Lib Target release Create Trace file Trace Path Days to keep trans.log Mode Mode as text Log on required Default User profile Cache Timeout (sec.) Session timeout Connection timeout Input buffer sizes Output buffer sizes (10) (5 0) (15) (50) (10) (7) (128) (32) (10) (10) (10) (10) (10) (1) (10) (1) (128) (9 0) (1) (10) (1) (10) (9 0) (9 0) (9 0) (9 0) (9 0) *AUTO, *MANUAL *PROD, *DEVELOP System & Method A/S Administration menu Cookie buffer sizes (9 0) Session type (10) TcpIp Heartbeat address (15) Sec.between Heartbeats (9 0) Max ses. pr Server job (9 0) Max trans.pr Server job (9 0) Max Sockets pr Server job(9 0) Server job priority (2 0) Session job priority (2 0) Job Pool Size (9 0) Coded character set ID (5 0) Protocol (6) Certificate Path & File (128) Certificate Password (32) Prerequest exit program (10) Prerequest exit PGM LIB (10) WebService URI (128) 187 *COOKIE, *URLREDIR, *COOKIE2 0=*CLASS 0=*CLASS 0=*JOBSTABLE *HTTP, *HTTPS What will be saved? · All objects in the application library except the job description named after the IceBreak server ID. · All objects in the IFS root path defined by the ADDICESVR’s keyword HTTPPATH. Including almost all subdirectories. Directory /System and /Exclude will NOT be saved. · The IceBreak server attributes needed for the framework installation program to create the server on the target system. · All the save operations above are collected in one IFS object named by the user. Normally with file extension .ifw (e.g. /IceBreak/FrameWorks/MyFramework.ifw) Note! · The target release will be the same as the one from the IceBreak server being exported. · Object owner of all objects in the http path are changed to QPGMR Universal Framework ID The first time you export a IceBreak server the export feature generates a Universal Framework ID. The Universal Framework ID are used to identify the framework when it is restored on the target system. When using this technique the installation process will be able to update the server next time the vendor releases a new version. Import a framework: 1. Logon to your IceBreak admin page on the target system; 2. Click on Configuration: 3. Click Frameworks The framework installations has three steps: 1. Downloading the IFW file from the IceBreak framework community website to your PC. 2. Uploading the IFW file from your PC to the IFS and register it to IceBreak. 3. Install the IFW file from IFS to a library and server root path, create all stuff needed and start the server. Downloading the IFW file from a website to your PC. · Click on the WEB->PC tab. · Select the framework you want to download · click green download arrow You can skip this first step if you have a local copy of a framework and are locally connected to the system i where IceBreak runs. Uploading the IFW file from your PC to the IFS and register it to IceBreak. System & Method A/S 188 IceBreak Now you have the IFW on your PC: · Click on the PC->IFS tab. · Find the file with “search” · Click “Upload” The IFW deployment file is then registered in the iceBreak server. Install the IFW file from IFS to a library and server root path · Click on the IFS->LIB tab. · Select the framework on the list by clicking the “+” sign · Follow the installation guide The IceBreak Framework Installer are shown with the following information's. Framework ID Enter the ID for the framework ID Port number IceBreak server are listening on one specific port number in the TCP/IP protocol. When you assign port numbers it is recommended that you check the port number and see if it is available. Use the NETSTAT *CNN command and see if your desired port is free for use. One port can only serve one server at the time. You can reuse the port number; however, you have to stop the server on that particular port before you start another. Description Enter the description for the server into this field. Application library name When the JIT compiler kicks in the output will be a genuine I5/OS program object. This program is placed in the application library. Since that is the case and the max length of a object in I5/OS i 10 char. you must ensure that the final object name is unique despite your IFS source is longer or is placed in subdirectories. HTTP IFS path This is the IFS location where all your resources for your applications and web sites "lives". By default the root path will be a subdirectory to the "/www" path also used by the Apache server. This allows you to share resources like .css . gif .html files between IceBreak applications and Apache Web server. Referring to the root path with in applications: The file name and path can be absolute or relative when you build applications i.e. using the ResponseWriteTag(Filename : TagName); This reference is according to the following rule: · /path/filename.ext This absolute from the IFS root · ./Filename.ext This is relative to the Server instance root path · Filename.ext This is relative to the browser relative "refer location" The above applies to application only. From the url to top level root is always the this root path for security reasons. If you want to make applications that serves other directories which is above the root, then make an application that includes this resource. then you have programmatic control over the security. System & Method A/S Administration menu 10.9 189 Display current server This list is all the available server variables and their corresponding values. This is achieved by the buildin function getServerVar(); You can learn how that program is build here: servervars. 10.10 Display current header info The list here is the information sent from you browser to the IceBreak server. Click here to learn more about the HTTP headers within a IceBreak program. 10.11 Display all servers IceBreak can be installed in different libraries on your system i.e. if you want to run it in several versions or if you want a dedicated production / development environment. Each version also gives you a dedicated subsystem along with a dedicated administration. The "Display all servers" gives you a complete list of server on the system despite which library it is configured in. You can sort the on library , port number or server name. A trailing list shows you the libraries that contains IceBreak servers - this includes also products where IceBreak runs as OEM. 10.12 Display joblog IceBreak supports a dedicated i5/OS job for each "browser" job. That means that you also a dedicated joblog for each browser job. This joblog is very convenient when you want to debug an applications. This is where you programs exceptions will be logged. However, when you run the servers with the application pool activated, the joblog gives less meaning since you will not know which job was serving the request - unless you set the pool size to one. 10.13 Display job IceBreak supports a dedicated i5/OS job for each "browser" job. The "display job" feature is very convenient when you want to debug an applications. You can see the current program stack and which files are open etc. However, when you run the servers with the application pool activated, the display job gives less meaning since you will not know which job was serving the request - unless you set the pool size to one. The "Display job" is equivalent to the "DSPJOB" i5/OS command. System & Method A/S 190 IceBreak 10.14 Display trace The trace contains - if activated on the server instance - all HTTP traffic between the client (browser) and the IceBreak server instance. The trace files is located on the IFS as a stream file. 10.15 Authorization This is where you configure the access to the administration menu in IceBreak. The configuration parameters are activated after you restart the server instance. 10.16 Subsystem configuration The behaviour of IceBreak subsystem can be configured here. Autostart the IceBreak subsystem after IPL. If you select this checkbox, an IceBreak auto-start job entry will be added to your controlling subsystem. If you prefer to start IceBreak - i.e. in the QSTRUP program - you can just click "NO" in the check box and use the following code: ICEBREAK/STRICESBS 10.17 Your information The information on this form will be used when you upgrade or register you licence of IceBreak. 10.18 License information Before you can use IceBreak you need a valid licence key. The Licence key can be obtained from the web site www.icebreak.org simply by clicking "order Licence code" from where you can select which service contract you will purchase and which type of IceBreak server you will be using depending on your needs. Shortly after you will receive an e-mail with the Licence key, which you have to enter here before you can use the IceBreak server. The licence key will determine which features will be available in you copy of IceBreak and what kind of service you will expect. 10.19 Build history log Each time a new version or IceBreak is created by IceBreak develop team - they will increment the build number. This log show a historical list of changes and additions to the IceBreak system. The build log is based on the data from the knowledge base which you can find on icebreak.org - and System & Method A/S Administration menu 191 you can post request for enhancements and inform us about bugs. 10.20 Open projects log Open projects log is a list of ongoing projects in the IceBreak community. It covers: · · · · Reported bugs which are not fixed yet Changes New features Enhancements The "open project log" is based on the data from the knowledge base which you can find on icebreak.org - and you can post request for enhancements and inform us about bugs. If you have requests or problems with IceBreak please consult this list before post a new request at icebreak.org. System & Method A/S Part XI Appendix 11 Appendix 11.1 Intergration to BlueSeries 193 Appendix: BluesSeries is a Back office system for mailing, faxing, short messages service and other B2B communication. You can access components in BlueSeries by the BlueSeries Bind-directory and header file. If You utilize the BlueSeries - you need to change the library list for the serverinstance to include the BlueSeries library. BlueSeries has a object model called a "Business Objects" which can be converted from and to XML documents, spool files, TXT files, CSV files and PDF files. You can acces the Business Object with the following: SetXvar Syntax: SetXvar ( Variable : Value ); Field Name Data type Variable VARCHAR(64) Value VARCHAR(256) Description The Name and path to an node in the business Object The value you want to set GetXvar Syntax: Value = GetXvar ( Variable); Field Name Data type Variable VARCHAR(64) Value VARCHAR(256) The Following is updating and retrieve a custom number in the object: System & Method A/S Description The Name and path to an node in the business Object The value you want to set 194 11.2 IceBreak Internal relation between CCSID and encoding schemes Appendix: Encoding ASCII Big5 Big5_HKSCS Big5_Solaris CNS11643 Cp037 Cp273 Cp277 Cp278 Cp280 Cp284 Cp285 Cp297 Cp420 Cp424 Cp437 Cp500 Cp737 Cp775 Cp838 Cp850 Cp852 Cp855 Cp856 Cp857 Cp860 Cp861 Cp862 Cp863 Cp864 Cp865 Cp866 Cp868 Cp869 Cp870 Cp871 Cp874 Cp875 Cp918 Cp921 Cp922 Cp930 Cp933 Cp935 Cp937 Cp939 Cp942 Cp942C Cp943 CCSID Description 367 American Standard Code for Information Interchange 950 8-bit ASCII T-Chinese BIG-5 950 Big5_HKSCS 950 Big5 with seven additional Hanzi ideograph character mappings for the Solaris zh_TW.BIG5 locale 964 Chinese National Character Set for traditional Chinese 037 IBM® EBCDIC US, Canada, Netherlands 273 IBM EBCDIC Germany, Austria 277 IBM EBCDIC Denmark, Norway 278 IBM EBCDIC Finland, Sweden 280 IBM EBCDIC Italy 284 IBM EBCDIC Spanish, Latin America 285 IBM EBCDIC UK 297 IBM EBCDIC France 420 IBM EBCDIC Arabic 424 IBM EBCDIC Hebrew 437 8-bit ASCII US PC 500 IBM EBCDIC International 737 8-bit ASCII Greek MS-DOS 775 8-bit ASCII Baltic MS-DOS 838 IBM EBCDIC Thailand 850 8-bit ASCII Latin-1 Multinational 852 8-bit ASCII Latin-2 855 8-bit ASCII Cyrillic 0 8-bit ASCII Hebrew 857 8-bit ASCII Latin-5 860 8-bit ASCII Portugal 861 8-bit ASCII Iceland 862 8-bit ASCII Hebrew 863 8-bit ASCII Canada 864 8-bit ASCII Arabic 865 8-bit ASCII Denmark, Norway 866 8-bit ASCII Cyrillic 868 8-bit ASCII Urdu 869 8-bit ASCII Greek 870 IBM EBCDIC Latin-2 871 IBM EBCDIC Iceland 874 8-bit ASCII Thailand 875 IBM EBCDIC Greek 918 IBM EBCDIC Urdu 921 8-bit ASCII Baltic 922 8-bit ASCII Estonia 930 IBM EBCDIC Japanese Extended Katakana 933 IBM EBCDIC Korean 935 IBM EBCDIC Simplified Chinese 937 IBM EBCDIC Traditional Chinese 939 IBM EBCDIC Japanese Extended Latin 942 8-bit ASCII Japanese 942 Variant of Cp942 943 Japanese PC data mixed for open env System & Method A/S Appendix Cp943C Cp948 Cp949 Cp949C Cp950 Cp964 Cp970 Cp1006 Cp1025 Cp1026 Cp1046 Cp1097 Cp1098 Cp1112 Cp1122 Cp1123 Cp1124 Cp1140 Cp1141 Cp1142 Cp1143 Cp1144 Cp1145 Cp1146 Cp1147 Cp1148 Cp1149 Cp1250 Cp1251 Cp1252 Cp1253 Cp1254 Cp1255 Cp1256 Cp1257 Cp1258 Cp1381 Cp1383 Cp33722 EUC_CN EUC_JP EUC_JP_LINUX EUC_KR EUC_TW GB2312 GB18030 GBK ISCII91 ISO2022CN ISO2022_CN_CNS ISO2022_CN_GB ISO2022CN_CNS ISO2022CN_GB ISO2022JP ISO2022KR System & Method A/S 943 948 944 949 950 964 970 1006 1025 1026 1046 1097 1098 1112 1122 1123 0 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1250 1251 1252 1253 1254 1255 1256 1257 1251 1381 1383 33722 1383 5050 0 970 964 1381 1392 1386 806 965 965 195 Japanese PC data mixed for open env 8-bit ASCII IBM Traditional Chinese 8-bit ASCII Korean KSC5601 Variant of Cp949 8-bit ASCII T-Chinese BIG-5 EUC Traditional Chinese EUC Korean ISO 8-bit Urdu IBM EBCDIC Cyrillic IBM EBCDIC Turkey 8-bit ASCII Arabic IBM EBCDIC Farsi 8-bit ASCII Farsi IBM EBCDIC Baltic IBM EBCDIC Estonia IBM EBCDIC Ukraine ISO 8-bit Ukraine Variant of Cp037 with Euro character Variant of Cp273 with Euro character Variant of Cp277 with Euro character Variant of Cp278 with Euro character Variant of Cp280 with Euro character Variant of Cp284 with Euro character Variant of Cp285 with Euro character Variant of Cp297 with Euro character Variant of Cp500 with Euro character Variant of Cp871 with Euro character MS-Win Latin-2 MS-Win Cyrillic MS-Win Latin-1 MS-Win Greek MS-Win Turkish MS-Win Hebrew MS-Win Arabic MS-Win Baltic MS-Win Russian 8-bit ASCII S-Chinese GB EUC Simplified Chinese EUC Japanese EUC for Simplified Chinese EUC for Japanese JISX 0201, 0208 , EUC encoding Japanese EUC for Korean EUC for Traditional Chinese 8-bit ASCII S-Chinese GB Simplified Chinese, PRC standard New simplified Chinese 8-bit ASCII 9 ISCII91 encoding of Indic scripts ISO 2022 CN, Chinese (conversion to Unicode only) CNS11643 in ISO 2022 CN form, Traditional Chinese (conversion from Unicode only) 1383 GB2312 in ISO 2022 CN form, Simplified Chinese (conversion from Unicode only) 965 7-bit ASCII for Traditional Chinese 1383 7-bit ASCII for Simplified Chinese 5054 7-bit ASCII for Japanese 25546 7-bit ASCII for Korean 196 IceBreak ISO8859_1 ISO8859_2 ISO8859_3 ISO8859_4 ISO8859_5 ISO8859_6 ISO8859_7 ISO8859_8 ISO8859_9 ISO8859_13 ISO8859_15 ISO8859_15_FDIS ISO-8859-15 JIS0201 JIS0208 JIS0212 JISAutoDetect Johab K018_R KSC5601 MacArabic MacCentralEurope MacCroatian MacCyrillic MacDingbat MacGreek MacHebrew MacIceland MacRoman MacRomania MacSymbol MacThai MacTurkish MacUkraine MS874 MS932 MS936 MS949 MS950 MS950_HKSCS SJIS TIS620 US-ASCII UTF8 UTF-16 UTF-16BE UTF-16LE UTF-8 Unicode UnicodeBig 819 912 0 914 915 1089 813 916 920 0 923 923 923 897 5052 0 0 ISO 8859-1 Latin Alphabet No. 1 ISO 8859-2 ISO Latin-2 ISO 8859-3 ISO Latin-3 ISO 8859-4 ISO Latin-4 ISO 8859-5 ISO Latin-5 ISO 8859-6 ISO Latin-6 (Arabic) ISO 8859-7 ISO Latin-7 (Greek/Latin) ISO 8859-8 ISO Latin-8 (Hebrew) ISO 8859-9 ISO Latin-9 (ECMA-128, Turkey) Latin Alphabet No. 7 ISO8859_15 ISO 8859-15, Latin alphabet No. 9 ISO 8859-15, Latin Alphabet No. 9 Japanese industry standard X0201 Japanese industry standard X0208 Japanese industry standard X0212 Detects and converts from Shift-JIS, EUC-JP, ISO 2022 JP (conversion to Unicode only) 0 Korean composition Hangul encoding (full) 878 Cyrillic 949 8-bit ASCII Korean 1256 Macintosh Arabic 1282 Macintosh Latin-2 1284 Macintosh Croatian 1283 Macintosh Cyrillic 0 Macintosh Dingbat 1280 Macintosh Greek 1255 Macintosh Hebrew 1286 Macintosh Iceland 0 Macintosh Roman 1285 Macintosh Romania 0 Macintosh Symbol 0 Macintosh Thai 1281 Macintosh Turkish 1283 Macintosh Ukraine 874 MS-Win Thailand 943 Windows® Japanese 936 Windows Simplified Chinese 949 Windows Korean 950 Windows Traditional Chinese NA Windows Traditional Chinese with Hong Kong S.A.R. of China extensions 932 8-bit ASCII Japanese 874 Thai industry standard 620 367 American Standard Code for Information Interchange 1208 UTF-8 (IBM CCSID 1208, which is not yet available on the System i5 platform) 1200 Sixteen-bit UCS Transformation Format, byte order identified by an optional byte-order mark 1200 Sixteen-bit Unicode Transformation Format, big-endian byte order 1200 Sixteen-bit Unicode Transformation Format, little-endian byte order 1208 Eight-bit UCS Transformation Format 13488 UNICODE, UCS-2 13488 Same as Unicode System & Method A/S Appendix 11.3 197 Manual Installation If you have problems with the standard installation program for IceBreak you can use the following method to install it manually: Start up the normal installation process as always. Press OK Press the Start and files needed will be unzipped and places in the directory entered into ”Extract to”. After the extract has finished the following panel will show up. Press the Cancel and Yes to leave the installation program. System & Method A/S 198 IceBreak Locate the Directory where you just extracted the installation files to: Copy the “IceBreak.savf” file to a directory in the IFS on the target System. Use Windows explorer or the System & Method A/S Appendix 199 IBMi Navigator. Sign on to a 5250 session and run the following commands as *SECOFR · CPYFRMSTMF FROMSTMF('/Mydir/IceBreak.savf') TOMBR('/qsys.lib/qtemp.lib/IceBreak.file') MBROPT(*REPLACE) · RSTLIB SAVLIB(BLUEICE) DEV(*SAVF) SAVF(QTEMP/ICEBREAK) RSTLIB(INSTBOX) · CHGCMD CMD(INSTBOX/INSTALL) PRDLIB(INSTBOX) If needed you can change the installation parameters, you can do so by change the data area call INSTBOX/INSTALLDFT. The layout of that data area looks like: Pos. Pos. Pos. Pos. Pos. Pos. Pos. 1 length 10 - The IceBreak installation library 11 length 10 – The database library 21 length 128 – The IceBreak root directory 149 length 128 – The ADMIN root directory 278 length 10 – ADMIN server name 288 length 5 – ADMIN port number 293 length 1 – ‘1’ indicate that the IceBreak menu should be duplicated into library QGPL The installation program is now ready to be executed with the following command: · INSTBOX/INSTALL 11.4 Technical decumentations 11.4.1 What is IceBreak IceBreak is a combined HTTP and application server for the Integrated Language Environment (ILE) on the System i platform. The purpose of IceBreak is not to have a cross platform solution but rather an optimized application server that runs even on the smallest System i. IceBreak is written in ILE (C/C++ and CLP) which eliminates any conversion when making procedure calls from the user application into the server core. In addition, because of IceBreak’s “platform System & Method A/S 200 IceBreak dependent” concept, it can utilize MI interface functions, user indexes and user spaces, to gain the most power out of the System i platform. IceBreak is a server platform for bringing the System i native languages RPG, COBOL, CLP, C and C++ to the web. IceBreak is modeled as a web servlet container for the ILE environment that brings you similar functionality to your application as a serverlet container for JAVA like Tomcat or WebSphere. 11.4.2 Application Server Programs as a concept IceBreak is based on the ASPX syntax developed by Microsoft for the .NET framework used in IIS (Internet Information Server) environment. ASPX is also inspired by other environments like JSP (Java Server Pages). The ASPX syntax has two components which consist of the presentation layer and the program logic. You switch between presentation and program logic by escaping back and forth with the <% and %> character sequence. See later in ”ASPX Source Parsing”. The feature of ASPX is the fact that you can isolate the presentation layer form the business logic – providing a Model View Control (MVC) structure on your design. On the other hand, the ASPX approach can also provide the combination ILE logic and the presentation layer which in turn can be a dangerous cocktail. Blending RPG logic with the HTML presentation layer is far from modern design concepts like Model-View-Control (MVC). However IceBreak has enhanced the ASPX syntax to “include” or refer to the presentations logic from the program logic to an external described presentation layer in a separate (X)HTML / XML / JSON file. This is very similar to the way that the ILE developer has used externally described display files for years. ASPX is for the same reason ideal for “quick-and-dirty” solutions and basic educational teaching: System & Method A/S Appendix 201 <%@ language=”RPGLE” %>

Hello world

<% return; %> Ninety percent of Microsoft powered internet solutions are based on ASPX. As a result, there is a large base of ASPX knowledge. Although IceBreak is a dedicated server platform for the System i ILE developers, it has attracted developers from the Microsoft .NET community by redefining RPG as “just another scripting language” for ASPX. 11.4.3 The Object model The host languages in IceBreak are all ILE, namely RPG, COBOL, C and CLP. These languages do not have an object model as we know it from the Object Oriented programming (OOP) world. IceBreak provides an interface so you are able to access the IceBreak object model directly from RPG, COBOL, C and CLP. This is done by processing the .ASPX application source with a precompiler that creates object wrapper functions to the object model. This can only be done by the fact that each object in the model only occurs once so an explicit object reference in not necessary. The object model is hidden from the application; however IceBreak allows the user via an API interface to communicate directly with all objects instantiated by the IceBreak server from within RPG, COBOL, C or CLP. Take a look at the communication flow between the IceBreak server and client web browsers: · The client places a request to the IceBreak server which creates a request object (1) · The request object is processed. Dependent on the content type either the form-parser for HTML or the XML-parser is executed for XML input. · ASPX Program initiates (3). You can retrieve data from the request object (2) and render the response object (5) · You can use imbedded SQL to make database I/O, call legacy code, use IBM API's or call IceBreak API's etc. · The Response object is prepared to the clients codepage and encoding scheme · IceBreak sends the response back to the client (6) The Objects used in the IceBreak server System & Method A/S 202 IceBreak When the client (the browser) requests a (X)HTML document from a web server, it will send a request to the server. The server then receives the response and renders the result in the browser canvas. Let us follow each of these objects involved in the process from the request to the response. 11.4.3.1 The Request Object: The Request object contains all data sent from the client. In the HTTP protocol that is the header and content. The header describes the content which can be either a "Form Object" or an "XML-Object". · · · · · MyVar=QryStr('URLParameter') MyVarNum=QryStrNum('NumericURLParameter') GetHeader(KeyWord) GetHeaderList(Name:Value:'*FIRST' | '*NEXT') Form2Ilob(IlobPtr : ‘FormField’); The Form parser and xml parser are working on the request object: 11.4.3.2 The Form Parser: The Form Parser initiates automatically when it is a HTML Form-object. The following functions are available in your ASPX-program: · Myvar=Form('FormVar'); · MyNumvar=FormNum('FormNumVar'); 11.4.3.3 The Session Object Fact: The Internet is "stateless" and that might be the biggest challenge when migrating existing 5250 applications to browser-based applications. Programs must be designed to process input, produce output, and then terminate. You cannot have open files or static memory between panels. The IceBreak server maintains a session with the client by creating a "session cookie." Even if the client browser is blocking "cookies" a session cookie is normally allowed. Sometimes you have to change the "allow session cookies" flag in the browser for the applications to work correctly. If session cookies are not an option, IceBreak also supports “Session stability by URL redirection.” In this case, the browser is redirected to a specific URL containing a pseudo sub-path which is the session id. Internally this session id can only be requested from the IP address that created the session. The System & Method A/S Appendix 203 session sub-path is purely virtual and is removed from any resource reference by the IceBreak server. Sessions are maintained as long as you want, and you can configure the duration of a session using the WRKICESVR or WRKXSVR command or from IceBreak’s browser ADMIN page. A session has a very small "footprint" and uses little system resources. · · · · · · Session object functions: MyVar = SessGetVar('MyVariable'); MyVarNum = SessGetVarNum('MyNumericVariable'); SessSetVar(''MyVariable'); SessSetVarNum(''MyNumericVariable'); IlobPtr = SessgetILOB(IlobName); 11.4.3.4 The XML parser: The XML parser is invoked automatically when the content in the request is a XML-document. That is when the content-type is set to "text/xml". Now you are ready to access any element or attribute in the request object by the X-Path syntax. Example: · Myvar=XmlGetValue('/element1/element2/element[elementnumber]@anattribute' : 'Defaultvalue'); The Build-in XML parser can also be used directly on stream files, strings and ILOB’s. This is discussed later. 11.4.3.5 The Server Object: The server object contains static server information such as the configuration parameters and dynamic information from the client. Server object functions: · MyVar = GetServerVar('AserverVariable'); · PointerToMyVar = GetServerVarPtr('AserverVariable'); See the appendix I for complete list of header values available. All i5/OS system values are also available by prefixing the system value with "SERVER_SYSVAL_". like: DayOfWeek = GetServerVar('SERVER_SYSVAL_QDAYOFWEEK'); The complete list of system values can be found in the i5/OS command WRKSYSVAL. Here are samples values Server variable Sysval Description Sample Value SERVER_SYSVAL_QDAYOFWEEK QDAYOFWEEK The day of week *THU SERVER_SYSVAL_QTIME 153856763 QTIME The current time 11.4.3.6 The Application Object: One static application object is maintained for each server instance. This object is accessible from all applications running within this server instance. The Application object is thread safe. This is implemented as a UserIndex placed in the application library call “ICEAPPLVAR” System & Method A/S 204 IceBreak Since it is located in the application library, values are available when deployed. Application object functions: · · · · · MyVar = ApplGetVar('MyVariable'); MyVarNum = ApplGetVarNum('MyNumericVariable'); ApplSetVar('MyVariable':’Text’); ApplSetVarNum('MyNumericVariable':1234); ApplClrVar('MyVariable'); 11.4.3.7 The Response Object: The Response object contains all data sent from the server to the client. In HTTP protocol this is the header and content. The header describes the content which can be of any type HTML, XML, GIF, TIF, PDF, etc. This is the place where you render your dynamic output data with the ASPX syntax. When the ASPX program quits, IceBreak sends the response to the client. Response object functions: · · · · · · · · · · · · · · · · · · · ResponseWrite(Value) ResponseWriteNL(Value) ResponseNLWrite(Value) ResponseEncTrim(Value) ResponseWriteILOB(IlobPtr) ResponseWriteLanguageMsg(msgid) ResponseWriteBLOB(LobLocator ) ResponseWriteCLOB(LobLocator ) SetContentType(MimeType) SetCharset(CharSet) AddHeader('Name' : 'Value') SetHeader('Name' : 'Value') Redirect('ToUrl') SetStatus(Code) SetCacheTimeout(Minutes) SetEncodingType(*HTML (default) | *XML | *NONE ) SetMarker (MarkerName : MarkerValue); ParseMarker (); ResponseRelease(); 11.4.3.8 Other function Some of the IceBreak API functions are not related to any object in the object model. They are, however; useful when making web-applications: Miscellaneous atomic function · · · · · · · · · · · · · · MyNum= Num(’12-34/456/789’); SetDecimalPoint ( DecimalPoint ); Fld = UrlDecode ( UrlField ); Fld = UrlEncode ( UrlField ); Ok = PutStreamString ( Filename: Filemode : Value : Xlate ); Ok = GetStreamString (Filename:Value : Offset : Length : Xlate ); Ok = Include (‘FileName ‘); Ok = IncludeUrlEncode(‘FileName’); Trace (‘TraceData’); Mimevar= GetMimeType (‘FileName or extention’ ); SQL_Execute_HTML(Sqlstmt : MaxRows ); SQL_Execute_XML(Sqlstmt : MaxRows ); SQL_Execute_JS(Sqlstmt : MaxRows ); Ok = HttpRequest( ReqUrl:ReqTimeOut:ReqMethod:ReqData:ReqContentType:ReqHeader:eqXlate: RespXl System & Method A/S Appendix 205 11.4.3.9 Internal Large Objects - ILOB's Host languages like RPG and COBOL have a limit in program variable size. IceBreak breaks that limit by utilizing userspaces and associates them to a session. The transfer of data back and forth between Request object or Response object can be done with help from ILOBS. Also SQL CLOBS and BLOBS can be mapped to ILOB’s. Consider a file upload application. When the user hits the “upload” button on a form this data can be placed in an ILOB up to 2Gbytes. This ILOB can now save itself as a stream file. The XML parser can parse it or it can be placed into DB/2 CLOB field. The access to IOB functions are available by including: /include QASPhdr,ilob ILOB Functions: · · · · · · · · · · · · · · · · · IlobPtr = ILOB_OpenPersistant(Library : Name); Ok = ILOB_DeletePersistant(IlobPtr); Ok = ILOB_Read(IlobPtr: String: Offset : Length); Ok = ILOB_ReadNext(IlobPtr: String :Length); Ok = ILOB_Write(IlobPtr : String :Offset); Ok = ILOB_LoadFromBinaryStream (IlobPtr: FileName); Ok = ILOB_LoadFromTextStream (IlobPtr: FileName); Ok = ILOB_SaveToBinaryStream (IlobPtr: FileName); Ok = ILOB_SaveToTextStream(IlobPtr: FileName); Ok = ILOB_Append(IlobPtr : String); Ok = ILOB_Clear (IlobPtr); DataPtr= ILOB_GetDataPtr(IlobPtr); Len = ILOB_GetLength(IlobPtr); ILOB_SetWriteBinary(IlobPtr; *ON|*OFF); ILOB_Close(IlobPtr); ILOB_Ilob2Clob( ClobLocator : IlobPtr : Offset : Length ); ILOB_Clob2Ilob( IlobPtr : ClobLocator : Offset : Length ); ILOB’s are also used for response and request objects in some application server session dispatcher modes (see later) 11.4.4 Creating Application Server Programs (ASPX): When an IceBreak server instance is configured, it is assigned a “root path” in the IFS and a “applications” library. Compiler and recompiles are based on Just-In-Time (JIT) compilation as follows: 1. 2. 3. The “hello.ASPX” applications is placed in the root path. The browser is invoked using an URL that hits the server instance and the hello.ASPX application. For example, http://MySeries:7001/hello.ASPX If the first file extension is “.ASPX” or “.ASMX”, IceBreak will determine if “HELLO” as an program object is in the application library. a. If not, the JIT compiler compiles the hello.ASPX application and runs the program object from the application library b. If the hello.ASPX application exists, the system checks to see if the source has been modified since this object creation timestamp i. If Yes, the JIT compiler re-compiles the hello.ASPX and runs the program object from the application library. ii. If No, the hello.ASPX program object is just run from the application library. If the compiler fails to produce an executable, IceBreak formats the compiler post list to HTML and returns the page to the browser. Since the compile failed, IceBreak does not run the application. If the IceBreak server instance is a “production” instance, it will call the application immediately and System & Method A/S 206 IceBreak ignore the JIT compiler. 11.4.4.1 Compile and run The precompiler looks up the first file extension in build-in MIME table (Physical file MIM00). There are three types of extensions that will trigger a program: .RPGLE .ASPX and .ASMX. The .RPGLE and .ASPX will be compiled into a “plain” *PGM object. The .ASMX is used as WebServices and result in a *SRVPGM (service program). See WebServices later. 11.4.4.2 ASPX program files - Normal web application programs When the precompiler is invoked it goes through the .ASPX source stream file and separates the code and the response object data from each other. The code fragments are left (almost) unchanged but the response data is placed in method call on the response object namely Response.Write(“..”); Since RPG and COBOL do not understand the Response object, it is accessed by the ResponseWrite(“…”); API wrapper function in IceBreak. The new source is placed in a source physical file called “QASPSRC” in the application library with a member name the same as the source stream file (first 10 characters). A program module is then created with the corresponding native CRTRPGMOD, CRTSQLRPG etc. commands depending on the “language=” compiler directive. (see later) The final program is created with the CRTPGM command where the service program SVC200, IceBreak server core, and call back procedures are bound to the final program resulting in the response data being placed as literal constants in the *PGM object. For this reason, the only object required at runtime is the *PGM object and the IceBreak server. 11.4.4.3 ASMX program files - WebServices When the precompiler is invoked it goes through the .ASMX source stream file and separates the code and the response object data from each other. For each procedure a prototype is created and the special parameter keywords “Input”, “Output” or “InOut” are the removed from the procedure interface. The “Input”, “Output” and “InOut” keywords are IceBreak extensions to the parameters in the RPG procedure interface declarations. A Special procedure wrapper is generated that: 1) Calls the X-path functions and pulls all input parameters from the SOAP body. 2) Calls the exported WebServices procedure. 3) Constructs the response XML SOAP document with response.write wrapper calls. This wrapper procedure has the same name as the target procedure suffixed by a “_”. The IceBreak server is calling this wrapper procedure when hit by a WebService request. The new source is placed in a source physical file called “QASPSRC” in the application library with a member name the same as the source stream file (first 10 characters). The procedure headers are placed in a file called “QSOAPHDR” in the application library with a member name the same as the source stream file (first 10 characters). So the WebService can be used as a “normal” service program as well. A WSDL file is produced containing the complete WebService definition for all exported procedures in the RPG program. The name is the same as the .ASMX file but with the .WSDL extension. This file is served when the WebService is called with ?WSDL from and URL like: http://MySeries:7001/MyWebService.ASMX?WSDL A program module is then created with the corresponding native commands such as CRTRPGMOD, CRTSQLRPG etc. depending on the “language=” compiler directive. (See later) System & Method A/S Appendix 207 The final service program is created with the CRTSRVPGM where the service program SVC200, IceBreak server core, and call back procedures are bound to the user written WebService service program. This means that all response data, SOAP header, SOAP body, is actually placed as literal constants in the *SRVPGM object and for that reason the only object required at runtime is the *SRVPGM object and the IceBreak server. IceBreak is dynamic loading, linking and procedure resolving the service program/ procedure containing the webservice to the IceBreak server core at runtime. This is similar to DLL under Windows. WebServices created in this manner can also be accessed by Microsoft DCOM by creating an IceBreak server instance for the same application library with a server type *SVC and installing the IceBreak DCOM proxy on any accessible windows server in the network. I.e. Any System i service program built that way can act as a Microsoft DCOM object. 11.4.4.4 Program activation group When an ASPX program runs, by default it inherits the IceBreak server default activation group. So if the user application terminates uncontrolled, IceBreak is able to recover from that error and send the joblog back to the user. When such error occurs the response status is automatically set to 501 – “Internal server error.” Otherwise the response status is set to 200, which is “OK”. The Status can however be overridden by the SetStatus(); response object function. The server instance program SVC019 is bound to the application server service program SVC200. Also the user application is also bound to SVC200 which makes the call stack very thin. System & Method A/S 208 IceBreak . 11.4.5 Dispatcher methods IceBreak has four different ways to run an application. Each server instance can be configured to run one of these: Dispatcher Method Scalability Design considerations Application isolation Application pooling High Yes – Clearing of fields / resetting files required Low Session persistent process Low None – File pointers / SQL commit boundaries are preserved High Multi process Medium Yes - Session may continue in a new process High Single session High/Low For Debug and data-queue like WebServices Low The one you pick depends on the requirements for your application. 11.4.5.1 Session persistent process Each client request results in one process that remains active until the session times out or is disconnected. The process remains active even if the socket connection is physically terminated. File pointers and variables are preserved when using “return.” The explicit need of interaction with the session object by SessSetVar and sessGetvar is not necessary. System & Method A/S Appendix 209 Session persistent process 11.4.5.2 Application pooling The pool is loaded when the server instance is started, that is the number of pre-established process is started. When the client connects, simple stream files are served by the connection thread. When it is an application, the first available application server instance in the pool receives the request. If none is available a new is started. Programs written for connection pooling have to re-initialize variables and reset file pointers between each request since the client may change for the next request. Explicit need of interaction with the session object by SessSetVar and sessGetvar is required to keep tract of the session. System & Method A/S 210 IceBreak Application pooling 11.4.5.3 Multi Process When the client connects, all requests are served by the application process. This process is alive as long as the socket is connected. The session object, however is maintained until the session times out or the session is disconnected Programs written for “multi process” pooling have to re-initialize variables and reset file pointers between each request since the socket may be closed by network equipment or the browser does not support “keep connection.” Explicit need of interaction with the session object by SessSetVar and sessGetvar is required to keep tract of session. System & Method A/S Appendix 211 Multi process 11.4.5.4 Single Session When the client connects, the connection is established by the dispatcher directly. The dispatcher does not dispatch anything but calls the application directly. This is useful for debugging purposes since the job number does not change for the server. It is also suitable for WebServices that use the “dataqueue” style. The client requests are queued in the socket layer and processed one at a time. File pointers, variables and SQL commit boundaries are preserved but explicit need of interaction with the session object by SessSetVar and sessGetvar is required to keep tract of session. For the same reason you might need to reset file pointer, variables, etc between request depending on the application type. Single session System & Method A/S 212 IceBreak 11.4.6 Programming 11.4.6.1 ASPX File Identification 1. An .ASPX file, like a .JSP file, is a blend of response document in XHTML, XML or HTML and program code. 2. You toggle between ASPX code and render the response document with the escape sequence <% and %>. 3. The ASPX code is inside the escape sequence tags <% and %> and the rendered mode is outside the escape sequence tags. 4. The programming language (script language) can not be determined from the file extension .ASPX. An .ASPX files is interpreted as an XHTML file until the <% %> escape sequence tags are encountered. 5. If the first character of the escape sequence is the @ sign, it is interpreted as a compiler/runtime directive: <%@ language=”RPGLE” %> 6. Each compilation step has its own parameter string: a. SQLOPT – if imbedded SQL is used b. MODOPT – for the CRTxxMOD command c. PGMOPT – for CRTPGM or SRTSRVPGM command 7. If the “language” directive is omitted, the default language is “RPG” 8. Following values are valid for parameter language: a. RPGLE b. SQLRPGLE c. CBLLE d. SQLCBLLE e. CLLE f. CLE g. SQLC 11.4.6.2 ASPX File parsing A simple ASPX program: <%@ language=”RPGLE” %>

Hello world

<% return; %> 1. The parsing starts in render mode but the first character encountered is the <% escape sequence for ASPX code. The first non-blank character is the @ sign which identifies it as a compiler directive. This means that any keyword and value are valid. 2. Next the compiler directive is terminated by the %> escape sequence which puts the code back into render mode. The rest is plain XHTML syntax. 3. On the last line, the <% escape sequence toggles back to ASPX code mode until a %> escape sequence is encountered which ends the ASPX file. System & Method A/S Appendix 213 11.4.6.3 How to place dynamic data at runtime There are two types of variables in IceBreak and the syntax is different. 1. Direct program variables are identified by the “=” sign as the first non-blank character in the ASPX code stream: <% = MyProgramVar %> The value must be in character format so packed, zoned, time and timestamp etc. data types must be cast into character format using the %char() RPG build-in-function. This syntax also applies for return values from function calls. Example: <%@ language=”RPGLE” %>

Hello world. Time is <% = %Char(%TimeStamp()) %>

<% return; %> 2. Marker variables are identified by the "$" sign as the first non-blank character in the ASPX code stream: <% $ MyMarkerVar %> The value must be in character format so packed, zoned, time and timestamp etc. data types must be cast into character format using the %char() RPG build-in-function. Markers are dynamic variables defined and used at runtime. Example: <%@ language=”RPGLE” %> <% SetMarker(‘timeValue’: %Char(%TimeStamp()); %>

Hello world. Time is <%$ timeValue %>

<% return; %> 11.4.6.4 Remarks Remarks can be stated in 3 ways: · If the parser is in ASPX CODE mode and finds a /*, any following code and XHTML is rendered in remark color and not syntax checked until a */ is found again · If the parser is in ASPX CODE mode and finds //, the rest of the line including XHTML is rendered in remark color and not syntax checked. · If the first char in the line is a * or blank + *, the rest of the line including XHTML is rendered in remark color and not syntax checked. Example: <%@ language=”RPGLE” %> System & Method A/S 214 IceBreak

Hello world. Time is <% /* = %Char(%TimeStamp()) */ %>

<% // Now terminate the program Return; %> 11.4.6.5 IceBreak language enhancements There have been a few powerful enhancements made to the ILE languages. These include the following: RPG: · Code is by default in free format if selected on the server instance · Free format code may start in position 1 · Fixed format spec. can start in any position. IceBreak will align the code to column 6. · Block comments start with /* and ending with */ · Keywords “Input”, “output” and “inout” are allowed for procedure interfaces and used with WebSevices. · “Var” macro for building D-spec in free format · SQL can be written from free format even on I5OS/v5.1 like: //' ----------------------------------------------------------------------//' Fetch - is retrieving the next row from the result set //' ----------------------------------------------------------------------Begsr Sql_Fetch; Exec SQL Fetch list into :recds; Exsr Sql_Monitor; Endsr; 11.4.6.6 I18N - internationalization IceBreak supports internationalization (‘I’ + 18 letters + ‘N’). The precompiler searches for the ^ character in XML/HTML/XHTML and .ASPX source. When found, the rest of the string until a “ or an ‘ is found is stored in the I18N_DFT message file in the application library. A string sequence for xhtml/xml/html can be made by encapsulate the text into brackets [ and ]. IceBreak stores the unique message id for that string instead of the text string itself. By creating new message files suffixed by the selected language from the browser, any .ASPX page will select the according language. However, when the message file or message id is not found, the text from the default message file I18N_DFT is displayed i.e if the browser is set to use the following languages: System & Method A/S Appendix 215 That is Danish, then Canadian English and final generic English. The IceBreak will search the messages in the following order: I18N_DA Danish I18N_EN_CA Canadian English I18N_EN generic English I18N_DFT Default language Example: <%@ language=”RPGLE” %> <% //' Translation can occure at paragraphs or any other html/xml tag //' the translation continues until next tag occures ... like: %>

^Text

<% /*' Also Transtaltion can occure at attribute values between ".." and '..'*/ %> <% /*' Finally you can let the translation span over many tags starting with ^[ and end with ] ' however, expantion of ASPX-variavbes are not valid in translation */ %>

^[This text contains bold tag, but i'll like to have it all in the translation messages file]

<% return %> 11.4.6.7 AJAX All server instances have a “/system” directory. This directory includes “ajax.js” which is a simple yet power full AJAX implementation which allows the user to create AJAX applications with a minimum of JavaScript knowledge. This example shows an html file that request “ajaxserver.ASPX” when you click the button: · Line 2 : the AJAX script is loaded; · Line 7 : ASPX program “ajaxServer.ASPX” is called. We want the response in “MyResult” · Line 8 : “MyResult” is the id of an “Div” tag. The inner HTML is replaced asynchronous by the response of “ajaxServer.ASPX” System & Method A/S 216 IceBreak
This is the “ajaxserver.ASPX” that returns a table content depending on the URL parameter. The Ajax will replace the “div” tag with id “myresult” with the result of the ASPX response object which will be a table component. <% F*Filename+IPEASFRlen+LKlen+AIDevice+.Keywords++++++++++++++++++++ +++++++++Comments++++++++ Fproduct1 if e k disk D pmanuid s like(manuid) /free *inlr = *on; pmanuid = qrystr('manuid'); %> <% chain pmanuid productr; dow not %eof(product1) and manuid = pmanuid; %> <% read productr; enddo; %>
<% = prodid %> <% = desc %>
11.4.7 IceBreak Macros IceBreak Macros can be simple macros that just expand at compile time. But macros can also be REXX-scripts which are run at compile time. COBOL: Since COBOL has a poor implementation of user function, macros are used. Macros are one line of code terminated by and “;” . Macros are stored in /system/Macros/macros.xml. End users can write generic macros by adding the macro to this XML file. Example: System & Method A/S Appendix 217 Main section. Do. MyCustNo = Request.Form("CustNo"); Move MyCustNo to CustNo of CustRec. Enddo. exit. This will expand to: Example: Main section. Do. call procedure "Request_Form" using reference MyCustNo content “CustNo” end-call Move MyField to CustNo of CustRec. Enddo. exit. 11.4.7.1 Using the simple macros The IceBreak precompiler predefines the following REXX variables: · $RETURNPARM o The name of the left side parameter used in function like macros: x=MyMacro(). here $RETURNPARM will be "X" · $PARM01 to $PARM99 o The parameter from the macros e.g.: MyMacro(Customer,Item) $PARM01 is "Customer" and $PARM02 is "Item" · $STMTNO o The ASPX-Source statement where the macro was found · $FILENAME o The ASPX-Source filename 11.4.7.2 Using script macros Script Macros are expanded into the ASPX-source by using "expand" IceBreak-REXX-build-in-function”. The IceBreak precompiler predefines the following REXX variables: · RETURNPARM o The name of the left side parameter used in function like macros: x=MyMacro(). here RETURNPARM will be "X" · PARM01 to PARM99 o The parameter from the macros e.g.: MyMacro(Customer,Item) PARM01 is "Customer" and System & Method A/S 218 IceBreak PARM02 is "Item" · STMTNO o The ASPX-Source statement where the macro was found · FILENAME o The ASPX-Source filename When using if/while comparison always embed the script in CDATA tags to avoid XML misinterpretation. Syntax The generic syntax of the macro is: returnparm = macroname(parm01, parm02 , parm03 ... parm99); where ";" is the macro identifier Macros are NOT case sensitive. All programming languages have a separate pool of macros. However SQL versions of the language shares the same pool as their host language. A "Macroidentifier" can be specific for each language. The "Macroidentifier" must be one char that is unique and not used in the language context. 11.4.7.3 Macro list Default Macro definitions. call procedure "Request_Form" using reference $RETURNPARM content $PARM01 end-call call procedure "Request_FormNum" using reference IcebreakFloat content $PARM01 end-call move IcebreakFloat to $RETURNPARM call procedure "Request_QueryString" using reference $RETURNPARM System & Method A/S Appendix content end-call 219 $PARM01 call procedure "Request_QueryStringNum" using reference IcebreakFloat content $PARM01 end-call move IcebreakFloat to $RETURNPARM call procedure "Response_Include" using reference $RETURNPARM content $PARM01 end-call call procedure "SetNoHeader" end-call call procedure "Response_Write" using content $PARM01 end-call move $PARM01 to IceBreakVarCharString move 16 to IceBreakVarCharLen call procedure "SetCharset" using IceBreakVarChar end-call expand(' call procedure "Request_FormNum" using'); expand(' reference IcebreakFloat'); expand(' content ' PARM01); expand(' end-call'); expand(' move IcebreakFloat to ' RETURNPARM); System & Method A/S 220 IceBreak 11.4.8 Security Considerations in IceBreak There are basically 3 ways you can present IceBreak applications to the WEB. What solution to select, is a normally a matter of company policy in relation to security issues. 1) The application has direct access to the WEB 2) The application will communicate through an Apache Server (Internal or External) 3) The application will communicate through a Secure Web server Confidentiality is a major goal in security. Using encryption functions, such as Secure Sockets Layer (SSL), you can ensure that network traffic cannot be read by an unauthorized user while in transit. See 7.4 11.4.8.1 Direct Access Considerations All networked systems should be secured to control remote access - Access to IFS Telnet FTP ODBC/JDBC Remote commands · Standard I5/OS (OS/400) security features can be used · IceBreak provides user log on features · All jobs in the session then run under the signed on user's profile allowing standard i5/OS (OS/400) security features to apply · Dynamic menus with options dependent upon the logged on user can be devised · ASPX programs run on the server, not in the browser · Access to data is controlled by ASPX program · End users do not have direct access to data on the server · Only the HTML created by the ASPX program is sent to the browser, users cannot see the program code, file names, or other elements of the business · Compiled objects on the IBMi cannot be manipulated. System & Method A/S Appendix 221 11.4.8.2 Apache Server The application can communicate through an Apache Server (Internal or External) Secure your IceBreak application by use of the well proven Apache Technology. IBM® embraced the widely popular open-source Apache server several years ago as the Hypertext Transfer Protocol (HTTP) server of choice for its Web products. The foundation of any On Demand Business application is the Web server, and IBM has made a significant investment in Apache to be that foundation. The broad investment in Apache across IBM's product offerings allows Web developers to leverage existing Apache skills and software to build applications for commercial use. This does also apply for IceBreak Considerations See the IBM Redbook: http://www.redbooks.ibm.com/redbooks/pdfs/sg246716.pdf System & Method A/S 222 IceBreak 11.4.8.3 Secure Web Server Communicate through a Secure Web server. Set up a server on the Web that supports one or more of the major security protocols such as SSL, HTTPS and PCT. This means that e.g. order form data from your browser is encrypted before being sent (uploaded) to the Web site, making it extremely difficult for a third party to decipher credit card numbers and other sensitive data that it might fraudulently capture. Considerations: See the IBM Redbook: http://www.redbooks.ibm.com/redbooks/pdfs/sg246716.pdf 11.4.8.4 Secure Sockets Layer (SSL) Confidentiality is a major goal in security. Using encryption functions, such as Secure Sockets Layer (SSL), you can ensure that network traffic cannot be read by an unauthorized user while in transit. SSL is widely used to do two things: to validate the identity of a Web site and to create an encrypted connection for sending credit card and other personal data. Look for a lock icon at the bottom of your browser when you order merchandise on the Web. If the lock is closed, you are on a secure SSL. System & Method A/S Appendix 223 HTTPS and Port Number 443 An SSL session is started by sending a request to the Web server with an HTTPS prefix in the URL, which causes port number 443 to be placed into the packets. Port 443 is the number assigned to the SSL application on the server. The Handshake After the two sides acknowledge each other, the browser sends the server a list of algorithms it supports, and the server responds with its choice and a signed digital certificate. From an internal list of certificate authorities (CAs) and their public keys, the browser uses the appropriate public key to validate the signed certificate. Both sides also send each other random numbers. Contact you local dealer for more details on certificates. Data for Secret Keys Is Passed The browser extracts the public key of the Web site from the server's certificate and uses it to encrypt a pre-master key and send it to the server. At each end, the client and server independently use the pre-master key and random numbers passed earlier to generate the secret keys used to encrypt and decrypt the rest of the session. System & Method A/S 224 IceBreak Appendix I – Server variables available. Server variable Description Sample Value SERVER_SOFTWARE The name and version of the running server IceBreak/V1R11BLD008 1 SERVER_ID Name of current server instance ICEUDV SERVER_DESCRIPTION Description of the server instance Test for pre installation SERVER_LOCAL_PORT The TCP/IP port number (from 1 to 65535) where the server is polling for requests 60001 SERVER_INTERFACE The TCP/IP interface where the server is listening for requests. (Interface created by OS/400 command ADDTCPIFC) *ANY SERVER_JOB_NAME The underlying OS/400 job name FAXUDV SERVER_JOB_USER The underlying OS/400 job user name (not the active user) IB SERVER_JOB_NUMBER The underlying OS/400 job internal job number 509556 SERVER_JOB_MODE The state of the server: "*PROD" or "*DEVELOP" *DEVELOP SERVER_LOGON_REQUIRED An authentication prompt is automatically displayed when the user request the page and are "unknown" (Not available yet) *NO SERVER_STARTUP_TYPE Whether the server should start when the subsystem is activated or must be started by STRICESVR or STRXSVR *AUTO SERVER_DEFAULT_USERPRO FILE The user profile used when starting a server instance process IB SERVER_ROOT_PATH The IFS path used for web document. This can not be relative but is fixed to the IFS-root /www/Icebreak SERVER_DFT_DOC The web document displayed when no specific document is requested. This is relative to the SERVER_ROOT_PATH Index.ASPX SERVER_CACHE_TIMEOUT Number of seconds before a document expires. 0=immediately. Servers in *DEVELOP mode always overrides this value to 0 so the cache always is refreshed 240 SERVER_INPUT_BUFFER_SIZ E Number of bytes in the input buffer (the Request Object). When zero a default of 1Mbytes is used 0 SERVER_OUTPUT_BUFFER_S IZE Number of bytes in the output buffer (the Response Object). When zero a default of 1Mbytes is used 0 SERVER_COOKIE_BUFFER_S IZE Number of bytes in the output buffer (the Response Object). When zero a default of 64Kbytes is used 0 SERVER_INITIAL_PGM_NAM E Name of program to set extra libray list etc. It is called when the server instance is initiate - Not each time a new client connects or *NONE SERVER_INITIAL_PGM_LIB Name of library where the initial program exists SERVER_JOBQ_NAME The jobqueue from where the server System & Method A/S Appendix Server variable Description 225 Sample Value process is started SERVER_JOBQ_LIB Name of library where the jobqueue exists" SERVER_APPLICATION_LIB This is where all your ASPX-programs are placed when they are compiled. This is where the QASPSRC file is created with your precompiled ASPX-program sources ICEDEV SERVER_TGTRLS OS/400 version V5R1M0 SERVER_TRACE_FILE The name of the trace file created when TRACE=*ON When blank, the file name defaults to Trace.txt in the SERVER_ROOT_PATH trace.txt SERVER_SESSION_TIMEOUT Number of seconds before the session automatically is terminated Default is 1440 seconds 1440 SERVER_SESSION_ID The Unique Session Timestamp-id; also it is the time when the session was started 2006-07-27-15.37.29.5 16500 SERVER_SESSION_NUMBER The Unique Session number; Also it is the job number of the first lightweight job that initiated the session 516500 SERVER_SYSTEM_NAME The system name from the network attribute DKEXP03 REMOTE_ADDR The remote TCP/IP address of the client web browser 192.168.5.3 REMOTE_PORT The remote TCP/IP port number negotiated by the TCP/IP layer 1892 REQUEST_HOST_NAME The TCP/IP address or name for the requested server dkexp03 REQUEST_METHOD The method the document was requested: GET parameters is parsed along the URL POST Parameters are parsed in the form object GET The complete header string Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave -flash, application/vnd.ms-exce l, application/vnd.ms-pow erpoint, application/msword, */* Referer: http://dkexp03:60001/t utorials/Tutorials.ASPX?t opic=ex01server.ASPX& desc=GetServerVar() Accept-Language: da,en;q=0.5 Accept-Encoding: gzip, deflate User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727) Host: dkexp03:60001 Connection: Keep-Alive Cookie: REQUEST_HEADER System & Method A/S 226 IceBreak Server variable Description Sample Value sys_sesid="2006-07-27 -15.37.29.516500"; sys_sesid="2006-07-27 -15.37.29.516500"; iNavigate__2=1 REQUEST_RAW The complete request, excluding the content REQUEST_CONTENT The content string QUERY_STRING Parameters sent along the GET or POST request after the document. The URL in the browser GET /tutorials/ex01server.AS PXHTTP/1.1 Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave -flash, application/vnd.ms-exce l, application/vnd.ms-pow erpoint, application/msword, */* Referer: http://dkexp03:60001/t utorials/Tutorials.ASPX?t opic=ex01server.ASPX& desc=GetServerVar() Accept-Language: da,en;q=0.5 Accept-Encoding: gzip, deflate User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727) Host: dkexp03:60001 Connection: Keep-Alive Cookie: sys_sesid="2006-07-27 -15.37.29.516500"; sys_sesid="2006-07-27 -15.37.29.516500"; iNavigate__2=1 System & Method A/S Part XII 228 12 IceBreak Acknowledgements IceBreak core Copyright (C) 2004-2010 System & Method A/S IceBreak core also ships with the following third party library. The IceBreak team acknowledges the Licence terms and conditions ZLIB Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly jloup@gzip.org Mark Adler madler@alumni.caltech.edu Read more on http://zlib.net/ System & Method A/S Index Index 166 administrator 165 API 168 authority 169 authorization 165 -Ccheck object 169 -Ddata structure 167, 168 disabled=disabled 166 DNS 170 DropDown 171, 172 dropdown list 166 -E167 -FFieldListOpen 167 FieldListRead() 167 -Hhost name 170 HostName 170 HtmlExtend 166 -IIFS -K- -L- -A- exists 170 kapital letters 167, 170 key 166 keywords 166 -<