|
SYS-CON.TV Webcasts
Comments
Did you read today's front page stories & breaking news?
SYS-CON.TV
|
Top Links You Must Click On
General Java Corba Project Browser
Corba Project Browser
Jun. 1, 1999 12:00 AM
With the rapid growth of the Internet, distributed Web-enabled applications are becoming popular. One of the most commonly used architectures for development of such applications is CORBA, which provides a platform, location and an implementation-language-neutral architecture for the development of distributed applications. In addition, the phenomenal interest in component technology has led to the development of CORBA Beans. Such CORBA components and objects will soon be available for use on the Web. When you encounter such a CORBA object, you may wish to use its services by dynamically discovering its properties (something similar to Introspect and Reflection in Java). CORBA supports this.
What Is Dynamic Invocation? The use of IR and DII not only benefits the client in discovering and using the object, but also helps its publisher add new features to the object anytime after its deployment. The client can then dynamically discover these new features and use them. The new interface definition is published in the IR by the developer. The client now has access to all the latest features provided by the application using the DII mechanism. DII is the "dream come true" for developers since it allows them to modify previously published CORBA objects without the need to recompile and redistribute client-side stubs. A practical example: you're developing a CORBA application for setting up an online store where customers visit, make some purchases and pay for purchases with a check "snail-mailed" to your account. You'll supply a client-side application that interfaces with your server application. The client application contains the compiled stubs required to use your server application. At a later time you may wish to provide the facility of payment by credit card. Adding a new purchase method in the IDL definition does this job. However, you'll need to supply the new stubs to all your clients. If you'd used the DII mechanism in the client application, the client would be able to discover the newly added method without the necessity of obtaining the new stub.
Object Browser To help understand the complex DII interface of CORBA, we'll discuss the design of the CORBA object browser. But first we'll touch on some aspects of locating the object on the Web using the Naming and URL Naming Services of Visigenic, the IOR (Interoperable Object Reference) and Interface Repository.
Locating Object: CORBA Naming Service and Web Naming Service Our object browser needs to locate the object before trying to use its services. A CORBA object publishes a reference to itself by registering its name with the Naming Service. This is done with the help of the bind or rebind method, in which the object reference is tied to its symbolic name. Before you use this method you must start the Naming Service. On Visigenic ORB (we use this for our development) you start the Naming Service using the following command line, with the root name specified as ABCOM:
vbj -DORBservices=CosNaming -DSVCnameroot=ABCOM DJDKrenameBug
tnameserv [-ORBInitialPort The principal task of the Naming Service is to keep track of the namespace, which is the collection of object names bound to a Naming Service. The namespace may contain a hierarchy of bindings extending over several domains just like a file system on your disk. If the namespace extends over several domains, it's called the Federated NameSpace. The binding is the logical association of the object reference to its symbolic name. A client obtains a reference to the Naming Service by calling the resolve_initial_references() method of the ORB. Once the initial context of the Naming Service is resolved, it calls the resolve method on the NamingContext to obtain a reference to the desired object. The whole task of name resolution is transparent to the client. Another way to publish your object is to convert the object reference to a string and store it in a file using ORB's object_to_string method. The method returns a stringified version of the IOR, which contains information such as IIOP version, Host, Port, etc., which helps to uniquely identify the object on the Web. The client reads the IOR from the specified file (usually with the extension .ior) at the given URL, and obtains a reference to the object using the information in the IOR. Visigenic requires that the extension given to the IOR file must be .ior if you wish to use Visigenic GateKeeper. Visigenic provides the URL Naming Service to locate an object using a URL rather than its generic name. This provides for interoperability among objects bound to ORBs on different machines. The following code segment shows you how to use Visigenic's URL Naming Service to locate an object running on a different ORB:
// create the resolver object
// locate object using resolver The URL Naming Service uses a Resolver Object to locate the .ior file and resolve the reference to the remote object. In the above code snippet we create a Resolver Object using the ResolverHelper provided with the URL Naming Service. The Resolver uses the locate method to search the specified IOR at a given URL. If the IOR file is found, it's read and the reference to the object running on the remote server is returned to the caller. The publisher must publish the IOR file on a Web server so the client can locate it using the URL Naming Service. If you're using Microsoft's IIS (Internet Information Server), you'll put this file in the InetPub/www.root folder or the folder defined for public access.
Interface Repository Prompt> irep IRname fileName The IRname is the name assigned to the Interface Repository, and fileName is the physical file used for storage. Once the IR is created, you can add your object definitions using the idl2ir utility: Prompt> idl2ir file.idl The IDL definition contained in file.idl is now added to the IR. Each entry in the IR contains a header describing the file name, time of creation, user name and location of the file on the machine. The IR stores information in simple text format. You can use a standard text editor to view this. A typical IR entry is shown below.
/* The following code snippet illustrates this process:
org.omg.CORBA.InterfaceDef objIntfce = obj._get_interface(); You may now use the attributes member of the FullInterfaceDescription class to obtain information on the various attributes published by the object. Similarly, you'll use the operations member of the FullInterfaceDescription class to obtain information on the various operations permitted on the object.
To recapitulate, so far you've learned how to: We've also seen how a client program retrieves this Interface Definition from the IR and discovers all the attributes and operations published by the object. Most important, you've discovered the object and would now like to use its services by invoking one or more of its published methods.
Dynamic Invocation Interface To invoke a method, you'll first need to construct a list of arguments (parameters) required by the method. CORBA provides an NVList object for constructing such a list. You use the create_list() method of ORB to construct it. NVList parameterList = orb.create_list(0); The NVList (Named Value List) contains the names and values for the various parameters required by the method. Initially the list is created with zero elements. You then add elements by using its add_value() method: parameterList.add_value(name, currentParameter, mode); where name is the string representing the name of the parameter being added, currentParameter is the object that represents the parameter and mode indicates whether the parameter is of IN, OUT or INOUT type. You'll need to add the required number of elements to the NVList depending on the number of parameters used by the desired method. Once an NVList is constructed, you create a request object and pass the parameters to it using the constructed NVList object. To create a request object, you use the _create_request() method of the CORBA Object class.
org.omg.CORBA.Object obj = new org.omg.CORBA.Object();
Once the request object is constructed, you can invoke the method on the server using the invoke() method: request.invoke(); This invokes the method on the server object and returns the result, if any, in the resultField NamedValue object. If the method uses OUT and INOUT types of parameters, you may examine their contents for the return values.
User Interface The user enters the name of the server object in the input panel of the browser and clicks on the introspect button. The name specified must be the name the object is registered under with the Naming Service. Alternatively, the user can specify the name of the IOR file along with the URL at which the file is located. A typical URL string may be specified as follows: http://www.abcom.com/abcom.ior Once an object is located, the browser displays its IDL in the tabbed pane as seen in Figure 1. You can now click on the "Operation and Attribute Listing" tab to see the various operations and attributes published by the server. If you want to examine an attribute, click on the desired one and its various properties will be displayed in a pop-up window. If you decide to invoke a method, click on the method name, which opens a window showing the various parameters required by the method (see Figure 1). If the method doesn't require parameters, it's directly executed. If it does, the type and mode are displayed for each one. Next to each parameter an edit box is provided in which the user can enter the desired parameter value. The browser, however, doesn't provide any validation on the parameter values. Once all the required parameter values are entered, the user clicks on the invoke button to invoke the server method. The program now builds the request object and invokes the method on the server. If the method completes successfully, the results will be displayed in a pop-up window (see Figure 1). The interface is fairly easy to use. We'll now look into the design of the browser.
Browser Design The ObjectBrowser class (see Listing 1) is the main class of the application and is derived from the JFrame class. It creates instances of InputPanel, OutputPanel, StatusBar and BackEnd classes. The main method creates an instance of ObjectBrowser class and displays the frame to the user. The init() method of the class adds the three user-interface elements InputPanel, OutputPanel and StatusBar to the main display window. The InputPanel is used for accepting the object reference from the user. The OutputPanel shows the IDL listing and the operations/attribute names to the user. The StatusBar provides a status display to the user. The ObjectBrowser class provides a utility method called resolveAndIntrospect(), which is called by the InputPanel class. The method receives the object reference that's to be resolved. The method calls the resolve() method of BackEnd class, and if the object is successfully resolved it calls the introspect() method of BackEnd class to introspect the object and to display the IDL to the user on the OutputPanel. The InputPanel class (see Listing 2) is derived from the JPanel and provides the user interface for accepting the object name. The user interface consists of an edit box and two buttons Introspect and Exit. The event handler for the Introspect button calls the resolveAndIntrospect() method on the ObjectBrowser class by passing the received object reference. As mentioned earlier, the object reference is either the object's registered name with the Naming Service or the complete URL containing the location of the IOR file. The OutputPanel class (see Listing 3), derived from JTabbedPane, contains two tab panes: one for displaying the IDL to the user, the other for displaying the lists of operations and attributes. The init() method sets up the two panes. The Interface Definition pane uses a TextArea control to display the IDL to the user. The Operation and Attribute pane creates two Box objects and adds JList control to each for displaying the operations and attributes. Whenever the user changes the selection in the attributes list control, the showAttribute-Description() method is called. This in turn creates an AttributeDescription object and displays the information about the selected attribute to the user. Similarly, whenever the user changes the selection in the operations list control, the showMethodDescription() method is called. This creates the OperationDescriptionTable object and displays it to the user. The updateList() method updates the contents of the list control by first clearing it and then filling it with the new data. The AttributeDescription class (see Listing 4) is derived from JFrame and displays the information on the selected attribute to the user. The class constructor receives the name of the attribute as a parameter and a reference to our ObjectBrowser class. The init() method calls its own getDescription() method to get the information on the desired attribute and then displays the information to the user by calling its displayFrame() method. The getDescription() method iterates through all the attributes defined in the fullObjectInterface variable and retrieves the mode and type information for the desired attribute. The displayFrame() method then displays the attribute name, mode and type to the user. The OperationDescriptionTable class (see Listing 5) derived from JFrame displays in tabular format the names of parameters required by the desired operation. The class also accepts the values for each IN and INOUT type of parameter from the user. In button event handler, if the user has clicked the invoke button, we copy the input parameters from the TextField objects in the table to a String array, which is then sent to the BackEnd object by calling its setParameters() method. The BackEnd will use these parameters while invoking the server method. Once the parameters are set, the program calls the local performDii() method, which passes the request to the processRequest() method of the BackEnd class. The BackEnd processes the request and displays the results. The StatusBar class (see Listing 6) is derived from the JLabel and is simply a utility class for displaying status messages in the browser window. Now we come to the most important class, BackEnd, which is responsible for all CORBA-related back-end processing (see Listing 7). The class constructor receives a reference to our ObjectBrowser and copies it into a local variable. The init() method first initializes the ORB by calling its init() method: orb = org.omg.CORBA.ORB.init (param, null); If the ORB is successfully initialized, we call resolve_initial_references() method on the ORB to resolve a reference to the Naming Service. We then narrow (type cast) the returned object to the NamingContext object type. The initialization of the BackEnd object is complete and the object now waits for its other methods (resolve, introspect, processRequest) to be invoked. The resolve() method receives the object as a string and tries to locate the object on either the current ORB or the ORB running at the specified URL:
if (!(resolved = resolveUsingName(object)))
NameComponent[] name = {new NameComponent(object, "")}; If this resolution fails, we try to resolve using the URL Naming Service. The method resolveUsingURL() obtains a reference to the URLNamingResolver and narrows it down to the proper data type as follows:
org.omg.CORBA.Object resolverObj = The StatusBar class (see Listing 6) is derived from the JLabel and is simply a utility class for displaying status messages in the browser window. Now we come to the most important class, BackEnd, which is responsible for all CORBA-related back-end processing (see Listing 7). The class constructor receives a reference to our ObjectBrowser and copies it into a local variable. The init() method first initializes the ORB by calling its init() method: orb = org.omg.CORBA.ORB.init (param, null); If the ORB is successfully initialized, we call resolve_initial_references() method on the ORB to resolve a reference to the Naming Service. We then narrow (type cast) the returned object to the NamingContext object type. The initialization of the BackEnd object is complete and the object now waits for its other methods (resolve, introspect, processRequest) to be invoked. The resolve() method receives the object as a string and tries to locate the object on either the current ORB or the ORB running at the specified URL:
if (!(resolved = resolveUsingName(object)))
NameComponent[] name = {new NameComponent(object, "")};
Next, we use the locate method to resolve the object reference:
obj = URLresolver.locate(object);
InterfaceDef objIntfce =
fullObjectInterface =
final int noAttributes =
for (int i = 0; i
Finally, we look at the most important method, processRequest(). This method obtains the name of the operation to be invoked as the parameter and invokes the method on the server object. First we obtain the index of the desired method from the list of operations described in the fullObjectInterface object:
for ( ; i
int noParameters =
NVList parameterList = orb.create_list(0);
Any currentParameter = orb.create_any(); The special type "Any" defined in CORBA is used to represent the element with any data type. We initialize this object with the proper data type by using the "type" member of parameters[i] variable. The program then examines the mode for the parameter, which can be IN, OUT or INOUT type. The method receives an input value through this parameter and returns the result to the caller through the same parameter. Depending on the value of the mode, we set our mode variable to the proper CORBA data type. For the IN type of parameter the mode variable is set to org.omg.CORBA.ARG_IN.value; for the OUT type it's set to org.omg.CORBA.ARG_OUT value; and for the INOUT type it's set to org.omg.CORBA.ARG_INOUT value. We also set an "accept" flag for each parameter. If the accept flag is set, it indicates we'll be assigning a value obtained from the user to this object (applicable to the IN and INOUT types of parameters). The program then retrieves the value entered by the user for the current parameter by using parametersValue array. Note that all parameter values are stored as String data type. We now set up a switch statement to convert this parameter value to the proper data type and assign it to our parameter object in an NVList. We check the parameter data type by using kind() method on the current parameter:
switch Once the parameter is initialized with the proper data type and its value, we add the parameter to an NVList using its add_value() method:
parameterList.add_value(
parameters[j].name,
Once the NVList for operation parameters is constructed, we need to create a Named Value object for the return value of the method. We construct and initialize this NamedValue object using the following lines of code:
Any resultParameter = orb.create_any();
org.omg.CORBA.NamedValue resultField =
Request request = The _create_request() method requires four parameters. The first specifies the CORBA context and is set to null in this case; the second specifies the operation name; the third specifies the NVList containing the list of parameters required by the operation; and the fourth is another NVList in which the return value, if any, is returned. You're now ready to invoke the method on the server, a simple process. You use invoke() method on the request object to invoke the method on the remote server:
request.invoke();
Having seen the design of the object browser, we now examine how to compile and run the entire application.
Running the Browser javac -classpath %SWINGPATH% %1 where SWINGPATH is the system variable defined on our system that sets up the class path for Java, Visigenic CORBA and Swing classes. The parameter to the batch file is our main Java class ObjectBrowser.java. If your classpath is set properly, running swingcompile batch file should compile all the relevant files. Before you run the browser, you need to do certain startup operations, such as starting OSAgent, starting the Naming Service, etc., with the help of startup.bat file (see Listing 9). This batch file starts the OSAgent using the following command line: start OSAgent c Next, it starts the interface repository using the following command line: start irep InterfaceRepository ABCOM.ir The command irep starts the repository service. The name of our repository is InterfaceRepository, and it's stored in the file called ABCOM.ir in the current folder. Next, the CORBA Naming Service is started using the following command line:
start vbj -DORBservices=CosNaming
This completes the operation of our startup batch file. When you run this batch file, you'll notice that three windows pop up on your terminal; one is used by OSAgent, the second by Interface Repository and the third by the Naming Service. Now we're ready to run our object browser, which is started using show.bat file (see Listing 10):
vbj -DORBservices=CosNaming -DSVCnameroot=ABCOM -VBJclasspath Running this batch file starts our object browser. You're now ready to discover any object either in the current ORB or the ORB running at some known URL.
We've provided a test server application for your convenience. It's called SampleServer (see IDL Listing in Sample.idl file) (Listing 11). The server provides three sample methods: The implementation files, along with the compiled code, can be downloaded from the JDJ Web site. You'll need to run idl2ir to load the IDL into your IR before running the SampleServer application. The application registers itself with the Naming Service using the name "SampleObject". Type this name in the browser input panel and click on introspect to display the IDL. You can then select any of the three listed methods, invoke them and test the result.
Conclusion
Acknowledgments
org.omg.CORBA.Object resolverObj = Reader Feedback: Page 1 of 1
Enterprise Open Source Magazine Latest Stories . . .
Subscribe to the World's Most Powerful Newsletters
Subscribe to Our Rss Feeds & Get Your SYS-CON News Live!
|
SYS-CON Featured Whitepapers
Most Read This Week |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||