📄 ch04.htm
字号:
<TT>}</TT></FONT></PRE><P>The <TT>getStockValue()</TT> method takes a <TT>String</TT>, attempts to finda match in the <TT>myStockSymbols</TT> data member, and returns the value for thestock symbol (if found). If the stock symbol is not found, a zero value is returned.<BLOCKQUOTE> <P><HR><B>Note:</B>Naturally, the <TT>getStockValue()</TT> method is an excellent candidate to raise an exception--if an invalid stock symbol were passed to the method, it could raise (for example) an <TT>InvalidStockSymbolException</TT> rather than return zero, as it currently does. This is an exercise at the end of the chapter. <HR></BLOCKQUOTE><PRE><FONT COLOR="#0066FF"><TT>// Return a sequence of all StockSymbols known by this StockServer.</TT><TT>public String[] getStockSymbols() {</TT><TT> String[] symbols = new String[myStockSymbols.size()];</TT><TT> myStockSymbols.copyInto(symbols);</TT><TT> return symbols;</TT><TT>}</TT></FONT></PRE><P>The <TT>getStockSymbols()</TT> method simply creates an array of <TT>String</TT>s,copies the stock symbols (contained in <TT>myStockSymbols</TT>) into the array, andreturns the array.</P><PRE><FONT COLOR="#0066FF"><TT>// Create and initialize a StockServer object.</TT><TT>public static void main(String args[]) {</TT></FONT></PRE><P>The <TT>main()</TT> method in <TT>StockServerImpl</TT> creates a <TT>StockServerImpl</TT>object, binds that object to a naming context, and then waits for clients to callmethods on that object.</P><PRE><FONT COLOR="#0066FF"><TT>try {</TT></FONT></PRE><P>Because the methods that <TT>main()</TT> will later call might throw exceptions,those calls are wrapped in a <TT>try</TT> <TT>...</TT> <TT>catch</TT> block.</P><PRE><FONT COLOR="#0066FF"><TT>// Initialize the ORB.</TT><TT>ORB orb = ORB.init(args, null);</TT></FONT></PRE><P>Before doing anything with the ORB, the server application must first initializethe ORB.</P><PRE><FONT COLOR="#0066FF"><TT>// Create a StockServerImpl object and register it with the</TT><TT>// ORB.</TT><TT>StockServerImpl stockServer = new StockServerImpl();</TT><TT>orb.connect(stockServer);</TT></FONT></PRE><P>Here a new <TT>StockServerImpl</TT> object is created and registered with theORB.</P><PRE><FONT COLOR="#0066FF"><TT>// Get the root naming context.</TT><TT>org.omg.CORBA.Object obj = orb.</TT><TT> resolve_initial_references("NameService");</TT><TT>NamingContext namingContext = NamingContextHelper.narrow(obj);</TT></FONT></PRE><P>Now for a little black magic. The CORBA Naming Service is a service that allowsCORBA objects to register by name and subsequently be located, using that name, byother CORBA objects. As mentioned before, use of the Naming Service will be describedin detail on Day 12, but the sample client application in this chapter will stillneed to be able to locate a server; therefore the Naming Service is introduced here,though somewhat prematurely. Consequently, in this chapter, don't worry if you don'tunderstand all the details of the Naming Service or how it is used.</P><P>In order for clients to connect to the <TT>StockServerImpl</TT>, they must havesome way of locating the service on the network. One way to accomplish this is throughthe CORBA Naming Service. Here, a <TT>NamingContext</TT> object is located by resolvinga reference to an object named <TT>NameService</TT>.</P><PRE><FONT COLOR="#0066FF"><TT>// Bind the StockServer object reference in the naming</TT><TT>// context.</TT><TT>NameComponent nameComponent = new NameComponent(ourPathName,</TT><TT> "");</TT><TT>NameComponent path[] = { nameComponent };</TT><TT>namingContext.rebind(path, stockServer);</TT></FONT></PRE><P>Now the <TT>NamingContext</TT> object is asked to bind the <TT>StockServerImpl</TT>object to the pathname defined earlier (<TT>StockServer</TT>). Clients can now querythe Naming Service for an object by this name; the Naming Service will return a referenceto this <TT>StockServerImpl</TT> object.</P><PRE><FONT COLOR="#0066FF"><TT>// Wait for invocations from clients.</TT><TT>java.lang.Object waitOnMe = new java.lang.Object();</TT><TT>synchronized (waitOnMe) {</TT><TT> waitOnMe.wait();</TT><TT>}</TT></FONT></PRE><P>Because the <TT>StockServerImpl</TT> object is now registered with the NamingService, the only thing left to do is to wait for clients to invoke methods on theobject. Because the actual handling of these method invocations occurs in a separatethread, the <TT>main()</TT> thread simply needs to wait indefinitely.</P><PRE><FONT COLOR="#0066FF"><TT> } catch (Exception ex) {</TT><TT> System.err.println("Couldn't bind StockServer: " + ex.</TT><TT> getMessage());</TT><TT> }</TT><TT> }</TT><TT>}</TT></FONT></PRE><P>If any exceptions are thrown by any of the methods called, they are caught andhandled here.<H3><A NAME="Heading6"></A><FONT COLOR="#000077">Compiling and Running the Server</FONT></H3><P>Now you're ready to compile and run the server. Compiling the server applicationis simple. If you're using an integrated development environment, use that tool's"build" command (or equivalent) to build the application. If you're usingthe JDK from the command line, change directories to the directory where <TT>StockMarket.idl</TT>is located (there should also be a directory called <TT>StockMarket</TT> containedin this directory). Then issue the command</P><PRE><FONT COLOR="#0066FF"><TT>javac StockMarket\StockServerImpl.java</TT></FONT></PRE><P>(You might have to substitute the appropriate directory separator for your platformin the preceding command.) This will compile the server implementation and all thesource files it depends on.<BLOCKQUOTE> <P><HR><B>Tip: </B>Before compiling the server, make sure that your <TT>CLASSPATH</TT> contains the appropriate directory or file for the CORBA classes. For Sun's <TT>JavaIDL</TT> package, the file (directory where <TT>JavaIDL</TT> is installed) <TT>/lib/classes.zip</TT> will appear in the <TT>CLASSPATH</TT>. Consult your CORBA product's documentation to determine your <TT>CLASSPATH</TT> setting. <HR></BLOCKQUOTE><P>Assuming that the server application compiled correctly, you're about ready torun the server. Before you do that, though, you need to run the Name Server. (Recallthat the client application uses the CORBA Naming Service to locate the server application;the Name Server provides the mechanism that makes this possible.)</P><P>The exact method for running the Name Server varies from product to product, butthe end result is the same. For Sun's <TT>JavaIDL</TT>, simply running <TT>nameserv</TT>will bring up the Name Server.</P><P>When the Name Server is running, you're ready to run the server. You can invokethe server with the command</P><PRE><FONT COLOR="#0066FF"><TT>java StockMarket.StockServerImpl</TT></FONT></PRE><P>For the sake of simplicity, you'll want to run the Name Server and your serverapplication on the same machine for now. If everything works correctly, you willsee output similar to Listing 4.4. The stock symbols and their values will, of course,vary, but you will see output resembling Listing 4.4 without any exception messagesfollowing the output.<H4><FONT COLOR="#000077">Listing 4.4. Sample StockServer output.</FONT></H4><PRE><FONT COLOR="#0066FF"><TT> 1: Generated stock symbols:</TT><TT> 2: PTLF 72.00064</TT><TT> 3: SWPK 37.671585</TT><TT> 4: CHHL 78.37782</TT><TT> 5: JTUX 75.715645</TT><TT> 6: HUPB 41.85024</TT><TT> 7: OHQR 14.932466</TT><TT> 8: YOEX 64.3376</TT><TT> 9: UIBP 75.80115</TT><TT>10: SIPR 91.1368311: XSTD 16.010124</TT> </FONT></PRE><P><BR>If you got this far, congratulations! You have successfully designed, implemented,and deployed a CORBA server application. After reveling in your success, feel freeto terminate the application because you won't have a client to connect to it untilthe end of this chapter. Alternatively, you can leave the server running to saveyourself the trouble of restarting it later (or just to impress and amaze your friends).<H2><A NAME="Heading7"></A><FONT COLOR="#000077">Building a CORBA Client</FONT></H2><P>In the first half of this chapter, you were left hanging with a server that couldn'tdo much because there were no clients to connect to it. Now you'll remedy that unfortunatesituation by implementing a client that will utilize the services provided by theserver you built. Because you've already written and compiled the IDL interfaces(and implemented them, for that matter), implementing the client will be a much simplerprocess. Additionally, clients are often (though not always) simpler than serversby nature, so they are easier to implement in that regard as well.<H3><A NAME="Heading8"></A><FONT COLOR="#000077">Implementing the Client</FONT></H3><P>As mentioned already, implementing the client is a straightforward process. Thereare only a handful of concepts involved: how to use client stubs in the client implementation,how to locate a server object, and how to use the interfaces of a server object afterit has been located.<H4><FONT COLOR="#000077">Using Client Stubs</FONT></H4><P>When you compiled <TT>StockServer.idl</TT>, the IDL compiler generated clientstubs as well as server skeletons. Because client stubs aren't used for server implementations,you ignored the stubs for the time being. Now, it's time to use them. If you're curious,open the <TT>_StockServerStub.java</TT> file and have a look at it. You'll see afair amount of cryptic code along with two familiar methods:</P><PRE><FONT COLOR="#0066FF"><TT>public float getStockValue(String symbol) {</TT><TT> ...</TT><TT>}</TT><TT>public String[] getStockSymbols() {</TT><TT> ...</TT><TT>}</TT></FONT></PRE><P>The implementations for these methods, as discussed before, marshal the parametersthrough the ORB to the remote object and then marshal the return value back to theclient. (This is what all that cryptic-looking code is doing.)</P><P>You really needn't concern yourself with the contents of <TT>_StockServerStub.java</TT>;all you need to know is that this file contains the client stub for the <TT>StockServer</TT>interface. The Java compiler is smart enough to compile this file automatically,but if you were implementing a client in C++, you'd have to be sure to link the clientstub object with the rest of the client application.</P><P>The other thing to know about the client stub is that it specifies the actualinterfaces for the server object. In other words, you can see in the preceding examplethat the <TT>getStockValue()</TT> method takes a Java <TT>String</TT> as a parameterand returns a Java <TT>float</TT>. Similarly, <TT>getStockSymbols()</TT> takes noparameters and returns a Java array of <TT>String</TT>s.<H4><FONT COLOR="#000077">Locating a Server Object</FONT></H4><P>Just as a server application is practically useless if it cannot make its locationknown, a client application cannot do useful work if it cannot locate services touse. This is where the CORBA Naming Service steps in again. After a server registersitself with the Name Server, clients can locate that server object through the NameServer, bind to that server object, and subsequently call methods on the server object.Again, do not be concerned if there are details of the Naming Service which escapeyou, as it will be discussed in greater detail on Day 12.</P><P>In the <TT>StockMarketClient</TT>, binding to the server object takes place inthe <TT>connect()</TT> method, as shown in Listing 4.5. This method first binds tothe Name Server by looking for an object with the name <TT>NameService</TT>. Uponsuccessfully locating a Name Server, the client proceeds to bind to an object withthe name <TT>StockServer</TT>, which incidentally is the same name you registeredthe <TT>StockServerImpl</TT> under (actually, the names must be the same if the exampleis to work successfully). After this object is bound, the client is ready to do somework.<H4><FONT COLOR="#000077">Listing 4.5. Binding to the StockServer server.</FONT></H4><PRE><FONT COLOR="#0066FF"><TT> 1: // Connect to the StockServer.</TT><TT> 2: protected void connect() {</TT><TT> 3: </TT><TT> 4: try {</TT><TT> 5: </TT><TT> 6: // Get the root naming context.</TT><TT> 7: org.omg.CORBA.Object obj = ourORB.</TT><TT> 8: resolve_initial_references("NameService");</TT><TT> 9: NamingContext namingContext = NamingContextHelper.narrow(obj);</TT><TT>10: </TT><TT>11: // Attempt to locate a StockServer object in the naming context.</TT><TT>12: NameComponent nameComponent = new NameComponent("StockServer",</TT><TT>13: "");</TT><TT>14: NameComponent path[] = { nameComponent };</TT><TT>15: myStockServer = StockServerHelper.narrow(namingContext.</TT><TT>16: resolve(path));</TT><TT>17: } catch (Exception ex) {</TT><TT>18: System.err.println("Couldn't resolve StockServer: " + ex);</TT><TT>19: myStockServer = null;</TT><TT>20: return;</TT><TT>21: }</TT><TT>22: </TT><TT>23: System.out.println("Succesfully bound to a StockServer.");24: }</TT></FONT></PRE><H4><FONT COLOR="#000077">Using Server Object Interfaces</FONT></H4><P>Listing 4.6 shows an example of how the server object interfaces are used, afterthe client has bound the server object. As you might expect, the client simply callsthe server methods as it sees fit. Again, you can refer to the client stub (<TT>_StockServerStub.java</TT>)or better yet, to the <TT>StockServer</TT> interface in <TT>StockServer.idl</TT>to see the method signatures for the <TT>StockServer</TT>. The usage of these methodsis clear-cut, as illustrated in Listing 4.6.<H4><FONT COLOR="#000077">Listing 4.6. Using the StockServer services.</FONT></H4><PRE><FONT COLOR="#0066FF"><TT> 1: // Do some cool things with the StockServer.</TT><TT> 2: protected void doSomething() {</TT><TT> 3: </TT>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -