Programming Examples

This section provides examples for the following:

Distributed System Management

An instance of AdminDistributedSystem implements the administrative interface for controlling, monitoring, and managing a GemFire distributed system.

The following examples show how to use the AdminDistributedSystemFactory class to define and create an instance of AdminDistributedSystem. The first example shows how to create a dedicated admin interface and the second example illustrates the method to create a colocated admin interface. All attributes set on DistributedSystemConfig (in these examples, a multicast address and port number) are used to define an AdminDistributedSystem.

Invoking com.gemstone.gemfire.admin.AdminDistributedSystem.connect configures the connection using DistributedSystemConfig system properties (including its defaults), and any settings in the gemfire.properties file.

The AdminDistributedSystemFactory.setEnableAdministrationOnly method enables you to configure GemFire administration as either dedicated or colocated. A dedicated admin interface limits the member only to administration APIs, while a colocated interface allows all GemFire APIs. To define an interface as dedicated, set the AdminDistributedSystemFactory.setEnableAdministrationOnly property to true as shown in the following example. The default value is false.

If setEnableAdministrationOnly is set to true, be careful to only use the GemFire APIs from the com.gemstone.gemfire.admin package. In particular, do not create a Cache or a normal DistributedSystem. For the caveats associated with using a colocated admin interface, see "Limitations for Using a Colocated Admin API."

Creating a Distributed System Administration Interface (dedicated to administration only)

AdminDistributedSystemFactory.setEnableAdministrationOnly(true);
DistributedSystemConfig config =                                     
    AdminDistributedSystemFactory.defineDistributedSystem();
config.setMcastAddress("224.0.0.250");
config.setMcastPort(10333);
AdminDistributedSystem admin = AdminDistributedSystemFactory.getDistributedSystem(config);
admin.connect();
// Wait for the connection to be made
long timeout = 30 * 1000;
try {
    if (!admin.waitToBeConnected(timeout)) {
        String s = "Could not connect after " + timeout + "ms";
        throw new Exception(s);
    }
} 
catch (InterruptedException ex) {
    String s = "Interrupted while waiting to be connected";
    throw new Exception(s, ex);
}

The following example creates an AdminDistributedSystem colocated on a DistributedSystem connection, which allows the Admin API and Caching API to be used in the same member.

Creating a Distributed System Administration Interface (colocated with DistributedSystem connection)

