SAS® AppDev Studio 3.0 Developer's Site

Using the webAF Middleware Server

The webAF Middleware Server uses a technique known as funneling, a process that daisy-chains method calls through Java middleware. Using more common Internet terminology, funneling means making multiple hops from the client to reach the server, with each of the hops points having possible computational intelligence.


There are only a few advantages, but they are quite important.

  1. Reduced memory consumption on the server with reuse of fewer SAS sessions, often one.
  2. Faster client startup since a server SAS session does not have to be created for subsequent clients.
  3. Information exchange between clients since common trap point is one server session.
  4. The clients can intercepts calls both at the client point and at the middleware point for filtering.

For an example of the memory savings, let us consider an example scenario with

  1. 10 PCs with Windows 95, running Microsoft's Internet Explorer which all connect to
  2. 1 Windows NT Web server which is also the SAS server.

Processes on the Web Server/SAS Server for access will include

  1. Web Server Daemon just as IIS
  2. RMIRegistry socket listener
  3. Java VM running RocfORB middleware
  4. SAS Session

For explanation and comparison purposes, two identical web pages are created in webAF with a TreeView containing a LibraryList. One will be funneled, one not. In both cases fixed, costs, such as running a Web Server, will be ignored.

For each method the client sessions create some objects on the server. Every client, regardless of originating browser, only creates a new partition on the server, a new reference at just a few K, and a new object at just a few K. The memory consumption by the above funneled processes on the server will include:

  1. RMIRegistry socket listener - normal consumption ~2 Meg
  2. Java VM running RocfORB middleware - normal consumption + new objects for indirection references - ~2 Meg
  3. SAS Session - normal consumption + client task partition + new objects - ~ 10Meg + number_clients * 600K

For 10 users this gives a total memory cost of 15 Meg.

Without funneling the same application is significantly more expensive, for example:

SAS Session - 10Meg * 10Sessions (one SAS session per client browser)

For a total cost of 101 Meg, for example, 6 times less memory is used when funneling with 10 users.

And the costs savings scale linearly, for a hundred users against a single server the savings escalate to nearly 1000 Meg.

However, this is not without its disadvantages to be discussed in the next section.


Here are the disadvantages:

  1. Small decrease in performance for a single client.
  2. Geometric decrease in based on number of clients as they block each other.
  3. Server space is unprotected for libname or macro collisions, only SCL lists and objects are protected.

The small decrease in performance is based on

  1. SAS/CONNECT for Java's throughput on Windows NT using TCP/IP sockets (rather than Tunneling) is approximately 100 methods/second.
  2. RMI's throughput on Windows NT using TCP/IP sockets is approximately 680 methods/second on a Pentium II / 266Mhz.

In the best case, single client performance is still reduced from 1/100th seconds,  0.01 seconds, for a method call to 1/100 + 1/680 = (100+680)/(100*680) = 0.0114 seconds.

Now, take the same scenario used in the advantages section, with 10 clients making concurrent calls. Since the middleware will have to block and queue every call except one, performance will degrade geometrically. For example, in a scenario with constant server interaction average method response time will be


Number_clients * ((rmi_time + sasConnectForJava_time)/(rmi_time *
sasConnectForJava_time)) = 10 * ((100+680)/(100*680)) = 0.114 seconds


sasConnectForJava_time = 1/100 = .01 seconds

For an application that is now 11 times slower.

So, making a worst case performance chart assuming concurrent keystrokes via:

data comp;
  users = 1;
  do while(users < 10000);
    funmem = 14 + users * .6;
	normmem = users * 10;
 	funspd = users * 780 / 68000;
	normspd = .01;
	space = (normmem - funmem) / funmem;
  	time = (normspd - funspd) / funspd;
  	users = users * 10;
proc print;
  format space time percent12.2;

Performance Chart

For Worst Case Response Time (Using Concurrent Keystrokes)

Users Funneled Memory Funneled Response Non-Funneled Memory Non-Funneled Response Space/Time Tradeoff
Not funneling is:
1 user 14.6 Meg 0.0115 secs 10 Meg 0.01 secs 31%smaller/12% faster
10 users 20.0 Meg 0.1147 secs 100 Meg 0.01 secs 400%larger/91% faster
100 users 74.0 Meg 1.1471 secs 1000 Meg 0.01 secs 1251%larger/99%faster
1000 users 614 meg 11.470 secs 10000 Meg 0.01 secs 1528%larger/99.9%faster

