iSeries EGL

All things EGL for the iSeries / i5 / Power System

Archive for June 2012

Calling a CL Program Using PCML

leave a comment »

Introduction

This post shows how to set up a call from EGL to a CL or RPG program residing on the iSeries. It employs a PCML solution using Java. The parts to be developed are

  • the EGL External Type which prototypes the Java methods of the Java program so that EGL can call them.
  • the PCML definition that describes the parameters to be passed to the CL or RPG program.

To get a better understanding about PCML, please refer to this reference material from IBM.

The example that follows is very simple in that the program being called does not modify the variables passed to it which would affect how the PCML program definition XML is coded.

This post divides the two areas of responsibility into sections for the Java code providing PCML support and the EGL service code that interfaces with the Java code. The first section is presented below.

Code required on the Java side of the landscape

This section illustrates the Java code and supporting PCML file that need to be supplied to the project. The exception is the Java class called BasePCML which is defined in a .jar-file to be included into your EGL project.

Setting up the interface using PCML

Shown below is the PCML definition. It’s an XML file. The entry program name=”SYSLOGC1″ declares the name of this PCML declaration for the program residing on the iSeries. The program’s location is described with the path statement that follows the program name. The entries that follow describe the name, type, length of each parameter to be passed to the program. The entry usage=”input” indicates the variable is input-only and won’t be returned to the caller.

<pcml version="1.0">
  <program name="SYSLOGC1" path="/QSYS.lib/INSOLIB.lib/SYSLOGC1.pgm">

      <data name="USERID" type="char" length="10" usage="input" />
      <data name="PGMNAME" type="char" length="30" usage="input" />
      <data name="FUNCNAME" type="char" length="50" usage="input" />
      <data name="EVENTID" type="char" length="08" usage="input" />
      <data name="LOGGINGLEVEL" type="char" length="10" usage="input" />
      <data name="MESSAGE" type="char" length="256" usage="input" />

  </program>
</pcml>

Fig.1 – The PCML definition for the iSeries program to be called.

 

The Base Java Class that Supports Program Calls Using PCML

The Java program shown below is the base class supporting PCML program calls. The generic nature of this class lends itself well for reuse and can best serve the development staff by being packaged into a .jar-file. The post at this link shows how this process is accomplished, but for now just know that this class has been through that process and the resulting .jar-file should be included in your project.

package com.app.pcml;

import java.io.IOException;
import java.math.BigDecimal;

import org.apache.log4j.Logger;

import com.ibm.as400.access.AS400;
import com.ibm.as400.access.AS400Message;
import com.ibm.as400.access.Trace;
import com.ibm.as400.data.PcmlException;
import com.ibm.as400.data.ProgramCallDocument;
 

/**
 * 
 * This is the Base class for all PCML based calls.  Classes should extend this class  
 * use the facilities provided here to call programs residing on the iSeries.
 * 
 * This class will be rarely modified, except for fixes and/or enhancements.
 * 
 * @author 
 *
 */
public class BasePCML {

	
	// use for PCML Tracing
	public static final boolean TRACE_PCML_ON = true;
	public static final boolean TRACE_PCML_OFF = false;
	
	private static boolean TRACE_PCML_SETTING = false;
	private static String TRACE_PCML_FILE = null;
	private String pcmlPathAndFileName = null;
	
	
	private AS400 as400 = null;
	
	//PCML document describing parameters
	private ProgramCallDocument pcmlDoc = null;
	
	// Return code from ProgramCallDocument.callProgram()
	private boolean returnCode = false;

	// Messages returned from the server
	String msgId, msgText;  
	
	String pcmlDocPackageName = null;
	
	/**
	 * 
	 * Constructor
	 * 
	 */
	public BasePCML(String mach, String user, String pswd, String pcmlDocPackageName) {
		as400 = new AS400(mach, user, pswd);

		try {
			
			pcmlDoc = new ProgramCallDocument(as400,pcmlDocPackageName);
 			
		} catch (PcmlException pcmle) {
			
			System.out.println(pcmle.getLocalizedMessage());	
			
		}
	}
	
 
	
	
	/**
	 * 
	 * When accessing values from the ProgramCallDocument class, you must
	 * specify the fully qualified name of the document element or  tag.
	 * The qualified name is a concatenation of the names of all the containing
	 * tags with each name separated by a period. EX: SYSSECUSER.parm1.ADUSERID
	 * 
	 * @param adUserId
	 */
	protected void setParm(String parmID, String value)  {
		
		try {
		
			pcmlDoc.setValue(parmID, value);
		
		} catch (PcmlException pcmle) {
			System.out.println ("Setting " + parmID + " value " + value + " failed.");
			System.out.println(pcmle.getLocalizedMessage());
			System.out.println(pcmle.getMessage());
			pcmle.printStackTrace();
		}
	} 
	

