Resource Consumer Demo

The Resource Consumer Demo illustrates the operation of the resource manager, in particular its support for active threads and for J9 memory spaces.

The demo consists of two parts - the Timer Bundle and the Resource Consumer Bundle.

Demo Components

The Resource Consumer Demo consists of two bundles located in the demo/bundles directory - Timer Bundle, which contains a timer service, and Resource Consumer Bundle, which on recurrently increases the time events requested from the Timer service creating bigger and bigger objects and more and more active threads. The JARs of the Timer Bundle and the Resource Consumer Bundle, respectively, are timer.jar and resmandemo.jar.

The main directory of Resource Consumer Demo is demo/framework/resman from the Framework Professional Edition Package . The directory holds the source files, the mk generation script for rebuilding the demo, an install.txt file for installation through the Kit Manager Bundle, a readme.txt file with short description of the demo.

Starting the Demo

The Resource Consumer Demo needs the mBS framework with enabled resource management - the mbs.resman.enabled system property should be true, and the ProSyst Util Bundle - it is packed in the putil.jar JAR from the bundles directory.

On JDK 1.5 and CVM 1.1, to have restrictions over active threads, besides mbs.resman.enabled set the mbs.resman.class system property to com.prosyst.mbs.impl.framework.module.resman.jdkv15.ResourceManagerImpl.

To have both active threads and memory space size restricted, you should start the demo on the J9 JVM. In this case, besides setting mbs.resman.enabled to true, with the mbs.resman.class system property you should specify the resource manager implementation corresponding to the used version of J9 - com.prosyst.mbs.impl.framework.module.resman.j9v2.J9ResourceManager.

Using an Install Script

The Resource Consumer Demo owns an install script for easier and faster installation of its components and necessary bundles. To get more details about starting the demo through this install script, refer to "General Rules for Demos".

Activating All Necessary Components Manually

Following is the procedure for starting the demo bundle by bundle:

  1. Set mbs.resman.enabled to true as described in the "System Properties" document.
  2. If you are to use the J9 JVM, set mbs.resman.class with the appropriate value.
  3. Start the mBS framework.
  4. Install and start the ProSyst Util Bundle (bundles/putil.jar) or make sure it is active. You can do this from the mConsole or the framework text console. For example, using the framework text console:
    fw.i -s putil.jar
  5. Install and start the Timer Bundle (demo/bundles/timer.jar) from the mConsole or the framework text console. For example, using the framework text console:
    fw.i -s ../../../demo/bundles/timer.jar
  6. Install and start the Resource Consumer Demo (demo/bundles/resmandemo.jar). For example, using the framework text console:
    fw.i -s ../../../demo/bundles/resmandemo.jar

Inside the Demo

As it was mentioned above, the Resource Consumer Demo consists of two bundles, Timer Bundle and Resource Consumer Bundle. The Timer Bundle provides a Timer service, which sends to a subscribed listener time-based events after a specified period of time. The Resource Consumer Bundle is a listener for the Timer service and on receiving an event it registers for another notification each time requesting more and more memory.

Both bundles declare specific resource requirements which the framework resource manager handles.

Timer Bundle

The Java components of the Timer Bundle are placed in the demo.resman.timer.service and in the demo.resman.timer.service.impl packages. The first package contains the Timer (it represents the Timer service) and TimerListener interfaces. The second package contains the bundle activator, the Timer service implementation - TimerImpl, and an event queue class - TimerQueueNode.

Bundle Activator

The activator of the Timer Bundle is demo.resman.timer.service.impl.TimerActivator. When the Timer Bundle is started, the start method of the activator is called. This method checks if the Resource Manager service (com.prosyst.mbs.framework.resman.ResourceManager) of the System Bundle is available. If this is true, the activator instantiates demo.resman.timer.service.impl.TimerImpl and registers it in the framework under the Timer interface.

public class TimerActivator implements BundleActivator {
       . . .
  public void start(BundleContext bc) throws BundleException {
       . . .
    resourceRef = bc.getServiceReference(ResourceManager.class.getName());
    if(resourceRef == null) {
      throw new RuntimeException("Resource Management Not Available!");        
    }
    ResourceManager resManager = (ResourceManager)bc.getService(resourceRef);
    timer = new TimerImpl(resManager);
    timer.start(); 
    sRegTimer = bc.registerService("demo.resman.timer.service.Timer",
timer,
null); . . . } . . . }
Listing 1.1: Timer Bundle activator.

Timer Service

The interface of the Timer service is demo.resman.timer.service.Timer and it is implemented by demo.resman.timer.service.impl.TimerImpl. In general, the main method of the Timer service is notifyAfter, which demo.resman.timer.service.TimerListener implementations call to subscribe for time events.

When called, the notifyAfter method implementation switches from the current resource context, which is the one of the calling bundle, to the memory space of the Timer Bundle by using the Resource Manager service. Then the TimerListener implementation, passed as method's argument, is added as a node into the timer queue (TimerQueueNode). After adding the node, the demo returns to the memory space of the requester.

     . . .  
public void notifyAfter(TimerListener listener, int timePeriod, int event) { String callerContext = null; . . .
callerContext = resManager.switchToContext(thisContext); . . . resManager.switchToContext(callerContext); }
Listing 1.2: Switching between resource contexts.

When a TimerListener implementation is notified by a TimerNodeQueue thread, the Timer Bundle switches to the listener's resource context thus creating objects in there.

Declared Bundle Requirements

