Customization

Ubik's behavior can be customized/altered in different ways. This section addresses some of these.

Logging

Ubik has its own logging system, in order to avoid forcing dependency on an external toolkit (if you're using Ubik with the JBoss Serialization library though, you'll be forced to depend on Log4j).

In general, you will not be interested in Ubik's logs: they're mostly meant for diagnostics purposes in the course of Ubik development.

By default, Ubik's logging level is set to ERROR. You can change that by setting the log level that you wish, using the ubik.rmi.log.level JVM property. The available levels are as follows - from lowest to highest priority:

  • TRACE
  • DEBUG
  • INFO
  • WARNING
  • ERROR
  • OFF
  • REPORT

At runtime, Ubik attempts to match the value of the ubik.rmi.log.level JVM property (if found) to one of the above levels - matching is case-insensitive. For example, the debug value for the property would set the level to DEBUG.

In addition, you can also redirect logging output to a file (Ubik logs to stdout by default). The abstraction for logging output is defined by the LogOutput interface. Implementations of the interface must have a public no-args constructor that allows instantiating the desired output at runtime, based on the following JVM property: ubik.rmi.log.output.class. As its name indicates, the value of the property must correspond to the fully-qualified name of the LogOutput implementation class to use.

To redirect to a file, you specify the FileLogOutput class. Upon instantiation, an instance of that class will initialize itself based on specific JVM properties (for which defaults will be used if the corresponding properties are not found). These properties are as follows:

  • ubik.rmi.log.file.name: specifies the name of the log file to create - defaults to ubik.log. Note that the file name specified by this property is expected NOT to have the extension. Ubik will add the .log extension at runtime.
  • ubik.rmi.log.file.max-archive: specifies the maximum number of archived log files to keep around.
  • ubik.rmi.log.file.size: indicates the maximum size (in MB) of the log file before it's rotated (defaults to 3 megs).
  • ubik.rmi.log.file.dir: specifies the path to the directory where log files are to be kept (defaults to the value of the user.dir JVM property).

Statistics

Ubik provides built-in statistics generation, which is disabled by default. You can turn it on by setting the ubik.rmi.stats.enabled JVM property to true.

If statistics generation is enabled, periodic output of these statistics will be performed. At what interval this output occurs is configurable through the ubik.rmi.stats.dump.interval JVM property (whose value is expected to be expressed in seconds). If the interval is not supplied (or if it's zero or less), no output will be performed.

By default, the output will be done to a file (named ubik-stats.log) under the user.dir directory. Which log file is used and how it is managed can be configured with JVM properties that are similar to the one used for configuring logging output:

  • ubik.rmi.log.file.name: specifies the name of the log file to create - defaults to ubik-stats.log. Note that the file name specified by this property is expected NOT to have the extension. Ubik will add the .log extension at runtime.
  • ubik.rmi.stats.log.file.max-archive: specifies the maximum number of archived log files to keep around.
  • ubik.rmi.stats.log.file.size: indicates the maximum size (in MB) of the log file before it's rotated (defaults to 3 megs).
  • ubik.rmi.stats.log.file.dir: specifies the path to the directory where log files are to be kept (defaults to the value of the user.dir JVM property).

Stubs

How stubs and related objects are created can be customized. Although doing this can be considered a bit low-level, we thought it was worth mentioning. Three types of customizations are supported:
  1. OID generation.
  2. StubInvocationHandler generation.

OID Generation

The OIDCreationStrategy interface specifies the behavior for creating the unique identifiers (instances of OID) for remote objects. One such OID is generated for each stub: it is kept in that stub's StubInvocationHandler (that interface is described in the next section).

The javadoc for both the OIDCreationStrategy and OID is complete enough to provide you with clear guidelines as to how to proceed. Once you have implementations for but, you have to register them with the Ubik runtime.

That is typically done prior to exporting remote objects. You would implement code such as the following:

Hub.getModules().getStubProcessor().insertOIDCreationStrategy(myStrategy);

StubInvocationHandler Generation

The StubInvocationHandler interface extends the JDK's java.lang.reflect.InvocationHandler interface. There exists by default different implementations of the StubInvocationHandler interface: one for each type of stub that Ubik supports.

Indeed, a StubInvocationHandler implementation is meant to be wrapped in a stub (which is a dynamic proxy), and provide the logic for that stub (that is, how that stub behaves on the client-side).

Delving into the details of how to implement an StubInvocationHandler is beyond the scope of this documentation: we would suggest you look at one of the existing implementations for starters: it is quite clear once you get your head around it. Basically, a StubInvocationHandler will wrap one or more RemoteRefContexts - each corresponding to an endpoint (i.e.: a server) with which the stub communicates.

Along with your StubInvocationHandler, you have to implement a StubInvocationHandlerCreationStrategy and register it with the StubProcessor module, like so:

Hub.getModules().getStubProcessor().insertHandlerCreationStrategy(myStrategy);

Stub Generation

Ubik stubs are dynamic proxies, generated using the JDK's mechanism. You can provide your own StubCreationStrategy: the constraint you must respect is that the stub you generate implement the Stub interface: a stub is expected to be able to return the StubInvocationHandler it encapsulates (meaning that whatever type of stub you decide to implement, it must somehow encompass a StubInvocationHandler). The default StubCreationStrategy should get you started on how to implement your own.

For Ubik's runtime to use your strategy, you have to register it with the StubProcessor module:

Hub.getModules().getStubProcessor().insertStubCreationStrategy(myStrategy);

Callbacks

The support for callbacks in Ubik can be further customized with specific JVM properties:

  • ubik.rmi.server.callback.max-threads: indicates how many threads (the default is 5) should be used to process incoming callback remote method calls, which are processed asynchronously by the threads (the command object corresponding to the method call sits on a queue until it is picked up by one of the threads). If using callbacks, you should benchmark you're application against expected levels of traffic, and determine the best configuration for you.
  • ubik.rmi.server.callback.outqueue.threads: indicates how many threads (default is 2) are used to send responses corresponding to the return value of remote method calls invoked through callbacks. When the thread that processes a callback is finished, it will put the result on an outgoing queue. The threads configured by this property are in turn in charge of relaying these results (in the form of callback responses) to the appropriate clients. It is important that the number of such threads be configured appropriately. Again, you should test to find the optimal configuration.