Visualizzazione post con etichetta RPG. Mostra tutti i post
Visualizzazione post con etichetta RPG. Mostra tutti i post

martedì 14 novembre 2017

Inviare allegati a un web service con MTOM. (parte due... con IBMi)

Nella prima parte abbiamo visto come scrivere un servizio web che accetti file inviati con MTOM, un sistema standard per la trasmissione di allegati non codificati in Base64, ora vediamo come trasferire il tutto su IBMi.

Dividiamo i passaggi sempre tra producer e consumer, prima quindi vediamo come installare il servizio sul server delle applicazioni integrato sulla macchina, poi come creare un client scritto in RPG che interroghi il servizio.

IL PRODUCER.


Di cosa abbiamo bisogno:

  • Una macchina IBMi con IAS versione 8.1 (io ho usato la versione del sistema operativo V7R1).

Ricordate il war prodotto da Maven nel progetto Eclipse? Nella cartella target... MTOMService.war, proprio quello. Bene, prendiamolo e trasferiamolo sull'IFS del nostro sistema, in qualunque modo e in qualunque cartella vogliate.

Ad esempio io uso FileZilla e ho caricato il file su /tmp

Ora dovremmo collegarci al server amministrativo della nostra macchina, prima però verifichiamo che sia operativo, altrimenti avviamolo con:
STRTCPSVR SERVER(*HTTP) HTTPSVR(*ADMIN)

Quindi apriamo il browser e indirizziamolo verso:

http://<host_nostra_macchina_IBMi>:2001/HTTPAdmin

e accediamo con un utente amministrativo.

Ci viene mostrata la lista dei server presenti nel sistema, dobbiamo creare un server delle applicazioni (come Tomcat) che ospiti la nostra servlet, per cui clicchiamo su "Crea server delle applicazioni":

Questo link è molto più semplice, rispetto a quello del DCM... valli a capire...

Scegliamo di usare la versione 8.1 del server:


e andiamo avanti accettando i default che ci vengono proposti, se non avevamo creato altri server delle applicazioni dovremmo avere il server INTAPPSVR in ascolto sulla porta 10000 della macchina.

Fermiamolo. Così com'è ora non riuscirebbe a instanziare la nostra servlet CXF, questo perché CXF non è compatibile con l'implementazione JAX-WS presente sul server, vanno usate le librerie che forniamo noi, per cui:

Stop. Dopo lo riavviamo con il tasto play.

Spostiamoci su terminale, dobbiamo modificare una configurazione prima di farlo ripartire, modifichiamo questo file:
EDTF STMF('/www/INTAPPSVR/lwi/conf/overrides/i5javaopts.javaopt')
Inserendo questa riga:
-Dcom.ibm.websphere.webservices.DisableIBMJAXWSEngine=true
In questo modo istruiamo la JVM a non far partire il server con il supporto nativo JAX-WS.

Ora possiamo ritornare alla gestione del server e farlo ripartire (vedi sopra).

Clicchiamo sul link "Gestisci applicazioni installate", vediamo che per ora è presente una fantomatica quanto solinga "Guida di Eclipse", premiamo sul tasto Installa per aggiungere la nostra applicazione e chiediamo di importare il nostro war caricato prima:


Accettiamo tutti i default, infine vedremo la nostra applicazione fare compagnia alla "Guida di Eclipse" (?).

Facciamo click sul nome della nostra applicazione per interrogarla, si apre una nuova finestra del browser e... errore 404! Vi ricordate che va aggiusto services alla fine del link, vero?

La lista dei servizi messi a disposizione!

Possiamo copiare il link al nostro WSDL per creare un ambiente di test nel solito SoapUI, ma penso che sia arrivato il momento di fare da soli e creare un client in RPG.

IL CONSUMER.


Cosa ci occorre:
  • HTTPAPI di S. Klement (versione usata 1.37)
  • WSDL2RPG di T. Raddatz (la versione 1.16.5, che ha introdotto il supporto a MTOM, seppur sperimentale)

 

Preparativi.


Installiamo le due utility, magari con il supporto a HTTPS, e iniziamo con il creare un libreria e un file di sorgenti:
CRTLIB LIB(ZENEXMPL) TEXT('Example programs')

CRTSRCPF FILE(ZENUTILS/QWSDL) RCDLEN(112) TEXT('WSDL 2 RPG Stubs')
e mettiamo tutto in lista librerie:
ADDLIBLE LIB(LIBHTTP)

