Quark Engine and JT400 - Part 1

In this multipart integration tutorial, we will show you how to use the famous IBM JT400 library to easily work with IBM i from a web browser. We will show you how easy it is to map JT400 classes to the web browser calls and we will show you how easy it is to create a web based IFS file browser.

If you already have an experience with JT400 then you already know that all other classes depend on AS400.class, connection definition that must be initialized first.

So, in this first part we will show a basic introduction initializing AS400 for Green Screens Quark Engine.

Before we start, let us give you a teaser. Following example code is what you will be calling from the web browser at the end of this demo.


// Initialize Quark engine
await Engine.init({api: api, service:api});

// Call JT400 AS400 class instance method to connect to the IBM i system
await io.greenscreens.AS400.login('as400.acme.com', 'QSECOFR', 'QSECOFR')

// Get list of files and directories from IBM i IFS file system
let files = await io.greenscreens.IFS.list('/')

// call when logout from web application
await io.greenscreens.AS400.logout()

Base idea is to create controller classes for every used JT400 class. For example, for AS400.class we will have an As400Controller, for IFS we will have IFSController and so on.

As AS400.class instance is shareable among all other JT400 classes to make remote calls to IBM i, we need to keep this class instance inside the user session. This can be done in multiple ways, but here we will use standard Java CDI injection to help us. However, storing data based on CDI requires classes to be Serializable, something AS400.class  does not implement so we need to create our own CDI Producers for AS400.class instance to be able to inject the same AS400 instance in multiple controllers.

For this we will create a CDI application level class instance responsible to provide a unique AS400 class instance on a session level.

@ApplicationScoped
public class SessionAttributeProducer implements Serializable {
		
	@Inject
	private HttpServletRequest servletRequest;

	@Produces
	@Default
	public AS400 sessionAS400AttributeDefault(final InjectionPoint ip) {
    
		final String name = AS400.class.getCanonicalName();
		final HttpSession session = servletRequest.getSession();
		
		AS400 as400 = (AS400) session.getAttribute(name);
		if (as400 == null) {
			as400 = new AS400();
			session.setAttribute(name, as400);
		}

		return as400;
	}

}

This class will be self-registered within Java CDI upon web application start and will allow us to always inject the same AS400 class instance on a session level scope. Injecting an AS400 instance like this...

@Inject
AS400 as400;

Every time Java CDI detects injection, sessionAS400AttributeDefault method will be called from a defined class instance. Now, let's create a Quark Engine Controller class which will be callable from a web browser through standard JavaScript calls.

@ExtJSDirect(paths = { "/ws", "/api" })
@ExtJSAction(namespace = "io.greenscreens", action = "AS400")
public class AS400Controller {

	@Inject 
	AS400 as400;
	
	@Inject @Autoinit
	HttpSession session;

	@ExtJSMethod("login")
	public ExtJSResponse login(@Required final String system, 
			@Required final String userName, 
			@Required final String password) {
		
		final ExtJSResponse.Builder resp = ExtJSResponse.Builder.create();

		try {
			as400.setSystemName(system);
			as400.authenticate(userName, password);			
			resp.setStatus(true);
		} catch (Exception e) {	
			resp.setMessage(e.getMessage());
		}
		
		return resp.build();
	}
	
	@ExtJSMethod("logout")
	public ExtJSResponse logout() {	
		as400.disconnectAllServices();
		session.invalidate();
		return new ExtJSResponse(true, null);
	}

}

This controller will provide mapping to login and logout methods available from the web browser. However, we also need to take care of clearing session resources. In this case, we need to make sure that AS400 session instances are really disconnected from the remote IBM i system even if the user simply closes the browser instead of properly signing-out through a web application.

For this, we must add a session listener which will clear all AS400 instances upon session destroy. Here is a simple example.

@WebListener
public class SessionProducer implements HttpSessionListener {
 
    @Override
    public void sessionCreated(final HttpSessionEvent se) {}

    /**
     * We want to ensure to release as400 resources if session is destroyed 
     */
     @Override
     public void sessionDestroyed(final HttpSessionEvent se) {

		final HttpSession session = se.getSession();
		final Enumeration<String> keys = session.getAttributeNames();
		
		while (keys.hasMoreElements()) {
			
			String key = keys.nextElement();
			Object obj = session.getAttribute(key);
		
			if (obj != null && obj instanceof AS400) {
				((AS400)obj).disconnectAllServices();	
			}
			
		}
		
	}

}

And now, our basic login and logout methods can be used from a web browser. Please note... when running this demo on IBM i, actually, you don't need server location, only username and password.  

Here we presented only a basic introduction, full code can be found on our Github repository here (demo1 package). We will leave to you to decode what remaining code not shown here does.

Next time we will show you how to use IFS with the Quark engine with everything we learned today and how easy it is to create Web Api for IFS browsing, aka web ftp service.

As the Quark engine is small, it is a good fit for microservices. This opens some new possibilities such as creating Java Micro services on IBM i and creating powerful mappings as shown here to be able to call backend RPG or COBOL programs and exposing them as a web service. But about that in one of the next blog posts.