ADVANCED USES FOR THE NAMING SERVICE

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

In the previous example, we looked at the two most basic uses for the Naming Service:

binding and resolution. Although these two functions are often the most used, they are by no means the only functions published by the Naming Service. In the next example, we build a distributed wine cellar management application. The server component stores a collection of wines, and the client application can browse the server’s wines as well as add to the collection. Once the client finds a wine in the server’s collection that it owns, that wine can be added to a client-side collection.

Starting with the server component, Listing 30.4 contains the IDL for the server, and Listing 30.5 contains the implementation of the WineServer class. The WineServer class simply exposes one method, addWine(), that accepts a wine to be categorized and the collection of categories used to classify the wine.

LISTING 30.4 THE IDL FOR THE WINE SERVER

interface WineI {

attribute string sVineyardName;

attribute string sType;

attribute string sAdditionalNotes;

attribute long vintage;

attribute long points;

attribute string sPointSource;

};

typedef sequence<string> stringSequence;

interface WineServerI {

void addWine(in stringSequence categories, in WineI wine);

};

LISTING 30.5 THE WineServer CLASS

import org.omg.CORBA.*;

import org.omg.CosNaming.*;

import com.visigenic.vbroker.services.CosNaming.*;

/**

* The WineServer class uses the CORBA Naming Service

* to maintain a collection of wines as categorized

* by the user.

*/

public class WineServer extends _WineServerIImplBase { private NamingContext _root;

private static ORB _orb;

private static BOA _boa;

public WineServer() { super("Wine Server");

// obtain the root context

_root = NamingContextHelper.bind(_orb, "NameService/1");

} /**

* The addWine() method is invoked by the client * when he wishes to add a new wine to the collection * maintained by the Naming Service.

*

* @param categories Collection of categories used to * classify the wine

* @param winw The wine to be added */

public void addWine(String categories[], WineI wine) { NamingContext root = _root;

int iLength = categories.length;

iLength";

NameComponent[] componentHolder == new NameComponent[1];

for(int i=0; i<iLength; i++) { componentHolder[0] == new NameComponent(categories[i], "");

// see if the context is already bound try{ root =

NamingContextHelper.narrow(

root.resolve(componentHolder)); } catch( Exception e ) {

// bind the new context try{ root =

root.bind_new_context(componentHolder); }

catch( Exception innerE ) {

System.out.println("inner: "+innerE);

}

} // catch } // for

// create a copy of the original WineI object

WineI newWine = new Wine();

newWine.sVineyardName(wine.sVineyardName());

newWine.sType(wine.sType());

newWine.sAdditionalNotes(wine.sAdditionalNotes());

newWine.vintage(wine.vintage());

newWine.points(wine.points());

newWine.sPointSource(wine.sPointSource());

// activate the new object _boa.obj_is_ready(newWine);

componentHolder[0] == new

NameComponent(categories[iLength], "");

// bind the object

try{ root.bind(componentHolder, newWine); }

catch( Exception e ) { System.out.println("e: "+e); } }

public static void main(String[] args)) { _orb = ORB.init();

_boa = _orb.BOA_init();

// create the WineServer application WineServer server = new WineServer();

// tell the BOA about the WineServer application _boa.obj_is_ready(server);

// notify the BOA that we are ready to wait for incoming

connections

_boa.impl_is_ready();

} }

Looking at the code in Listing 30.5, you’ll see some obvious parallels to the code in the initial example. However, in this situation, the object-binding process is expanded to be more robust. In the initial example, all binds were performed under the assumption that the NameComponent object being bound was not already in use. The bindObject() method simply iterated through the new NameComponent objects and called the bind_new_context() method to add them to the name graph. In this example, every call to bind_new_context() is preceded with an invocation of the resolve() method. If the resolve() method does not throw an exception, we know that the NameComponent object is already part of the name graph. If an exception is thrown, we know that the NameComponent object is not present in the name graph and can

proceed to add it. Due to the fact that we may be adding many unique wines that all have the same parent categories, this more robust version of the bindObject() method is very much needed.

Moving from the server to the client itself, we perform a two-step exploration of the code.

First, we look at the code that interacts with the Naming Service. Second, we explore the code that builds the User Interface (UI). After all code has been examined, we fire up the application and give the Naming Service a run for its money.

Listing 30.6 contains the code for the class WineClient. This class contains methods used to traverse the name graph, bind to the Naming Service, and ask the WineServer to add wines to the collection. Some additional code is used to launch the GUI. As you examine the class, pay specific attention to the code that interacts with the Naming Service (all GUI specific code will be covered later).

LISTING 30.6 THE WineClient CLASS INTERACTS WITH WineServer AND THE NAMING SERVICE

import java.awt.*;

import java.util.*;

import org.omg.CORBA.*;

import org.omg.CosNaming.*;

import com.visigenic.vbroker.services.CosNaming.*;

