Part 2 - Screen To JSON extraction

In this chapter of modernization tutorial, we will show how to create screen data extract definition used to generate pure JSON data object.

Generated object is combined with HTML template to generate UI screen which modernization engine will inject into loaded UI layer.

TIP: This system is terminal agnostic meaning we can use any web technology we like without vendor lock-in.

Screen extraction definition have five main segments:

  • templates - define which html screen template will be used
  • hotspots - define extraction definition of screen actions (PFnn) and screen options
  • fields - define name of screen field based on field order
  • data - define flat data extraction from screen as field data and field labels
  • grids - define subfile region extraction

Templates

Templates segment defines which HTML template engine will load. We can define different template for mobile and for browser or different templates based on uuid/host. For example, different template for production and test environment.

Here is template sample definition.

{
  "templates": {
    "default": {
        "html" : "screen/web/wrkactjob.html",
        "output": "#wrapper"
    },
    "os" :{
      "android" : {
          "html" : "screen/mobile/wrkactjob.html"
      }
    }
  }
}

Hotspots

Hotspots are screen area that contains PFn available actions and field options mostly used for subfile screens.

Hotspot definitions will create list of available actions which can be used in HTML template in different ways. For example, for mobile version we will create context menu with actions as Exit (F3), Cancel (F12) etc... While in web version we will create ribbon with buttons titled to action descriptions.

Here is basic definition which defines screen region that contains hotspots.

{
  "options" : {"row":4, "col":1, "rows":18, "cols": 78, "sort:true", "reverse" : true},
  "actions" : {"row":21, "col":1, "rows":22, "cols": 78, "sort:true", "reverse" : true},
}

NOTE: "options" and "actions" can also be an array of json definitions as PFn actions can de located on multiple places on the screen.

Fields

Define screen field name based on field order in terminal screen.

In following example (signon screen) we defined first field on the screen to be user and second to be password.

In our HTML template we can refer to those names. (will be described in detail in Part 3 of this tutorial)

{
  "fields": {
    "user": 1,
    "password": 2
  }
}

Flat data

Flat data is simple screen mapping mechanism used to extract text from specific portion of the screen. Extracted text will be attached to defined name. Name itself is used inside HTML template just as for field definitions.

Here is sample for signon screen. Extracted data are screen information from upper right corner plus bottom line error message.

{
  "data": {
    system : [1,69,8],
    r2c69 : {"row":2, "col":69, "len":10, "name":"subsystem" },
    r3c69 : {"row":3, "col":69, "len":10, "name":"displayName" },
    r23c39 : {"row":23, "col":39, "len":40, "name":"ibm" },
    r23c0 : {"row":23, "col":0, "len":40, "name":"error" },
    r5c16 : {"row":5, "col":16, "len":30, "name":"userlbl", "field" : "user", "trim" : "\\." }
  }
}

As you can see, there are two formats available:

  • array based - will use key name in resulting JSON data and row/col/len extraction values
  • object based - will use key name or value from name property if defined

Grids

Grids are definition for screen subfile. While data extraction format itself is not different than for flat data, general grids format is different.

Reason lays in subfiles. Subfiles can have different design, can show us different layout based on user preference, PFn function etc. For example, WRKACTJOB use F11 to switch between different view modes so we have to create different screen mapping rules.

General structure is:

{
 grids : {
    byStatus: {...},
    byElapse: {...},
    byThread: {...},
    byStatusExtA : {...}
 }
}

Base principle is to create tab pages in HTML template with clickable buttons which will be replacement for F11 action. Whenever user clicks on one of buttons F11 will be sent to terminal. Terminal will switch view and modernization engine will detect one of grids definition to use. Base on definition, different data will be extracted.

Each grid segment definition has four main types:

  • def - general subfile definition
  • headers - subfile header region - to generate table header columns
  • data - 1st subfile record data region
  • totals - region of totals if exists

Headers, data and totals are the same as for Flat data export so we will skip them.

Def segment is responsible for subfile detection. Here are the most important parameters:

  • name - will be used in resulting JSON as key name of grid data array
  • rows - how many rows subfile have
  • rowHeight - how many lines each row has
  • match - matching rule - to detect specific subfile display mode
  • pivot - if true, will rotate gird by trnasofming cols to row
  • reverseCol - if true, will reverse order of columns
  • reverseRow - if true, will reverse order of rows
  • asObj - if true, every row will be as JSON object, not as string array
  • opts - other fixed data that will be added to resulting JSON - we are using those data for tabbed display in HTML template so that we know which subfile design we are showing.

Summary

In this part we learned basic screen extraction definition structure used to generate plain JSON data which will be used inside HTML template to generate screen web page.

In next tutorial we will show how to prepare HTML based screen templates.

For the end, here are basic screen extraction definitions for signon screen, main menu screen and wrkactjob screen.

Samples

Sigon definition