This table only applies to worst case concurrent response time, that is, if the users either pressed a key simultaneously or before the server had serviced the last request queuing up subsequent requests. Memory remains fairly constant. If the requests were staggered then only the 12% response time degradation would be noticed.


In addition to the basic three pieces required for all zero-install client/server Java applications communicating with a SAS server:

  1. Browser client
  2. Web server
  3. SAS server

Now another piece is added

  1. Java middleware

The implementation of this is currently via RMI for the initial hops with a back-end protocol of either SAS/CONNECT for Java or HTTP-Tunnel, later the initial hops protocol will be changed to be user specifiable.

First the applet is loaded on to the local machine's VM, this is either from the Web server or from the local disk.

Then, in establishing the connection, the webAF system classes (in webAF.jar), note that funneling is specified for this connection to SAS.

Now object creation requests go through the middleware.



  1. A script is included with the Web Server installation portion of webAF. On Windows NT, a shortcut is added in the AppDev Studio group named webAF Middleware Server. Selecting this shortcut will start the webAF Middleware Server (sometimes referred to as RocfORB).

  2. An administration application is included in order to customize how the Middleware Server functions. On Windows NT, a shortcut is added in the AppDev Studio group named webAF Middleware Server Administration. Selecting this shortcut will start the administration application:

webAF Middleware Server Administrator


This application will allow you to specify the maximum number of clients allowed per SAS session on any given host. Once the maximum number of clients has been reached for a SAS session a new SAS session will be started for any subsequent clients. Once that SAS session reaches the maximum number a new SAS session will be started, and so on. If a host is not listed in the administration application an unlimited (up to system resources) number of clients will use a single SAS session on that host. To remove a host from the list simply set the Maximum Clients to 0. The webAF Middleware Server will reload these settings automatically once the Apply button has been pressed, making the changes take effect immediately. Note that the administration application writes changes to the <AppDev Studio HOME>/Java/SAS/funnel.cfg file.

Application development within webAF:

  1. Click Use Funnel to share a SAS session in the ConnectionCustomizer Configuration Tab.


With RMI, the protocol used to connect to the Java middleware which then connects to the server, the middleware connection will either use

  1. JRMP - Java Remote Method Protocol
  2. IIOP - Internet Inter-Orb Protocol

Currently only JRMP is supported. This imposes extra considerations, for example, when calling a method:

ReturnValueType retval = remoteObject.methodCall(parameter);

there are a few possibilities for parameter, it either subclasses or implements

  1. java.rmi.server.UnicastRemoteObject - call by reference
  2. - call by value
  3. neither - ERROR

This presents a problem when using funneling as middleware depending on the structure of the application, consider using DataWarehouse.

ReturnValueList = remoteObject.method(updateList1,updateList2)

The ReturnValueList is always OK, it is the output parameter, so call-by-reference or call-by-value is ok.

However updateList1 is not ok, as the method call goes from

Browser RMIProxy - Middleware J2Proxy - SAS

The list is passed by the RMI proxy as call-by-value since HList is a serializable type. The middleware J2 proxy then copies the contents of the lists to the data stream through SAS/CONNECT to SCL. SCL then modifies the contents, which are then stream back to the J2 proxy. The J2 proxy empties its client's list object, the middleware list, and repopulates it with the list from the data stream. The RMI proxy, on the other hand, has already completed its work and does not know that it needs to updates its local list, so it never gets its data. Written as steps the above method call would be:

  1. Browser RMIProxy - send updatelist1, updatelist2 by value
  2. J2Proxy - send updatelist1, updatelist2 by value
  3. SASProxy - create SAS list from updatelist1, updatelist2 value
  4. SASproxy call method
  5. SASproxy - create streamed returnvaluelist, updatelist1, updatelist2
  6. J2Proxy - create returnvaluelist, then empty updatelist1, updatelist2 and populate from stream
  7. RMIProxy - read returnvaluelist from stream

The updated parameter lists get lost, which is a problem. One circumvention to this problem is to mandate a policy of

outputvalue = remoteobject.method(inputvalue,inputvalue)

rather than

outputvalue = remoteobject.method(updatevalue,updatevalue)

This has the added benefit of improving performance, as the user would then clearly dictate what gets sent over the wire and what does not.