The OpenGTS Web Frontend

The great thing about OpenGTS is that you get a complete Tracking System with a backend, with a large number of Device Communication Servers and a Webfrontend to interact with the System (besides command lines) and observe the Trackers. The track.war meets all formal requirements of a Web Archive and runs in any Servlet Container and - this is worth noting - is completely independant from the installation in %GTS_HOME%. So you can run your productive server with Tomcat and Database and use the web manager to deploy the web application. Or, as demonstrated in the Eclipse section you can import the complete war (into different projects) to your Eclipse workspace. On the other hand you can also run various DCS on a separate machine to write the Tracking Data to the Database, being the only connection between frontend and the actual tracking. In other words: OpenGTS has a very practical fragmentation to scale the components hard- and software.

Remember that the first steps into OpenGTS was the analysis of the package, jar and war structures. Similar to this categorization we can split the track/Track Frontend into three main components:

  • Administration of Accounts, Users and Devices
  • Mapdisplay for Devices and Device Groups
  • Reporting - from IT perspective a user interface for prepared SQL statements

We will not go into setting up the Frontend, which is described elaborately in the OpenGTS Config pdf. Remember that the standard installation is the prerequisite of the analysis on this website. So please run ant all and deploy the track.war to Tomcat as described. And preferably you should import track.war into Eclipse to step through the code.

Track._doWork

In the configuration section the initialization and loading of the (track.) war file was described and the method

/* handle POST/GET request */
private void _doWork(isPost, request, response, privLabel)
        throws ServletException, IOException

was identified as the 'Controller' of the Frontend logic. This method is called (more than) with every request to dispatch the requested page, which then retrieves records from the database, map tiles from the map server etc. 

Let's look at the structure of this core method to understand the Frontend Control. When calling the method or the ..track/Track URL respectively for the first time many String values are still empty "":

/* URL query string */
String requestURL  = "http://localhost:8080/map/Track"
String queryString = ""
/* action request */
String pageName    = "" // query only
String cmdName     = "" // query only ("page_cmd")
String cmdArg      = "" // query only
/* currently logged-in account/user */
String loginAcctID = "" // session only
String loginUserID = "" // session only
/* account/user */
String userEmail   = "" // session or query
String accountID   = "" // session or query
String userID      = "" // session or query
String enteredPass = "" // query only
String entEncPass  = "" // query only

and from the comments we can conclude that the method distinguishes between an open session or a query. We'll have a closer look later. Anyhow the variables indicate the information gathered for a session: account, user, password, device, group and more. The method makes use of the private label to adjust frontend entries with the Tracking System Configuration and Database. You can also find the hardcoded paths to the resouces being used like DIRECTORY_CSS, DIRECTORY_JS and DIRECTORY_IMAGES.

After authentication and security handling the most important task is to serve requested pages, which is indicated in the beginning:

    /* adjust page request */
    if (cmdName.equals(Constants.COMMAND_LOGOUT) || pageName.equals(PAGE_LOGIN)) {
        Track.clearSessionAttributes(request); // start with a clean slate
        pageName = PAGE_LOGIN;
    }

We can see that the pageName holds the value for a page.
The actual value can be found in Constants.java

    public  static final String PAGE_LOGIN = "login"; // login page

where you can find an overview of most pages (or rather their names) addressed through the web application. Here is a list of Constants related to the individual Java Class representing a Webpage:

