THE GENERIC PULL EVENT MODEL

Một phần của tài liệu sams java distributed objects (Trang 567 - 574)

As was stated in the earlier discussion of the push and pull event models, each presents pros and cons. Because the push event model involves network traffic only when an event needs to migrate to the client, there’s no bandwidth wasted on extraneous communication. Additionally, the push model does not depend on a client asking for events and therefore lends itself to timely event delivery. The one major downside to the push model is that the event channel must invoke methods on the client object itself. In many situations, the event channel and server will exist somewhere on the Internet, and the client will exist behind a firewall. Because most firewalls are configured to not allow incoming connections (including method invocations), the push model will fail here. As an alternative, the pull model exists such that events are stored at the supplier and delivered to the consumer only when asked for. The consumer still communicates with the supplier via the event channel; event requests are passed through the channel to the actual target.

In a fashion similar to our investigation of the generic push event model, we’ll first examine the IDL supplied by the Event Service and then develop a demonstration application. The application developed is a version of the earlier portfolio example;

however, the pull event model is employed. To conserve space, only the two classes that manage event sending and receiving are printed in the book; all GUI code is contained on the CD-ROM. Note that this GUI code differs little from the GUI code for the push example. In fact, the only difference is that the PortfolioGUI class instantiates a GenericPullListener object (to watch for stock value changes) instead of a GenericPushListener object.

Starting our exploration of the pull event model, Listing 31.7 contains the IDL interfaces

that the event channel exposes for use during pull-based event communication.

LISTING 31.7 SECTIONS OF THE CosEventComm AND CosEventChannelAdmin MODULES DEALING WITH THE GENERIC PULL EVENT MODEL

module CosEventComm {

exception Disconnected{};

interface PullSupplier {

any pull () raises(Disconnected);

any try_pull (out boolean has_event) raises(Disconnected);

void disconnect_pull_supplier();

};

interface PullConsumer {

void disconnect_pull_consumer();

};

};

module CosEventChannelAdmin { exception AlreadyConnected {};

exception TypeError {};

interface ProxyPullSupplier: CosEventComm::PullSupplier { void connect_pull_consumer(

in CosEventComm::PullConsumer pull_consumer) raises(AlreadyConnected);

};

interface ProxyPullConsumer: CosEventComm::PullConsumer { void connect_pull_supplier(in CosEventComm::PullSupplier

pull_supplier) raises(AlreadyConnected,TypeError);

};

interface ConsumerAdmin {

ProxyPushSupplier obtain_push_supplier();

ProxyPullSupplier obtain_pull_supplier();

};

interface SupplierAdmin {

ProxyPushConsumer obtain_push_consumer();

ProxyPullConsumer obtain_pull_consumer();

};

interface EventChannel {

ConsumerAdmin for_consumers();

SupplierAdmin for_suppliers();

void destroy();

};

};

In a fashion almost identical to the push event model, both the event supplier and consumer begin by binding to an object that implements the EventChannel interface.