The Timer Bundle owns a requirement XML , called TimerRes.xml, in which it declares its requirements towards the J9 resource manager. In particular, these requirements are for allocating a memory space with NewSegmentSize 24000 bytes and with OldSegmentSize 18000 bytes.

<?xml version="1.0" standalone="yes"?>
<BundleRequirements>
  <Resources>
    <VM name="j9">
      <Resource>
        <Name>NewSegmentSize</Name>
        <Requirement>24000</Requirement>
      </Resource>
      <Resource>
        <Name>OldSegmentSize</Name>
        <Requirement>18000</Requirement>
      </Resource>
    </VM>
  </Resources>
</BundleRequirements>
Listing 1.3: Bundle Requirements' XML of the Timer Bundle.

After the required memory from the Timer Bundle exceeds the limits settled for a memory space in the requirement XML, an OutOfMemoryError is thrown.

Resource Consumer Bundle

The Resource Consumer Bundle provides no services. It contains a demo.resman.timer.service.TimerListener implementation that "eats" memory on each received event from the Timer service. In addition, the Resource Consumer Bundle declares requirements for active threads, which illustrates the mechanism for thread management.

The components of the Resource Consumer Bundle are placed in the demo.resman.resconsumer package. It contains the bundle activator and the implementation of TimerListener.

Bundle Activator

The activator of the Resource Consumer Bundle is ResourceConsumerActivator. When the bundle is started, the activator's start method is invoked. It checks if the Timer service is registered in the framework. If the service presents in the service registry, a service object is retrieved. Then, a TimerListener implementation (ResourceConsumerTimerListener) object is created and is registered to receive one notification after 2 seconds. If the Timer service is not registered, the activator registers a service listener for it.

public class ResConsumerActivator implements BundleActivator, ServiceListener {
       . . .
  public void start(BundleContext bc) throws BundleException {
       . . .
    sRef = bc.getServiceReference(Timer.class.getName());
    if (sRef != null) activate();
      bc.addServiceListener(this, "(objectClass=" + Timer.class.getName() + ")");
    } 
       . . .
} . . . private void activate() { timer = (Timer) bc.getService(sRef); if (timer != null) { listener = new ResConsumerTimerListener(timer, 2); timer.notifyAfter(listener, 2, listener.count); } else { . . . } } . . . }
Listing 2.1: Subscribing for time events.

TimerListener Implementation

The implementation of the demo.resman.timer.service.TimerListener interface is ResourceConsumerTimerListener. The timer method implemented from TimerListener is called to indicate an event coming from the Timer service. When such an event is received, ResourceConsumerTimerListener registers again for another timer event. At every registration, the notification event value is doubled and a piece with byte size equal to this doubled notification event multiplied by 10000 is requested. The ResourceConsumerTimerListener also creates a new ResourceConsumerThread thread each time the timer method is called.

Creating bigger and bigger objects triggers the mechanism for restriction of the memory for the Timer Bundle. Creating more and more active threads provokes the mechanism for restriction of the Resource Consumer Bundle active threads.

When the size of memory space for the Resource Consumer Bundle exceeds the one defined by the Timer Bundle, then an OutOfMemoryError is thrown. However the bundle continues to operate as if it has called the notifyAfter method before the OutOfMemoryError. Therefore its timer method is invoked later. If the cycle continues long enough (about 10 minutes), then the timer stops dumping OutOfMemoryError messages. This happens when the Resource Consumer Bundle's memory space remains with just a few free bytes and the timer method receives an OutOfMemoryError before being able to add its listener again.

  private Timer timer;
  private volatile boolean recurrent;
 
  protected int count = 1;
  private Vector memKeeper;
  private Vector threadsKeeper;
  private static int size;
  private static int period = 3; 
  private int numTh = 0; 
       . . .
  public void timer(int event) { 
    if (recurrent) {
      count = (count * 2) % 1000;
      timer.notifyAfter(this, period, count);
    }
    size = 10000 * event;
    try {
      ResConsumerActivator.log.info("[ResConsumerTimerListener] trying to allocate "
+ size
+ " bytes of memory... "); memKeeper.addElement(new byte[size]); ResConsumerActivator.log.info("[ResConsumerTimerListener] ok."); } catch (Throwable th) { ResConsumerActivator.log.info("[ResConsumerTimerListener] failed to allocate memory. "
+ th); memKeeper.removeAllElements(); } try { ResConsumerActivator.log.info("[ResConsumerTimerListener] trying to create thread"); ResConsumerThread next = new ResConsumerThread(numTh); numTh ++; threadsKeeper.addElement(next); ResConsumerActivator.log.info("[ResConsumerTimerListener] ok."); } catch(Exception exc) { ResConsumerActivator.log.info("[ResConsumerTimerListener] Thread Creation Failed "
+ exc.getMessage()); ((ResConsumerThread)threadsKeeper.elementAt(0)).stopIt(); try { threadsKeeper.removeElementAt(0); } catch(Exception e) {} } } . . .
Listing 2.2: Providing a recurrent increase of allocated memory and active threads count.

Declared Bundle Requirements

In a requirement XML the Resource Consumer Bundle manifests a requirement for 50 active threads. If the thread number is exceeded, then new threads won't be created.

<?xml version="1.0" standalone="yes"?>
<BundleRequirements>
  <Resources>
<VM>
<Resource>
<Name>BundleThreads</Name>
<Requirement>50</Requirement>
</Resource>
</VM>
</Resources>
</BundleRequirements>
Listing 2.3: Resource requirements of the Resource Consumer Bundle.

Framework Demos