ADDLIBLE LIB(WSDL2RPG)

ADDLIBLE LIB(ZENEXMPL)
WSDL2RPG è un utility che crea le procedure necessarie ad assemblare la SOAP Envelope ed effettua la chiamata tramite HTTPAPI. I moduli creati vanno compilati ed assemblati in un service program che andrà collegato ai nostri programmi.
Per creare i sorgenti necessari usiamo il comando:
WSDL2RPG URL('http://localhost:10000/MTOMService/services/archiveServer?wsdl') SRCFILE(ZENEXMPL/QWSDL) SRCMBR(MTOM01) TYPE(*STUB) STRLEN(256) ATTACHMENT(*YES) PARMSTRUCT(*STMF) STRUCTSTMF('/tmp/MTOM01.log' *YES)
e selezioniamo con 1 tutti i metodi esposti dal servizio web: stiamo dicendo all'utility di creare il necessario per l'interrogazione di entrambi i metodi, con il supporto per l'invio di allegati.
Vengono creati i seguenti sorgenti nel file creato prima:
MTOM01      RPGLE       Web Service: ArchiveServerPort
MTOM01001   RPGLE       Web Service: archiveFile()
MTOM01002   RPGLE       Web Service: getFile()
Da questi sorgenti vanno creati i moduli, ma prima sono necessarie delle modifiche per attivare la ricezione MTOM, dato che - come dicevo prima - è sperimentale. Apriamo il sorgente MTOM01001:
STRSEU SRCFILE(ZENEXMPL/QWSDL) SRCMBR(MTOM01001)
(ma potete anche usare RDi.)

Dobbiamo cercare l'istruzione:
g_hMsgCtx = MessageContext_new();
e modificarla così:
g_hMsgCtx = MessageContext_new(cTrue);
(tutto qui.)

La stessa cosa va fatta anche per il sorgente MTOM01002.

Ora possiamo compilare:
CRTRPGMOD MODULE(ZENEXMPL/MTOM01) SRCFILE(ZENEXMPL/QWSDL) SRCMBR(MTOM01)

CRTRPGMOD MODULE(ZENEXMPL/MTOM01001) SRCFILE(ZENEXMPL/QWSDL) SRCMBR(MTOM01001)

CRTRPGMOD MODULE(ZENEXMPL/MTOM01002) SRCFILE(ZENEXMPL/QWSDL) SRCMBR(MTOM01002)
e creare il service program.
CRTSRVPGM SRVPGM(ZENEXMPL/MTOM01) MODULE(ZENEXMPL/MTOM01 ZENEXMPL/MTOM01001 ZENEXMPL/MTOM01002) EXPORT(*ALL) TEXT('MTOM Service Example') BNDSRVPGM((*LIBL/WSDL2RPGRT) (*LIBL/MIME) (*LIBL/HTTPMIME) (*LIBL/BASICS1)) BNDDIR(QC2LE)

 

Implementiamo.


L'utility ha creato le procedure necessarie per interrogare il nostro web service, e noi abbiamo compilato il programma di servizio per utilizzarle, in particolare la procedura:

 ArchiveServerPort_archiveFile 

effettua la chiamata al servizio archiveFile della nostra applicazione e se andiamo a indagare la sua definizione vediamo che richiede in ingresso:
  • una struttura dati i_tns_archiveFile di tipo tns_archiveFileRnmd_t : sono i parametri da passare al web service;
  • una struttura dati o_msg di tipo wsdl_errText_t : contiene eventuali messaggi di errore;

in uscita invece popola una struttura dati di tipo tns_archiveFileResponse_t che contiene la risposta del web service.

NB: le strutture dati tns_archiveFileRnmd_t e tns_archiveFileResponse_t sono modellate dall'utility secondo quanto è stato dichiarato nel WSDL, rispecchiano quindi la stessa struttura dello schema XML!

NB2: l'utility rinomina le procedure e le strutture dati secondo i nomi del nostro web service e i suoi metodi, normalmente quindi le procedure descritte sopra cambiano sempre nome per ogni web service di cui facciamo lo stub, ad esempio il template per i nomi visti prima sono:
  • procedura principale: <Nome_Web_Service>_<Nome_Metodo> ;
  • struttura dati ingresso: tns_<Nome_Metodo>Rnmd_t ;
  • struttura dati uscita: tns_<Nome_Metodo>Response_t .