	/**
	 * Set a String value in the PCML document.
	 * @param field java.lang.String
	 * @param value java.math.BigDecimal
	 * @param indices int[]
	 */
	public void setParm(String field, String value, int[] indices) {
		
		if (value != null) {
			try {
				// Set the value in the PCML document
				pcmlDoc.setValue(field, indices, value);
			}
			catch (PcmlException e) {
				System.out.println("PCML Exception in PCMLRequest::setValue");
				System.out.println(e.getLocalizedMessage());
				System.out.println(e.getMessage());
				e.printStackTrace();
			}
			catch (Exception e) {
				System.out.println("Exception in PCMLRequest::setValue");
				System.out.println(e.getMessage());
				e.printStackTrace();
			}
		}
	}
	
	
	/**
	 * Set a BigDecimal value in the PCML document.
	 * @param field java.lang.String
	 * @param value java.math.BigDecimal
	 */
	public void setParm(String field, BigDecimal value) {
		if (value != null) {
			try {
				// Set the value in the PCML document
				pcmlDoc.setValue(field, value);
			}
			catch (PcmlException e) {
				System.out.println("PCML Exception in PCMLRequest::setValue");
				System.out.println(e.getLocalizedMessage());
				System.out.println(e.getMessage());
				e.printStackTrace();
			}
			catch (Exception e) {
				System.out.println("Exception in PCMLRequest::setValue");
				System.out.println(e.getMessage());
				e.printStackTrace();
			}
		}
	}
	

	
	/**
	 * Set a BigDecimal value in the PCML document.
	 * @param field java.lang.String
	 * @param value java.math.BigDecimal
	 * @param indices int[]
	 */
	public void setParm(String field, BigDecimal value, int[] indices) {
		if (value != null) {
			try {

				// Set the value in the PCML document
				pcmlDoc.setValue(field, indices, value);
			}
			catch (PcmlException e) {
				System.out.println("PCML Exception in PCMLRequest::setValue");
				System.out.println(e.getLocalizedMessage());
				System.out.println(e.getMessage());
				e.printStackTrace();
			}
			catch (Exception e) {
				System.out.println("Exception in PCMLRequest::setValue");
				System.out.println(e.getMessage());
				e.printStackTrace();
			}
		}
	}
	
	
	/**
	 * 
	 *  Call the program
	 *  
	 */
	protected void callProgram(String programName) {
		
		try {
			
			returnCode = pcmlDoc.callProgram(programName);
			
            if(returnCode == false)              {
                // Retrieve list of server messages
                AS400Message[] msgs = pcmlDoc.getMessageList(programName);
                
                // Iterate through messages and write them to standard output
                System.out.println("**********************************************************");
                System.out.println("**  " + programName + " failed. See messages below               **");
                for (int m = 0; m < msgs.length; m++)                  {
                    msgId = msgs[m].getID();
                    msgText = msgs[m].getText();
                    System.out.println("    " + msgId + " - " + msgText);
                }
                
            }
            
		
		} catch (PcmlException pcmle) {
			System.out.println("Call to SYSSECUSER failed.");
			System.out.println( pcmle.getMessage() );
		}
		
	}
	
	
	/**
	 * Return a String value from the PCML document. 
	 * 
	 * @return java.lang.String
	 * @param parmName
	 *            java.lang.String
	 */
	protected String getParm(String parmName) {
		
		try {
			
			return (String) pcmlDoc.getValue(parmName);
			
		} catch (PcmlException e) {

			System.out.println("PCML Exception in PCMLRequest::getString");
			System.out.println(e.getLocalizedMessage());
			System.out.println(e.getMessage());

			e.printStackTrace();
		} catch (Exception e) {
			System.out.println("Exception in PCMLRequest::getString");
			System.out.println(e.getMessage());
		}
		
		//Returning a zero-length string
		return "";
	}

