iSeries EGL

All things EGL for the iSeries / i5 / Power System

Archive for the ‘Tomcat on iSeries’ Category

How to Read the Environment Variable Assigned to Tomcat

leave a comment »


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.


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() ;


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)";
			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;
			msg = "StartupServlet.init(): Examples of valid config values are: 'localhost', 'TEST' or 'PROD'.";

		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 = ""}
    function getRuntimeEnvironment() returns(string);

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();




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;    

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


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.


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 DB Connection during runtime

leave a comment »

Using Tomcat’s JVM parameter values to facilitate DB connections

This post will illustrate how a database connection can be established to one of two separate iSeries machines.

Before we get going, for some background you should probably read this post first. Its is about the configuration of the server’s (Tomcat) JVM property value for run-time environment ‘localhost’, ‘TEST’ and ‘PROD’.


The application’s externally defined property values

The application’s configuration data is contained in an external XML file, a common practice in web application development. For this discussion it will suffice to say the application’s configuration data has already been read during the application’s initialization phase conducted when the application is started. During this phase the data is cached into an EGL BasicRecord type i.e. ‘configDataRecord’ which can then be passed to the application’s services as a parameter. In this manner all services can gain access to the application’s configuration data.

Shown below are the entries placed in our XML configuration file that describe connection criteria for MACH1 and MACH2 used for the developer’s (localhost) server, the test (TEST) machine and the production (PROD) machine. (User id’s and passwords are obfuscated.) Library entries, of which there is only one in this example, are separated by spaces. Note the libraries established for each machine for each development environment. In this way, each connection for each machine is assigned to the correct library ensuring the proper set of data is used for each environment. This method ensures that the developer does not have to prefix or qualify SQL statements with embedded library names, which does not translate well when moving the application from a TEST server to a PROD server.

<entry key="localhost.MACH1MachineId">MACH1</entry> <entry key="localhost.MACH1UserID">**********</entry> <entry key="localhost.MACH1Password">**********</entry> <entry key="localhost.MACH1URL">jdbc:as400:MACH1;prompt=false;naming=system;libraries=DEVLIB;transaction isolation=none;</entry> <entry key="localhost.MACH2MachineId">MACH2</entry> <entry key="localhost.MACH2UserID">**********</entry> <entry key="localhost.MACH2Password">**********</entry> <entry key="localhost.MACH2URL">jdbc:as400:MACH2;prompt=false;naming=system;libraries=DEVLIB;transaction isolation=none;</entry> <entry key="TEST.MACH1MachineId">MACH1</entry> <entry key="TEST.MACH1UserID">**********</entry> <entry key="TEST.MACH1Password">**********</entry> <entry key="TEST.MACH1URL">jdbc:as400:MACH1;prompt=false;naming=system;libraries=TESTLIB;transaction isolation=none;</entry> <entry key="TEST.MACH2MachineId">MACH2</entry> <entry key="TEST.MACH2UserID">**********</entry> <entry key="TEST.MACH2Password">**********</entry> <entry key="TEST.MACH2URL">jdbc:as400:MACH2;prompt=false;naming=system;libraries=TESTLIB;transaction isolation=none;</entry> <entry key="PROD.MACH1MachineId">MACH1</entry> <entry key="PROD.MACH1UserID">**********</entry> <entry key="PROD.MACH1Password">**********</entry> <entry key="PROD.MACH1URL">jdbc:as400:MACH1;prompt=false;naming=system;libraries=PRODLIB;transaction isolation=none;</entry> <entry key="PROD.MACH2MachineId">MACH2</entry> <entry key="PROD.MACH2UserID">**********</entry> <entry key="PROD.MACH2Password">**********</entry> <entry key="PROD.MACH2URL">jdbc:as400:MACH2;prompt=false;naming=system;libraries=PRODLIB;transaction isolation=none;</entry>

Fig.1 – The application’s XML configuration file


Making the Connection

Shown below is the EGL code that resides in an EGL service program. The variable ‘server’, passed to the function containing this code, is used to govern which set of logic is to be executed. The value determines the values for the variables ‘machineID’, ‘userid’ and ‘password’.

Once these values are obtained the value for ‘runtimeEnvironment’ is used to obtain the correct connection string or URL. For localhost, this value will come from the XML configuration data. For TEST or PROD, the connection URL is obtained from the JNDI-defined connection criteria established in Tomcat’s context.xml file. See this post for information about that.

//Obtain the runtimeEnvrionment variable from the configuration data cache runtimeEnvironment = StrLib.clip(configDataRecord.runtimeEnvironment); //The program defined variable 'server' contains either 'MACH1' or 'MACH2' if (server == configDataRecord.MACH1MachineId) machineID = configDataRecord.MACH1MachineId; userid = configDataRecord.MACH1UserID; password = configDataRecord.MACH1Password; if (runtimeEnvironment == CommonLibrary.CONST_LOCALHOST) connectionString = configDataRecord.MACH1URL; end if (runtimeEnvironment == CommonLibrary.CONST_TEST) connectionString = "jdbc/MACH1"; end if (runtimeEnvironment == CommonLibrary.CONST_PROD) connectionString = "jdbc/MACH1"; end end if (server == configDataRecord.MACH2MachineId) machineID = configDataRecord.MACH2MachineId; userid = configDataRecord.MACH2UserID; password = configDataRecord.MACH2Password; if (runtimeEnvironment == CommonLibrary.CONST_LOCALHOST) connectionString = configDataRecord.MACH2URL; end if (runtimeEnvironment == CommonLibrary.CONST_TEST) connectionString = "jdbc/MACH2"; end if (runtimeEnvironment == CommonLibrary.CONST_PROD) connectionString = "jdbc/MACH2"; end end //Make the connection sqlLib.connect(connectionString, userid, password);