{

  "description": "",
  "timestamp": 0,
  "version": 0,
  "type" : "screen",

  "templates": {
    "default": {
        "html": "screen/web/signon.html",
        "output": "#wrapper"
    },
    "os" :{
      "android" : {
           "html": "screen/mobile/signon.html",
           "output": "#wrapper"
      }
    }
  },

  "fields": {
    "user": 1,
    "password": 2
  },

  "data": {
    r1c69 : {"row":1, "col":69, "len":8, "name":"system" },
    r2c69 : {"row":2, "col":69, "len":10, "name":"subsystem" },
    r3c69 : {"row":3, "col":69, "len":10, "name":"displayName" },
    r23c39 : {"row":23, "col":39, "len":40, "name":"ibm" },
    r23c0 : {"row":23, "col":0, "len":40, "name":"error" },

    r5c16 : {"row":5, "col":16, "len":30, "name":"userlbl", "field" : "user", "trim" : "\\." }
  },

  "grids" : {}
}

Main menu definition

{

  "description": "",
  "timestamp": 0,
  "version": 0,
  "type" : "screen",

  "templates": {
    "default": {
          "html" : "screen/web/main.html",
          "output": "#wrapper"
    },
    "os" :{
      "android" : {
         "html" : "screen/mobile/main.html",
         "output": "#wrapper"
      }
    }
  },

  "options" : {"row":4, "col":1, "rows":17, "cols": 79, "type" : "opt", "sort" : true},
  "actions" : {"row":21, "col":0, "rows":22, "cols": 79, "type" : "fn"},

  "fields": {
     "command" : 1
  },

  "data": {
      "title" : [0,20,50],
      "error" : [23,0,79]
  },

  "grids": {
  }
}

Wrkactjob definition