Properties props = new Properties();
props.setProperty("mcast-address", "224.0.0.250");
props.setProperty("mcast-port", "10333");
// Before connecting to either AdminDistributedSystem or DistributedSystem, 
// call setEnableAdministrationOnly.
AdminDistributedSystemFactory.setEnableAdministrationOnly(false);
DistributedSystem connection = DistributedSystem.connect(props);
DistributedSystemConfig config = AdminDistributedSystemFactory.defineDistributedSystem(connection, null);
AdminDistributedSystem admin = AdminDistributedSystemFactory.getDistributedSystem(config);
admin.connect();
// Wait for the connection to be made
long timeout = 30 * 1000;
try {
    if (!admin.waitToBeConnected(timeout)) {
        String s = "Could not connect after " + timeout + "ms";
        throw new Exception(s);
    }
} 
catch (InterruptedException ex) {
    String s = "Interrupted while waiting to be connected";
    throw new Exception(s, ex);

You can use the AdminDistributedSystem admin object to start and stop all managed members of the distributed system:

Starting a Distributed System

this.system.start();

Stopping a Distributed System

this.system.start();

Stopping a Distributed System

this.system.stop();

Limitations for Using a Co-located Admin API

While using the Admin API, the following limitations must be noted:
  • The AlertListener listens only for remote alerts.
  • The Admin API can manage only remote members.
  • The connection does not display as an Admin connection.

Accessing Distributed System Processes

Once instantiated, the AdminDistributedSystem can be used to access the various distributed system entities. The following code iterates through the list of all member applications in the system and identifies a match by name. The interface also provides a list of locators, through getDistributionLocators and a list of cache servers, through getCacheVms.

Locating a System Member by Name
SystemMember findMember(String name) throws AdminException {
    if (name == null) {
        return null;
    }
    SystemMember[] apps = this.system.getSystemMemberApplications();
    for (int i = 0; i < apps.length; i++) {
        if (name.equals(apps[i].getName())) {
            return apps[i];
        }
    }
    return null;
}

Starting and Stopping Managed Entities

Locators and cache servers are started and stopped when the distributed system is started and stopped. They can also be started and stopped individually. The DistributionLocator and CacheVm interfaces extend ManagedEntity, which provides start and stop methods. This example stops the selected cache server.

Stopping a cacheserver
CacheVm csvr = (CacheVm) this.entity.getObject();
csvr.stop();

Accessing System Member Information

Applications and cache servers are system members. In the admin API, applications are represented by SystemMember objects, and the CacheVm interface extends the SystemMember interface. Through the SystemMember interface you can access configuration parameters, license information and the member’s AdminDistributedSystem object. This code lists basic SystemMember information:

Listing System Member Details
void listSystemMember() {
    SystemMember member = (SystemMember) this.entity.getObject();
    System.out.println("System Member Application Details:");
    System.out.println("\t" + "id: " + member.getId());
    System.out.println("\t" + "host: " + member.getHost());

    ConfigurationParameter[] configs = member.getConfiguration();
    System.out.println("Configuration Parameters:");
    for (int i = 0; i < configs.length; i++) {
        System.out.println("\t" 
            + configs[i].getName() + "=" + configs[i].getValueAsString());
    }

    try {
        StatisticResource[] stats = member.getStats();
        System.out.println("Statistic Resources:");
        for (int i = 0; i < stats.length; i++) {
            System.out.println("\t" + stats[i].getName());
        }
    } catch (AdminException e) {
        e.printStackTrace();
    }
}

Cache Management

The SystemMember interface also provides the SystemMemberCache object, which allows you to manage cache attributes, cache statistics, and cache regions. This example retrieves the SystemMemberCache object from a SystemMember.

Retrieving a Member's Cache

SystemMember member = (SystemMember) this.entity.getObject();
SystemMemberCache cache = member.getCache();

This example lists the cache contents after updating its information with the refresh method.

Listing Cache Contents

void listSystemMemberCache() {
    SystemMemberCache cache = (SystemMemberCache) this.entity.getObject();
    cache.refresh();
    
    System.out.println("System Member Cache Details:");
    System.out.println("\t" + "id: " + cache.getId());
    System.out.println("\t" + "name: " + cache.getName());
    System.out.println("\t" + "isClosed: " + cache.isClosed());
    System.out.println("\t" + "lockTimeout: " + cache.getLockTimeout());
    System.out.println("\t" + "lockLease: " + cache.getLockLease());
    System.out.println("\t" + "searchTimeout: " + cache.getSearchTimeout());
    System.out.println("\t" + "upTime: " + cache.getUpTime());

    System.out.println("Region Names:");
    Set regionNames = cache.getRegionNames();
    for (Iterator it = regionNames.iterator(); it.hasNext();) {
        System.out.println("\t" + it.next());
    }

    System.out.println("Cache Statistics:");
    Statistic[] stats = cache.getStatistics();
    for (int i = 0; i < stats.length; i++) {
        System.out.println("\t" + 
                stats[i].getName() + "=" + stats[i].getValue());
    }
}

In addition to the information it gives you, the SystemMemberCache allows you to configure what the cache does, including starting CacheVms in remote caches. For complete details on available functionality, see the online Java API documentation. The next section shows region management in the cache.

Region Management

The SystemMemberCache interface allows you to create regions in the cache. While a cache is usually managed by its own member, this capability is particularly useful for dynamically creating regions in a cacheserver. You can create a region in a cacheserver that outlives any of the applications that create or use it. For more information, see "Replication and Local Destroy and Invalidate Operations." If you need to create regions across many members, you might be better served by the dynamic region functionality, described in "Dynamic Region Management."

This example shows region creation using the SystemMemberCache.

Creating a Region

void createRegion(String command) throws AdminException {
    String name = parseName(command);
    if (name.length() == 0) {
        System.out.println("Please provide a name for the region");
    }
    else {
        if (this.entity.getContext().isSystemMemberCache()) {
            SystemMemberCache cache = 
                (SystemMemberCache) this.entity.getObject();
            AttributesFactory fac = new AttributesFactory();
            SystemMemberRegion rgn = 
                cache.createRegion(name, fac.create());
        }
        else {
            System.out.println("Please choose a cache context before creating a region.");
        }
    }
}

This region creation method returns a SystemMemberRegion, similar to how the Cache and Region interfaces operate in the com.gemstone.gemfire.cache package.

As with the other administrative entities, Region contents are available through the API. This example lists a region’s attributes and number of entries.

Retrieving Region Contents

void listSystemMemberRegion() {
    SystemMemberRegion region = (SystemMemberRegion) this.entity.getObject();
    region.refresh();
    
    System.out.println("System Member Region Details:");
    System.out.println("\t" + "name: " + region.getName());
    System.out.println("\t" + "entryCount: " + region.getEntryCount());

    System.out.println("Region Attributes:");
    System.out.println("\t" + "UserAttribute: " + region.getUserAttribute());
    System.out.println("\t" + "CacheLoader: " + region.getCacheLoader());
    System.out.println("\t" + "CacheWriter: " + region.getCacheWriter());
        . . . 
    System.out.println("\t" + "DataPolicy: " + region.getDataPolicy());
        
    System.out.println("Region Statistics:");
    System.out.println("\t" + "LastModifiedTime: " 
        + region.getLastModifiedTime());
    System.out.println("\t" + "LastAccessedTime: " 
        + region.getLastAccessedTime());
    System.out.println("\t" + "HitCount: " + region.getHitCount());
    System.out.println("\t" + "MissCount: " + region.getMissCount());
    System.out.println("\t" + "HitRatio: " + region.getHitRatio());
}

Health Monitoring

This example registers and configures health MBeans for the distributed system, then invokes a setupHealthForAllHosts method to create health monitoring instances for all machines running distributed system components.

Configuring Health Objects

private void setupHealthMonitors() throws Exception {
// register the GemFireHealth MBean for the system...
    this.healthName = (ObjectName) this.mbs.invoke(this.systemName, 
                "monitorGemFireHealth",new Object[0], new String[0]);

    String systemId = (String) this.mbs.getAttribute(this.systemName, "id");

// get the names of the default health config MBeans 
    this.systemHealthConfigName = 
        new ObjectName("GemFire:type=DistributedSystemHealthConfig,id=" 
                + systemId);
    this.defaultHealthConfigName = new ObjectName
        ("GemFire:type=GemFireHealthConfig,id=" + systemId + ",host=default");
    . . . 
    Integer seconds = (Integer)
        this.mbs.getAttribute(this.defaultHealthConfigName,
                "healthEvaluationInterval");

// Configure StringMonitor for the health attribute on GemFireHealth MBean
    this.healthMonitorName = 
        new ObjectName("monitors:type=String,attr=health,system=" + systemId);
    this.mbs.createMBean("javax.management.monitor.StringMonitor",                                                  
                this.healthMonitorName);

    AttributeList al = new AttributeList();
    al.add(new Attribute("ObservedObject", this.healthName));
    al.add(new Attribute("ObservedAttribute", "healthStatus"));
    al.add(new Attribute("GranularityPeriod", 
                new Integer(seconds.intValue() * 1000))); // in millis
    al.add(new Attribute("StringToCompare", 
                GemFireHealth.GOOD_HEALTH.toString()));
    al.add(new Attribute("NotifyMatch", new Boolean(true)));
    al.add(new Attribute("NotifyDiffer", new Boolean(true)));
    this.mbs.setAttributes(this.healthMonitorName, al);
    
    this.mbs.addNotificationListener(this.healthMonitorName, 
                this, null, this.mbs);
    this.mbs.invoke(this.healthMonitorName, "start", 
                new Object[0], new String[0]);
    . . . 

// next register health config MBeans for each host in the system...
    setupHealthForAllHosts();
}

The setupHealthForAllHosts method runs through all system members, calling another method, checkHostFor, that checks to see if the member’s host has a health configuration registered. This is how the setupHealthForAllHosts method works:

Iterate System Members, Registering Health Configuration for the Member’s Machines
private void setupHealthForAllHosts() throws Exception {
// make sure health config MBeans are registered for application hosts...
    ObjectName[] memberNames = (ObjectName[])
        this.mbs.invoke(this.systemName, "manageSystemMemberApplications",
        new Object[0], new String[0]);
    for (int i = 0; i < memberNames.length; i++) {
        checkHostFor(memberNames[i]);
    }
}

This is the checkHostFor method:

Register Health Configuration for Each Member’s Machine
private void checkHostFor(ObjectName memberName) throws Exception {
    if (memberName == null) return;
    synchronized(this.healthConfigHostMap) {

// get the member's host...
        String host = (String) this.mbs.getAttribute(memberName, "host");

// is there a config MBean registered for the host yet?
        ObjectName gemfireHealthConfigName =
            (ObjectName) this.healthConfigHostMap.get(host);

        if (gemfireHealthConfigName == null 
                || !this.mbs.isRegistered(memberName)) {
// if not registered, create a new config MBean for the host...
            gemfireHealthConfigName = 
                    (ObjectName)this.mbs.invoke(this.healthName, 
                            "manageGemFireHealthConfig",
                            new Object[] { host },
                            new String[] { "java.lang.String" });
            this.healthConfigHostMap.put(host, gemfireHealthConfigName);
        }
    }
}

Once the health configuration is registered, when changes happen in the system the listener is notified and can handle the events. In this example case, if a new member has joined, the method calls checkHostFor to make sure the member’s host has a health configuration registered. In all events, the method prints a message to standard output.

Event Handler for Health-Related Notifications

public void handleNotification(Notification notification, Object handback) {
    String type = notification.getType();
    System.out.println("handleNotification: " + type);
    if ("gemfire.distributedsystem.member.joined".equals(type)) {
        String memberId = notification.getMessage();
        System.out.println("MEMBER JOINED: " + memberId);
// Make sure the new member’s machine has a registered health configuration
        try {
            checkHostFor(findSystemMember(memberId));
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
    else if ("gemfire.distributedsystem.member.left".equals(type)) {
        String memberId = notification.getMessage();
        System.out.println("MEMBER LEFT: " + memberId);
    }
    else if ("gemfire.distributedsystem.member.crashed".equals(type)) {
        String memberId = notification.getMessage();
        System.out.println("MEMBER CRASHED: " + memberId);
    }
    else if ("gemfire.distributedsystem.alert".equals(type)) {
        String alert = notification.getMessage();
        System.out.println("ALERT: " + alert);
    }
    else if (MonitorNotification.STRING_TO_COMPARE_VALUE_DIFFERED.equals(type)) {
        String health = notification.getMessage();
        System.out.println("HEALTH UPDATED: " + health);
    }
}