	/**
	 * Return a String value from the PCML document.
	 *  
	 * @return java.lang.String
	 * @param field java.lang.String
	 * @param indices int[]
	 */
	public String getString(String field, int indices[]) {
		try {
			return (String) pcmlDoc.getValue(field, indices);
		}
		catch (PcmlException e) {
			System.out.println("PCML Exception in PCMLRequest::getString");
			System.out.println(e.getLocalizedMessage());
			System.out.println(e.getMessage());
			e.printStackTrace();
		}
		catch (Exception e) {
			System.out.println("Exception in PCMLRequest::getString");
			System.out.println(e.getMessage());
		}
		return null;
	}
	
	
	/**
	 * Return a BigDecimal value from the PCML document.
	 * 
	 * @return java.math.BigDecimal
	 * @param field java.lang.String
	 */
	public BigDecimal getBigDecimal(String field) {
		try {
			return (BigDecimal) pcmlDoc.getValue(field);
		}
		catch (PcmlException e) {
			System.out.println("PCML Exception in PCMLRequest::getBigDecimal");
			System.out.println(e.getLocalizedMessage());
			System.out.println(e.getMessage());
			e.printStackTrace();
		}
		catch (Exception e) {
			System.out.println("Exception in PCMLRequest::getBigDecimal");
			System.out.println(e.getMessage());
		}
		return null;
	}


	/**
	 * Return a BigDecimal value from the PCML document.
	 *  
	 * @return java.math.BigDecimal
	 * @param field java.lang.String
	 */
	public BigDecimal getBigDecimal(String field, int[] indices) {
		try {
			return (BigDecimal) pcmlDoc.getValue(field, indices);
		}
		catch (PcmlException e) {
			System.out.println("PCML Exception in PCMLRequest::getBigDecimal");
			System.out.println(e.getLocalizedMessage());
			System.out.println(e.getMessage());
			e.printStackTrace();
		}
		catch (Exception e) {
			System.out.println("Exception in PCMLRequest::getBigDecimal");
			System.out.println(e.getMessage());
		}
		return null;
	}
	
	
	/**
	 * 
	 */
	public void disconnectAS400() {
		as400.disconnectService(AS400.COMMAND);
	}	
	
}


Fig.2 – The Java class ‘BasePCML’. The developer does not need to code this!!!

 

The Java Class that will call the iSeries Program

This class extends the base class shown above. It is tailored to call a specific program.

package com.app.pcml;

/**
 * 
 * This class extends BasePCML to facilitate the execution of program
 * / residing on the iSeries.
 * 
 * All processes associated with the program to be called will be encapsulated
 * in methods of this class.
 * 
 * @author  
 *
 */
public class CallSYSLOGC1 extends BasePCML {
	
        //The name of the program being called
	public static final String PROGRAM_NAME = "SYSLOGC1";
	
	//Package-file name of the Program interface defined using PCML
	private static final String PCML_DOC_PACKAGE_NAME = "com.app.pcml.SYSLOGC1.pcml";
	
	//Parm related literals referencing the parm-names in the PCLM file
	public static final String USER_ID 			= "SYSLOGC1.USERID";
	public static final String LOGGING_PROGRAM_NAME		= "SYSLOGC1.PGMNAME";
	public static final String FUNCTION_NAME		= "SYSLOGC1.FUNCNAME";
	public static final String EVENT_ID			= "SYSLOGC1.EVENTID";
	public static final String LOGGING_LEVEL		= "SYSLOGC1.LOGGINGLEVEL";
	public static final String MESSAGE			= "SYSLOGC1.MESSAGE";
	
	//Known error message(s) returned in parm OUT_VALUE
	public static final String ERROR_MESSAGE_01 = " ";
	public static final String ERROR_MESSAGE_02 = " ";		
	