Se non abbiamo idea di come utilizzare questa procedura e non vogliamo partire da zero, niente paura! WSDL2RPG ci permette di costruire in automatico un programma di esempio con il comando:
WSDL2RPG URL('http://localhost:10000/MTOMService/services/archiveServer?wsdl') SRCFILE(ZENEXMPL/QWSDL) SRCMBR(MTOM01001T) TYPE(*PGM) STUB(MTOM01001)
e selezionando il metodo archiveFile e ancora:
WSDL2RPG URL('http://localhost:10000/MTOMService/services/archiveServer?wsdl') SRCFILE(ZENEXMPL/QWSDL) SRCMBR(MTOM01002T) TYPE(*PGM) STUB(MTOM01002)
e selezionando il metodo getFile.

Ora abbiamo due sorgenti di due programmi che testano le due procedure, dobbiamo solo modificare qualche riga per poter fargli fare quello che vogliamo. Iniziamo dal programma per fare l'upload: MTOM01001T.
STRSEU SRCFILE(ZENEXMPL/QWSDL) SRCMBR(MTOM01001T)
(come prima, potete usare RDi)

Prima di tutto inseriamo dei parametri di ingresso, in modo che il programma possa essere utilizzato in maniera variabile (al momento i parametri sono fissi) tramite un comando, cerchiamo:
D MTOM01001T...
D                 PR
e
D MTOM01001T...
D                 PI
e sotto inseriamo:
D description                         like(
D                                     tns_archiveRequest_t.description)
D fileLoad                            like(
D                                     tns_archiveRequest_t.fileLoad)
D fileName                            like(
D                                     tns_archiveRequest_t.fileName)
D fileType                            like(
D                                     tns_archiveRequest_t.fileType)
D key                                 like(
D                                     tns_archiveRequest_t.key)
Quindi spostiamo i parametri in ingresso nella struttura dati che contiene i parametri della Request, che diventa:
parameters.request.fileName = fileName;
parameters.request.fileType = 'application/pdf';
parameters.request.key = key;
parameters.request.description = description;
alla fine aggiungiamo il nostro allegato:
parameters.request.fileLoad = 'cid:'+
     ArchiveServerPort_archiveFile_Attachments_addFile(
        filePath: parameters.request.fileType);
NB: la procedura ArchiveServerPort_archiveFile_Attachments_addFile serve per aggiungere un allegato, richiede il percorso del file sull'IFS e il suo MIME-Type e ritorna l'identificativo della sezione http dove verrà inserito, come al solito il nome può cambiare e il template è:
<Nome_Web_Service>_<Nome_Metodo>_Attachments_addFile.

Ora tocca al programma per fare il download: MTOM01002T.
STRSEU SRCFILE(ZENEXMPL/QWSDL) SRCMBR(MTOM01002T)
In maniera simile a prima aggiungiamo i parametri, che è uno solo: la chiave del documento registrata in upload. Per cui cerchiamo:
D MTOM01002T...
D                 PR
e
D MTOM01002T...
D                 PI
e sotto inseriamo:
D key                                 like(
D                                     tns_getFile_t.key)
E poi facciamo sempre in modo che il nostro input finisca nei parametri della Request:
parameters.key = key;

Ora possiamo compilare:
CRTRPGMOD MODULE(ZENEXMPL/MTOM01001T) SRCFILE(*LIBL/QWSDL) SRCMBR(MTOM01001T) DBGVIEW(*LIST) TRUNCNBR(*NO)

CRTPGM PGM(ZENEXMPL/MTOM01001T) MODULE(ZENEXMPL/MTOM01001T) TEXT('MTOM Service Example - Test Upload') BNDSRVPGM((ZENEXMPL/MTOM01)) BNDDIR(QC2LE) ACTGRP(*NEW)

CRTRPGMOD MODULE(ZENEXMPL/MTOM01002T) SRCFILE(*LIBL/QWSDL) SRCMBR(MTOM01002T) DBGVIEW(*LIST) TRUNCNBR(*NO)

CRTPGM PGM(ZENEXMPL/MTOM01002T) MODULE(ZENEXMPL/MTOM01002T) TEXT('MTOM Service Example - Test Download') BNDSRVPGM((ZENEXMPL/MTOM01)) BNDDIR(QC2LE) ACTGRP(*NEW)

