diff --git a/docs/Makefile b/docs/Makefile
index 1b8d299..e370c2a 100644
--- a/docs/Makefile
+++ b/docs/Makefile
@@ -1,20 +1,20 @@
-# Minimal makefile for Sphinx documentation
-#
-
-# You can set these variables from the command line.
-SPHINXOPTS =
-SPHINXBUILD = sphinx-build
-SPHINXPROJ = XMLSERVICE
-SOURCEDIR = .
-BUILDDIR = _build
-
-# Put it first so that "make" without argument is like "make help".
-help:
- @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
-
-.PHONY: help Makefile
-
-# Catch-all target: route all unknown targets to Sphinx using the new
-# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
-%: Makefile
- @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
\ No newline at end of file
+# Minimal makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+SPHINXPROJ = XMLSERVICE
+SOURCEDIR = .
+BUILDDIR =_build
+
+# Put it first so that "make" without argument is like "make help".
+help:
+ @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+.PHONY: help Makefile
+
+# Catch-all target: route all unknown targets to Sphinx using the new
+# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
+%: Makefile
+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/docs/ccsids.rst b/docs/ccsids.rst
new file mode 100755
index 0000000..35b7e17
--- /dev/null
+++ b/docs/ccsids.rst
@@ -0,0 +1,255 @@
+
+
+XMLSERVICE/Toolkit CCSID
+========================
+
+`Goto Main Page`_
+
+.. _Goto Main Page: index.html
+
+XMLSERVICE should just work
+-------------------------------
+In general if you are using DB2 connections 1/2 tier and settings for your Apache or user profile are valid (not 65535), you will not need any additional CCSID manipulation/configuration.
+
+..
+ If you are unfamiliar with 2-tier DB2 CCSID please try following link before reading this page [[PHP/DB2CCSID | DB2 CCSID]].
+
+CCSID - what do?
+----------------
+
+Few other topics dealing with web programs cause more frustrations over IBM i CCSID settings.
+
+CCSID conflict between web scripts (clients) and IBM i PGMs (server)
+--------------------------------------------------------------------
+Any good conflict needs a basic difference in philosophy causing all the trouble.
+
+* *Client (ASCII)* - web scripts typically wish to run ASCII 819/1208 (PHP), code set(s) laptop
+* *Server (EBCDIC)* - IBM i PGMs generally run EBCDIC (RPG/Cobol/CLP), code set(s) main frame
+
+CCSID rule -- always a conversion client/server
+-----------------------------------------------
+The basic operational code set differences between client (ASCII) / server (EBCDIC) required a conversion for all character data moving between client/server to be of value on either side. Your CCSID setting options are many, experimentation is usually required, but perhaps this web page helps avoid hours of frustrating tinkering attempting to adjust multitude of software "products" where CCSID conversions is possible.
+
+Happens 99 times out of 100 when not working (CCSID 65535)
+----------------------------------------------------------
+You cannot run IBM i PHP and interact with IBM i DB2, PGM, SRVPGM (xmlservice), when your IBM i machine is default ship setting of 65535. Change the default ship Zend Server setting and you will likely be up and running.
+
+I run 65535 xmlservice on my V6R1 machine (among other machines)
+::
+
+ DSPSYSVAL SYSVAL(QCCSID)
+ Coded character set
+ identifier . . . . . : 65535 1-65535
+
+
+Change these files and restart everything (web, db2, xmlservice, tec.)
+
+I. Apache: /www/zendsvr/conf/httpd.conf <-- (ILE Apache side)
+::
+
+ DefaultFsCCSID 37 ... or 280 (Italian) ... or so on ...
+ CGIJobCCSID 37 ... or 280 (Italian) ... or so on ...
+
+This often fixes majority of web script issue
+
+II. FastCGI: /www/zendsvr/conf/fastcgi.conf <-- THIS file (PASE side)
+::
+
+ CCSID=819 and LANG=C,
+ which works nearly anywhere (UNIX default).
+
+Note:
+
+ - This file must be ASCII 819, so careful with editor or will not work (EDTF especially).
+ - CCSID=1208 can be a problem for PHP extensions, so most configurations use CCSID=819 and take specific script action to encode/decode 1208 data (see xmlservice hex/before/after)
+
+III. User profile -- DB2 connections
+::
+
+ CHGUSRPRF USRPRF(IAM37) CCSID(37)
+
+This fixes most DB2 CCSID client/server problems both 1-tier and 2-tier
+
+*-- or (skip I. - III.)--*
+
+IV. change system ccsid for everything on the machine
+::
+
+ CHGSYSVAL SYSVAL(QCCSID) VALUE(37)
+
+Note:
+
+ - some legacy applications may not work, should work but..., so check things out
+ - *65535* means HEX (or binary), which also means no conversion and 65535 is essentially doomsday for most any application trying to work between PASE and DB2 (most any client and DB2).
+
+ ::
+
+ client (ASCII 819) + server (EBCDIC 65535) = junk-you-can't-read-or-use = xmlservice fails
+
+
+Now **the rest of the story** 65535 problem is common, so IBM i DB2 folks force a reasonable job CCSID for SOME remote connections (based on primary language generally), but NOT all connections (PASE and others), therefore observationally you may see some applications work (client access products) and others will not (PHP).
+
+1) Specific examples for XMLSERVICE
+
+ - Command user ccsid override
+
+ ::
+
+ if ($i5persistentconnect) $conn = db2_pconnect($database,$user,$password);
+ else $conn = db2_connect($database,$user,$password);
+ if (!$conn) die("Bad connect: $database,$user");
+ $stmt = db2_prepare($conn, "call $libxmlservice.iPLUG4K(?,?,?,?)");
+ if (!$stmt) die("Bad prepare: ".db2_stmt_errormsg());
+
+ $ipc = "/tmp/packers"; // *** RIGHT HERE internalKey/IPC
+ $ctl = "*sbmjob"; // *** run state full
+
+ $clob = "\n";
+ $clob .= "\n";
+ $clobIn = $clob;
+ $clobOut = "";
+
+ $ret=db2_bind_param($stmt, 1, "ipc", DB2_PARAM_IN);
+ $ret=db2_bind_param($stmt, 2, "ctl", DB2_PARAM_IN);
+ $ret=db2_bind_param($stmt, 3, "clobIn", DB2_PARAM_IN);
+ $ret=db2_bind_param($stmt, 4, "clobOut", DB2_PARAM_OUT);
+ $ret=db2_execute($stmt);
+
+ var_dump($clobOut);
+
+ $xmlobj = simplexml_load_string($clobOut);
+
+ if (!$xmlobj) die("Bad XML output");
+
+ $clobOut = pack("H*",(string)$xmlobj->cmd->hex);
+
+ var_dump($clobOut);
+
+ OUTPUT:
+ > php zzhexccsidcmd.php
+ string(527) "
+ "
+ string(176) "
+ QGPL QTEMP QDEVELOP QBLDSYS QBLDSYSR
+
+
+ QSYS QSYS2 QHLPSYS QUSRSYS
+
+
+
+
+ - Program ccsid override
+
+ ::
+
+ if ($i5persistentconnect) $conn = db2_pconnect($database,$user,$password);
+ else $conn = db2_connect($database,$user,$password);
+ if (!$conn) die("Bad connect: $database,$user");
+ $stmt = db2_prepare($conn, "call $libxmlservice.iPLUG512K(?,?,?,?)");
+ if (!$stmt) die("Bad prepare: ".db2_stmt_errormsg());
+
+ $ipc = "/tmp/packers"; // *** RIGHT HERE internalKey/IPC
+ $ctl = "*sbmjob"; // *** run state full
+
+ $clob = "\n";
+ $clob .= "\n";
+ $clobIn = $clob;
+ $clobOut = "";
+
+ $ret=db2_bind_param($stmt, 1, "ipc", DB2_PARAM_IN);
+ $ret=db2_bind_param($stmt, 2, "ctl", DB2_PARAM_IN);
+ $ret=db2_bind_param($stmt, 3, "clobIn", DB2_PARAM_IN);
+ $ret=db2_bind_param($stmt, 4, "clobOut", DB2_PARAM_OUT);
+ $ret=db2_execute($stmt);
+
+ var_dump($clobOut);
+
+ $xmlobj = simplexml_load_string($clobOut);
+
+ if (!$xmlobj) die("Bad XML output");
+
+ $clobOut = pack("H*",(string)$xmlobj->pgm->parm->data);
+
+ var_dump($clobOut);
+
+
+ OUTPUT:
+ > php zzhexccsidpgm.php
+ string(273) "
+ "
+ string(43) "Hi there i am ok on return from xmlservice."
+
+
+
+
+2) Specific examples for New PHP Toolkit
+
+ - CCSID override - PHP Toolkit/CW
+
+ Simple CCSIDs only require setting the CCSID via QCCSID or in Apache. The overrides directly below are intended for for languages with more complex needs such as Hebrew or Japanese, or when individual pieces of data are encoded differently (such as a combination of 819 and 1208).
+
+ The easiest way to try these CCSID settings is with three new settings in toolkit.ini:
+ ::
+
+ advanced CCSID options. Use all three options together.
+ ccsidBefore = '819/37'
+ ccsidAfter = '37/819'
+ useHex = true
+
+ Uncomment the three settings and then adjust the ccsidBefore and ccsidAfter values according to your needs.
+
+ Another way to set these global CCSID settings is with the method setToolkitServiceParams(). In your code, after connecting with $conn::getInstance(* etc.), set the parameters with this statement:
+ ::
+
+ $conn->setToolkitServiceParams(array('ccsidBefore'=>'819/37', 'ccsidAfter'=>'37/819', 'useHex'=>true));
+
+ This technique works identically to changing INI values, except that this coding technique can be re-done over and over with different settings before each program/command call.
+
+ These "global" CCSID techniques work with both the new API and the CW, and will convert not only data/commands and command output, but the names of programs, libraries, and functions. You may notice that your data will be converted to hex inside the toolkit and then converted back to readable text by the toolkit.
+
+ For more fine-grained control over parameter data--that is, the ability to use a different CCSID conversion for each parameter, if desired--chain several new methods to AddParameterChar() like so: (new API only--not in CW):
+ ::
+
+ $param[] = $conn->AddParameterChar('both', 10,'CODE', 'CODE', $code)
+ ->setParamCcsidBefore('819/37')
+ ->setParamCcsidAfter('37/819')
+ ->setParamUseHex(true);
+
+
+ These parameters can also be passed as AddParameterChar() function parameters directly but it's easier to use the setParam… methods above.
+
+ Note:
+
+ These advanced CCSID settings do not affect some of the handmade API calls in the CW such as getting object lists. Helping those may be a future enhancement.
+
+
+If you wish to see how XMLSERVICE implements these overrides, see the following URL, under the heading: "CCSID user override - xmlservice options (hex/before/after)".
+
+
+
+..
+ [--Author([[http://youngiprofessionals.com/wiki/index.php/XMLSERVICE/XMLSERVICECCSID?action=expirediff | s ]])--]
+ [--Tony "Ranger" Cairns - IBM i PHP / PASE--]
+
+
+
diff --git a/docs/connections.rst b/docs/connections.rst
new file mode 100755
index 0000000..1f8303f
--- /dev/null
+++ b/docs/connections.rst
@@ -0,0 +1,424 @@
+XMLSERVICE Connections
+======================
+
+`Goto Main Page`_
+
+.. _Goto Main Page: index.html
+
+Sometimes a real conversation helps ...
+---------------------------------------
+
+**Customer wants to know how to remain stateless, but get the benefit of being able to audit the use of RPG subprocedure invocations via XMLToolkit without toggling back and forth (different QSQSRVR jobs).**
+
+ Stateless may use multiple QSQSRVR jobs (toggling), this is definition of 'stateless' in PHP fastcgi environment (working correct).
+
+
+**Will ToolkitService object using persistent db2 connections and "stateless => true" help single QSQ job?**
+
+ Toolkit "stateless => true" via db2 transport using db2_connect or db2_pconnect makes no difference, fastcgi implies unpredictable QSQSRVR job will be used (command line slightly more predictable over web).
+
+
+**Why 'unpredictable' QSQ?**
+
+ It's all web PHP fastcgi 'random' worker selection, NOTHING to do with ibm_db2 'connection' persistent or non-persistent, toolkit connection is irrelevant. Apache web site using fastcgi routes "randomly" to any available PHP worker job php-cgi, therefore 'random' php-cgi worker using db2_(p)connect<>QSQSRVR will also appear 'random'. To wit, you end up different QSQSRVR jobs (toggle back and forth). Technically, fastcgi protocol, PHP workers poll a single fastcgi socket waiting to take some work, ZS on i at /www/zendsvr6/logs/fcgi-njjjineh.sock (sock name random). As each php worker strips work off fastcgi socket (1st come == 1st do), the worker is busy communicating on 'private web socket' running script until finished (no longer waiting). Combination of natural web worker selection (browser +/- KeepAlive), and fastcgi socket poll for work, results in 'random' appearance QSQ job toolkit usage, DB2 connection just came along for ride in back seat of the 1950 PHP fastcgi roadster.
+
+
+**Help me be one-and-only-one job?**
+
+ The only way to assure private connection back to same XTOOLKIT job is 'internalKey'=>'/tmp/XTOOLKIT_job_1' ('ipc'=/tmp/XTOOLKIT_job_1').
+
+
+
+XMLSERVICE connections discussed this page
+----------------------------------------------
+
+- Stateless -- clean running come/go, "full open/close," start/stop connection to be used by any requester. Must set LIBL during each request
+- State full -- State retained between requests: LIBL, transactions, etc., "private" connection used by one requester/task for a long period of time (like 5250)
+- State full -- hybrid "private/persistent" connection shared by many requesters, but keep open PGM, files, etc.
+- State full -- reservation hybrid "private/persistent" connection exclusively held for a period each requesters, but returned back to pool for re-use (rare use)
+
+The jobs involved in "connections":
+::
+
+ I. Stateless
+ (job 1) (job 2) (job 3)
+ Apache FastCGI DB2 (stateless)
+ ------- --------------- ---------------------
+ browser/client ->thread-->socket->php-cgi
+ --->$ctl="*here"; -->QSQSRVR+XMLSERVICE
+ shut down after
+ each request
+ ("stateless")
+
+ II. State full
+ (job 2) (job 3) (job 4)
+ FastCGI QSQ (proxy) XMLSERVICE (state full)
+ --------------- --------------------- ------------------------
+ -->socket->php-cgi
+ --->$ctl="*sbmjob";
+ --->$ipc="/tmp/sally"; -->QSQSRVR+XMLSERVICE -->XMLSERVICE
+ alive until stopped
+ ("state full")
+
+
+ Jobs originates::
+
+ (job 1) Apache picks any thread (1st level routing)
+ (job 2) FastCGI all "non-busy" worker php-cgi wait on unix domain socket /www/zend2/logs/fcgi-hmjadgek.sock (2nd level routing)
+ (job 3) php-cgi - database connections odbc, ibm_db2, pdo_ibm (3rd level routing)
+ db2_pconnect() attach to pooled/persistent QSQ (matching profile) but leaves connection open on exit
+ db2_connect() acquires a unused pre-start QSQ (or starts one) then attaches to QSQ (profile), and returns to unused pool on exit
+ (job 3) XMLSERVICE -- Stateless -- run inside QSQ job and clean-up after each request (3rd level routing)
+ $ctl = "*here";
+ (job 4) XMLSERVICE -- State full -- run in separate job that any QSQ job can call using IPC (4th level routing)
+ $ctl = "*sbmjob";
+ $ipc = "/tmp/sally";
+
+Drivers involved in conection::
+
+ 400 server start-up Common usage Big picture Comments
+ STRTCPSVR SERVER(*HTTP)
+
+ port 80 or 10088 or … (REST/HTTP interface)
+
+ 1-tier - XMLCGI CLIENT <==> IBM HTTP Server <==> XMLCGI (CLI server mode) <==> QSQxxxx <==> IBM i Resources XMLCGI + CLI
+ PASE library (no start needed)
+
+ no port
+
+ 1-tier - PHP ibm_db2+pdo_ibm+odbc (Native PASE CLI libdb400.a driver) CLIENT (PASE libdb400.a driver) <==> QSQxxx <==> IBM i Resources Native PASE CLI libdb400.a driver (IBM Rochester)
+ STRHOSTSVR SERVER(*DATABASE)
+
+ port 8471 (database)
+
+ 2-tier - PHP odbc interface (IBM i Client Access odbc driver interface) CLIENT (Client Access drivers) <==> QZDAxxxx <==> IBM i Resources Client Access odbc-based drivers (IBM Rochester)
+ STRTCPSVR SERVER(*DDM)
+
+ port 446 (DDM/DRDA)
+
+ 2-tier - PHP ibm_db2+pdo_ibm (DB2 Connect driver interface) CLIENT (DB2 Connect drivers) <==> QRWxxxx <==> IBM i Resources DB2 CLI DRDA-based DB2 Connect drivers (IBM Toronto)
+
+
+
+
+1) Stateless -- no LIBL, come/go
+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+These connections are traditional web requests "full open/close" clean running start/stop connection to be used by any requester.
+
+- Stateless
+
+::
+
+ $ctl = "*here";
+
+ (1) (2) (3)
+ Apache FastCGI DB2 (server mode)
+ ------- --------------- ---------------------
+ browser/client -->thread--socket->php-cgi--->QSQSRVR(profile fred)
+ XMLSERVICE (fred) <--shut down after each request
+ --->QSQSRVR(profile sally)
+ XMLSERVICE (sally) <--shut down after each request
+ --->QSQSRVR(profile john)
+ XMLSERVICE (john) <--shut down after each request
+
+
+Example new Toolkit (stateless):
+
+::
+
+ if ($i5persistentconnect) $conn = db2_pconnect($database,$user,$password);
+ else $conn = db2_connect($database,$user,$password);
+ try { $ToolkitServiceObj = ToolkitService::getInstance($conn); }
+ catch (Exception $e) { die($e->getMessage()); }
+ $ToolkitServiceObj->CLCommand("CHGLIBL LIBL(FREDFLIN WILMAFLIN) CURLIB(FREDFLIN)");
+
+**Stateless:**
+If you choose $ctl='\*here', you will run in the calling process DB2 connection (QSQSRVR job).
+When XMLSERVICE completes your XML script it will shut down to nothing, considered stateless and holds zero state on return.
+
++ In general you will run slower in stateless mode (CW default / Toolkit default), because XMLSERVICE has to keep starting things over and over and over again, but perhaps not an issue if you have CPU to burn.*
++ The is no semaphore locking or shared memory ipc when running as stateless (\*here), because only one sally client/server is a pair, but of course there may be many sally client/server pairs on the same machine.*
++ There is no "memory" of the LIBL in stateless, so it must be set EVERY time before use.*
+
+
+2) State full -- LIBL, transactions, etc.
+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+These connections are traditional 5250-like "private" connection used by one requester/task for a long period of time.
+
+State full (most RPG programs)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+::
+
+ $ctl = "*sbmjob";
+ $ipc = "/tmp/sally";
+ -- or --
+ $ipc = "/tmp/john";
+ (1) (2) (3) (4)
+ Apache FastCGI DB2 (server mode) XMLSERVICE
+ ------- --------------- --------------------- ----------
+ -->thread--socket->php-cgi--->QSQSRVR(profile sally)---.->XMLSERVICE (sally) <--alive until stopped (or idle timemout)
+ --->QSQSRVR(profile john)--. |
+ -->thread--socket->php-cgi--->QSQSRVR(profile fred) | |
+ --->QSQSRVR(profile sally)---.
+ --->QSQSRVR(profile fred) |
+ --->QSQSRVR(profile john)--.--->XMLSERVICE (john) <--alive until stopped (or idle timemout)
+
+Example new Toolkit (state full)::
+
+ $internalKey = '/tmp/packers';
+ if ($i5persistentconnect) $conn = db2_pconnect($database,$user,$password);
+ else $conn = db2_connect($database,$user,$password);
+ try { $ToolkitServiceObj = ToolkitService::getInstance($conn); }
+ catch (Exception $e) { die($e->getMessage()); }
+ $ToolkitServiceObj->setToolkitServiceParams(array(
+ 'InternalKey'=>$internalKey, // *** RIGHT HERE internalKey/IPC
+ // *** run state full
+ // use SBMJOB command run in new job
+ // PHP can call again, again, again
+ // with /tmp/packers and get
+ // same job every time
+ // same library list (*LIBL)
+ // same PGMs with open files, etc.
+ // exactly like 5250 sign-on screen
+ 'plug'=>"iPLUG32K")); // max size data i/o (iPLUG4K,32K,65K.512K,1M,5M,10M,15M)
+ // state full - MUST do this ONCE ONLY after start/sbmjob of XMLSERVICE job
+ // then forget about it (unless you choose to change libl)
+ $ToolkitServiceObj->CLCommand("CHGLIBL LIBL(FREDFLIN WILMAFLIN) CURLIB(FREDFLIN)");
+ /* Do not use the disconnect() function for "state full" connection */
+ /* NEVER EVER USE THIS ... $ToolkitServiceObj->disconnect(); */
+ /* Why? *immed kill of job, not nice or sync, just kill */
+ /* Use idle timeout for "state full" / "private" connections */
+
+**State full**: If you choose ``$ctl="\*sbmjob"`` + ``$ipc="/tmp/packers"``, you will run in a separate job past
+the calling DB2 connection (child job of QSQSRVR). This $ctl/$ipc combination will allow you to return to the
+same XMLSERVICE job from any connection to the machine, therefore considered "state full" and any called program
+can keep open files, transactions, etc. (just like a real RPG 5250 program does mate).
+
++ $ipc='/tmp/anything' can be any unique/accessible directory you want to route you back to same XMLSERVICE job (\*sbmjob), but usually anchored in /tmp directory because xmlservice will try to create it if missing.
++ Technically $ipc="/tmp/packers" is a unique IFS machine location in posix function ftok('/tmp/packers') which presents a unique numeric key representing /tmp/packers that is used for XMLSERVICE shared memory and semaphores creation/attach (XMLSERVICE uses shared memory/semaphores for communication).
++ Shared memory + semaphore locking is only required for state full connections ($ctl="\*sbmjob" + $ipc="/tmp/packers"), where each sally XMLSERVICE semaphore "front door lock" will allow only one sally client to chat with a XMLSERVICE job, the other sally requesters will wait until they are invited to chat (just like the dentist office).
++ Security is managed through IFS shared memory / semaphores access control just like any other IFS file, so once profile sally owns an active XMLSERVICE ctl+ipc then no other profile can attach to the active XMLSERVICE job ... well ... except for high authority profiles like \*SECOFR (of course).
++ With version 1.6.6 state full XMLSERVICE connections are ended via configurable idle timeout $ctl .= " \*idle(3000)", you may keep the jobs alive forever using $ctl .= " \*idle(0)" to match the original version behavior. There are other options for client wait $clt .= " \*wait(30)" and waiting for called program to return $ctl .= " \*call(200)" and various actions that can be taken for each wait/timer (busy,kill,etc.).
++ In this example we have been using one sally client/server $ipc="/tmp/packers", you can of course have many different sally client/server ($ipc="/tmp/packers", $ipc="/tmp/vikings", $ipc="/tmp/bears", etc.) and each of these sally ipcs may have many clients chatting with each sally server ipc ... sort of a sally work load balancing dream situation where we can clone a new sally ipc server for each task at hand.
++ You only need to set the LIBL once in state full (unless you want to change LIBL for some reason).
+
+**Toolkit State full (with IPC) - avoid start up/shut down XMLSERVICE (NOT toolkit default)**
+
++ avoid using toolkit disconnect ($ctl="\*immed") to leave XMLSERVICE up and running (will timeout shut down if idle for 1/2 hour)
++ choose a the minimum plug size need for the task to avoid send/receive extra blanks
++ TURN DEBUG and LOGS off in toolkit to avoid IFS file write (takes forever in computer timings)
++ db2_pconnect() - persistent or "shared" connection with toolkit avoids acquire/release QSQ jobs (NOT toolkit default)
+
+
+XMLSERVICE adopt authority issues
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When using ctl+ipc "state full" jobs is a generally bad idea to "adopt authority" as originating profile sally will lose all access ... and ... in fact ipc may become unreachable causing a orphan XMLSERVICE (client is still sally, ipc is still sally's, but adopt xmlservice server becomes fred).
+
+Two choices:
+
+ a) If you MUST "adopt authority" do it in a stateless job (\*here), where full connection processing may undo "left over switch profile" potential damage on the way out of XMLSERVICE script. This option should always work.
+ b) Be very careful to return back to sally profile EACH TIME leaving xmlservice sending data back to the waiting sally client ... sort of good manners talk to sally client as sally server (adopted fred can speak/do only when asked, then go away)
+
+**Note**:
+We are thinking about forcing "switch back to originating profile on the way back" within XMLSERVICE code, but have not yet understood what that means to PHP wrappers like CW, so the mission is at the moment in your called program and/or PHP wrapper/user code.
+
+3) State full -- hybrid "private/persistent" connection
+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+These connections are hybrid "private/persistent" connection shared by many requesters, but keep open PGM, files, etc.
+
+Worried about too many IPC's/XMLSERVICE jobs??
+
+The following gives you a hybrid "private/persistent" connection
+
+* most all the benefits for called RPG (state full, open files, etc.)
+* but only $maxpool XMLSERVICE jobs
+
+Try this simple technique for pooled IPC's/XMLSERVICE jobs ``$internalKey = '/tmp/packers'.rand(1,$maxpool)``
+
+* IF your application set can tolerate multi-client shared access to a pool of persistent/private/semi-stateless connections the random technique should work well.
+* However, if you need your client make a exclusive reservation see the next topic
+
+**State full -- hybrid "private/persistent" connection**
+
+::
+
+ $maxpool = 3;
+ // -- PHP raw ---
+ $ctl = "*sbmjob";
+ $ipc = "/tmp/sally".rand(1,$maxpool);
+ // -- or PHP toolkit --
+ $internalKey = '/tmp/sally'.rand(1,$maxpool)
+
+ (1) (2) (3) (4)
+ Apache FastCGI DB2 (server mode) XMLSERVICE
+ ------- --------------- --------------------- ----------
+ -->thread--socket->php-cgi--->QSQSRVR(profile sally)--.
+ -->thread--socket->php-cgi--->QSQSRVR(profile sally)--|
+ : |
+ -->thread--socket->php-cgi--->QSQSRVR(profile sally)--|->XMLSERVICE (/tmp/sally1) <--alive until stopped (or idle timemout)
+ -->thread--socket->php-cgi--->QSQSRVR(profile sally)--|->XMLSERVICE (/tmp/sally2) <--alive until stopped (or idle timemout)
+ -->thread--socket->php-cgi--->QSQSRVR(profile sally)--|->XMLSERVICE (/tmp/sally3) <--alive until stopped (or idle timemout)
+ : |
+ -->thread--socket->php-cgi--->QSQSRVR(profile sally)--|
+ -->thread--socket->php-cgi--->QSQSRVR(profile sally)--.
+
+3 XMSLERVICE jobs handle work for all sally clients using the site
+
+Example new Toolkit (hybrid "private/persistent" connection)::
+
+ $maxpool = 40; // 40 jobs good enough to handle my machine needs
+
+ if ($i5persistentconnect) $conn = db2_pconnect($database,$user,$password);
+ else $conn = db2_connect($database,$user,$password);
+
+ try { $ToolkitServiceObj = ToolkitService::getInstance($conn); }
+ catch (Exception $e) { die($e->getMessage()); }
+
+ $internalKey = '/tmp/packers'.rand(1,$maxpool);
+ $ToolkitServiceObj->setToolkitServiceParams(array(
+ 'InternalKey'=>$internalKey, // *** RIGHT HERE internalKey/IPC $maxpool jobs for service
+ 'plug'=>"iPLUG32K")); // max size data i/o (iPLUG4K,32K,65K.512K,1M,5M,10M,15M)
+
+ /* Do not use the disconnect() function for "state full" connection */
+ /* NEVER EVER USE THIS ... $ToolkitServiceObj->disconnect(); */
+ /* Why? *immed kill of job, not nice or sync, just kill */
+ /* Use idle timeout for "state full" / "private" connections */
+
+
+* So simple, why does it work???
+
+ + Works much same as Apache FastCGI PHP jobs (even using random), because $maxpool "child XMLSERVICE workers" can be increased to match machine workload (tinker-trial-error) ... just like Apache threads ... just like PHP children ... all the same
+ + Most web requests are sub-second, so even on routing collision by random it is a short wait.
+
+
+* Could i dedicate different pools to different tasks ???
+
+ + Yes, a bag full of really low effort work ``(/tmp/packers1-40, /tmp/vikings1-40)``.
+
+
+* Could i dedicate different user ids to different pools as well as tasks???
+
+ + Yes, a bag full of really low effort work ``(/tmp/packers1-40, /tmp/vikings1-40)``.
+
+
+* Can i idle timeout unused XMLSERVICE jobs ???
+ + Yes of course, toolkit.ini setting or specify manually.
+ + NEVER EVER USE THIS ... ``$ToolkitServiceObj->disconnect();``
+
+
+* Should i use persistent connections??
+
+ + db2_pconnect -- Yes of course, it will save the time "attaching" a QSQSRVR job
+ + db2_connect -- However, you can use same technique with full open/close (yes it does work, try it)
+
+
+* Can i prestart jobs?
+
+ + Yes, but they will start on web demand which i think is much better (just like Apache)
+
+ ::
+
+ SBMJOB CMD(CALL PGM(ZENDSVR/XMLSERVICE) PARM('/tmp/packers1')) JOBD(ZENDSVR/ZSVR_JOBD) USER(PACKERS)
+ SBMJOB CMD(CALL PGM(ZENDSVR/XMLSERVICE) PARM('/tmp/vikings1')) JOBD(ZENDSVR/ZSVR_JOBD) USER(VIKINGS)
+
+
+
+4) State full -- reservation hybrid "private/persistent" connection
+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+These connections are hybrid "private/persistent" connection exclusively held for a period of time by each requesters, but returned back to pool for re-use.
+
+If your client needs to start/use/stop a reservation hybrid "private/persistent" connection, use the appropriate keyword in your XML sent to XMLSERVICE to gain exclusive rights to the hybrid "private/persistent" connection.
+
+* unique-user-key -- acquire exclusive IPC if available
+* -- must appear XML every request job held forever until see
+* unique-user-key -- release IPC for any other use
+* Errors:
+
+ + -- non-matching key results in error almost instantly (no wait)
+ ::
+
+ busy response (1301060):
+
+ 1301060
+ IPC owner busy
+
+
+ + thoughtful setting server idle timeout can control unwanted reservation hangs due to careless users or errors ** $ctl .= " \*idle(60)" **
+
+**hybrid "private/persistent" connection with reservation**
+
+::
+
+ $maxpool = 3;
+ // -- PHP raw ---
+ $ctl = "*sbmjob";
+ $ipc = "/tmp/sally".rand(1,$maxpool);
+ // -- or PHP toolkit (not available yet -- Alan) --
+
+ (1) (2) (3) (4)
+ Apache FastCGI DB2 (server mode) XMLSERVICE
+ ------- --------------- --------------------- ----------
+ -->thread--socket->php-cgi--->QSQSRVR(profile sally)--.
+ -->thread--socket->php-cgi--->QSQSRVR(profile sally)--|
+ : |
+ -->thread--socket->php-cgi--->QSQSRVR(profile sally)--|->XMLSERVICE (/tmp/sally1) <--alive until stopped (or idle timemout)
+ unique-user-key <--exclusive reservation until stopped
+
+ unique-user-key
+ -->thread--socket->php-cgi--->QSQSRVR(profile sally)--|->XMLSERVICE (/tmp/sally2) <--alive until stopped (or idle timemout)
+ unique-user-key <--exclusive reservation until stopped
+
+ unique-user-key
+ -->thread--socket->php-cgi--->QSQSRVR(profile sally)--|->XMLSERVICE (/tmp/sally3) <--alive until stopped (or idle timemout)
+ unique-user-key <--exclusive reservation until stopped
+
+ unique-user-key
+ : |
+ -->thread--socket->php-cgi--->QSQSRVR(profile sally)--|
+ -->thread--socket->php-cgi--->QSQSRVR(profile sally)--.
+
+3 XMSLERVICE jobs handle work for all sally clients using the site
+However, reservation locks exclusive use until reservation is stopped.
+
+Example new Toolkit (hybrid "private/persistent" connection with reservation)::
+
+ --- unfortunately reservation is not available in PHP wrapper yet (Alan) ---
+ --- raw xml pseudo code version of what happens follows start/use/stop ---
+ -- no time out --
+ $ctl .= " *idle(0)"
+ -- request 1 --
+
+
+ -- request 2 (two minutes later) --
+
+
+ -- request 3 (1/2 hour later) --
+
+
+ -- request n (2 hours later) --
+
+
+
+..
+ [--Author([[http://youngiprofessionals.com/wiki/index.php/XMLSERVICE/XMLSERVICEConnect?action=expirediff | s ]])--]
+ [--Tony "Ranger" Cairns - IBM i PHP / PASE--]
+
diff --git a/docs/date-time-timestamp.rst b/docs/date-time-timestamp.rst
new file mode 100755
index 0000000..1a0ea97
--- /dev/null
+++ b/docs/date-time-timestamp.rst
@@ -0,0 +1,682 @@
+
+XMLSERVICE/Toolkit Date, Time, Timestamp
+========================================
+
+`Goto Main Page`_
+
+.. _Goto Main Page: index.html
+
+Date, Time, Timestamp - what do?
+--------------------------------
+Time and date are easy, correct size character buffer and pass any format you want. Essentially xmlservice/toolkit works without formal knowledge of date, time, timestamp formats, simply passing another set of characters in memory for a parameter (pass-by-reference mostly), called program most likely throws exception when format incompatible (see with any MI debugger).
+
+
+1) New PHP Toolkit Samples
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ZZDATE (D datfmt(\*iso))
+""""""""""""""""""""""""""
+
+::
+
+ getMessage()); }
+ $ToolkitServiceObj->setToolkitServiceParams(
+ array('InternalKey'=>$internalKey, // route to same XMLSERVICE job /tmp/myjob1
+ 'subsystem'=>"QGPL/QDFTJOBD", // subsystem/jobd to start XMLSERVICE (if not running)
+ 'plug'=>"iPLUG32K")); // max size data i/o (iPLUG4K,32K,65K.512K,1M,5M,10M,15M)
+ // *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ // * zzdate: check date parm
+ // *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ // P zzdate B export
+ // D zzdate PI D
+ // D myDate D datfmt(*iso)
+ // * vars
+ // D retDate s D datfmt(*iso)
+ // /free
+ // retDate=myDate;
+ // myDate=d'2007-09-30';
+ // return retDate;
+ // /end-free
+ // P E
+ $param[] = $ToolkitServiceObj->AddParameterChar ('both', 10, 'ZZDATE', 'myDate', '2009-05-11');
+ $retrn[] = $ToolkitServiceObj->AddParameterChar ('both', 10, 'ZZDATE', 'retDate', '2002-02-02');
+ $result = $ToolkitServiceObj->PgmCall('ZZSRV', $libxmlservice, $param, $retrn, array('func'=>'ZZDATE'));
+ // var_dump($result);
+ /* in/out param myDate */
+ $myDate = "XMLSERVICE i/o param myDate: ".$result["io_param"]["myDate"];
+ echo "$myDate\n";
+ $expect = '2007-09-30';
+ if (strpos($myDate,$expect)<1) die("Fail missing $expect\n");
+ /* return value retDate */
+ $retDate = "XMLSERVICE return retDate: ".$result["retvals"]["retDate"];
+ echo "$retDate\n";
+ $expect = '2009-05-11';
+ if (strpos($retDate,$expect)<1) die("Fail missing $expect\n");
+ /* all good */
+ echo "Success\n";
+ ?>
+
+
+ZZDATEUSA (D datfmt(\*USA))
+"""""""""""""""""""""""""""""
+
+::
+
+ getMessage()); }
+ $ToolkitServiceObj->setToolkitServiceParams(
+ array('InternalKey'=>$internalKey, // route to same XMLSERVICE job /tmp/myjob1
+ 'subsystem'=>"QGPL/QDFTJOBD", // subsystem/jobd to start XMLSERVICE (if not running)
+ 'plug'=>"iPLUG32K")); // max size data i/o (iPLUG4K,32K,65K.512K,1M,5M,10M,15M)
+ // *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ // * zzdateUSA: check date parm
+ // *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ // P zzdateUSA B export
+ // D zzdateUSA PI D datfmt(*USA)
+ // D myDate D datfmt(*USA)
+ // * vars
+ // D retDate s D datfmt(*USA)
+ // /free
+ // retDate=myDate;
+ // myDate=d'2007-09-30';
+ // return retDate;
+ // /end-free
+ // P E
+ $param[] = $ToolkitServiceObj->AddParameterChar ('both', 10, 'ZZDATEUSA', 'myDate', '05/11/2009');
+ $retrn[] = $ToolkitServiceObj->AddParameterChar ('both', 10, 'ZZDATEUSA', 'retDate', '2002-02-02');
+ $result = $ToolkitServiceObj->PgmCall('ZZSRV', $libxmlservice, $param, $retrn, array('func'=>'ZZDATEUSA'));
+ // var_dump($result);
+ /* in/out param myDate */
+ $myDate = "XMLSERVICE i/o param myDate: ".$result["io_param"]["myDate"];
+ echo "$myDate\n";
+ $expect = '09/30/2007';
+ if (strpos($myDate,$expect)<1) die("Fail missing $expect\n");
+ /* return value retDate */
+ $retDate = "XMLSERVICE return retDate: ".$result["retvals"]["retDate"];
+ echo "$retDate\n";
+ $expect = '05/11/2009';
+ if (strpos($retDate,$expect)<1) die("Fail missing $expect\n");
+ /* all good */
+ echo "Success\n";
+ ?>
+
+ZZTIME (T timfmt(\*iso))
+""""""""""""""""""""""""""
+
+::
+
+ getMessage()); }
+ $ToolkitServiceObj->setToolkitServiceParams(
+ array('InternalKey'=>$internalKey, // route to same XMLSERVICE job /tmp/myjob1
+ 'subsystem'=>"QGPL/QDFTJOBD", // subsystem/jobd to start XMLSERVICE (if not running)
+ 'plug'=>"iPLUG32K")); // max size data i/o (iPLUG4K,32K,65K.512K,1M,5M,10M,15M)
+ // *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ // * zztime: check time parm
+ // *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ // P zztime B export
+ // D zztime PI T
+ // D myTime T timfmt(*iso)
+ // * vars
+ // D retTime s T timfmt(*iso)
+ // /free
+ // retTime=myTime;
+ // myTime=t'12.34.56';
+ // return retTime;
+ // /end-free
+ // P E
+ $param[] = $ToolkitServiceObj->AddParameterChar ('both', 8, 'ZZTIME', 'myTime', '09.45.29');
+ $retrn[] = $ToolkitServiceObj->AddParameterChar ('both', 8, 'ZZTIME', 'retTime', '02.02.02');
+ $result = $ToolkitServiceObj->PgmCall('ZZSRV', $libxmlservice, $param, $retrn, array('func'=>'ZZTIME'));
+ // var_dump($result);
+ /* in/out param myDate */
+ $myTime = "XMLSERVICE i/o param myTime: ".$result["io_param"]["myTime"];
+ echo "$myTime\n";
+ $expect = '12.34.56';
+ if (strpos($myTime,$expect)<1) die("Fail missing $expect\n");
+ /* return value retTime */
+ $retTime = "XMLSERVICE return retTime: ".$result["retvals"]["retTime"];
+ echo "$retTime\n";
+ $expect = '09.45.29';
+ if (strpos($retTime,$expect)<1) die("Fail missing $expect\n");
+ /* all good */
+ echo "Success\n";
+ ?>
+
+
+ZZTIME (T timfmt(\*USA))
+""""""""""""""""""""""""""
+
+::
+
+ getMessage()); }
+ $ToolkitServiceObj->setToolkitServiceParams(
+ array('InternalKey'=>$internalKey, // route to same XMLSERVICE job /tmp/myjob1
+ 'subsystem'=>"QGPL/QDFTJOBD", // subsystem/jobd to start XMLSERVICE (if not running)
+ 'plug'=>"iPLUG32K")); // max size data i/o (iPLUG4K,32K,65K.512K,1M,5M,10M,15M)
+ // *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ // * zztimeUSA: check time parm
+ // *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ // P zztimeUSA B export
+ // D zztimeUSA PI T timfmt(*USA)
+ // D myTime T timfmt(*USA)
+ // * vars
+ // D retTime s T timfmt(*USA)
+ // /free
+ // retTime=myTime;
+ // myTime=t'12.34.00';
+ // return retTime;
+ // /end-free
+ // P E
+ $param[] = $ToolkitServiceObj->AddParameterChar ('both', 8, 'ZZTIMEUSA', 'myTime', '09:45 AM');
+ $retrn[] = $ToolkitServiceObj->AddParameterChar ('both', 8, 'ZZTIMEUSA', 'retTime', '02:02 PM');
+ $result = $ToolkitServiceObj->PgmCall('ZZSRV', $libxmlservice, $param, $retrn, array('func'=>'ZZTIMEUSA'));
+ // var_dump($result);
+ /* in/out param myDate */
+ $myTime = "XMLSERVICE i/o param myTime: ".$result["io_param"]["myTime"];
+ echo "$myTime\n";
+ $expect = '12:34 PM';
+ if (strpos($myTime,$expect)<1) die("Fail missing $expect\n");
+ /* return value retTime */
+ $retTime = "XMLSERVICE return retTime: ".$result["retvals"]["retTime"];
+ echo "$retTime\n";
+ $expect = '09:45 AM';
+ if (strpos($retTime,$expect)<1) die("Fail missing $expect\n");
+ /* all good */
+ echo "Success\n";
+ ?>
+
+ZZSTAMP (Z)
+"""""""""""
+
+::
+
+ getMessage()); }
+ $ToolkitServiceObj->setToolkitServiceParams(
+ array('InternalKey'=>$internalKey, // route to same XMLSERVICE job /tmp/myjob1
+ 'subsystem'=>"QGPL/QDFTJOBD", // subsystem/jobd to start XMLSERVICE (if not running)
+ 'plug'=>"iPLUG32K")); // max size data i/o (iPLUG4K,32K,65K.512K,1M,5M,10M,15M)
+ // *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ // * zzstamp: check timestamp parm
+ // *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ // P zzstamp B export
+ // D zzstamp PI Z
+ // D myStamp Z
+ // * vars
+ // D retStamp s Z
+ // /free
+ // retStamp=myStamp;
+ // myStamp=z'1960-12-31-12.32.23.000000';
+ // return retStamp;
+ // /end-free
+ // P E
+ $param[] = $ToolkitServiceObj->AddParameterChar ('both', 26, 'ZZSTAMP', 'myStamp', '2011-12-29-12.45.29.000000');
+ $retrn[] = $ToolkitServiceObj->AddParameterChar ('both', 26, 'ZZSTAMP', 'retStamp', '2002-02-02-02.02.02.000000');
+ $result = $ToolkitServiceObj->PgmCall('ZZSRV', $libxmlservice, $param, $retrn, array('func'=>'ZZSTAMP'));
+ // var_dump($result);
+ /* in/out param myDate */
+ $myStamp = "XMLSERVICE i/o param myStamp: ".$result["io_param"]["myStamp"];
+ echo "$myStamp\n";
+ $expect = '1960-12-31-12.32.23.000000';
+ if (strpos($myStamp,$expect)<1) die("Fail missing $expect\n");
+ /* return value retStamp */
+ $retStamp = "XMLSERVICE return retStamp: ".$result["retvals"]["retStamp"];
+ echo "$retStamp\n";
+ $expect = '2011-12-29-12.45.29.000000';
+ if (strpos($retStamp,$expect)<1) die("Fail missing $expect\n");
+ /* all good */
+ echo "Success\n";
+ ?>
+
+
+
+
+2) XMLSERVICE Raw XML Samples
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ZZDATE (D datfmt(\*iso))
+""""""""""""""""""""""""""
+
+::
+
+ xpath('/script/pgm');
+ if (!$allpgms) die("Missing XML pgm info");
+ // -----------------
+ // output pgm call
+ // -----------------
+ // only one program this XML script
+ $pgm = $allpgms[0];
+ $name = $pgm->attributes()->name;
+ $lib = $pgm->attributes()->lib;
+ $func = $pgm->attributes()->func;
+ // pgm parms
+ $parm = $pgm->xpath('parm');
+ if (!$parm) die("Fail XML pgm parms missing ($lib/$name.$func)\n");
+ $var = $parm[0]->data->attributes()->var;
+ $actual = (string)$parm[0]->data;
+ $expect='2007-09-30';
+ if ($actual != $expect) die("parm: $var ($actual not $expect) ($lib/$name.$func)\n");
+ // pgm data returned
+ $retn = $pgm->xpath('return');
+ if (!$retn) die("Fail XML pgm return missing ($lib/$name.$func)\n");
+ $var = $retn[0]->data->attributes()->var;
+ $actual = (string)$retn[0]->data;
+ $expect='2009-05-11';
+ if ($actual != $expect) die("return: $var ($actual not $expect) ($lib/$name.$func)\n");
+
+ // good
+ echo "Success ($lib/$name.$func)\n";
+
+ // *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ // * zzdate: check date parm
+ // *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ // P zzdate B export
+ // D zzdate PI D
+ // D myDate D datfmt(*iso)
+ function getxml() {
+ $clob = <<
+
+ ENDPROC;
+ return test_lib_replace($clob);
+ }
+ ?>
+
+
+ZZDATEUSA (D datfmt(\*USA))
+"""""""""""""""""""""""""""""
+
+::
+
+ xpath('/script/pgm');
+ if (!$allpgms) die("Missing XML pgm info");
+ // -----------------
+ // output pgm call
+ // -----------------
+ // only one program this XML script
+ $pgm = $allpgms[0];
+ $name = $pgm->attributes()->name;
+ $lib = $pgm->attributes()->lib;
+ $func = $pgm->attributes()->func;
+ // pgm parms
+ $parm = $pgm->xpath('parm');
+ if (!$parm) die("Fail XML pgm parms missing ($lib/$name.$func)\n");
+ $var = $parm[0]->data->attributes()->var;
+ $actual = (string)$parm[0]->data;
+ $expect='09/30/2007';
+ if ($actual != $expect) die("parm: $var ($actual not $expect) ($lib/$name.$func)\n");
+ // pgm data returned
+ $retn = $pgm->xpath('return');
+ if (!$retn) die("Fail XML pgm return missing ($lib/$name.$func)\n");
+ $var = $retn[0]->data->attributes()->var;
+ $actual = (string)$retn[0]->data;
+ $expect='05/11/2009';
+ if ($actual != $expect) die("return: $var ($actual not $expect) ($lib/$name.$func)\n");
+
+ // good
+ echo "Success ($lib/$name.$func)\n";
+
+ // *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ // * zzdateUSA: check date parm
+ // *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ // P zzdateUSA B export
+ // D zzdateUSA PI D datfmt(*USA)
+ // D myDate D datfmt(*USA)
+ function getxml() {
+ $clob = <<
+
+ ENDPROC;
+ return test_lib_replace($clob);
+ }
+ ?>
+
+ZZTIME (T timfmt(\*iso))
+""""""""""""""""""""""""""
+
+::
+
+ xpath('/script/pgm');
+ if (!$allpgms) die("Missing XML pgm info");
+ // -----------------
+ // output pgm call
+ // -----------------
+ // only one program this XML script
+ $pgm = $allpgms[0];
+ $name = $pgm->attributes()->name;
+ $lib = $pgm->attributes()->lib;
+ $func = $pgm->attributes()->func;
+ // pgm parms
+ $parm = $pgm->xpath('parm');
+ if (!$parm) die("Fail XML pgm parms missing ($lib/$name.$func)\n");
+ $var = $parm[0]->data->attributes()->var;
+ $actual = (string)$parm[0]->data;
+ $expect='12.34.56';
+ if ($actual != $expect) die("parm: $var ($actual not $expect) ($lib/$name.$func)\n");
+ // pgm data returned
+ $retn = $pgm->xpath('return');
+ if (!$retn) die("Fail XML pgm return missing ($lib/$name.$func)\n");
+ $var = $retn[0]->data->attributes()->var;
+ $actual = (string)$retn[0]->data;
+ $expect='09.45.29';
+ if ($actual != $expect) die("return: $var ($actual not $expect) ($lib/$name.$func)\n");
+
+ // good
+ echo "Success ($lib/$name.$func)\n";
+
+ // *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ // * zztime: check time parm
+ // *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ // P zztime B export
+ // D zztime PI T
+ // D myTime T timfmt(*iso)
+ function getxml() {
+ $clob = <<
+
+ ENDPROC;
+ return test_lib_replace($clob);
+ }
+ ?>
+
+ZZTIMEUSA (T timfmt(\*USA))
+"""""""""""""""""""""""""""""
+
+::
+
+ xpath('/script/pgm');
+ if (!$allpgms) die("Missing XML pgm info");
+ // -----------------
+ // output pgm call
+ // -----------------
+ // only one program this XML script
+ $pgm = $allpgms[0];
+ $name = $pgm->attributes()->name;
+ $lib = $pgm->attributes()->lib;
+ $func = $pgm->attributes()->func;
+ // pgm parms
+ $parm = $pgm->xpath('parm');
+ if (!$parm) die("Fail XML pgm parms missing ($lib/$name.$func)\n");
+ $var = $parm[0]->data->attributes()->var;
+ $actual = (string)$parm[0]->data;
+ $expect='12:34 PM';
+ if ($actual != $expect) die("parm: $var ($actual not $expect) ($lib/$name.$func)\n");
+ // pgm data returned
+ $retn = $pgm->xpath('return');
+ if (!$retn) die("Fail XML pgm return missing ($lib/$name.$func)\n");
+ $var = $retn[0]->data->attributes()->var;
+ $actual = (string)$retn[0]->data;
+ $expect='09:45 AM';
+ if ($actual != $expect) die("return: $var ($actual not $expect) ($lib/$name.$func)\n");
+
+ // good
+ echo "Success ($lib/$name.$func)\n";
+
+ // *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ // * zztimeUSA: check time parm
+ // *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ // P zztimeUSA B export
+ // D zztimeUSA PI T timfmt(*USA)
+ // D myTime T timfmt(*USA)
+ function getxml() {
+ $clob = <<
+
+ ENDPROC;
+ return test_lib_replace($clob);
+ }
+ ?>
+
+
+ZZSTAMP (Z)
+"""""""""""
+
+::
+
+ xpath('/script/pgm');
+ if (!$allpgms) die("Missing XML pgm info");
+ // -----------------
+ // output pgm call
+ // -----------------
+ // only one program this XML script
+ $pgm = $allpgms[0];
+ $name = $pgm->attributes()->name;
+ $lib = $pgm->attributes()->lib;
+ $func = $pgm->attributes()->func;
+ // pgm parms
+ $parm = $pgm->xpath('parm');
+ if (!$parm) die("Fail XML pgm parms missing ($lib/$name.$func)\n");
+ $var = $parm[0]->data->attributes()->var;
+ $actual = (string)$parm[0]->data;
+ $expect='1960-12-31-12.32.23.000000';
+ if ($actual != $expect) die("parm: $var ($actual not $expect) ($lib/$name.$func)\n");
+ // pgm data returned
+ $retn = $pgm->xpath('return');
+ if (!$retn) die("Fail XML pgm return missing ($lib/$name.$func)\n");
+ $var = $retn[0]->data->attributes()->var;
+ $actual = (string)$retn[0]->data;
+ $expect='2011-12-29-12.45.29.000000';
+ if ($actual != $expect) die("return: $var ($actual not $expect) ($lib/$name.$func)\n");
+
+ // good
+ echo "Success ($lib/$name.$func)\n";
+
+ // *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ // * zzstamp: check timestamp parm
+ // *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ // P zzstamp B export
+ // D zzstamp PI Z
+ // D myStamp Z
+ function getxml() {
+ $clob = <<
+
+ ENDPROC;
+ return test_lib_replace($clob);
+ }
+ ?>
+
+
+
+
+..
+ [--Author([[http://youngiprofessionals.com/wiki/index.php/XMLSERVICE/XMLSERVICEDate?action=expirediff | s ]])--]
+ [--Tony "Ranger" Cairns - IBM i PHP / PASE--]
diff --git a/docs/debugging.rst b/docs/debugging.rst
new file mode 100755
index 0000000..65b48c2
--- /dev/null
+++ b/docs/debugging.rst
@@ -0,0 +1,1112 @@
+XMLSERVICE/Toolkit debugging and service
+========================================
+
+`Goto Main Page`_
+
+.. _Goto Main Page: index.html
+
+Who is this page for?
+---------------------
+Instructions designed for IBM i developer learning PHP and XMLSERVICE ...
+
+Debug technique: It's as easy as 1-2-3-4-5-6-7-8-9 :)
+-----------------------------------------------------
+a) Run the test script that contains control "\*debug" and script will "hang" while it waits on #2
+
+ ``$ctl .= " *debug";``
+
+ 1. A MSGW inquiry message in DSPMSG QSYSOPR will be generated by the toolkit. Note the job information (number, name, user) provided in the MSGW.
+
+ #. STRSRVJOB using that job information as parameters.
+
+ #. STRDBG with the program and library you wish to debug.
+
+ #. Answer the MSGW. Any answer will do--"G" is fine.
+
+ #. The RPG program source will appear in debug mode in your terminal, ready to step through, allowing you to inspect variables, etc.
+
+ #. When done inspecting and stepping, let the RPG program complete (using function keys indicated on screen).
+
+ #. ENDDBG
+
+b) ENDSRVJOB
+
+Other debug options::
+
+ Job1 (threaded) Job 2 Job 3 (DB2 userid/password) Job 4 (optional XTOOLKIT job)
+ (ctl=*debugcgi) (ctl=*debugproc) (ctl=*debug)
+ browser -> Apache ->XMLCGI (Apache CGI child) -> QSQSRVR (XMLSERVICE *here)
+ -> QSQSRVR (XMLSERVICE client) -> XTOOLKIT (XMLSERVICE ipc=/tmp/flinstone)
+
+ $ctl .= " *debugcgi"; // Job 2 - debug XMLCGI to see REST/HTTP data passed by client (when using REST only)
+ $ctl .= " *debugproc"; // Job 3 - debug XMLSERVICE "client" to see DB2 passed data (DB2 interface)
+ $ctl .= " *debug"; // Job 4 - debug XMLSERVICE "server" to see XMLSERVICE calls (DB2 interface)
+ // Note: when ctl='*here', both XMLSERVICE "client"/"server"
+ // are in QSQSRVSR job (NO XTOOLKIT job)
+ // remote: Attaching with LUW drivers changes QSQSRVR ...
+ // CLIENT (Client Access drivers) <==> QZDAxxxx
+ // CLIENT (DB2 Connect drivers) <==> QRWxxxx
+
+
+..
+ Tips
+ ----
+ This is a collection of debug tips and where you may find your problem data.
+ * [[#logs | Check the logs (click here) ...]] -- viewing PHP logs is often enough to solve a problem
+ ** [[#phplog | Check PHP log for messages (click here) ...]]
+ ** [[#httplog | Check Apache logs for messages (click here) ...]]
+ ** [[#newlog | Check PHP toolkit logs for messages (click here) ...]]
+ * [[#jobactive | Check active XMLSERVICE job (click here) ...]]
+ ** WRKACTJOB -- ``5=work -> 10. Display job log -> F10=Display detailed messages`` can be very revealing
+ ** WRKACTJOB -- ``5=work -> 11. Display call stack -> F5=Refresh`` watch stack during stress runs
+ * [[#levels | Check one level at a time (click here) ...]] -- run simple tests up web site food chain can be very revealing
+ ** Download tests: 2012-05-18 - [[ Attach:levels-1.4.zip | levels-1.4.zip]] -- simple tests for each level
+ ** [[#level0 | Level 0 -- PHP working (click here) ...]]
+ ** [[#level1 | Level 1 -- Apache/PHP working (click here) ...]]
+ ** [[#level2 | Level 2 -- db2 connection working (click here) ...]]
+ ** [[#level3 | Level 3 - XMLSERVICE XML interface working (click here) ...]]
+ ** [[#level4 | Level 4 -- PHP New Toolkit working (click here) ...]]
+ ** [[#level5 | Level 5 -- PHP CW Toolkit working (optional) (click here) ...]]
+ * [[#debugger | Stop XMLSERVICE for debugger attach (click here) ..]]
+ ** [[#debuggerfind | WRKACTJOB find XMLSERVICE private mode only (click here) ...]]
+ ** [[#debuggerstop | XMLSERVICE QSYSOPR message stop anytime (click here) ...]]
+ * additional links common XMLSERVICE error information
+ ** [[XMLSERVICEFAQ | %blue%{XMLSERVICE FAQ}%%]] - have issues, try here
+ ** [[XMLSERVICEERROR | %blue%{XMLSERVICE ERRORS}%%]] - errors, try here
+ ** [[XMLSERVICEConnect | %blue%{XMLSERVICE Connections}%%]] - XMLSERVICE/Toolkit connections
+ ** [[XMLSERVICEConfig | %blue%{XMLSERVICE Performance}%%]] - performance XMLSERVICE
+ * PASE debug secrets (for a PASE geek) ...
+ ** [[PASE/Geek]] - everything about PASE from a geek
+ ** [[PASE/PASEDebug]] - debug secrets
+ * The following links are associated with my machine environment and may be helpful.
+ ** [[Apache/ab | Apache ab tool]] -- Apache ab web site stress tests are performed from the 5250 command line (call qp2term) or ssh myibmi using PASE (see Apache ab link install instructions)
+ *** You can run stress tests from 2-tier Linux/Windows using Apache ab tool, but i am using Apchae ab from PASE.
+ *** Apache ab tool is not perfect, but if you use relatively "sane" number of browsers like -c 10 it will work.
+ *** Apache ab test is designed to drive CPU to 100% (a good thing), so don't panic about CPU
+ ** [[Java/SystemDebugger | GUI System Debugger]] -- GUI debugger always available on IBM i
+ ** [[FastCGI/FastCGI | Apache FastCGI]] -- Apache FastCGI is used for PHP on IBM i, this link may be helpful.
+ ** [[PHP/IASP | PHP via iASP]] -- My machine setup using iASP Zend Server data.
+ *** Many of the examples below reference %red%/MYASP2/www/zend2%% because i am running all my Zend Server data in an Apache ZEND2 configuration on port 80 using iASP /MYASP2 ``(http://myibmi/hello.php)``.
+ *** Your configuration is more likely Zend Server out-of-the-box-install running in /www/zendsvr on port 10088 (http://myibmi:10088/hello.php)
+
+Working with service provider?
+------------------------------
+
+Here are a few common things that can provide useful information if working with outside support people.
+
+0) easy way 1.7.1 ... just send provider XMLSERVLOG/LOG and XMLSERVLOG/DUMP in SAVF
+
+assuming you have a trace of the issue (see xmlservice logging instructions)
+
+1) what do you see in error logs for simple tests ???
+
+::
+
+ call qp2term
+ > tail /usr/local/zendsvr/var/log/php.log
+ > tail /myasp2/www/zend2/logs/error_log.Q112061800
+ > tail /myasp2/www/zend2/logs/access_log.Q112061800
+
+2) Summarize configuration (below)???
+
+ My Example
+
+ ::
+
+ SYSASP -- ZENDSVR library ... everything as installed
+ SYSASP -- /usr/local/zendsvr ... everything as installed
+ SYSASP -- /tmp ... many Zend "enterprise" components use /tmp
+ MYASP2 -- /myasp2/www/zend2 ... ALL "user data" moved from /www/zendsvr (/conf, /logs, /htdocs)
+ More ... /myasp2/www/zend2
+ -- NO symbolic links between SYSAPS and MYASP2 for true "independent"ASP.
+ -- config files /myasp2/www/zend2/conf
+ attach: fastcgi.conf
+ attach: httpd.conf
+
+3) Around time of simple test failure ... do you see job logs?
+
+ *wrkoutq*
+
+ ::
+
+ If jobs are still active (php-cgi, etc.) ...
+ wrkactjob
+ 5 ZEND2 QTMHHTTP BCI .0 PGM-QZSRHTTP SIGW
+ ZEND2 QTMHHTTP BCI .0 PGM-php-cgi.bi THDW
+ 5 ZEND2 QTMHHTTP BCI .0 PGM-php-cgi.bi TIMW
+ 10. Display job log, if active, on job queue, or pending
+ F10 -- full job log
+
+4) Around time of simple test failure ... do you see VLOGS???
+
+ ::
+
+ STRSST
+ 1. Start a service tool
+ 5. Licensed Internal Code log
+ 1. Select entries from the Licensed Internal Code (LIC) log
+ Specify Licensed Internal Code Log Selection Values
+ -- leave as is enter ---
+ 0100A890 i5/OS PASE 4700 0013 06/15/12 09:03:43 7 <--- PASE
+ 0100A891 LIC log interface 0401 0100 06/15/12 09:04:08 1
+ 0100A892 Signals management 4600 0001 06/15/12 09:04:51 255
+ 0100A893 Process management 1300 0001 06/18/12 21:02:06 1
+
+ Maybe look for PASE, storage management, ASP, so on around "failure time"
+
+ Note:
+ You can also dump logs to spool ...
+
+When you have no idea (dumping many processes)?
+-----------------------------------------------
+
+ Some times you just have no idea what is going on, here is a handy macro to dump a lot of stacks.
+
+ ::
+
+ STRSST/STRDST
+ 1. Start a service tool
+ 4. Display/Alter/Dump
+ 1. Display/Alter storage
+ ... or option for dump to printer ...
+ 2. Licensed Internal Code (LIC) data
+ 14. Advanced analysis
+ Option Command
+ 1 processinfo
+
+ In this case dumping all process dealing with keyword "ZEND" appearing in job ...
+
+ Specify Advanced Analysis Options
+ Output device . . . . . . : Display
+ Type options, press Enter.
+ Command . . . . : PROCESSINFO
+ Options . . . . . -NAMES ZEND
+
+ Note:
+ Information dumped printer/display is same as paseps macro.
+
+
+
+Check active XMLSERVICE job
+---------------------------
+
+If you are using private connections (InternalKey or $ipc='/tmp/packers'), the XMLSERVICE job is probably available for examination with wrkactjob.
+::
+
+ Work with Active Jobs LP0264D
+ 05/17/12 11:35:12
+ CPU %: .0 Elapsed time: 00:00:00 Active jobs: 313
+
+ Type options, press Enter.
+ 2=Change 3=Hold 4=End 5=Work with 6=Release 7=Display message
+ 8=Work with spooled files 13=Disconnect ...
+ Current
+ Opt Subsystem/Job User Type CPU % Function Status
+ 5 XTOOLKIT DB2 BCH .0 PGM-XMLSERVICE SEMW
+
+1) Use ``option 5=work -> 10. Display job log -> F10=Display detailed messages`` to examine joblog on errors ...
+
+::
+
+ Display All Messages
+ System: LP0264D
+ Job . . : XTOOLKIT User . . : DB2 Number . . . : 435915
+
+ >> CALL PGM(XMLSERVICE/XMLSERVICE) PARM('/tmp/packers')
+ Pointer not set for location referenced.
+ Application error. MCH3601 unmonitored by ZZSRV at statement 0000000448,
+ instruction X'0000'.
+
+
+2) Use ``option 5=work -> 11. Display call stack -> F5=Refresh`` to examine stack during stress tests ...
+
+::
+
+ Display Call Stack
+ System: LP0264D
+ Job: XTOOLKIT User: DB2 Number: 437582
+ Thread: 0000000C
+
+
+ Type Program Statement Procedure
+ 1 QCMD QSYS /01C8
+ XMLSERVICE XMLSERVICE _QRNP_PEP_XMLSERVICE
+ XMLSERVICE XMLSERVICE 1133 XMLSERVICE
+ XMLSERVICE XMLSERVICE 4607 RUNSERVER
+ XMLSERVICE XMLSERVICE 2983 SIGSETTIMEOUT
+ XMLSERVICE XMLSERVICE 2876 SIGTIMEROFF
+ QP0SSRV1 QSYS 19 setitimer
+ QP0SSRV2 QSYS 159 qp0sitimer__F12qp0sitimer_t >
+
+Check the logs
+--------------
+
+Check PHP log for messages
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+On my IBM i machine::
+
+ EDTF STMF('/usr/local/zendsvr/var/log/php.log')
+ -- or --
+ call qp2term (or ssh myibmi)
+ > tail /usr/local/zendsvr/var/log/php.log
+ ... stuff
+ ... in /MYASP2/www/zend2/htdocs/hello.php on line 1
+
+On my Linux machine::
+
+ $ tail /usr/local/zend/var/log/php.log
+ [16-May-2012 16:30:12] PHP Warning: db2_close() expects parameter 1 to be resource ...
+
+
+Check Apache logs for messages
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error logs for date in question::
+
+ EDTF STMF('/myasp2/www/zend2/logs/error_log.Q112051500')
+ -- or --
+ call qp2term (or ssh myibmi)
+ > tail /myasp2/www/zend2/logs/error_log.Q112051500
+ [Tue May 15 17:10:11 2012] [error] [client 9.5.158.38] CGI PROGRAM /QSYS.LIB/XMLSERVICE.LIB/XMLCGI.PGM RETURNED EXCEPTION ID CEE9901
+ [Tue May 15 17:10:11 2012] [error] [client 9.5.158.38] SEE JOBLOG FOR JOB 428979/QTMHHTTP /ZEND2
+
+access logs for date in question::
+
+ EDTF STMF('/myasp2/www/zend2/logs/access_log.Q112051500')
+ -- or --
+ call qp2term (or ssh myibmi)
+ > tail /myasp2/www/zend2/logs/access_log.Q112051500
+ 9.5.158.38 - - [15/May/2012:17:47:41 -0500] "GET /cgi-bin/xmlcgi.pgm?db2=LP0264D
+
+
+Check PHP Toolkit logs for messages
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+toolkit.ini logfile
+::
+
+ EDTF STMF('/usr/local/zendsvr/share/ToolkitApi/toolkit.log')
+ -- or --
+ call qp2term (or ssh myibmi)
+ > tail /usr/local/zendsvr/share/ToolkitAPI/toolkit.log
+ 15 May 2012 22:53:35.752099 Running stateless; no IPC needed. Service library: ZENDSVR
+ 15 May 2012 22:53:36.588466 i5Error: num=14 cat=9 msg="No more entries." desc="No more entries."
+
+ location set in toolkit.ini ...
+ EDTF STMF('/usr/local/zendsvr/share/ToolkitApi/toolkit.ini')
+ [log]
+ ; warnings and errors will be written to the logfile.
+ logfile = "/usr/local/zendsvr/share/ToolkitApi/toolkit.log"
+
+toolkit.ini debugLogFile
+::
+
+ EDTF STMF('/usr/local/zendsvr/share/ToolkitApi/debug.log')
+ -- or --
+ call qp2term (or ssh myibmi)
+ > tail /usr/local/zendsvr/share/ToolkitAPI/debug.log
+
+
+
+ location set in toolkit.ini ...
+ EDTF STMF('/usr/local/zendsvr/share/ToolkitApi/toolkit.ini')
+ ; debug turns PHP toolkit's debug mode on or off (true/false). Default log file: /usr/local/zendsvr/share/ToolkitApi/debug.log
+ ; This log will grow large, so leave this false when you do not need to log everything.
+ debug = true
+ debugLogFile = "/usr/local/zendsvr/share/ToolkitApi/debug.log"
+
+PHP and XMLSERVICE bad XML
+::
+
+ EDTF STMF('/tmp/bad.xml')
+ -- or --
+ > tail /tmp/bad.xml
+ start
+
+ ENDPROC;
+ $clobIn = test_lib_replace($xml);
+
+ // xml common text replacement
+ function test_lib_replace($xml) {
+ global $libxmlservice, $iOPM;
+ if (!$iOPM) {
+ $was = array("xyzlibxmlservicexyz");
+ $now = array("$libxmlservice");
+ }
+ else {
+ $was = array("xyzlibxmlservicexyz","setOptions(array('customControl'=>'*debug')).``
+
+ Run your script.
+ The script will "hang" while it waits on #2 below...
+ (move to green screen 5250 for steps 2-10)
+
+2. A MSGW inquiry message in DSPMSG QSYSOPR will be generated by the toolkit.
+3. Note the job information (number, name, user) provided in the MSGW.
+4. STRSRVJOB using that job information as parameters.
+5. STRDBG with the program and library you wish to debug.
+6. Answer the MSGW. Any answer will do--"G" is fine.
+7. The RPG program source will appear in debug mode in your terminal, ready to step through, allowing you to inspect variables, etc.
+8. When done inspecting and stepping, let the RPG program complete (using function keys indicated on screen).
+9. ENDDBG
+#. ENDSRVJOB
+
+
+..
+ [--Author([[http://youngiprofessionals.com/wiki/index.php/XMLSERVICE/XMLSERVICEDebug?action=expirediff | s ]])--]
+ [--Tony "Ranger" Cairns - IBM i PHP / PASE--]
diff --git a/docs/errors.rst b/docs/errors.rst
new file mode 100755
index 0000000..b8fcf51
--- /dev/null
+++ b/docs/errors.rst
@@ -0,0 +1,238 @@
+XMLSERVICE Errors
+=================
+`Goto Main Page`_
+
+.. _Goto Main Page: index.html
+
+
+Common errors
+-------------
+
+::
+
+ 3401
+
+ 1301011
+
+
+
+
+errnoile 3401 -- usually means another process with a different user profile is using IPC (/tmp/packers3)
+
+::
+
+ 3021
+ 1301009
+ IPC getshm fail
+
+
+'Hung' semaphores/shared memory associated with a user never suppose to happen, but have seen in rare occasion. The following commands can be used to remove "hung" semaphores/shared memory associated with a user assuming you have appropriate authority to run like SECOFR, etc. (Ranger welcomes you to Unix geek-ville).
+
+Example::
+
+ grep -i qtm means ipcrm for (QTM)HHTTP ...
+
+ endTCPSVR SERVER(*HTTP) INSTANCE(ZENDSVR) -- suggest end web server
+
+ call qp2term
+ > ipcs | grep -i qtm | awk '{print "ipcrm -" tolower($1) " "$2}' -- show action, but NOT do action
+ > ipcs | grep -i qtm | awk '{print "ipcrm -" tolower($1) " "$2}' | sh -- remove semaphores/shared memory
+
+ strTCPSVR SERVER(*HTTP) INSTANCE(ZENDSVR) -- suggest start web server
+
+
+::
+
+ 1000005
+ PASE resolve failed
+
+
+The program you tried to call, shown here as "MYPGM" (in the CDATA tag), was not found. Make sure you specified the library and program correctly, including upper or lower case (usually upper case).
+
+::
+
+ 1480002
+ XMLCGI invalid
+ *NONE
+
+\*NONE requires a special compile of the RPG source and is NOT enabled in production versions of the toolkit by default.
+It is most useful for demos with custom security like this site, if you try on your machine you will likely get 1480002
+error XMLCGI. You can find details in plugerr_h.
+
+
+ILE errno
+---------
+
+Errno Values for UNIX-Type Functions
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Programs using the UNIX(R)-type functions may receive error information as errno values.
+The possible values returned are listed here in ascending errno value sequence.
+
+::
+
+ Name Value Text
+ EDOM 3001 A domain error occurred in a math function.
+ ERANGE 3002 A range error occurred.
+ ETRUNC 3003 Data was truncated on an input, output, or update operation.
+ ENOTOPEN 3004 File is not open.
+ ENOTREAD 3005 File is not opened for read operations.
+ EIO 3006 Input/output error.
+ ENODEV 3007 No such device.
+ ERECIO 3008 Cannot get single character for files opened for record I/O.
+ ENOTWRITE 3009 File is not opened for write operations.
+ ESTDIN 3010 The stdin stream cannot be opened.
+ ESTDOUT 3011 The stdout stream cannot be opened.
+ ESTDERR 3012 The stderr stream cannot be opened.
+ EBADSEEK 3013 The positioning parameter in fseek is not correct.
+ EBADNAME 3014 The object name specified is not correct.
+ EBADMODE 3015 The type variable specified on the open function is not correct.
+ EBADPOS 3017 The position specifier is not correct.
+ ENOPOS 3018 There is no record at the specified position.
+ ENUMMBRS 3019 Attempted to use ftell on multiple members.
+ ENUMRECS 3020 The current record position is too long for ftell.
+ EINVAL 3021 The value specified for the argument is not correct.
+ EBADFUNC 3022 Function parameter in the signal function is not set.
+ ENOENT 3025 No such path or directory.
+ ENOREC 3026 Record is not found.
+ EPERM 3027 The operation is not permitted.
+ EBADDATA 3028 Message data is not valid.
+ EBUSY 3029 Resource busy.
+ EBADOPT 3040 Option specified is not valid.
+ ENOTUPD 3041 File is not opened for update operations.
+ ENOTDLT 3042 File is not opened for delete operations.
+ EPAD 3043 The number of characters written is shorter than the expected record length.
+ EBADKEYLN 3044 A length that was not valid was specified for the key.
+ EPUTANDGET 3080 A read operation should not immediately follow a write operation.
+ EGETANDPUT 3081 A write operation should not immediately follow a read operation.
+ EIOERROR 3101 A nonrecoverable I/O error occurred.
+ EIORECERR 3102 A recoverable I/O error occurred.
+ EACCES 3401 Permission denied.
+ ENOTDIR 3403 Not a directory.
+ ENOSPC 3404 No space is available.
+ EXDEV 3405 Improper link.
+ EAGAIN 3406 Operation would have caused the process to be suspended.
+ EWOULDBLOCK 3406 Operation would have caused the process to be suspended.
+ EINTR 3407 Interrupted function call.
+ EFAULT 3408 The address used for an argument was not correct.
+ ETIME 3409 Operation timed out.
+ ENXIO 3415 No such device or address.
+ EAPAR 3418 Possible APAR condition or hardware failure.
+ ERECURSE 3419 Recursive attempt rejected.
+ EADDRINUSE 3420 Address already in use.
+ EADDRNOTAVAIL 3421 Address is not available.
+ EAFNOSUPPORT 3422 The type of socket is not supported in this protocol family.
+ EALREADY 3423 Operation is already in progress.
+ ECONNABORTED 3424 Connection ended abnormally.
+ ECONNREFUSED 3425 A remote host refused an attempted connect operation.
+ ECONNRESET 3426 A connection with a remote socket was reset by that socket.
+ EDESTADDRREQ 3427 Operation requires destination address.
+ EHOSTDOWN 3428 A remote host is not available.
+ EHOSTUNREACH 3429 A route to the remote host is not available.
+ EINPROGRESS 3430 Operation in progress.
+ EISCONN 3431 A connection has already been established.
+ EMSGSIZE 3432 Message size is out of range.
+ ENETDOWN 3433 The network currently is not available.
+ ENETRESET 3434 A socket is connected to a host that is no longer available.
+ ENETUNREACH 3435 Cannot reach the destination network.
+ ENOBUFS 3436 There is not enough buffer space for the requested operation.
+ ENOPROTOOPT 3437 The protocol does not support the specified option.
+ ENOTCONN 3438 Requested operation requires a connection.
+ ENOTSOCK 3439 The specified descriptor does not reference a socket.
+ ENOTSUP 3440 Operation is not supported.
+ EOPNOTSUPP 3440 Operation is not supported.
+ EPFNOSUPPORT 3441 The socket protocol family is not supported.
+ EPROTONOSUPPORT 3442 No protocol of the specified type and domain exists.
+ EPROTOTYPE 3443 The socket type or protocols are not compatible.
+ ERCVDERR 3444 An error indication was sent by the peer program.
+ ESHUTDOWN 3445 Cannot send data after a shutdown.
+ ESOCKTNOSUPPORT 3446 The specified socket type is not supported.
+ ETIMEDOUT 3447 A remote host did not respond within the timeout period.
+ EUNATCH 3448 The protocol required to support the specified address family is not available at this time.
+ EBADF 3450 Descriptor is not valid.
+ EMFILE 3452 Too many open files for this process.
+ ENFILE 3453 Too many open files in the system.
+ EPIPE 3455 Broken pipe.
+ ECANCEL 3456 Operation cancelled.
+ EEXIST 3457 File exists.
+ EDEADLK 3459 Resource deadlock avoided.
+ ENOMEM 3460 Storage allocation request failed.
+ EOWNERTERM 3462 The synchronization object no longer exists because the owner is no longer running.
+ EDESTROYED 3463 The synchronization object was destroyed, or the object no longer exists.
+ ETERM 3464 Operation was terminated.
+ ENOENT1 3465 No such file or directory.
+ ENOEQFLOG 3466 Object is already linked to a dead directory.
+ EEMPTYDIR 3467 Directory is empty.
+ EMLINK 3468 Maximum link count for a file was exceeded.
+ ESPIPE 3469 Seek request is not supported for object.
+ ENOSYS 3470 Function not implemented.
+ EISDIR 3471 Specified target is a directory.
+ EROFS 3472 Read-only file system.
+ EUNKNOWN 3474 Unknown system state.
+ EITERBAD 3475 Iterator is not valid.
+ EITERSTE 3476 Iterator is in wrong state for operation.
+ EHRICLSBAD 3477 HRI class is not valid.
+ EHRICLBAD 3478 HRI subclass is not valid.
+ EHRITYPBAD 3479 HRI type is not valid.
+ ENOTAPPL 3480 Data requested is not applicable.
+ EHRIREQTYP 3481 HRI request type is not valid.
+ EHRINAMEBAD 3482 HRI resource name is not valid.
+ EDAMAGE 3484 A damaged object was encountered.
+ ELOOP 3485 A loop exists in the symbolic links.
+ ENAMETOOLONG 3486 A path name is too long.
+ ENOLCK 3487 No locks are available.
+ ENOTEMPTY 3488 Directory is not empty.
+ ENOSYSRSC 3489 System resources are not available.
+ ECONVERT 3490 Conversion error.
+ E2BIG 3491 Argument list is too long.
+ EILSEQ 3492 Conversion stopped due to input character that does not belong to the input codeset.
+ ETYPE 3493 Object type mismatch.
+ EBADDIR 3494 Attempted to reference a directory that was not found or was destroyed.
+ EBADOBJ 3495 Attempted to reference an object that was not found, was destroyed, or was damaged.
+ EIDXINVAL 3496 Data space index used as a directory is not valid.
+ ESOFTDAMAGE 3497 Object has soft damage.
+ ENOTENROLL 3498 User is not enrolled in system distribution directory.
+ EOFFLINE 3499 Object is suspended.
+ EROOBJ 3500 Object is a read-only object.
+ EEAHDDSI 3501 Hard damage on extended attribute data space index.
+ EEASDDSI 3502 Soft damage on extended attribute data space index.
+ EEAHDDS 3503 Hard damage on extended attribute data space.
+ EEASDDS 3504 Soft damage on extended attribute data space.
+ EEADUPRC 3505 Duplicate extended attribute record.
+ ELOCKED 3506 Area being read from or written to is locked.
+ EFBIG 3507 Object too large.
+ EIDRM 3509 The semaphore, shared memory, or message queue identifier is removed from the system.
+ ENOMSG 3510 The queue does not contain a message of the desired type and (msgflg logically ANDed with IPC_NOWAIT).
+ EFILECVT 3511 File ID conversion of a directory failed.
+ EBADFID 3512 A file ID could not be assigned when linking an object to a directory.
+ ESTALE 3513 File handle was rejected by server.
+ ESRCH 3515 No such process.
+ ENOTSIGINIT 3516 Process is not enabled for signals.
+ ECHILD 3517 No child process.
+ EBADH 3520 Handle is not valid.
+ ETOOMANYREFS 3523 The operation would have exceeded the maximum number of references allowed for a descriptor.
+ ENOTSAFE 3524 Function is not allowed.
+ EOVERFLOW 3525 Object is too large to process.
+ EJRNDAMAGE 3526 Journal is damaged.
+ EJRNINACTIVE 3527 Journal is inactive.
+ EJRNRCVSPC 3528 Journal space or system storage error.
+ EJRNRMT 3529 Journal is remote.
+ ENEWJRNRCV 3530 New journal receiver is needed.
+ ENEWJRN 3531 New journal is needed.
+ EJOURNALED 3532 Object already journaled.
+ EJRNENTTOOLONG 3533 Entry is too large to send.
+ EDATALINK 3534 Object is a datalink object.
+ ENOTAVAIL 3535 IASP is not available.
+ ENOTTY 3536 I/O control operation is not appropriate.
+ EFBIG2 3540 Attempt to write or truncate file past its sort file size limit.
+ ETXTBSY 3543 Text file busy.
+ EASPGRPNOTSET 3544 ASP group not set for thread.
+ ERESTART 3545 A system call was interrupted and may be restarted.
+ ESCANFAILURE 3546 An object has been marked as a scan failure due to processing by an exit program associated with the scan-related integrated file system exit points.
+
+
+
+
+..
+ [--Author([[http://youngiprofessionals.com/wiki/index.php/XMLSERVICE/XMLSERVICEError?action=expirediff | s ]])--]
+ [--Tony "Ranger" Cairns - IBM i PHP / PASE--]
diff --git a/docs/examples.rst b/docs/examples.rst
new file mode 100755
index 0000000..8fbda50
--- /dev/null
+++ b/docs/examples.rst
@@ -0,0 +1,341 @@
+
+
+XMLSERVICE Examples
+===================
+`Goto Main Page`_
+
+.. _Goto Main Page: index.html
+
+The following foils include running examples you can click to help get started as you learn about this Open Source.
+
+* :ref:`part-1`
+* :ref:`part-2`
+
+Goal of Open Source XMLSERVICE RPG library is flexibility, enabling ANY sort of transport local/remote connection with any language available in your enterprise to call resources on your IBM i machine. XMLSERVICE primary transport interface in production today is DB2 connections using included stored procedures (xmlstoredp.srvpgm iPLUGxxxx). XMLSERVICE secondary transport interface used mostly demos is Apache REST connection (xmlcgi.pgm). However, XMLSERVICE allows writing your own custom transport (anything you imagine). XML Service and Toolkit on-going mission is to add new function, improve performance, expand uses, with goal of never impacting existing customers.
+
+
+**Warning**: This is an active IBM i education machine, occasionally examples may not work, try back later.
+
+.. _part-1:
+
+Part 1 - Protect your investment
+--------------------------------
+
+* XML Service Access Native IBM i Objects from any language using XML
+* XML Service completely free/safe commercial use download (Github)
+* XML Service examples HTML/XML (no PHP, no RPG)
+* XML Service examples RPG (no PHP)
+* XML Service vs. DB2 Stored Procedures - Why use XML Service at all?
+* XML Service protect your investment summary
+
+
+XML Service - is free
+^^^^^^^^^^^^^^^^^^^^^
+
+* XML Service is completely free/safe commercial use
+
+ * BSD license, download, keep any source copy forever (safe)
+
+* XML Service written in RPG open source (you can change it)
+
+ * Techniques used IBM i calls are stable, unlikely to change (ever)
+
+* XML Service is supported Open Source
+
+ * XML Service fix/add improvement goal is never impact current customers
+
+
+XML Service - XML everything
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+* XML input <> XML output
+
+ * Any device
+ * Any language
+ * Any local/remote connection
+ * Any IBM i service (PGM, CMD, System API, DB2, PASE)
+
+
+
+XML Service - IBM i Native Access through XML
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+* Access Native IBM i Objects from any language using XML
+
+ * Local or remote IBM i: IBM i local, IBM i-2-IBM i, Linux/Unix/Windows-2-IBM, etc.
+ * Any language access: PHP, Ruby, Java, Perl, RPG, no language at all (HTML/XML)
+ * Many Native Object Types: DB2 SQL and Native, Program call, Procedure call, Data Area, Data Queue, Message Queue, Commands, System values, Spool files, PASE utilities
+
+* Local or remote call interfaces to XMLSERVICE (included RPG download)
+
+ * Primary: call DB2 stored procedures local or remote (iPLUG4K - iPLUG15M)
+ * Secondary: call REST HTTP local or remote (xmlcgi.pgm)
+
+
+XML Service - Moving Parts
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+* Any language
+
+ * Browser HTML/XML
+ * Script PHP, Ruby, JavaScript, etc.
+ * Compiled RPG, C, etc.
+
+* Any local/remote connection
+
+ * Linux/Unix/Windows/Mac ibm_db2/odbc/REST to IBM i
+ * Native IBM i ibm_db2/odbc/REST to IBM i
+
+
+XML Service public "stateless" (\*here)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+* XMLSERVICE public "stateless" (CTL='\*here', IPC='\*NA')
+
+ * profile FRED (any public QSQ)
+ * profile SALLY (any public QSQ)
+ * profile RITA (any public QSQ)
+ * profile XAVIER (any public QSQ)
+
+* XMLSTOREDP->XMLSERVICE (QSQ)
+
+ * QSQ temporary profile use (stateless)
+ * QSQ return to pool on script end
+ * XMLSERVICE restart every request (web style)
+
+
+XML Service private "state full" (\*sbmjob)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+* XMLSERVICE private "state full" (CTL='\*sbmjob', IPC='/tmp/xxxx')
+
+ * profile FRED XTOOLKIT myjob1,myjob2 (private)
+ * profile SALLY XTOOLKIT sallyjob1 (private)
+ * profile RITA XTOOLKIT nursejob (private)
+ * profile XAVIER XTOOLKIT xjob1,xjob2,xjob3,xjob4,xjob5 (private)
+
+* XMLSTOREDP (QSQ)
+
+ * QSQ temporary profile use (stateless)
+ * QSQ return to pool on script end
+
+* XMLSERVICE (XTOOLKIT)
+
+ * XTOOLKIT owned by profile (private)
+ * XTOOLKIT job never ends (until killed)
+ * XTOOLKIT full state programming (5250 style)
+
+
+
+XML Service Configuration
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+* Apache REST (xmlcgi.pgm)
+* DB2 stored procedures (xmlstoredp.srvpgm iPLUGxx)
+
+
+XML Service - Example HTML/XML (no PHP, no RPG)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+* XML Service HTTP browser direct (xmlcgi.pgm)
+
+ * web enable via httpd.conf
+
+ ::
+
+