Working with Events

Events and the CASActionResults Class

By default, all server events are returned as part of the CASActionResults object that is returned by the invoke() method. This means that you have access to all events after the action is complete. Alternatively, you can register a listener for each type of event to receive the event as it is streamed from the server.

Log Events

Log events are generated by the server when information is sent to the log. A log event consists of a type (such as WARN or ERROR) and a message.

If you want to receive log events as they are streamed from the server, you need to register a CASLogEventListener on the action options object before you invoke the action:

// Set the log event listener. This handles the log events as they
// come from the server instead of accessing them from the results
// after the action is complete.
options.setLogEventListener(new CASLogEventListener() {

    @Override
    public boolean handleLogEvent(CASActionOptions options, CASLogEvent logEvent) {

        System.out.println("# " + logEvent);

        // Return the propagate flag. If true, the log event
        // is propagated to the result object. Otherwise nothing
        // else will be done with the log event.
        return false;
    }
});

Performance Events

Performance events are generated by the server when an action is designed to inform the caller about certain performance characteristics of the action. A performance event can include timings (elapsed time, CPU time, and so on), memory usage, node usage, and CPU core usage.

If you want to receive performance events as they are streamed from the server, you need to register a CASPerformanceEventListener on the action options object before you invoke the action:

// Set the performance event listener. This handles the performance events as they
// come from the server instead of accessing them from the results
// after the action is complete.
options.setPerformanceEventListener(new CASPerformanceEventListener() {

    @Override
    public boolean handlePerformanceEvent(CASActionOptions options, CASPerformanceEvent performanceEvent) {

        System.out.println("# " + performanceEvent);

        // Return the propagate flag. If true, the performance event
        // is propagated to the result object. Otherwise nothing
        // else will be done with the performance event.
        return false;
    }
});

Disposition Events

Disposition events are generated by the server when an action completes or fails. A disposition event contains a severity, reason, and message.

If you want to receive disposition events as they are streamed from the server, you need to register a CASDispositionEventListener on the action options object before you invoke the action:

// Set the disposition event listener. This handles the disposition events as they
// come from the server instead of acessing them from the results
// after the action is complete.
options.setDispositionEventListener(new CASDispositionEventListener() {

    @Override
    public boolean handleDispositionEvent(CASActionOptions options, CASDispositionEvent dispositionEvent) {

        System.out.println("# " + dispositionEvent);

        // Return the propagate flag. If true, the disposition event
        // is propagated to the result object. Otherwise nothing
        // else will be done with the disposition event.
        return false;
    }
});

Message Tag Events

A message tag event is different from the other event types. For a few actions, the action can send a message back to the client during the invocation of the action to request additional information. This is done with a message tag. See com.sas.cas.message.CASMessageHeader for the list of tags.

The addTable action in the table action set is an example of an action that uses message tag events. The addTable action sends a message back to the client so that the client can determine when to send data rows to the server and populate a table. In order to handle this message, which has a DATA tag, you must register a message tag handler (of type CASMessageTagHandler) on the action options.

The following code shows an example of CASMessageTagHandler, which simply returns no data:

@Override
public boolean handleMessageTag(CASMessageTagEvent event) throws CASException, IOException {

    // Just create the table; don't send any rows
    CASDataAppender.sendZeroRows(event);

    // Do not propagate the response
    return false;
}

To use this message tag handler, you must register the handler on the action options before you invoke the action:

options.setMessageTagHandler(CASMessageHeader.TAG_DATA, <the handler>);

To send data rows to the server (to append data to the table), use this message handler, which is more sophisticated than the first example:

@Override
public boolean handleMessageTag(CASMessageTagEvent event) throws CASException, IOException {

    // Get the variable list
    Addtablevariable[] vars = (Addtablevariable[]) event.getOptions().get(AddTableOptions.KEY_VARS);
    Integer reclen = (Integer) event.getOptions().get(AddTableOptions.KEY_RECLEN);
    if (reclen == null) {
        // This shouldn't happen. The server should have verified.
        throw new CASException("Missing reclen");
    }
	
    // Create our data appender
    CASDataAppender appender = new CASDataAppender(event, vars, reclen, bufSize);

    // Creates a new random generator with the given seed
    Random r = new Random(0);
 
    for (int i = 0; i < nrows; i++) {
        appender.setDouble(0,  i);
        appender.setString(1,  "Some String at " + i);
        appender.setDouble(2,  r.nextDouble());
        appender.appendRecord();
    }

    appender.close();

    // Do not propagate the response
    return false;
}

The preceding code is suitable for handling message tag events from the addTable action (com.sas.actions.table.AddTableOptions class). Another action that uses message tag events, the upload action (a specialized com.sas.cas.io.UploadDataTagHandler class), is available. It accepts a filename or an InputStream as the input.

Server Events

You can register for a few types of events generated by the server. These events include:

  • Caslib list has changed
  • Table list has changed
  • Action set has been added
  • Data source list has changed
  • Permissions have changed

To register for one or more of these events, add an event listener:

client.addEventListener(CASConstants.EVENT_FLAG_CASLIBS, new CASEventListener() {
    @Override
    public void handleCASEvent(long flag) {
        // Do something with the event
    }
});

You can register for multiple events:

client.addEventListener(
    CASConstants.EVENT_FLAG_CASLIBS | CASConstants.EVENT_FLAG_TABLES, 
    new CASEventListener() {
        @Override
        public void handleCASEvent(long flag) {
            // Do something with the event
            if (flag == CASConstants.EVENT_FLAG_CASLIBS) {
                // Do something - the caslibs have changed
            }
            else if (flag == CASConstants.EVENT_FLAG_TABLES) {
                // Do something - the tables have changed
            }
        }
    });

Server events are packaged as part of an action response, so these are not asynchronous events. Event notification occurs when an action completes. Some types of clients might desire to "poll" for events. This can be done simply by invoking any action, such as com.sas.cas.actions.builtins.PingOptions.

Socket Events

The CASSocketEventListener class provides callbacks for when a new socket connection is established and when a socket connection is closed. This enables you to customize socket settings, such as the time-out.

// Register our socket event listener
client.setSocketEventListener(new CASSocketEventListener() {

    @Override
    public void handleSocketConnectionEvent(CASClientInterface client, Socket socket) {
        System.out.println("Socket opened");
    }

    @Override
    public void handleSocketClosedEvent(CASClientInterface client, Socket socket) {
        System.out.println("Socket closed");
    }
});
Last updated: June 24, 2025