Abbiamo i nostri due programmi di test, ma potrebbe essere utile fare due comandi per poterli utilizzare, iniziamo creando il comando per inviare:
STRSEU SRCFILE(ZENEXMPL/QWSDL) SRCMBR(SNDMTOM) TYPE(CMD) TEXT('Web Service: archiveFile() - Upload Comand')
e modifichiamo il sorgente SNDMTOM così:
CMD        PROMPT('MTOM Service Upload')

PARM       KWD(DESC)              +
           MIN(1)                 +
           TYPE(*CHAR)            +
           VARY(*YES *INT2)       +
           LEN(128)               +
           CASE(*MIXED)           +
           PROMPT('File description' 1)

PARM       KWD(PATH)              +
           MIN(1)                 +
           TYPE(*CHAR)            +
           VARY(*YES *INT2)       +
           LEN(128)               +
           CASE(*MIXED)           +
           PROMPT('File path' 2)

PARM       KWD(NAME)              +
           MIN(1)                 +
           TYPE(*CHAR)            +
           VARY(*YES *INT2)       +  
           LEN(128)               +
           CASE(*MIXED)           +
           PROMPT('File name' 3)

PARM       KWD(TYPE)              +
           MIN(1)                 +
           TYPE(*CHAR)            +
           VARY(*YES *INT2)       +
           LEN(128)               +
           CASE(*MIXED)           +
           PROMPT('File type' 4)

PARM       KWD(KEY)              +
           MIN(1)                 +
           TYPE(*CHAR)            +
           VARY(*YES *INT2)       +
           LEN(20)                +
           CASE(*MIXED)           +
           PROMPT('Key' 5)
Stessa cosa per il comando per ricevere: RCVMTOM.
STRSEU SRCFILE(ZENEXMPL/QWSDL) SRCMBR(RCVMTOM) TYPE(CMD) TEXT('Web Service: archiveFile() - Download Comand')
e quindi:
CMD        PROMPT('MTOM Service Download')

PARM       KWD(KEY)              +
           MIN(1)                 +
           TYPE(*CHAR)            +
           VARY(*YES *INT2)       +
           LEN(20)                +
           CASE(*MIXED)           +
           PROMPT('Key' 1)
Infine non ci resta che creare anche questi oggetti:
CRTCMD CMD(ZENEXMPL/SNDMTOM) PGM(ZENEXMPL/MTOM01001T) SRCFILE(ZENEXMPL/QWSDL) SRCMBR(SNDMTOM)

CRTCMD CMD(ZENEXMPL/RCVMTOM) PGM(ZENEXMPL/MTOM01002T) SRCFILE(ZENEXMPL/QWSDL) SRCMBR(RCVMTOM)

Ora possiamo testare i nostri programmi! Assicuriamoci di avere un file PDF da utilizzare per i nostri scopi salvato su IFS, per comodità io mi riferirò a un ipotetico file testfile.pdf presente in /tmp, iniziamo inviando il file:
ZENEXMPL/SNDMTOM DESC('Test file.') PATH('/tmp/testfile.pdf') NAME(renamed.pdf) TYPE('application/pdf') KEY(TEST1)
(lo salviamo sotto altro nome, giusto per provare.)

Il messaggio *** Success *** in fondo al terminale ci indica che la trasmissione è avvenuta, ma dove è stato salvato il file? Ricordate che l'applicazione stampa in output il path di archiviazione? Però questo output non è interattivo, è salvato in un file apposito nel percorso dell'istanza del server:
DSPF STMF('/www/INTAPPSVR/lwi/logs/lwistdout.txt')
dall'output notiamo che i file temporanei sono gestiti per singola istanza, per cui troviamo il file salvato qui:
DSPF STMF('/www/INTAPPSVR/lwi/temp/uploaded/renamed.pdf')
Ora quindi proviamo a recuperare il file appena archiviato:
ZENEXMPL/RCVMTOM KEY(TEST1)
Ancora, il messaggio *** Success *** ci indica che tutto è ok, questa volta però spetta alla nostra procedura salvare il file, che di default salva tutti gli allegati in /tmp/attachments:
WRKLNK OBJ('/tmp/attachments')

Considerazioni.


La funzione MTOM dell'utility è un'aggiunta interessante ed è stato divertente approcciarsi a questa metodologia e farla funzionare su IBMi, ricordo però che è ancora in fase sperimentale, e non è quindi esente da mancanze e bug che ne potrebbero limitare l'usabilità, nel caso vi invito a contattare l'autore per segnalare eventuali problemi che potrebbero essere corretti in una futura release!

