Top Banner

Application Programming with ZAppSvr


The purpose of this document is to help the developer be productive quickly. In order to get started there are a few things that you need to know, and examples are the best way to illustrate how to apply knowledge. Since ZAppSvr has so many potential uses, we will need separate documents to highlight various features. We'll start here with the programming basics to get you started.

For the purposes of this document we will presume that you are using the NetBeans IDE (http://www.NetBeans.org) for development. If you are using a different IDE, the information will still be helpful in setting up your programming environment. A more experienced user, or a developer with special requirements may set things up differently, but we are assuming a lower level of experience so we don't fail to cover some basic information you might need.


Configuring your IDE for Developing with ZCache
img

The jars that come with ZAppSvr need to be included in the Compile-time Libraries.

plugin img

Set the "Main Class" to Main and make sure the Working directory point to the directory/folder you are developing in.

 

Getting Started Writing Your Application

 

Writing an application for ZAppSvr simply consists of writing a Plugin class. This single class is pooled and accessed by as many threads as you have configured ZAppSvr to use. Your Plugin is handed references to all the data needed by your Plugin, which you can use to meet your service design goals.

Global data that all threads (instances of your Plugin) need, is stored in a globally accessible Hashtable (globalHash). This mechanism can be used any way you prefer.

A method in your Plugin called runOnceInit(), will be used by ZAppSvr to set up your objects in the global Hashtable so that only one instance of each object is created, and all needed structures are prepared at runtime. If, for example, you have set up ZAppSvr for 500 threads, the runOnceInit() routine will only be run once to establish the starting run environment. The runOnceInit() method will not be executed for the other 499 instances of your plugin. This avoids duplicate object creation at startup.

In addition to this, your application can access ZCReplicator services. These services (currently just two, more to follow) allow you to transfer files to, and delete files from, server groups in a load balanced deployment environment. This means you can receive a file and place it on all servers in a defined server group. You can also delete a file easily. We’ll discuss these two methods in greater detail in our example application.

ZAppSvr is designed to leverage load balancing as a fundamental and integrated part of this application server environment. Application clustering becomes a natural part of your application, just by using the ZAppSvr application deployment model. We’ll illustrate this in our examples.

The following is an example Plugin file, that shows you the basic skeletal structure of your Plugin class. This basic structure is all you need to get started writing your Plugin. In our example, no matter what you request you are returned a short html message “Hello World”.

You can use this little program to verify that your debugging environment is set up properly. You should have your IDE configured so that you can start your project in the debugger and step through the Plugin code. Note that the execute() method is what is executed when a request is received, provided that the request meets the requirements of the authentication list (see configuration).

import java.awt.*;
import java.util.*;
import java.text.*;
import java.net.*;
import java.io.*;


public class Plugin			
{
  private Object[]  o          = null;
  private String[]  reqArray   = null;
  private String[]  strings    = null;
  private String    ipAddress  = null;
  private String    hostName   = null;
  private byte[]    postData   = null;
  private byte[]    retData    = null;
  private Hashtable globalHash = null;
  private Vector    outHdrAdd  = null;
  private Vector    customLog  = null;
  private InetAddress inetAdr  = null;
  private Boolean   isSSL      = null;
  private ZAppSvrUtilities zsu = null;
  
  public Plugin()
  {		
  }

  public void runOnceInit(Hashtable h)
  {
     // initialize any classes you need here, and add them to Hashtable h
  }

  public void execute( Object[] inobj )
  {		
     o = inobj;
     reqArray      = (String[])inobj[0];     // the complete request header
     ipAddress     = (String)inobj[1];       // the ip address of the requestor
     globalHash    = (Hashtable)inobj[2];    // the repository of global objects
     outHdrAdd     = (Vector)inobj[3];       // add items to the return header
     customLog     = (Vector)inobj[4];       // custom logger
     strings       = (String[])inobj[5];     // group and hostname information
     postData      = (byte[])inobj[6];       // POST request data
     hostName      = (String)inobj[8];       // hostname for this request
     inetAdr       = (InetAddress)inobj[9];  // inetAddress object
     isSSL         = (Boolean)inobj[10];     // is request from SSL
     zsu           = (ZAppSvrUtilities)inobj[11]; // useful utilities
    
     retData = myFunc(); // place your code here... whatever you want to do..

     retReq(retData); 
  }

  private void retReq( byte[] ba ) // this is a sample method you can use to return data
  {
      o[7] = ba;  // THIS LINE IS REQUIRED unless you assign the data directly to o[7];
  } 

	
  public byte[] myFunc() // see ZeroPoint application Server How-To for more details
  {
     return (new String("<html>Hello World</html>")).getBytes();
  }
}
ZAppSvr Utilities

ZAppSvr has a few utilities that allow you direct access to internal services you can leverage in writing your applications. Here is the interface that describes these services:

public interface ZAppSvrUtilities
{
  // ZCReplicator routines
  public void sendFileToGroup(String groupname, String path, byte[] data);
  public void deleteFileFromGroup(String groupname, String path);
  
  // Generally useful routines
  public byte[] setHtmlRetData( String ststr, java.util.Vector outHeaderAdd, byte[] outputData );
  
  // Load Balancer Routines
  // returns IP address, port of best choice for group 
  public String[] getBestSvrChoice(String groupname);
  public void setSvrBusy( String groupname, String ipaddress );
  public void clrSvrBusy( String groupname, String ipaddress );
}	

ZCReplicator routines provide you with the means to distribute and maintain files on servers that are part of a load balanced group. On high demand networks, maintaining mirrored file sets is simplified by using these tools. There are other tools that cover these issues, but there are times and applications where having a built in mechanism can be extremely helpful. For example if you have a web service where customers upload images that need to be replicated on other servers in the group, this utility is very nice. Deleting existing images pose the same issues.

Since ZAppSvr is an application server and load balancer, we need these load balancer tools to identify (where needed) which server would be best to use, and to notify ZAppSvr that our service is using that server. You can use getBestSvrChoice() to return the best server to use for your current operation. The String[] that is returned, contains the IP address in position 0, and the port in position 1.

Once you’ve selected the server, you need to use setSvrBusy( groupname, ipaddress ) to signal the load balancer that a process is running on that target server. clrSvrBusy( groupname, ipaddress ) is used after the process is complete to signal that the server is no longer in use.

public byte[] setHtmlRetData( String ststr, java.util.Vector outHeaderAdd, byte[] outputData )

Usage goes something like this; You create a dynamic response, (some html code) and you want to return that data to the requestor. To do this you need header information, status codes, etc. In this case you might call the routine like this:

retData  = setHtmlRetData( "200", outHeaderAdd, outputData );

In this example the return code was 200, outHeaderAdd is a Vector reference for modifying the return header that is passed into the execute() method in your plugin. outputData is the data you want to return in byte[] form. o[7] is a passed reference to your plugin that provides direct access to the data that is sent to the requestor. It is very handy for web service design. Usage is optional.

The other utilities provided are routines that we find we use often, and are provided in case they might be of benefit to the developer.

The two methods cvtToInt() and cvtToLong() are provided because they are considerably faster than Sun’s methods for accomplishing the same tasks, and easier to use.

 


Frequently Asked Developer Questions

A developer new to ZAppSvr can run into a few issues. Here are a few common answers:

If my service is not HTTP, how do I use ZAppSvr?

ZAppSvr is a request-response server, and while it can be used to easily create and manage HTTP based web services, the advantages of ZAppSvr extend well beyond HTTP and web pages. There is no strict enforcement of HTTP protocol, which means the request data arrives at your Plugin as it was sent, and you can do whatever you want to do in your application and return any data you choose. This creates an open environment that allows you great flexibility.

Let's say you wanted to send an encrypted message to ZAppSvr, and get an answer the was also encoded. You can use the HTTP POST protocol to send a binary packet of data to ZAppSvr using the command POST (i.e. myMessage.enc) in HTTP the post will be processed and expects a length encoded block of binary data. Your Plugin would decrypt the message, encrypt the response, and reply with a length-encoded reply. Only the "myMessage.enc" request would be visible in the packet.

Your application would not be a browser in this case, and would receive the data in response to the query and decrypt the encoded message for the user.

The fact is that except for the request definitions (GET, POST) you can define your own protocol to accomplish anything you want by using the headers, request, and POST binary encoding options. You can accomplish anything you want with ZAppSvr.

The benefits to this methodology are:

  • Easy routing and load balancing of stateless and stateful applications.
  • Much higher performance by avoiding remotely invoked objects and associated overhead required by such technology.
  • Industry standard protocol, and avoidance of unforseeable side affects of network filtering and processing (i.e. caching engines, etc.)
  • Flexibility. The ability to mix services within a single homogeneous network environment

Why do I keep getting 404 returned on every request?

Probably the most common problem you can have is failing to assign the new byte[] data that you want to return to the requestor to o[7]. This will result in a 404, File Not Found error. If your byte[] is returned empty, the request is automatically sent to appropriate web server target. The 404 error is returned to the user from the web server.

Why is my Plugin not working?

This error is usually caused by not adding the proper filter to the list found in Options->Plugin Process List Config. If you wanted to process all html requests, you would put *.htm* in the list. You could also limit processing to a specific request. See the configuration documentation for more details.

What's the Target in Configuration?

The target server is the web server where you are going to store web content. It can be local or somewhere else. It’s up to you. If you want to load balance you will have a list of servers for the load balancer to choose from.

 

©Copyright 2017, ZeroPoint, LLC.      Questions? Comments? Email Us.