	/**
	 * Constructor
	 * 
	 * Obtains connection criteria to the iSeries to enable program execution
	 * in addition to passing to the parent class the Package-file name of the 
	 * Program interface defined using PCML.
	 * 
	 */
	public CallSYSLOGC1( String mach, String user, String pswd ) {
		 
		super(mach, user, pswd, PCML_DOC_PACKAGE_NAME);
		
	}	

	
	/**
	 *  
	 * Write entry into file SYSTLMP which is the log file on the iSeries. 
	 * 
	 * @param activeDirectoryName
	 * @return String iSeriesUser
	 * 
	 */
	public void log(String userID, String pgmName , String functionName, String eventID, String loggingLevel, String message ) {
		
		//Set the parms
		super.setParm(USER_ID, userID);
		super.setParm(LOGGING_PROGRAM_NAME, pgmName);
		super.setParm(FUNCTION_NAME, functionName);
		super.setParm(EVENT_ID, eventID);
		super.setParm(LOGGING_LEVEL, loggingLevel);
		super.setParm(MESSAGE, message);
		
		//Call
		super.callProgram(PROGRAM_NAME);
		
 		return;
	}
}

Fig.3 – The Java class that calls the CL program on the iSeries. CallSYSLOGC1.java

 
The developer needs to provide values as they relate to the program that needs to be called. The entries are listed here.

  1. //The name of the program being called public static final String PROGRAM_NAME = "SYSLOGC1";
  2. //Package-file name of the Program interface defined using PCML private static final String PCML_DOC_PACKAGE_NAME = "com.app.pcml.SYSLOGC1.pcml";
  3. //Parm related literals referencing the parm-names in the PCLM file public static final String USER_ID = "SYSLOGC1.USERID"; public static final String LOGGING_PROGRAM_NAME = "SYSLOGC1.PGMNAME"; public static final String FUNCTION_NAME = "SYSLOGC1.FUNCNAME"; public static final String EVENT_ID = "SYSLOGC1.EVENTID"; public static final String LOGGING_LEVEL = "SYSLOGC1.LOGGINGLEVEL"; public static final String MESSAGE = "SYSLOGC1.MESSAGE";
  4. //Java Method public void log(String userID, String pgmName , String functionName, String eventID, String loggingLevel, String message ) { //Set the parms super.setParm(USER_ID, userID); super.setParm(LOGGING_PROGRAM_NAME, pgmName); super.setParm(FUNCTION_NAME, functionName); super.setParm(EVENT_ID, eventID); super.setParm(LOGGING_LEVEL, loggingLevel); super.setParm(MESSAGE, message); //Call super.callProgram(PROGRAM_NAME); return; }

Fig.4 – The entries in the Java program unique to each program called.

List item 1. establishes the program name.

Item 2. describes the package name within which the PCML file resides. Note the names are not separated by slashes (“/”) as usual. This is a departure for the norm and is required in this case.

Item 3. describes the list of parameters as defined by the PCML file seen in Fig.1.

Item 4. describes the name of the method that will be called by the EGL program. Note that the parameters passed to the method match the parameters defined by the PCML definition shown in Fig.1.

Code required on the EGL side of the landscape

This section illustrates the EGL code that need to be supplied to the project.

 

The EGL code

The first thing that needs to be coded is the EGL External Type that describes the constructor of the class and the Java method that is to be called by the EGL service.

Shown below is the EGL External Type. ExternalType parts map EGL to external language elements. In this case. we’re mapping the constructor and the methods of the Java class called CallSYSLOGC1.java presented above in Fig.3.

package com.mig.logviewer.externaltypes;

externalType CallSYSLOGC1 type JavaObject{PackageName = "com.app.pcml"}
    
    constructor(mach String in,  user String in, pswd String in );
    function log(USERID String in, PGMNAME String in,  FUNCNAME String in, EVENTID String in, LOGGINGLEVEL String in,  MESSAGE String in) ;
        
end

Fig.5 – The External Type “SYSLOGC1.egl”

 

Shown below is the EGL service code that instantiates a new object (syslogc1) that is derived from the Java class named CallSYSLOGC1.java which has been mapped by the EGL External Type (SYSLOGC1.egl).

       
        syslogc1 CallSYSLOGC1 =  new CallSYSLOGC1("S1039255", "EGLCONNECT", "eg1c0nn3c7");
        user string = "None";
        programName string = "LoggingViewer";                               //30 bytes
        functionName string = "handler: getRuntimeEnvironmentReturn()";     //50 bytes
        eventID string = "";                                                //08 bytes
        loggingLevel string = "DEBUG     ";                                      //10 bytes
        message string = "Runtime Environment Variable for server is '" + runtimeEnvironment + "'";
        syslogc1.log(user, programName, functionName, eventID, loggingLevel, message);