Di seguito alcuni link utili:
  • il sito di Raddatz ha una serie di manuali che spiegano più ampiamente l'utility e le sue procedure;
  • la mailing list di Klement: è per avere aiuto per HTTPAPI, però viene data risposta anche a domande su WSDL2RPG;
  • Il repository dove ho rilasciato i sorgenti di questo esempio: i sorgenti vanno importati poi a mano nella libreria ZENEXMPL, oppure ho preparato un SAVF che può essere ripristinato sulla macchina (salvato come V7R1M0);
  • Configurazioni particolari per fa funzionare CXF su WebSphere;
  • Manuale dello IAS.

sabato 25 aprile 2015

Even the OVERLAYs shift

If you though that what explained here was referred only to the text fields in a SCS compiled as an AFPDS, you couldn't have been more wrong! Even the graphics is shifted in the same way, here explained a method to solve it:

1. Draw your OVERLAY normally


Draw it with Word, Publisher, Libreoffice, finish it off with Photoshop or Gimp, take it from a pdf file, scan a scribble... you can do whatever you want, the important thing is that the width and height of the page are the same of your printing (A4? 210 × 297 mm or 8.27 × 11.69 inches).

2. Set the printer driver

First of all, you must download it from here:
http://www-01.ibm.com/support/docview.wss?uid=nas8N1011940.
Download it, unzip it in a folder, create a new printer in the Windows Control Panel on a local port of FILE: type, search for the drivers into the folder where you extracted the files, and then install the driver called "Generic InfoPrint 300dpi AFP".

Now, with the right mouse button on the fresh created printer, click on Printing Preferences and then on Advanced. Here the so desired view:


The idea is to set the driver so that it cuts out the sheet's unprintable borders, the same that we inserted in the FRONTMGN parameter:


using millimeters

using inches

in this case inches are more accurate.

 


3. Import in the system

Print your layout on the newly created printer, a window will appear asking to save a file, you can use the name that you want, I'll name it layout.prn for convenience.
Now let's write down some command, first of all , transfer layout.prn on your system IFS, for example into /tmp, then create a new physical file:

CRTPF FILE(QGPL/QOVLSRC) RCDLEN(1024) MAXMBRS(*NOMAX) MBR(*NONE)
 LVLCHK(*NO)

file name, library and length are not so important, only copy layout.prn in a new member:

CPYFRMSTMF
 FROMSTMF('/tmp/layout.prn') 
 TOMBR('/qsys.lib/qgpl.lib/qovlsrc.file/layout.mbr') 
 MBROPT(*REPLACE) 
CVTDTA(*NONE) ENDLINFMT(*FIXED) TABEXPN(*NO) 

and then:

CRTOVL OVL(QGPL/LAYOUT) FILE(QGPL/QOVLSRC) MBR(*OVL)

in order to create the object LAYOUT typed *OVL in QGPL.

4. Place your OVERLAY at the beginning of the printable area





As for the title, place LAYOUT into your printer file:

OVERLAY(QGPL/LAYOUT 0 0) 

the (0,0) position point out the top left corner of the printable area set with the FRONTMGN parameter.


Feels good.


sabato 18 aprile 2015

Anche gli OVERLAY si spostano

Voi speravate che quanto spiegato qui riguardasse solo i campi di testo di un SCS compilato come AFPDS, e invece no! Anche la grafica viene spostata, ecco come rimediare:

1. Disegnate il vostro OVERLAY normalmente


Disegnatelo con Word, Publisher, Libreoffice, rifinitelo con Photoshop o Gimp, prendetelo da un pdf, scannerizzate uno scarabocchio... potete fare come volete, l'importante è che sia delle dimensioni del foglio impostate nella misura della stampa (A4? 210 × 297 mm , 8.27 × 11.69 pollici) .

2. Impostate il driver di stampa

Che poi prima lo dovete scaricare, qui:
http://www-01.ibm.com/support/docview.wss?uid=nas8N1011940.
Una volta scaricato, estraete tutto in una cartella, create una nuova stampante locale dal Pannello di Controllo di Windows su porta di tipo FILE: , cercate i driver nella cartella dove avete estratto i file, dovreste installare il driver "Generic InfoPrint 300dpi AFP".

Ora tasto destro sulla stampante creata, poi cliccate su Proprietà Stampante e poi su Preferenze, ecco l'agognata schermata:


L'idea è di impostare il driver per ritagliare i bordi non stampabili del foglio, cioè gli stessi che abbiamo inserito nel parametro FRONTMGN:

per i millimetri

per i pollici

In questo caso i pollici sono più precisi.

 


3. Importate sul sistema

Stampate il vostro layout sulla nuova stampante creata, vi chiederà di salvare un file in una posizione, salvate con il nome che volete, per comodità lo chiamero layout.prn.
Ora un po' di comandi, innanzitutto, trasferite layout.prn sull'IFS del sistema ad esempio in /tmp, poi create un nuovo file fisico:

CRTPF FILE(QGPL/QOVLSRC) RCDLEN(1024) MAXMBRS(*NOMAX) MBR(*NONE)
 LVLCHK(*NO)

nome, libreria e lunghezza non sono importanti, dovete solo copiare layout.prn in un nuovo membro:

CPYFRMSTMF FROMSTMF('/tmp/layout.prn') 
 TOMBR('/qsys.lib/qgpl.lib/qovlsrc.file/layout.mbr') 
 MBROPT(*REPLACE) CVTDTA(*NONE) ENDLINFMT(*FIXED) TABEXPN(*NO)

e poi:

CRTOVL OVL(QGPL/LAYOUT) FILE(QGPL/QOVLSRC) MBR(*OVL)


per creare l'oggetto LAYOUT di tipo *OVL in QGPL.

4. Posizionate il vostro OVERLAY all'inizio dell'area stampabile





Come da titolo, posizionate LAYOUT nel vostro printer file:

OVERLAY(QGPL/LAYOUT 0 0) 

la posizione (0,0) indica l'angolo in alto a sinistra dell' area stampabile impostata con il parametro FRONTMGN.


Feels good.





domenica 2 novembre 2014

Honey, my AFP prints shifted.

II'll put this post here as a reminder for me and for whom has to deal with it:  the AFP prints shift. You have your print and you say: "Good, let's try it in *AFPDS, won't it be the same?". You'd compile your good old PRTF
like this:
CRTPRTF FILE(LIB/PRTF) DEVTYPE(*AFPDS)
and you'd print it. Some field shifted, others didn't. Ok, let's try it in PDF. Correct.

(average user reaction)

Flipping the tables like our friend RageGuy is not needed! The design of the Host Print Transform API (info) is to be "blamed" for all of this. In order to keep compatibility with IPDS systems, it shifts all the fields that fall into the unprintable borders of the sheet! That is well described in this article of the Support site.

For example, we could have this printer configuration:
CHGOUTQ OUTQ(QUEUE) TRANSFORM(*YES) MFRTYPMDL(*HP5)
We are teaching the system to use the HPT function in order to print on a PCL5 compatible printer, this kind of configuration sets the unprintable borders at 1/6 of an inch top and bottom and 1/4 of an inch left and right.
Those values are fixed into the terminal personalization object called QSYS/QWPHPLSR5 that corresponds to *HP5, the PDF transformation uses another personalization: that explains the different output!

You may say: "You know, my (laser) printer doesn't have UNPRINTABLE borders!" And I'd respond: "LOL! Yeah, and I climb mountains using a single finger like Manolo!". If you really insist on reducing the margins, you can set up a personalization object starting from *HP5 (for example).

Note: the margins are wide, guess why? To grant compatibilty with a vast number of printers.