public class WineClient {

private BOA _boa;

private NamingContext _root;

private WineServerI _wineServer;

public WineClient() { ORB orb = ORB.init();

_boa = orb.BOA_init();

_root = NamingContextHelper.bind(orb, "NameService/1");

_wineServer = WineServerIHelper.bind(orb);

WineClientGUI gui = new WineClientGUI(this, _wineServer, _boa);

gui.setSize(350,350);

gui.setVisible(true);

}

public void addWine(String[] sCategories,, WineI wine) { _boa.obj_is_ready(wine);

_wineServer.addWine(sCategories, wine);

}

public List obtainNameGraph() throws Exception { return obtainNameGraph(_root, new List(), 0);

} /**

* Obtains a List object displaying a hierarchical

* view of all wines represented by the specified * name graph.

*

* @param root The name graph to traverse * @param lstWines The list being build

* @param iLevel Indicator of the current indent */

public List obtainNameGraph(NamingContext root, List lstWines,

int iLevel) throws Exception { // create the holder objects used for out parameters BindingIterator iterator = null;

BindingIteratorHolder iteratorHolder

= new BindingIteratorHolder(iterator);

BindingListHolder listHolder

= new BindingListHolder(new Binding[0]);

// obtain the first 100 bindings

root.list(100, listHolder, iteratorHolder);

// place the graph items into the string array;

Binding[] bindingList == listHolder.value;

int iLength = bindingList.length;

for(int i=0; i<iLength; i++) { Vector vecNext = new Vector();

NameComponent[] name == bindingList[i].binding_name;

int iNameLength = name.length;

for(int j=0; j<iNameLength; j++) {

StringBuffer sbCurrentItem = new StringBuffer();

for(int k=0; k<iLevel; k++) {

sbCurrentItem.append(" "); // 3 spaces per indent

}

sbCurrentItem.append(name[j].id);

lstWines.addItem(sbCurrentItem.toString());;

}

// recurse with new context

if(bindingList[i].binding_type ==

BindingType.ncontext) {

obtainNameGraph(NamingContextHelper.narrow (root.resolve(name)), lstWines, iLevel+1);

}

else { // references a WineI object

StringBuffer sbCurrentItem = new StringBuffer();

for(int k=0; k<iLevel+1; k++) {

sbCurrentItem.append(" "); // 3 spaces per indent

}

sbCurrentItem.append(WineIHelper.narrow(root.resolve(name)) .sVineyardName());

lstWines.addItem(sbCurrentItem.toString());

} }

return lstWines;

}

public static void main(String[] args)) { WineClient client = new WineClient();

} }

In the WineClient class, the most interesting code is executed during the

obtainNameGraph() method. In this method, the NamingContext.list() method is executed recursively, giving a picture of all NamingContext and WineI objects represented by the root node. In addition to traversing the name graph, the

obtainNameGraph() method places all found information in a hierarchically formatted List object.

Moving beyond the WineClient class, two additional classes help form the client application. The class WineClientGUI (contained in Listing 30.7) is the base GUI for the whole system. It displays the collection of available wines, the collection of owned wines, and prompts the user to add wines to the local collection or to the server

collection. When a user asks to add a wine to the server collection (contained in Listing 30.8), the WineInfo dialog is spawned. It collects the appropriate information and asks the server to add the wine to the collection. When a user asks that a server wine be added to the local collection, the doBuyWine() method in the WineClientGUI takes care of the transfer.

LISTING 30.7 THE WineClientGUI CLASS IS THE BASE GUI FOR THE ENTIRE CLIENT APPLICATION

import java.awt.*;

import java.awt.event.*;

import java.util.*;

import org.omg.CORBA.*;

import org.omg.CosNaming.*;

public class WineClientGUI extends Frame implements ActionListener {

private WineClient _wineClient;

private List _listWinesOwned;

private Vector _vecWinesOwned;

private List _listWinesAvailable;

private Button _btnBuySelected;

private Button _btnAddWine;

private WineServerI _wineServer;

private BOA _boa;

public WineClientGUI(WineClient wineClient,

WineServerI wineServer, BOA boa) { _wineClient = wineClient;

_wineServer = wineServer;

_boa = boa;

_listWinesOwned = new List();

_vecWinesOwned = new Vector();

buildScreen();

} /**

* Builds or rebuilds the screen

*/

public void buildScreen() { removeAll();

try{ _listWinesAvailable = _wineClient.obtainNameGraph(); } catch( Exception e) {}

Panel pnlWines = new Panel();

pnlWines.setLayout(new GridLayout(1,2,10,10));

pnlWines.add(new ListPanel("Wines Available",

_listWinesAvailable));

pnlWines.add(new ListPanel("Wines Owned", _listWinesOwned));

Panel pnlButtons = new Panel();

pnlButtons.setLayout(new GridLayout(1,2,10,10));

pnlButtons.add(_btnBuySelected =

new Button("Buy Selected Wine"));

pnlButtons.add(_btnAddWine = new Button("Add Wine To Server"));

_btnBuySelected.addActionListener(this);

_btnAddWine.addActionListener(this);

setLayout(new BorderLayout(10,10));

add(pnlWines, "Center");

add(pnlButtons, "North");

doLayout();

} /**

* Invoked when the human user clicks on a Button object

*/

public void actionPerformed(ActionEvent ae) { if(ae.getSource() == _btnAddWine) doAddWine();

else doBuyWine();

} /**

* Adds a wine to the collection represented

* by the name graph.

*/

private void doAddWine() {

WineInfo info = new WineInfo(this, _wineServer, _boa);

info.pack();

info.setVisible(true);

} /**

* Adds the selected wine to our personal * collection.

*/

private void doBuyWine() {

// add vineyard name to list

_listWinesOwned.addItem(_listWinesAvailable.getSelectedItem());

} /**

* Utility class used to facilitate GUI building */

class ListPanel extends Panel {

public ListPanel(String sLabel, List lst) { setLayout(new BorderLayout(10,10));

add(new Label(sLabel), "North");

add(lst, "Center");

} } }