Fig.6 – The EGL code that calls the method (log)in CallSYSLOGC1.java”

Summary

This post has shown how to use PCML in an EGL application to call a program residing on the iSeries. It uses EGL’s external type to map to a Java class included into the EGL project which is then called by the EGL service program.

 

Written by iseriesadmin

June 29, 2012 at 1:45 pm

Exporting Java Classes Into a .jar-file For Use In Other Projects

leave a comment »

Introduction

This post describes how to export Java classes to create a .jar-file so that the exported classes can be reused by other projects. This is presented in an EGL project context, but the same steps are involved for any Java project as well.

Export the Java Class

The screen show shown below starts the process by ight-clicking on the Java class to expose the popup menu from which the Export option is selected.

Fig.1 – Begin by right-clicking the class to show the pop-up menu.

To continue with the export process follow the options as shown by the following screen shots.

Fig.2 – Select the option shown and select “Next”

 

In this screen shot, open and select the package (or packages) containing the Java class (or classes) to be exported. Select the package required and the destination directory.

Fig.3 – “Finish”

 
 

Importing the Jar File into Your Project

Copy the .jar-file to the project’s lib directory as shown. This is where all of the project’s .jar-files reside.

Fig.4 –

 

Select the project directory as shown and right-click to expose the pop-up menu. Add the .jar-file to the project’s build path as shown

Fig.5 –

 

Select the tab marked “Libraries” and then select the button marked “Add JARS…”

Fig.6 –

 

Expand the project directory then the directory labeled “WebContent” and finally “Lib” as shown. Select the .jar-file to be added. In this case, there is only one.

Fig.7 –

 

When completed you will see the .jar-file under the lib directory as before however, because it is now part of the project’s build path, it has been included among the other .jar-files under the project.

Fig.8 –

 

Summary

This post illustrated how to export a Java class into a .jar-file and then import it into an EGL project for reuse. Placing the .jar-file in the “WebContent/lib” directory gives the project access to those resources when the project is deployed onto Tomcat however, the IDE is not aware of them. By adding the .jar-file to the project’s class path or build path it gives the IDE access to the classes during development (content assist) and when it builds the project for running inside the IDE.

How to Read the Environment Variable Assigned to Tomcat

leave a comment »

Introduction

This post illustrates how to read the environment variable (EV) assigned to Tomcat’s JVM at the time Tomcat is started. The variable was assigned within Tomcat’s startup script to indicate Tomcat’s role as being a development server, a test server or a production server. The values were “localhost”, “TEST” or “PROD” respectively. To learn how the EV is assigned to Tomcat’s JVM select this link.

Approach

EGL does not support access to JVM variables as Java does. To solve the problem of reading the value a Java program must be employed to be called from EGL. Shown below is the Java program that reads the variable to be returned to the EGL program. Specifically the line of interest is this one:
runtimeEnvironment = System.getProperty(“runtimeEnvironment”).trim() ;


package com.app.runtime;

public class RuntimeEnvironment {