org.opengts.war.track.page         Constant name              value
--------------------------         -------------              -----
AccountInfo.java                   PAGE_ACCOUNT_INFO       = "acct.info";          
AccountLogin.java                  PAGE_LOGIN              = "login";              
ChangePassword.java                PAGE_PASSWD             = "passwd";             
DeviceInfo.java                    PAGE_DEVICE_INFO        = "dev.info";           
DriverInfo.java                    PAGE_DRIVER_INFO        = "driver.info";        
ForgotPassword.java                PAGE_PASSWD_EMAIL       = "passwd.email";       
GroupInfo.java                     PAGE_GROUP_INFO         = "group.info";         
HtmlWrapper.java                   PAGE_HTML_WRAP          = "htmlWrapper";        
NewAccount.java                    PAGE_ACCOUNT_NEW        = "acct.new";           
ReportDisplay.java                 PAGE_REPORT_SHOW        = "report.show";        
ReportMenu.java                    PAGE_MENU_REPORT        = "menu.rpt";           
ReportMenuDeviceDetail.java        PAGE_MENU_RPT_DEVDETAIL = "menu.rpt.devDetail"; 
ReportMenuDriverPerformance.java   PAGE_MENU_RPT_PERFORM   = "menu.rpt.devPerf";   
ReportMenuFleetDetail.java         PAGE_MENU_RPT_GRPDETAIL = "menu.rpt.grpDetail"; 
ReportMenuFleetSummary.java        PAGE_MENU_RPT_GRPSUMMRY = "menu.rpt.grpSummary";
ReportMenuIFTA.java                PAGE_MENU_RPT_IFTA      = "menu.rpt.iftaDetail";
ReportMenuSysAdmin.java            PAGE_MENU_RPT_SYSADMIN  = "menu.rpt.sysSummary";
SysAdminAccounts.java              PAGE_SYSADMIN_ACCOUNTS  = "sysAdmin.accounts";  
TopMenu.java                       PAGE_MENU_TOP           = "menu.top";           
TrackMap.java                      ???
TrackMapDevice.java                PAGE_MAP_DEVICE         = "map.device";         
TrackMapFleet.java                 PAGE_MAP_FLEET          = "map.fleet";          
UserInfo.java                      PAGE_USER_INFO          = "user.info";          
ZoneInfo.java                      PAGE_ZONE_INFO          = "zone.info";          

Note that the RequestProperties are not part of the Servlet Specification, but simply a helper class to hold values to be passed to the servlet mechanism at a later point.

/* store the RequestProperties instance in current request to allow access from TagLibs */
        request.setAttribute(PARM_REQSTATE, reqState);

The actual setting of the pageName to a WebPage variable looks like this:

    /* get requested page */
    WebPage trackPage = privLabel.getWebPage(pageName); // may return null
    if (trackPage != null)
        reqState.setPageName(pageName);

After going through the required variables the org.opengts.db.tables.Account is loaded, if it exists, has not expired, is active and is authorized (look for the /* comments */ to identify each check. Next the account/user/password is validated and the org.opengts.db.tables.User is loaded and the login is logged:

[INFO_|01/03|Track._doWork:1207] Login SysAdmin: sysadmin/admin    [From 0:0:0:0:0:0:0:1]
[INFO_|01/03|Track._doWork:1209] Login Account/User: virtex/kbeigl [From 0:0:0:0:0:0:0:1]

Towards the end of the method some special pages are handled

   /* Reverse Geocode */
   if (pageName.equals(PAGE_REVERSEGEOCODE) { ... return; }
   /* Address/PostalCode Geocode */
   if (pageName.equals(PAGE_GEOCODE) { ... return; }
   /* Check Rule Trigger */
   if (pageName.equals(PAGE_RULE_EVAL)) { ... return; }

If these pages don't occure the interesting part is to set a 'trackPage'

   /* do we have a 'trackPage'? */
   if (trackPage == null) {
       // occurs when 'pageName' is either blank or invalid
              :
   /* get page */
   trackPage = privLabel.getWebPage(pageName); // should not be null

which is always a class implementing the interface WebPage with a set of methods familiar to the Tracking System, where they can be handled in the same way. As an example you can look at the method (with quite a few occurrences):

   Track._displayLogin(reqState, pleaseLogin, false);

At the end of the method, after the target page has been selected it can finally be served with

   /* dispatch to page */
   reqState.setPageNavigationHTML(trackPage.getPageNavigationHTML(reqState));
trackPage.writePage(reqState, "");
return;

So now we have a rough overview of what's going on. Depending on your intentions you should set a debug point a the beginning of the method a step through it repeatedly to find out where to place your individual modifications.

On this site we'll take a different approach. We'll try to strip down track.war exclusively to the Map Display part of the application on the next page.

 « Tracking map.war »