After binding to the EventChannel object, event suppliers obtain a SupplierAdmin object by invoking the for_suppliers() operation, and event consumers obtain a ConsumerAdmin object by invoking the for_consumers() operation. Through the xxx""" objects, suppliers and consumers actually connect to the channel. Once connected to the channel, consumers query the channel for available events. The event channel then queries registered suppliers for available events.

Moving beyond the event channel, the CosEventComm module defines interfaces implemented by the event suppliers and consumers. The PullConsumer interface is implemented by consumers and simply defines the disconnect_pull_consumer() method, which is invoked when the consumer is disconnected from the event channel.

The PullSupplier interface is implemented by event suppliers, and it defines two important methods. Both the pull() and try_pull()methods are invoked by the event channel when a consumer requests an event from the channel. The try_pull() method is used when a consumer simply wants to query for potential available events.

This method is nonblocking, and a consumer is not guaranteed an event return value. To indicate the presence of an event, the try_pull() method accepts a boolean “out”

parameter, indicating whether a valid event is being returned. When the pull() method is invoked, the consumer will block until a valid event is returned.

Now that you have an understanding of how the generic pull event model functions, stop reading for a minute and convert the stock portfolio example over to use the pull event model. Because the earlier example is designed such that event communication is performed in two unique classes, the amount of code that needs to be changed is rather minimal. The one major difference, however, is that the supplier cannot simply post event after event, and the consumer cannot sit passively and wait for events to arrive. The consumer must enter into a unique thread of execution and poll the event channel for available events. The supplier, instead of sending out events in a unique thread, must enter a wait state and be prepared to post events when ready.

Once you’ve attempted to convert the solution yourself, take a look at the event supplier class in Listing 31.8 and the event consumer class in Listing 31.9. Compiling and running this new version of the solution is identical to the process used with the generic push version.

LISTING 31.8 SENDING EVENTS USING THE GENERIC PULL EVENT MODEL

import java.util.*;

import org.omg.CosEventComm.*;

import org.omg.CosEventChannelAdmin.*;

import org.omg.CORBA.*;

/**

* The GenericPullQuoteServer generates events

* containing price data on stock quotes.

*/

public final class GenericPullQuoteServer extends _PullSupplierImplBase {

private String[] _sSymbols = {"INKT", "MSFT",

"ORCL",

"CNWK","XCIT",

"PSFT",

"LU", "CPQ","WMT",

"DIS"};

private Random _random;

private org.omg.CORBA.ORB _orb;

private org.omg.CORBA.BOA _boa;

private ProxyPullConsumer _pullConsumer;

public GenericPullQuoteServer() { // bind to the orb

_orb = ORB.init();

// obtain a reference to the boa _boa = _orb.BOA_init();

_random = new Random();

// bind to the event channel

EventChannel channel = EventChannelHelper.bind(_orb);

// obtain a ProxyPullConsumer object.

_pullConsumer =

channel.for_suppliers().obtain_pull_consumer();

// connect as an event supplier

try{ _pullConsumer.connect_pull_supplier(this); } catch( AlreadyConnected ac ) {}

_boa.impl_is_ready();

} /**

* Invoked when we are disconnected from the

* event channel.

*/

public void disconnect_pull_supplier() { try{ _boa().deactivate_obj(this); } catch( SystemException e) { }

} /**

* Chooses (at random) one of the ten

* supported symbols.

*/

private String getRandomSymbol() {

return _sSymbols[Math.abs(_random.nextInt() % 10) -0];

} /**

* Generates a random value for a quote

* between 0 and 300

*/

private float getRandomPrice() {

return Math.abs(_random.nextInt() % 300) -0;

} /**

* Creates a new QuoteUpdateI object with

* random values

*/

private QuoteUpdateI obtainRandomQuoteUpdate() { QuoteUpdateI quote =

new QuoteUpdate(getRandomSymbol(), getRandomPrice());

_boa.obj_is_ready(quote);

return quote;

} /**

* Invoked by the event channel when an event is needed

* by the consumer

*/

public org.omg.CORBA.Any pull() throws Disconnected { if(_pullConsumer = null) throw new Disconnected();

// obtain an Any object from the ORB

org.omg.CORBA.Any eventObject = _orb.create_any();

// add a QuoteUpdateI object to the Any object

eventObject.insert_Object(obtainRandomQuoteUpdate());

// post the event return eventObject;

} /**

* Invoked by the event channel when an event may or may not

* be needed by the consumer. Since we provide a steady stream * of quote events, simply call pull()

*/

public org.omg.CORBA.Any try_pull(org.omg.CORBA.BooleanHolder

hasEvent)

throws org.omg.CORBA.SystemException, Disconnected {

hasEvent.value = true; // indicate the presence of an event

return pull();

}

public static void main(String[] args)) { GenericPullQuoteServer server = new GenericPullQuoteServer();

} }

LISTING 31.9 RECEIVING EVENTS USING THE GENERIC PULL EVENT MODEL

import java.util.*;

import org.omg.CosEventComm.*;

import org.omg.CosEventChannelAdmin.*;

/**

* The GenericPullListener class is notified via its

* pull() method whenever a new price is available

* for a given quote.

*/

public class GenericPullListener extends _PullConsumerImplBase implements Runnable {

private Hashtable _hshPortfolio;

private PortfolioGUI _portfolioGUI;

private ProxyPullSupplier _pullSupplier;

private Thread _thread;

public GenericPullListener(Hashtable hshPortfolio, PortfolioGUI portfolioGUI) { _hshPortfolio = hshPortfolio;

_portfolioGUI = portfolioGUI;

// bind to the orb

org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init();

// obtain a reference to the boa

org.omg.CORBA.BOA boa = orb.BOA_init();

// obtain a reference to the event channel

EventChannel channel = EventChannelHelper.bind(orb);;

// connect as a listener for pull events _pullSupplier =

channel.for_consumers().obtain_pull_supplier();;

try{ _pullSupplier.connect_pull_consumer(this); } catch( AlreadyConnected ac ) {}

_thread = new Thread(this);

_thread.start();

} /**

* Queries the event channel for available events

*/

public void pull() throws Disconnected { // query and extract the event data org.omg.CORBA.Object object =

_pullSupplier.pull().extract_Object();

// narrow (cast) the event data as a QuoteUpdateI object

QuoteUpdateI quoteUpdate = QuoteUpdateIHelper.narrow(object);

// check to see if the updated price represents // an active holding.

String sSymbol = quoteUpdate.sSymbol();

if(_hshPortfolio.containsKey(sSymbol)) { synchronized(_hshPortfolio) {

// update the stock value in the portfolio StockOwnership stock =

(StockOwnership)_hshPortfolio.get(sSymbol);

stock.setPrice(quoteUpdate.fNewPrice());

}

// repaint the portfolio screen _portfolioGUI.updatePortfolio();

} } /**

* The disconnect_pull_consumer() method is invoked

* by the event channel when we are disconnected

* from the event channel.

*/

public void disconnect_pull_consumer() { _pullSupplier.disconnect_pull_supplier();

}

/**

* Periodically poll for available events */

public void run() {

boolean bContinue = true;

while(bContinue) {

try{ _thread.sleep(1000); } catch( Exception e ) {}

try{ pull(); }

catch( Disconnected d) { bContinue = false;

disconnect_pull_consumer();

} } } }

FROM HERE

This chapter addressed the important topic of the CORBA Event Service. As you develop distributed applications, chances are you’ll need some mechanism for event-based communication, and the Event Service is a valid candidate for use. The advantage of going with the Event Service over a homebrewed version is twofold. First of all, you’re using a standard API, which means new developers entering a team are likely to have knowledge of its functionality. Second, because the event channel is already developed, you save significant development time. You don’t need to develop and test code that can handle potentially thousands of events being posted to the channel at the same time.

As you continue to explore all that CORBA has to offer, you’ll find that the following chapters complement this chapter’s coverage of the Event Service:

• Chapter 21, “CORBA Overview”

• Chapter 22, “CORBA Architecture”

• Chapter 23, “Survey of CORBA ORBs”

• Chapter 30, “The Naming Service”

Chapter 32: Interface Repository, Dynamic Invocation, Introspection, and Reflection

Overview

An object in both the CORBA universe and the Java universe serves a variety of purposes. At one level, it has the ability to interact in business processes, represent data, and generally model some real-world entity. In addition, an object also has the ability to enter into a dialogue in which it describes the features it exports. For example, an object in a patient management system can model patient data and also be asked if it supports methods that obtain demographic information. The ability to query an object at runtime is called either introspection or reflection and is supported both by Java objects and by CORBA objects. Developers producing CORBA solutions in Java are able to mix and match both techniques to achieve the best of both worlds.

This chapter takes a look at discovering information about objects using both the Java reflection model and the CORBA introspection model. Specifically, the following information is covered:

• How the Java reflection model describes objects

• How the CORBA introspection model describes objects

• How the interface repository aids the CORBA introspection model

• How to dynamically invoke methods on objects

The 1.02 release of the JDK introduced minimal reflection capabilities that Java objects could expose. Although useful to some extent, these capabilities were very rudimentary and were far from sophisticated. The 1.1 release of the JDK changed this by greatly enhancing the ability of an object to describe itself. In this initial section, we first look at the classes and interfaces that enable reflection and then build an application that dynamically invokes methods on a variety of objects. Following the coverage of the Java reflection model, we move on to coverage of the CORBA reflection (or introspection) model.

Một phần của tài liệu sams java distributed objects (Trang 567 - 574)

Tải bản đầy đủ (PDF)

(693 trang)