	private String runtimeEnvironment = null;
	private String clazz = null;
	
	
	/**
	 * Constructor
	 */
	public RuntimeEnvironment() {
	
	}
	
	
	/**
	 * 
	 */
	public String getRuntimeEnvironment() {
		

        //Get the Server property that holds the environment value.  This value will be
        //"localhost" for the developer's PC, "TEST" for the test server, or "PROD" for 
        //the production server.  This value is instrumental to acquiring the correct 
        //property values for the machine/environment in which this application is running.
		try {
			runtimeEnvironment = System.getProperty("runtimeEnvironment").trim() ;
		} catch (Exception ex) {
			System.out.println(" StartupTasks.init()  Server instance not found. " + ex.getMessage() );
		}
		
		if ((runtimeEnvironment == null)) {
			String msg = "Server not configured with runtime environment value. Value = "
					+ runtimeEnvironment
					+ ". (Valid config value: -DruntimeEnvironment='localhost' or TEST or PROD)";
			System.out.println(msg);
			runtimeEnvironment = "localhost";
			System.out.println(" RuntimeEnvironment.getRuntimeEnvironment()  Default environment will be " + runtimeEnvironment  );
		}
		
		
		if (runtimeEnvironment.equals("localhost")
				|| runtimeEnvironment.equals("TEST")
				|| runtimeEnvironment.equals("PROD")) {
		} else {
			String msg = 
					"RuntimeEnvironment.getRuntimeEnvironment(): The server is not configured with correct runtime envrionment value. Value = "
					+ runtimeEnvironment;
			System.out.println(msg);
			msg = "StartupServlet.init(): Examples of valid config values are: 'localhost', 'TEST' or 'PROD'.";
			System.out.println(msg);

		}
		
		System.out.println(clazz+ " **********************************************************************");
		System.out.println(clazz+ " LoggingViewer application startup phase");
		System.out.println(clazz+ "   Reading Server Argument for run-time environment parameter.");
		System.out.println(clazz + "     Server Run-Time Environment  : " + runtimeEnvironment);
		System.out.println(clazz + " ");
		System.out.println("LoggingViewer Runtime Environment is '" + runtimeEnvironment + "'.");
	
		return runtimeEnvironment;
	}
	
}

Fig.1 – The Java class ‘RuntimeEnvironment’

 

The strategy employed by RuntimeEnvironment is straight forward; the method getRuntimeEnvironment() reads the variable runtimeEnvironment the value of which has been assigned to the JVM. (Refer to this post to see how that was done.) In the event that a variable is not found, due mostly to the fact the developer may have elected not to assign it to their test server running on their local machine, the Java method will return “localhost” as a default value. As noted in the link which shows how to assign the values to the server, the values for “TEST” and “PROD” have already been assigned to Tomcat.

Since the Java class will need to be in all EGL projects the class has been packaged into a .jar-file so it can be reused. To use the class in your project, simply add the .jar-file to the “lib” directory under “WebContent”. Then add the .jar-file to the project’s class path. To learn how this is done select this link and read the section titled “Importing the Jar File into Your Project”.

 

Calling the Java method from EGL

This section describes how to create the EGL External Type and the EGL service, both of which are required when calling a Java program from EGL.

The EGL External Type Definition

First, create an external type to describe to EGL the Java class and its methods.


externalType RuntimeEnvironment type JavaObject{PackageName = "com.app.runtime"}
    
    constructor();
    function getRuntimeEnvironment() returns(string);
        
end

Fig.2 – The EGL External type named ‘RuntimeEnvironment’

 
The external type is an EGL part that describes an interface to another program of a different type. In this context it is the bridge between the EGL world and the Java world. The type shown above describes the Java constructor and the method named getRuntimeEnvironment() .

Calling Using a Dedicated Service

Next, create an EGL service that will use the Java class described by the external type, above.

import com.mig.logviewer.externaltypes.RuntimeEnvironment;

// service
service RuntimeService

    function getRuntime() returns(string)
        
        //Instantiate an object of RuntimeEnvironment.  Call it 'runtime'.
        //This uses the external type named 'RuntimeEnvironment'
        runtime RuntimeEnvironment = new RuntimeEnvironment();

        //Call runtime's getRuntimeEnvironment() method to get the runtime value.
        runtimeEnvironment string = runtime.getRuntimeEnvironment();

        return(runtimeEnvironment);

    end

end

Fig.3 – EGL service that will use the Java class

 

Calling the Java method from EGL

Finally, below is the EGL program code that calls the Java method to get the runtime environment variable established for Tomcat’s JVM.

The EGL function presented is part of the startup processing phase of the EGL project’s web-page. It begins by creating a dedicated service object called runtimeService which will is derived from the EGL Service program created above. Next, the EGL code calls the service’s getRuntime()method, which returns the value for Tomcat’s runtime environment variable.


    function start()

        //Initialize the application by getting the runtime environment from the 
        //server and reading property file values.
        runtimeService RuntimeService{@dedicatedService};
        call RuntimeService.process() 
            returning to initServiceReturn 
                        onException ServiceLib.runtimeServiceReturn;    
                        
    end

    function runtimeServiceReturn(runtimeEnvironment String in)
        
        globalDataRecord GlobalDataRecord = SessionLibrary.getGlobalDataRecord();
        globalDataRecord.runtimeEnvironment = runtimeEnvironment ;
        SessionLibrary.setGlobalDataRecord(globalDataRecord);  

    end


