• No results found

Compile the client

catch (Exception ex) {

System.out.println("*** Client error! ***");

ex.printStackTrace();

} } }

7. Compile the client.

From the directory above directory SimpleCORBAExample, execute the following command:

javac HelloClient.java 8. Run the application.

This requires three steps...

(i) Start the CORBA naming service.

This is achieved via the following command:

tnameserv Example output:

Figure 6.3 Starting the CORBA naming service under Java IDL.

The above command starts up the Java IDL Transient Nameservice as an object server that assumes a default port of 900. To use a different port (which would normally be necessary under Sun's Solaris operating system for ports below 1024), use the ORBInitialPort option to specify the port number. For example:

tnameserv -ORBInitialPort 1234 (ii) Start the server in a new command window.

For our example program, the command will be:

java HelloServer

(Since there is no screen output from the server, no screenshot is shown here.) Again, a port other than the default one can be specified. For example:

java HelloServer -ORBInitialPort 1234

(iii) Start the client in a third command window.

For our example program, the command will be:

java HelloClient

(As above, a non-default port can be specified.)

The expected output should appear in the client window, as shown in Figure 6.5.

Figure 6.4 Output from the HelloClient CORBA program.

The above example was deliberately chosen to be as simple as possible, since the central objective was to familiarise the reader with the basic required process, rather than to introduce the complexities of a realistic application. Now that this process

has been covered, we can apply it to a more realistic scenario. This will be done in the next section.

6.4 Using Factory Objects

In real-world applications, client programs often need to create CORBA objects, rather than simply using those that have already been set up. The only way in which this can be done is to go through a published factory object interface on the ORB.

For each type of object that needs to be created, a factory object interface must be defined in the IDL specification (on the ORB) and implemented on the server. The usual naming convention for such interfaces is to append the word Factory to the name of the object type that is to be created. For example, an object of interface Account would be created by an AccountFactory object. The AccountFactory object will contain a creation method that allows connecting clients to create Account objects. The name of this creation method may be anything that we wish, but it is convenient to prepend the word 'create' onto the type of the object to be created.

Thus, the AccountFactory's creation method could meaningfully be called createAccount. Assuming that an Account object requires only an account number and account name at creation time, the AccountFactory interface in the IDL specification would look something like this:

interface AccountFactory {

Account createAccount(in long acctNum,

in string acctName);

};

This method's implementation will make use of the new operator to create the Account object. Like our other interface implementations, this implementation must extend the appropriate idlj-generated 'ImplBase' class (which, in this case, is _AccountFactoryImplBase). Following the convention of appending the word 'Servant' to such implementations, we would name the implementation AccountFactoryServant. Thus, the implementation would have a form similar to that shown below.

class AccountFactoryServant

extends _AccountFactoryImplBase {

public Account createAccount(int acctNum, String acctName) {

return (new AccountServant(

acctNum, acctName));

} }

However, it would appear that we have merely moved the object creation problem on to the factory interface. Connecting clients cannot create factory objects, so how can they gain access to the creation methods within such objects? The simple answer is that the server will create a factory object for each factory interface and register that object with the ORB. Clients can then get a reference to the factory object and use the creation method of this object to create CORBA application objects.

Assuming that a client has obtained a reference to the AccountFactory object created by the server and that this reference is held in the variable acctFactoryRef, the client could create an Account object with account number 12345 and account name 'John Andrews' with the following code:

Account acct = acctFactoryRef.createAccount(

12345,"John Andrews");

For non-persistent objects, methods to destroy CORBA objects should also be defined (though we shall not be doing so).

To illustrate the use of factory interfaces and their associated factory objects, the rest of this section will be taken up by a specific example.

Example

We shall consider how Java IDL may be used to provide platform-independent access to stock items. Although only one item of stock will be used for illustration purposes, this could easily be extended to as many items of stock as might be required by a real-world application. The same basic steps will be required here as were used in the simple CORBA application of the last section, and the same numbering will be used here to indicate those steps.

1. Create the IDL file.

The file will be called StockItem.idl and will hold a module called Sales. This module will contain interfaces called StockItem and StockItemFactory. The former will hold the attributes and operations associated with an individual item of stock.

For simplicity's sake, the attributes will be stock code and current level, while the operations will be ones to increase and decrease the stock level of this particular stock item. Since the stock code should never be changed, it will be declared read-only. The StockItemFactory interface will hold method createStockItem, which will be used to create a StockItem object with specified stock code and stock level (as indicated by the parameters of this operation). The contents of StockItem.idl are shown below.

module Sales {

interface StockItem {

readonly attribute string code;

attribute long currentLevel;

long addStock(in long incNumber);

long removeStock(in long decNumber);

};

interface StockItemFactory {

StockItem createStockItem(in string newCode,

in long newLevel);

};

};

2. Compile the IDL file.

As in the previous example, client and server will be run on the same machine, so the -f flag will be followed by all. The command to execute the idlj compiler, then, is:

idlj –fall StockItem.idl

This causes a sub-directory with the same name as the module (i.e., Sales) to be created, holding the following twelve files (six each for the two interfaces):

StockItem.java

StockItemHelper.java

StockItemHolder.java

StockItemOperations.java

_StockItemImplBase.java

_StockItemStub.java

StockItemFactory.java

StockItemFactoryHelper.java

StockItemFactoryHolder.java

StockItemFactoryOperations.java

_ StockItemFactoryImplBase.java

_ StockItemFactoryStub.java