LISTING 30.8 THE WineInfo DIALOG PROMPTS THE USER TO ADD A NEW WINE TO THE SERVER COLLECTION

import java.awt.*;

import java.awt.event.*;

import org.omg.CORBA.*;

/**

* Prompts the user to add a new wine, and adds it to the name graph

*/

public final class WineInfo extends Dialog implements ActionListener {

private Choice _chcVarietal;

private Choice _chcGrape;

private TextField _txtVineyardName;

private TextField _txtNotes;

private TextField _txtVintage;

private TextField _txtPoints;

private TextField _txtPointSource;

private Button _btnAdd;

private Button _btnCancel;

private WineServerI _wineServer;

private BOA _boa;

private WineClientGUI _gui;

public WineInfo(WineClientGUI gui, WineServerI wineServer, BOA boa) {

super(gui, "Add Wine", true);

_wineServer = wineServer;

_boa = boa;

_gui = gui;

_chcVarietal = new Choice();

_chcVarietal.addItem("Red");

_chcVarietal.addItem("White");

_chcVarietal.addItem("Blush");

_chcGrape = new Choice();

_chcGrape.addItem("Zinfandel");

_chcGrape.addItem("Cabernet Sauvignon");

_chcGrape.addItem("Chardonnay");

_chcGrape.addItem("Merlot");

_chcGrape.addItem("Pinot Noir");

_chcGrape.addItem("Shiraz");

setLayout(new GridLayout(8,2,10,10));

add(new Label("Varietal"));

add(_chcVarietal);

add(new Label("Grape"));

add(_chcGrape);

add(new Label("Vineyard name"));

add(_txtVineyardName = new TextField(20));

add(new Label("Notes"));

add(_txtNotes = new TextField(20));

add(new Label("Vintage"));

add(_txtVintage = new TextField(20));

add(new Label("Points"));

add(_txtPoints = new TextField(20));

add(new Label("Point Source"));

add(_txtPointSource = new TextField(20));

add(_btnCancel = new Button("Cancel"));

add(_btnAdd = new Button("Add"));

_btnCancel.addActionListener(this);

_btnAdd.addActionListener(this);

} /**

* Invoked when the user clicks on a Button */

public void actionPerformed(ActionEvent ae) { if(ae.getSource() == _btnAdd) doAdd();

setVisible(false);

} /**

* Adds a wine to the server */

private void doAdd() {

WineI wine = getDataAsWineObject();

_boa.obj_is_ready(wine);

String[] sCat == new String[2];

sCat[0] == wine.sType();

sCat[1] == _chcGrape.getSelectedItem();

_wineServer.addWine(sCat, wine);

_gui.buildScreen();

} /**

* Creates a WineI object using the data in * the UI widgets

*/

private WineI getDataAsWineObject() { WineI wine = new Wine();

wine.sVineyardName(_txtVineyardName.getText());

wine.sType(_chcVarietal.getSelectedItem());

wine.sAdditionalNotes(_txtNotes.getText());

try{

wine.vintage(Integer.parseInt(_txtVintage.getText())); } catch( NumberFormatException nfe ) {}

try{

wine.points(Integer.parseInt(_txtPoints.getText())); } catch( NumberFormatException nfe ) {}

wine.sPointSource(_txtPointSource.getText());

return wine;

} }

Once you’ve spent some time with the code in the previous listings, you should finalize your understanding by actually running the application. You should already have the Inprise ORB and Naming Service installed from running the first application. If not, do so now. After the ORB software is up and running, compile all IDL and Java code for the wine application and then launch the Naming Service by entering

java -DORBservices=CosNaming

com.visigenic.vbroker.services.CosNaming.ExtFactory NameService wine_log

Next, launch the server by entering java WineServer

and the client by entering java WineClient

When the application is up and running, you should see something similar what’s shown in Figure 30.3.

Figure 30.3: The wine application in action.

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

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

(693 trang)