Fig.4 – EGL function calling a service program

 

The call back function receives the variable runtimeEnvironment returned by the service call. The value of the variable is then stored in an instance of an EGL basic record called globalDataRecord In this manner the runtimeEnvironment variable can be used throughout the life of the program simply by passing the globalDataRecord as the parameter. Think of it as a container for global values.
 

Summary

This post has shown how to create a Java class to provide a function not available by EGL alone. Specifically, we have seen how to create an EGL External Type, an EGL Service and the code used to call the service to receive values returned.

Making a Dialog Box

leave a comment »

The Dialog Box in EGL

This post illustrates how to code a simple dialog box to show a message that instructs the user to be patient while some background activity is executing. One common activity is the loading of data with which to populate the screen.

Shown below is the EGL code that performs the following steps:

  1. Create a label to contain the message.
  2. Create the GridLayout and assigns the label as a child component.
  3. Create a dialog box and assign GridLayout containing the label as a child component.

    //Create a label to contain the message.  Assigning text is optional at this time as it will probably be replaced at runtime.
    loggingViewerDialog_TextLabel1 TextLabel{ layoutData = new GridLayoutData{ row = 1, column = 1 }, text = "Please wait while data is being loaded." };
    
    //Create the GridLayout and assign loggingViewerDialog_TextLabel1 as a child
    loggingViewerDialog_GridLayout GridLayout{ layoutData = new GridLayoutData{ row = 2, column = 3,
        horizontalSpan = 1, verticalAlignment = GridLayoutLib.VALIGN_TOP }, cellPadding = 4, rows = 3, columns = 3,
        children = [ loggingViewerDialog_TextLabel1 ] };
    
    //Create a dialog box and assign loggingViewerDialog_GridLayout as a child 
    loggingViewerDialog DojoDialog {title = "Wait",  children = [ loggingViewerDialog_GridLayout ]} ;

Fig.1 – EGL code for a simple dialog box.

The code shown below shows how to display the dialog box.

    loggingViewerDialog.showDialog();

Fig.2 – Displaying the dialog box.

To hide the dialog, use the following code.

    loggingViewerDialog.hideDialog();

Fig.3 – Hiding the dialog box.

This is the resulting dialog box.

A simple Dialog Box

Written by iseriesadmin

June 22, 2012 at 8:32 am

Posted in EGL DojoDialog

Tagged with

DojoTextField Validation

leave a comment »

How to Validate Values in a Text Field

Shown below is the screen segment allowing for the entry of a number which controls the number of records returned from a SQL statement.

Field to be validated

Shown below is the EGL code used to present the above segment into the browser page. The variable ‘recordSizeLimitField’ holds the instance of a DojoTextField that has been defined as an input-required field. If the field is left blank at the time the form is submitted the message declared with ‘inputRequiredMessage’ is presented.


    TextLabel9 TextLabel{ layoutData = new GridLayoutData{ row = 2, column = 1 }, text = "Limit results to " };
    recordSizeLimitLabel TextLabel{ layoutData = new GridLayoutData{ row = 2, column = 3 }, text = "records." };
    recordSizeLimitField DojoTextField { inputRequired=true, maxLength=4, inputRequiredMessage="Please supply a value for this field.", layoutData = new GridLayoutData{ row = 2, column = 2 } };

Fig.1 – The field and field label definition

Shown below is the EGL code used to define the Model, View and Controller (MVC) in addition to the name of the function used to validate the field.


    recordSizeLimitField_Model String { inputRequired=yes };
		recordSizeLimitField_Controller Controller { @MVC 
      { model=recordSizeLimitField.text, 
        view=recordSizeLimitField as Widget},
        validators = [recordSizeLimitField_Validator]
    };
    
    recordSizeLimitField_FormField FormField { 
      controller = recordSizeLimitField_Controller, 
      nameLabel = recordSizeLimitLabel
    };
	
    loggingViewerForm FormManager { 
    entries = [ recordSizeLimitField_FormField ]};

Fig.2 – The Model, View, Controller (MVC), FormField and FormManager