(Compatibility is the favourite word of  Big Blue - isn't it?)

Even if you personalized your terminal, you could still be having this repositioning: text field or graphic, if they are located in the unprintable area they are "gently" moved to the printable area.
In order to solve this situation, the Support Site suggests three ways, let's see them.

  1. Move all the fields in the printable area


That is the "your problem" solution: armed with a graded ruler, you can easily perform calculations: if you print 15 CPI with 1/4 of an inch of unprintable border, the first printable column is the fifth.

Characters per Inch
(CPI) Value
Unprintable Border
in CPI
Earliest Starting
Column
5
5 / 4 = 1.2
3
10
10 / 4 = 2.5
4
12
12 / 4 = 3
4
13.3
13.3 / 4 = 3.325
5
15
15 / 4 = 3.75
5
16.7 o 17.1
16.7 / 4 = 4.175
6
18
18 / 4 = 4.5
6
20
20 / 4 = 5
6

Clearly, moving all the initial fields could mean refactoring the entire print...

  2. Change the FRONTMGN parameter


It's the best solution, pratically you'd set the margins of *HP5 in the print itself. This way you'll move all the fields of the print and you won't let the HPT function do what it wants; you can add this parameter during the creation or like a substitution:
CRTPRTF FILE(LIB/PRTF) FRONTMGN(0.17 0.25) UOM(*INCH)

CHGPRTF FILE(LIB/PRTF) FRONTMGN(0.17 0.25) UOM(*INCH)

OVRPRTF FILE(PRTF) FRONTMGN(0.17 0.25) OVERSCOPE(*JOB) 
        UOM(*INCH)

Please note that the unity of measure parameter (UOM) is set on inches. If instead you want to use centimeters you could go like this:
CRTPRTF FILE(LIB/PRTF) FRONTMGN(0.43 0.64) UOM(*CM)

CHGPRTF FILE(LIB/PRTF) FRONTMGN(0.43 0.64) UOM(*CM)

OVRPRTF FILE(PRTF) FRONTMGN(0.43 0.64) OVERSCOPE(*JOB) UOM(*CM)

  3. Printing in raster mode


That is the "meh" solution: you can set up a terminal personalization by setting the raster mode on, in the section:
:RASTERMODE
 SCS=NO
 AFP=NO.
change this fields
 SCS=YES
 AFP=YES.
With this configuration, you make the HPT function treat everything as graphic, translating even the character fields as bitmap (that's it, rasterizing), what will it imply?

- the fields in the unprintable borders won't be shifted but cropped,
- the resulting spool file is larger and the printing production slows down,
- you should install a couple of options in order to grant the compatibility with all the fonts (AFP Compatibility Fonts - IBM AFP Font Collection for IBM Operating System - Advanced Function Printing DBCS Fonts/400),
- if you have a tool that translates from PCL to PDF (one above all: GhostPDL), the text won't be selected.

...seriously!?

IBM makes available additional terminal personalizations (download the SAVF), some of them have the raster mode activated (like PCL5RASTER), and some other type and models (MFRTYPMDLs) with the raster mode are already installed in the system: *IBM4076, *HP310, *HP320, *HP500, *HP520 and *HP540.

In conclusion, create your printer files with:
CRTPRTF FILE(LIB/PRTF) FRONTMGN(0.17 0.25) UOM(*INCH)
And here you go!


P.S.: if you don't know, AFPDS is the graphic format made available by IBM, OS integrated.
You can do a lot of good things like changing fonts, inserting barcodes, impressing images and graphics to the prints, all this using keywords in the printer file (Did I say that it is integrated?).

http://afpcinc.org/
 (There is a Consortium that promotes it.)

(Bwahahaha! I found this on Google Images, it brings here, ask me nothing.)

domenica 5 ottobre 2014

Tesoro, mi si sono spostati gli AFP

Lascio qui questo post a monito mio e di quanti si cimenteranno: le stampe AFP si spostano. Avete la vostra bella stampa e dite: "Bene, ora proviamo a crearla come *AFPDS, non dovrebbe essere uguale?" Compilate il vostro bel PRTF
con
CRTPRTF FILE(LIB/PRTF) DEVTYPE(*AFPDS)
e stampate. Alcuni campi vengono spostati, altri no. Provate allora a farne un pdf. Corretto.

(reazione utente medio)

Non serve ribaltare i tavoli come il nostro amico RageGuy! La "colpa" di tutto questo è di come è stata pensata l'api Host Print Transform (info), che per mantanere una compatibilità con sistemi IPDS sposta tutta la grafica che ricade dentro i bordi non stampabili del foglio!
Tutto è spiegato bene in questo articolo del Support.

Prendiamo la nostra stampante così configurata:
CHGOUTQ OUTQ(QUEUE) TRANSFORM(*YES) MFRTYPMDL(*HP5)
In pratica, stiamo dicendo al sistema di utilizzare la funzione HPT su una stampante configurata come compatibile PCL5, una configurazione del genere fissa i margini non stampabili a 1/6 di pollice in alto e in basso e 1/4 di pollice a sinistra e destra.
Questi valori sono impostati nell' oggetto di personalizzazione di terminale QSYS/QWPHPLSR5 che corrisponde a *HP5, la trasformazione in PDF usa un'altra personalizzazione, che non ha quei margini lì, ecco spiegata la differenza di output!
Voi direte: "Ma la mia stampante (laser) può stampare al VIVO del foglio!"
E io rispondo: "LOL! Sì, e io scalo e montagne con un dito come Manolo!" Se proprio volete ridurre i margini, allora modificatevi un oggetto di personalizzazione terminale a partire da *HP5 (ad esempio).
NB: i margini sono piuttosto larghi, potete indovinare perchè? Per compatibilità con il maggior numero di stampanti.

(Compatibilità è la parola preferita di Big Blue - no?)

Anche personalizzando un terminale potreste incappare nello spostamento maledetto: che sia campo di testo o grafica, se ricade nell'area non stampabile viene "gentilmente" fatto accomodare da HPT dentro l'area stampabile.
Per ovviare a questo problema il Support propone tre vie, vediamole.

1. Spostate tutti i campi che rientrano nell'area non stampabile


Questa è la soluzione "arrangiati": riga meccanografica alla mano, i calcoli sono presto fatti, con 1/4 di margine non stampabile, se stampi a 15 CPI la prima colonna utile è la quinta.

Caratteri per Pollice
(CPI) Valore
Bordo Non Stampabile
in CPI
Prima Colonna
Stampabile
5
5 / 4 = 1.2
3
10
10 / 4 = 2.5
4
12
12 / 4 = 3
4
13.3
13.3 / 4 = 3.325
5
15
15 / 4 = 3.75
5
16.7 o 17.1
16.7 / 4 = 4.175
6
18
18 / 4 = 4.5
6
20
20 / 4 = 5
6

Certo, spostare i campi iniziali potrebbe voler dire ripensare l'intera stampa...

  2. Modificate il parametro FRONTMGN


E' la soluzione migliore, in pratica fissate i margini di *HP5 direttamente nella stampa, in questo modo spostate tutti i campi della stampa e non lasciate fare a HPT quello che vuole; potete inserire il parametro in fase di creazione o come sovrapposizione:
CRTPRTF FILE(LIB/PRTF) FRONTMGN(0.17 0.25) UOM(*INCH)

CHGPRTF FILE(LIB/PRTF) FRONTMGN(0.17 0.25) UOM(*INCH)

OVRPRTF FILE(PRTF) FRONTMGN(0.17 0.25) OVERSCOPE(*JOB) 
        UOM(*INCH)

Notate il parametro unità di misura (UOM) fissato sui pollici, se si usano i centimetri:
CRTPRTF FILE(LIB/PRTF) FRONTMGN(0.43 0.64) UOM(*CM)

CHGPRTF FILE(LIB/PRTF) FRONTMGN(0.43 0.64) UOM(*CM)

OVRPRTF FILE(PRTF) FRONTMGN(0.43 0.64) OVERSCOPE(*JOB) UOM(*CM)

3. Stampate in raster mode


Questa è la soluzione meh: potete modificare una personalizzazione di terminale attivando il raster mode, nella sezione:
:RASTERMODE
 SCS=NO
 AFP=NO.
modificate i campi
 SCS=YES
 AFP=YES.
Con questa configurazione dite a HPT di considerare tutto come grafica, quindi tradurre anche i campi di testo in bitmap (appunto, rasterizzare), cosa comporta questo?

- I campi nell'area non stampabile non vengono spostati ma vengono tagliati,
- la stampa è più pesante e la produzione della stessa è più lenta,
- dovete installare un paio di opzioni per la massima compatibilità con tutti i font (AFP Compatibility Fonts - IBM AFP Font Collection for IBM Operating System - Advanced Function Printing DBCS Fonts/400),
- se avete un tool che traduce da PCL a PDF (tipo GhostPDL), il testo risulterà non selezionabile,

insomma meh.

IBM mette a disposizione anche qualche personalizzazione di terminale aggiuntiva (scaricate il SAVF), alcune delle quali predisposte per il raster mode (tipo PCL5RASTER), alcuni tipi e modelli (MFRTYPMDLs) in raster mode sono invece già presenti nel sistema: *IBM4076, *HP310, *HP320, *HP500, *HP520 e *HP540.

In conclusione, create le vostre stampe con:
CRTPRTF FILE(LIB/PRTF) FRONTMGN(0.17 0.25) UOM(*INCH)
e siete a posto!


PS: per chi  non lo conoscesse, l' AFPDS è il formato grafico messo a disposizione da IBM, integrato nel sistema operativo.
Permette di fare tante belle robe tipo cambiare font, inserire barcode, imprimere loghi e grafiche alle stampe, il tutto utilizzando apposite keyword da mettere nel Printer File (ho detto che era integrato?).

http://afpcinc.org/
 (Esiste un consorzio che lo promuove.)

(ahahahah, questa l'ho trovata su Google Immagini e porta qui, non so perché)