[[GenericPackager]]

== GenericPackager

After writing multiple ISOFieldPackager implementations, jPOS developer Eoin
Flood came up with a nice idea: writing a GenericPackager that would read an
XML configuration file and instantiate an ISOFieldPackager on-the-fly.

[NOTE]
======
Because packagers are usually instantiated once during the life time of an
application, there's no performance impact between a packager implemented
in pure Java or the GenericPackager that reads an XML only at initialization
time.
======

Using this approach, the same packager we've seen in the previous example can
be easily configured using +GenericPackager+ and a simple XML file like this:

.ISO-8583 version 1993 packager configuration
====

[source,xml]
----
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE isopackager PUBLIC
        "-//jPOS/jPOS Generic Packager DTD 1.0//EN"
        "http://jpos.org/dtd/generic-packager-1.0.dtd">

<!-- ISO 8583:1993 (BINARY) field descriptions for GenericPackager -->

<isopackager>
  <isofield
      id="0"
      length="4"
      name="Message Type Indicator"
      pad="false"
      class="org.jpos.iso.IFB_NUMERIC"/>
  <isofield
      id="1"
      length="16"
      name="Bitmap"
      class="org.jpos.iso.IFB_BITMAP"/>
  <isofield
      id="2"
      length="19"
      name="Primary Account number"
      pad="false"
      class="org.jpos.iso.IFB_LLNUM"/>
  <isofield
      id="3"
      length="6"
      name="Processing Code"
      pad="false"
      class="org.jpos.iso.IFB_NUMERIC"/>
  <isofield
      id="4"
      length="12"
      name="Amount, Transaction"
      pad="false"
      class="org.jpos.iso.IFB_NUMERIC"/>
   ...
   ...
   ...
  <isofield
      id="126"
      length="999"
      name="Reserved for private use"
      class="org.jpos.iso.IFB_LLLCHAR"/>
  <isofield
      id="127"
      length="999"
      name="Reserved for private use"
      class="org.jpos.iso.IFB_LLLCHAR"/>
  <isofield
      id="128"
      length="8"
      name="Message authentication code field"
      class="org.jpos.iso.IFB_BINARY"/>
</isopackager>
----
====

GenericPackager uses a DTD defined in `jpos/src/main/resources/org/jpos/iso/packager/genericpackager.dtd`
that looks like this:

----
<?xml version="1.0" encoding="UTF-8"?>

<!ELEMENT isopackager (isofield+,isofieldpackager*)*>
<!ATTLIST isopackager maxValidField CDATA        #IMPLIED>
<!ATTLIST isopackager bitmapField   CDATA        #IMPLIED>
<!ATTLIST isopackager firstField    CDATA        #IMPLIED>
<!ATTLIST isopackager emitBitmap    (true|false) #IMPLIED>
<!ATTLIST isopackager headerLength  CDATA        #IMPLIED>

<!-- isofield -->
<!ELEMENT isofield (#PCDATA)>
<!ATTLIST isofield id     CDATA        #REQUIRED>
<!ATTLIST isofield length CDATA        #REQUIRED>
<!ATTLIST isofield name   CDATA        #REQUIRED>
<!ATTLIST isofield class  NMTOKEN      #REQUIRED>
<!ATTLIST isofield token  CDATA        #IMPLIED>
<!ATTLIST isofield pad    (true|false) #IMPLIED>

<!-- isofieldpackager -->
<!ELEMENT isofieldpackager (isofield+,isofieldpackager*)*>
<!ATTLIST isofieldpackager id       CDATA        #REQUIRED>
<!ATTLIST isofieldpackager name     CDATA        #REQUIRED>
<!ATTLIST isofieldpackager length   CDATA        #REQUIRED>
<!ATTLIST isofieldpackager class    NMTOKEN      #REQUIRED>
<!ATTLIST isofieldpackager token    CDATA        #IMPLIED>
<!ATTLIST isofieldpackager pad      (true|false) #IMPLIED>
<!ATTLIST isofieldpackager packager NMTOKEN      #REQUIRED>
<!ATTLIST isofieldpackager emitBitmap (true|false) #IMPLIED>
<!ATTLIST isofieldpackager maxValidField CDATA        #IMPLIED>
<!ATTLIST isofieldpackager bitmapField CDATA        #IMPLIED>
<!ATTLIST isofieldpackager firstField  CDATA        #IMPLIED>
<!ATTLIST isofieldpackager headerLength  CDATA        #IMPLIED>
----

GenericPackager's DTD eases the configuration of nested messages
(an ISO-8583 field that is a full ISO-8583 message itself), e.g.:

[source,xml]
----
   ...
   ...
  <isofieldpackager
      id="127"
      length="255"
      name="FILE RECORS(S) ACTION/DATA"
      class="org.jpos.iso.IFB_LLHBINARY"
      packager="org.jpos.iso.packager.GenericSubFieldPackager">
      <isofield
          id="0"
          length="1"
          name="FILE UPDATE COD"
          class="org.jpos.iso.IFE_CHAR"/>
      <isofield
          id="1"
          length="19"
          name="ACCOUNT NUMBER"
          pad="true"
          class="org.jpos.iso.IFB_LLHNUM"/>
      <isofield
          id="2"
          length="4"
          name="PURGE DATE"
          pad="true"
          class="org.jpos.iso.IFB_NUMERIC"/>
      ...
      ...
      ...
  </isofieldpackager>
----

[NOTE]
======
The +GenericPackager+ uses an entity resolver that recognizes the PUBLIC DTD
in order to avoid loading it over the internet. This is particularly important
when you run your system in a DMZ with limited access to the outside world.

In order to take advantage of the entity resolver, you need to make sure
that your packager configuration starts with the following preamble:

------
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE isopackager PUBLIC
        "-//jPOS/jPOS Generic Packager DTD 1.0//EN"
        "http://jpos.org/dtd/generic-packager-1.0.dtd">
------
======