Shown below is the EGL code used to define the function ‘recordSizeLimitField_Validator’.


    function recordSizeLimitField_Validator(input String in) returns(String?)
    	
        if( !( input is numeric )  )
       	   InfoBus.publish("validate.field.relations", "ERROR");
           return("This value is not numeric. Please correct and retry");
        end
       
    end

Fig.3 – The validator function referenced by ‘recordSizeLimitField_Model’ in Fig.2

 

Behavior

When the field is left blank and the “Submit” button is selected the following is presented.

When the “!’ is selected, the message is presented.

When an invalid value is entered and the “Submit” button is selected the following is presented.

When the “!’ is selected, the following message is presented.

Written by iseriesadmin

June 19, 2012 at 1:45 pm

Registering JNDI Data Source Names with Tomcat

leave a comment »

Introduction

This post shows how to make JNDI-based entries into Tomcat’s context.xml file to register multiple database connection resources.

Making JNDI data source entries

The following entries where made to Tomcat’s ‘context.xml’ file for the data source names shown.


<Resource name="jdbc/MACH1" auth="Container" type="javax.sql.DataSource" maxActive="4" maxIdle="2" maxWait="10000" username="********" password="********" driverClassName="com.ibm.as400.access.AS400JDBCDriver" url="jdbc:as400:MACH1;prompt=false;naming=system;libraries=PRODLIB;transaction isolation=none;"/> <Resource name="jdbc/MACH2" auth="Container" type="javax.sql.DataSource" maxActive="4" maxIdle="2" maxWait="10000" username="********" password="********" driverClassName="com.ibm.as400.access.AS400JDBCDriver" url="jdbc:as400:MACH2;prompt=false;naming=system;libraries=DEVLIB;transaction isolation=none;"/>

*NOTE* For display purposes the entries above have had the names of the servers obfuscated. For example, the reference to “MACH1” represents the DNS name of the production server while “MACH2” represents the DNS name of the server known as the “Web Box”. Therefore the correct names should be substituted. The same holds true for the libraries.

Written by iseriesadmin

June 10, 2012 at 10:24 am

Tomcat In Development, Test and Production Environments

leave a comment »

Introduction

This post shows how a JVM variable can be employed on Tomcat’s startup command to declare a server instance as either a development server, a test server or a production server. An application can then retrieve this value during its startup processing phase to determine the database to which a connection must be made. To see how EGL can read this JVM variable value select this link.

Variable Indicating Development, Test and Production Servers

The value assigned to the parameter “runtimeEnvironment” indicates the role of the Tomcat server. For the developer’s server, usually running inside the IDE (RDi) the value for this parameter will be “localhost”. For the test and production Tomcat servers running on the iSeries, there are two valid values which are “TEST” and “PROD”. For example this parameter will designate the server as a production server:

-DruntimeEnvironment=”PROD”

All applications should obtain the value of this variable during its startup phase. For Java, this is a startup servlet. For EGL, it will be a service.

Shown below is the command that starts a Tomcat server. It has been modified to set the environment variable and its value, in this case, ‘PROD’.


java -ms64m -Duser.dir="$CATALINA_BASE" -Dcatalina.base="$CATALINA_BASE" -Dcatalina.home="$CATALINA_HOME" -Djava.awt.headless=true -DruntimeEnvironment="PROD" org.apache.catalina.startup.Bootstrap "$@" start

All parameter name/value pairs begin with “-D”.

Why Do This?

The intent is to inform the application about the role of the server, i.e. the developer’s desktop machine in which case the value will default to “localhost” for the developer’s server, “TEST” for the test server and “PROD” for the production server. Once the value is obtained the application’s logic can then determine the proper database connection to use in addition to reading the correct set of property values established for the application. The diagram shown clarifies this.

Fig.1 – Diagram showing roles of three Tomcat servers defined by a JVM variable (Click to enlarge)

Conclusion

This post revealed how a name/value pair can be established for a given Tomcat server instance so that an application may interrogate the value of the named parameter. With the value obtained the application’s logic can then determine the correct database to which a connection must be made. In this way the development staff can be confident their application can be safely run on a test server with the knowledge that it will not update production data. When it comes time to deploy to the production server, the application does not have to be modified in any way and its logic will again connect to the correct production oriented database as well as being able to obtain the correct values from the application’s property file.

Written by iseriesadmin

June 10, 2012 at 9:57 am