{

  "description": "",
  "timestamp": 0,
  "version": 0,
  "type" : "screen",

  "templates": {
    "default": {
        "html" : "screen/web/wrkactjob.html",
        "output": "#wrapper"
    },
    "os" :{
      "android" : {
          "html" : "screen/mobile/wrkactjob.html"
      }
    }
  },

  "options" : {"row":4, "col":1, "rows":18, "cols": 78},
  "actions" : {"row":21, "col":1, "rows":22, "cols": 78},

  "fields": {

  },

  "data": {
    "fid" : 0,
    "title" :  [0,29,21],
    "system" : [0,71,8],
    "date" :   [1,61,8],
    "time" :   [1,71,8],
    "jobs" :   [2,62,4],
    "error" : [23,1,79]
  },

  "grids": {

    "byStatus": {

      "def": {
        "name":"subfile",
        "opts" : {
          "type" : "default",
          "big" : false,
          "byStatus" : "active"
        },
        "match": {"row":8, "col":46, "text":"Function"},
        "rows": 9,
        "rowHeight": 1,
        "pivot" : false,
        "reverseCol" : true,
        "reverseRow" : true
      },

      "headers": [
        "Option",
        [8,  6, 13],
        [8, 21, 11],
        [8, 33,  5],
        [8, 39,  5],
        [8, 46, 15],
        [8, 62,  8]
      ],

      "data": [
        "",
        [9,  6, 13],
        [9, 21, 11],
        [9, 33,  5],
        [9, 39,  5],
        [9, 46, 15],
        [9, 63,  8]
      ],
      "totals" : []
    },


    "byElapse": {

      "def": {
        "name":"subfile",
        "opts" : {
          "byElapse" : "active",
          "type" : "elapsed",
          "big" : false
        },
        "match" : {"row":8, "col":59, "text":"AuxIO"},
        "rows": 9,
        "rowHeight": 1
      },
      "headers": [
        "Option",
        [8,  6, 13],
        [8, 21,  4],
        [8, 27,  5],
        [8, 33,  3],
        [8, 42,  3],
        [8, 47,  3],
        [8, 54,  3],
        [8, 59,  5],
        [8, 66,  5]
      ],
      "data": [
        "",
        [9,  6, 13],
        [9, 21,  5],
        [9, 27,  5],
        [9, 33,  4],
        [9, 42,  3],
        [9, 47,  3],
        [9, 52,  5],
        [9, 59,  5],
        [9, 66,  5]
      ],
      "totals" : []
    },
    
    "byThread": {

      "def": {
        "name":"subfile",
        "opts" : {
          "byThread" : "active",
          "type" : "thread",
          "big" : false
        },
        "match" : {"row":8, "col":54, "text":"Threads"},
        "rows": 9,
        "rowHeight": 1
      },

      "headers": [
        "Option",
        [8,  6, 13],
        [8, 21,  4],
        [8, 33,  6],
        [8, 41,  4],
        [8, 47,  5],
        [8, 54,  7],
        [8, 64,  7]
      ],

      "data": [
        "",
        [9,  6, 12],
        [9, 21, 10],
        [9, 33,  6, null, "float"],
        [9, 41,  4],
        [9, 47,  5],
        [9, 54,  6],
        [9, 64,  7]
      ],
      "totals" : []
    },


    "byStatusExtA": {

      "def": {
        "name":"subfile",
        "opts" : {
          "type" : "default",
          "big" : true,
          "byStatus" : "active"
        },

        "match": {"row":3, "col":46, "text":"Function"},
        "rows": 16,
        "rowHeight": 1
      },
      "headers": [
        "Option",
        [3,  6, 13],
        [3, 21, 11],
        [3, 33,  5],
        [3, 39,  5],
        [3, 46, 15],
        [3, 62,  8]
      ],
      "data": [
        "",
        [4,  6, 13],
        [4, 21, 11],
        [4, 33,  5, null, "float"],
        [4, 39,  5],
        [4, 46, 15],
        [4, 63,  8]
      ],
      "totals" : []
    },

    "byStatusExtB": {

      "def": {
        "name":"subfile",
        "opts" : {
          "type" : "default",
          "big" : true,
          "byStatus" : "active"
        },
        "match": {"row":4, "col":46, "text":"Function"},
        "rows": 15,
        "rowHeight": 1
      },
      "headers": [
        "Option",
        [4,  6, 13],
        [4, 21, 11],
        [4, 33,  5],
        [4, 39,  5],
        [4, 46, 15],
        [4, 62,  8]
      ],
      "data": [
         "",
        [5,  6, 13],
        [5, 21, 11],
        [5, 33,  5, null, "float"],
        [5, 39,  5],
        [5, 46, 15],
        [5, 63,  8]
      ],
      "totals" : []
    },

    "byElapseExtA": {

      "def": {
        "name":"subfile",
        "opts" : {
          "byElapse" : "active",
          "type" : "elapsed",
          "big" : true
        },
        "match": {"row":3, "col":59, "text":"AuxIO"},
        "rows": 16,
        "rowHeight": 1
      },
      "headers": [
        "Option",
        [3,  6, 13],
        [3, 21,  4],
        [3, 27,  5],
        [3, 33,  3],
        [3, 42,  3],
        [3, 47,  3],
        [3, 54,  3],
        [3, 59,  5],
        [3, 66,  5]
      ],
      "data": [
        "",
        [4,  6, 13],
        [4, 21,  5],
        [4, 27,  5, null, "float"],
        [4, 33,  4],
        [4, 42,  3],
        [4, 47,  3],
        [4, 52,  5],
        [4, 59,  5],
        [4, 66,  5]
      ],
      "totals" : []
    },

    "byElapseExtB": {

      "def": {
        "name":"subfile",
        "opts" : {
          "byElapse" : "active",
          "type" : "elapsed",
          "big" : true
        },

        "match": {"row":4, "col":59, "text":"AuxIO"},
        "rows": 15,
        "rowHeight": 1
      },
      "headers": [
        "Option",
        [4,  6, 13],
        [4, 21,  4],
        [4, 27,  5],
        [4, 33,  3],
        [4, 42,  3],
        [4, 47,  3],
        [4, 54,  3],
        [4, 59,  5],
        [4, 66,  5]
      ],
      "data": [
        "",
        [5,  6, 13],
        [5, 21,  5],
        [5, 27,  5, null, "float"],
        [5, 33,  4],
        [5, 42,  3],
        [5, 47,  3],
        [5, 52,  5],
        [5, 59,  5],
        [5, 66,  5]
      ],
      "totals" : []
    },


    "byThreadExtA": {

      "def": {
        "name":"subfile",
        "opts" : {
          "byThread" : "active",
          "type" : "thread",
          "big" : true
        },
        "match" : {"row":3, "col":54, "text":"Threads"},
        "rows": 16,
        "rowHeight": 1
      },

      "headers": [
        "Option",
        [3,  6, 13],
        [3, 21,  4],
        [3, 33,  6],
        [3, 41,  4],
        [3, 47,  5],
        [3, 54,  7],
        [3, 64,  7]
      ],

      "data": [
        "",
        [4,  6, 12],
        [4, 21, 10],
        [4, 33,  6, null, "float"],
        [4, 41,  4],
        [4, 47,  5],
        [4, 54,  6],
        [4, 64,  7]
      ],
      "totals" : []
    },
    
    "byThreadExtB": {

      "def": {
        "name":"subfile",
        "opts" : {
          "byThread" : "active",
          "type" : "thread",
          "big" : true
        },
        "match" : {"row":4, "col":54, "text":"Threads"},
        "rows": 15,
        "rowHeight": 1
      },

      "headers": [
        "Option",
        [4,  6, 13],
        [4, 21,  4],
        [4, 33,  6],
        [4, 41,  4],
        [4, 47,  5],
        [4, 54,  7],
        [4, 64,  7]
      ],

      "data": [
        "", 
        [5,  6, 12],
        [5, 21, 10],
        [5, 33,  6, null, "float"],
        [5, 41,  4],
        [5, 47,  5],
        [5, 54,  6],
        [5, 64,  7]
      ],
      "totals" : []
    }

  }
}