Fig.2 – Tomcat’s context.xml


Problem? What problem?

While everything explained so far is accurate, there is one problem, if it can be called that. It’s more of a developmental artifact than anything else and can be spotted in the configuration file. Everything will still work, but there are entries which have been rendered superfluous. Can you spot the problem? Hint: see the JNDI entries for comparison. Post your thoughts on this in the comments section below this post.



So, there we have it. We’ve seen how Tomcat configuration and the application’s externally defined property values can facilitate connections to a given database for a whole list of different machines. The value of this effort should be self-evident, that is, it does not promote hard-coded connection criteria in the application’s code which, without modifications, would prohibit deployment across multiple run time environments represented by the developer’s machine, the test or QA machine and finally the production machine.

Tomcat on the iSeries. Running Headless.

leave a comment »

First things, first. The server

When running Tomcat on the iSeries a few modifications to its startup script are required. First, the iSeries is headless, meaning it has no keyboard, monitor or mouse attached. (Yes, there are admin consoles, but this isn’t the same thing.)

In our case, Tomcat is running in a UNIX environment therefore the startup script for Tomcat is Do not modify the windows version (catalina400.bat)

Within, Tomcat’s startup command (shown below) must be modified to include an additional parameter beyond the original parameters already supplied to the command.


Variable to indicate the server is operating in a ‘Headless’ state

The parameter “-Djava.awt.headless=true” is used to indicate to Java that the system, i.e the iSeries, is operating in a configuration in which the display device, keyboard, or mouse is lacking. See this link for a full explanation

The full command is :

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

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

Without the parameter, this stack-trace is produced, which is complaining about graphics, which the iSeries does not have. This is the clue indicating the proper course of action which results in the use of the parm.

SEVERE: Critical error during deployment: java.lang.UnsatisfiedLinkError at java.lang.Throwable.( at java.lang.Error.( at java.lang.LinkageError.( at java.lang.UnsatisfiedLinkError.( at sun.java2d.Disposer.( at at com.sun.imageio.spi.InputStreamImageInputStreamSpi.createInputStreamInstance( at javax.imageio.ImageIO.createImageInputStream( at org.richfaces.application.InitializationListener$AWTInitializer.initialize( at org.richfaces.application.InitializationListener.onStart( at org.richfaces.application.InitializationListener.processEvent( at javax.faces.event.SystemEvent.processListener( at com.sun.faces.application.ApplicationImpl.processListeners( at com.sun.faces.application.ApplicationImpl.invokeListenersFor( at com.sun.faces.application.ApplicationImpl.publishEvent( at com.sun.faces.config.ConfigManager.publishPostConfigEvent( at com.sun.faces.config.ConfigManager.initialize( at com.sun.faces.config.ConfigureListener.contextInitialized( at org.apache.catalina.core.StandardContext.listenerStart( at org.apache.catalina.core.StandardContext.start( at org.apache.catalina.core.ContainerBase.addChildInternal( at org.apache.catalina.core.ContainerBase.addChild( at org.apache.catalina.core.StandardHost.addChild( at org.apache.catalina.startup.HostConfig.deployWAR( at org.apache.catalina.startup.HostConfig.deployApps( at org.apache.catalina.startup.HostConfig.check( at sun.reflect.NativeMethodAccessorImpl.invoke( at sun.reflect.DelegatingMethodAccessorImpl.invoke( at java.lang.reflect.Method.invoke( at org.apache.tomcat.util.modeler.BaseModelMBean.invoke( at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke( at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke( at org.apache.catalina.manager.ManagerServlet.check( at org.apache.catalina.manager.HTMLManagerServlet.doPost( at javax.servlet.http.HttpServlet.service( at javax.servlet.http.HttpServlet.service( at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter( at org.apache.catalina.core.ApplicationFilterChain.doFilter( at org.apache.catalina.filters.CsrfPreventionFilter.doFilter( at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter( at org.apache.catalina.core.ApplicationFilterChain.doFilter( at org.apache.catalina.core.StandardWrapperValve.invoke( at org.apache.catalina.core.StandardContextValve.invoke( at org.apache.catalina.authenticator.AuthenticatorBase.invoke( at org.apache.catalina.core.StandardHostValve.invoke( at org.apache.catalina.valves.ErrorReportValve.invoke( at org.apache.catalina.core.StandardEngineValve.invoke( at org.apache.catalina.connector.CoyoteAdapter.service( at org.apache.coyote.http11.Http11Processor.process( at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process( at$ at . . .