Given by Nancy McCracken, Chao Wei Ou, Geoffrey Fox at ARL Database Tutorial and CPS616 on February 98. Foils prepared 5 Feb 98
Outside Index
Summary of Material
We overview CORBA in general and then describe its use with Java Clients and Servers using the simple ORB available from the JavaIDL JDK 1.2 release from Sun. |
We give two simple examples : Hello world and the simple counter also shown with Visigenic ORB |
The JavaIDL ORB is not production quality but can be used to develop Java language CORBA objects which can then be used with other more sophisticated ORB's in production mode. |
Note the Java Language CORBA IDL is common to all ORB's |
JavaIDL respects this IDL binding and provides both a client or server implementation which respect IIOP and so interfaces with other vendor systems |
JavaIDL is a "JORB" -- a Java server implementation of CORBA |
Outside Index
Summary of Material
Geoffrey Fox, Nancy McCracken, Chao-Wei Ou |
Northeast Parallel Architectures Center at Syracuse University |
111 College Place, Syracuse, NY 13244 |
http://www.npac.syr.edu/ |
We overview CORBA in general and then describe its use with Java Clients and Servers using the simple ORB available from the JavaIDL JDK 1.2 release from Sun. |
We give two simple examples : Hello world and the simple counter also shown with Visigenic ORB |
The JavaIDL ORB is not production quality but can be used to develop Java language CORBA objects which can then be used with other more sophisticated ORB's in production mode. |
Note the Java Language CORBA IDL is common to all ORB's |
JavaIDL respects this IDL binding and provides both a client or server implementation which respect IIOP and so interfaces with other vendor systems |
JavaIDL is a "JORB" -- a Java server implementation of CORBA |
CORBA objects differ from typical programming language objects in these ways:
|
CORBA object developers need know nothing of where their clients will be, what hardware or OS they will run on, or what language they will be written in. |
CORBA objects approach universal accessibility. |
The CORBA specification has been written by the Object Management Group, a consortium of some 700 software vendor and user organizations. |
Client |
Object Implementation |
Request |
ORB |
An Object Invocation from a JavaIDL Client |
Client |
Object Implementation |
ORB Core |
ORB Dependent Interface |
IDL |
Stubs |
ORB |
Interface |
Static IDL |
Skeleton |
Implementation |
Support Interface |
The Structure of Object Request Broker Interfaces |
Client |
ORB Core |
ORB Dependent Interface |
IDL |
Stubs |
Request |
A Client using the Stub Interface |
Object Implementation |
ORB Core |
ORB Dependent Interface |
ORB |
Interface |
Static IDL |
Skeleton |
Implementation |
Support Interface |
An Object Implementation Receiving a Request |
IDL |
Definition |
Implementation |
Installation |
Stubs |
Skeleton |
Interface |
Repository |
Implementation |
Repository |
Client |
Object Implementation |
Interface and Implementation Repositories |
A client of an object has access to an object reference for the object, and invokes operations on the object. A client knows only the logical structure of the object according to its interface and experiences the behavior of the object through invocations. |
JavaIDL clients see objects and ORB interfaces through the perspective of the Java language mapping, bringing the ORB right up to the programmer's level. Clients are maximally portable. |
Client code has no knowledge of the implementation of the object or which ORB is used to access the implementation. |
Language and ORB Dependent Object Invocation |
ORB Object References |
Stubs for |
Interface A |
Stubs for |
Interface B |
Clients |
Client |
Side |
Stubs |
for Remote Objects |
User Provided |
Generated by ORB from IDL |
An object implementation provides the semantics of the object, usually by defining data for the object instance and code for the object's methods. |
Often the implementation will use other objects or additional software to implement the behavior of the object. In some cases, the primary function of the object is to have side-effects on other things that are not formal CORBA objects.
|
Note that a client of one ORB (say JavaIDL) can access objects from other ORB's (say Visigenic) as IIOP provides interoperability |
Methods for |
Interface A |
Skeleton for |
Interface A |
Up-Call to Methods |
User Provided |
Generated by ORB from IDL |
An Object Reference is the information needed to specify an object within an ORB. Both clients and object implementations have an opaque notion of object references according to the Java language mapping, and thus are insulated from the actual representation of them. |
The representation of an object reference handed to a client is only valid for the lifetime of that client. |
The language mapping also provides additional ways to access object references in a typed way for the convenience of the programmer. |
There is a distinguished object reference, the null reference, guaranteed to be different from all object references, that denotes no object. In Java, this is a Java null. |
To invoke a CORBA object, you need a reference for the object. There are two ways to get a reference for a CORBA object:
|
It's common to encounter CORBA objects whose operations return references to other objects. |
There is a Java interface to the stubs for each interface type. |
The stubs present access to the OMG IDL-defined operations on an object in a way that is easy for programmers to predict once they are familiar with OMG IDL and the language mapping.
|
The Interface Repository is a service that provides persistent objects that represent the IDL information in a form available at runtime. |
The JavaIDL runtime does not include an implementation of an Interface Repository and one is not generally required by clients at runtime. |
JavaIDL depends on a separate ORB, generally the one managing the services that the JavaIDL client is trying to access, to provide one if needed. |
The Implementation Repository contains information that allows the ORB to locate and activate implementations of objects. |
Ordinarily, installation of implementations and control of policies related to the activation and execution of object implementations is done through operations on the Implementation Repository. |
In addition to its role in the functioning of the ORB, the Implementation Repository is a common place to store additional information associated with implementations of ORB objects. (e.g., debugging information, administrative control, resource allocation, security, etc) |
The Implementation Repository supports the implementation of object servers. It is not needed by clients in order to access servers. |
To statically invoke an operation on a CORBA object, a Java client needs two things:
|
Of these, the client developer is only interested in the object reference; the stub class is generated automatically and its instances are created and invoked automatically. |
For each interface defined in an IDL module, the generated package (by idltojava) contains the following items of interest to the client programmer: (e.g., Foo.idl)
|
CORBA dynamic invocation uses an object called a request to hold everything pertinent to an invocation: the object reference, the name of the operation, its parameters, and space for the result. The client builds a request object describing an operation, then calls the request's invoke method, which dispatches the request just as a stub would. When the invoke method returns, the result is available in the request object. |
The key to dynamic invocation is the ability of requests to hold self-describing data. This facility enables a request object to represent any invocation of any operation, regardless of its parameters are. |
OMG IDL supports inheritance; the top of the hierarchy is Object in OMG IDL, org.omg.CORBA.Object in Java. (Note that both CORBA and Java define Object, but they are the tops of different type hierarchies.) |
Some operations, notably name lookup and unstringifying, return org.omg.CORBA.Objects, which you narrow (using a helper class generated by idltojava) to the derived type you want the object to be. CORBA objects must be explicitly narrowed because the Java runtime cannot always know the exact type of a CORBA object. |
To create a Java object you use the new() operator; to delete a Java object you do nothing; the garbage collector reclaims it for you. CORBA clients never create CORBA objects, only servers do. |
As a client, to create a CORBA object, you invoke another object which is the factory for the type of object you want created; the factory returns an object reference for you to use to invoke the new object. Typically the factory is implemented by the same server that implements the object type. |
Neither is there any standard way to delete a CORBA object. Because a CORBA object may be shared by many clients around a network, it is hard to know when an object has, in Java terms, become garbage. In general, only the object server is in a position to know, and then only if the server developer provides a "destroy" operation for the object. |
A transient CORBA object has the same lifetime as the execution of the server process that creates it. When a server terminates, its transient objects disappear with it. Transient objects are often used to effect asynchronous communication between applications and objects. |
By contrast, a persistent object lives until it is explictly destroyed. If a client has a reference to a persistent CORBA object, that reference can be used even if the object's server is not running--an ORB will start the server when it (the ORB) receives an invocation on the object. |
At present, Java IDL supports only transient object servers. Although persistent object servers can't yet be written in JavaIDL, Java applets and applications can be clients of persistent CORBA objects with different ORB's -- which can of course be written in Java language |
To implement a server for transient CORBA objects of some type, you write a Java class called a servant, which inherits from a class called the servant base; servant base classes are optionally generated by the idltojava compiler. |
An instance of a transient CORBA object is implemented by an instance of its servant class. |
The servant base class is the CORBA type-specific interface between the ORB and the servant code for the type. It unmarshals incoming parameters, invokes servant methods, marshals results, and directs the ORB to return results to the client ORB. |
A servant class extends its servant base with a method for each operation in the IDL interface definition it implements. |
module <identifier> |
{ |
<type declaration> |
<constant declaration> |
<exception declaration> |
interface <identifier> [:<inheritance>] |
{ |
<type declaration> |
<constant declaration> |
<exception declaration> |
[<op_type>] <identifier> (<parameters>) [raises exception] [context]; |
: |
}; |
interface <identifier> [:<inheritance>] |
: |
}; |
boolean |
char/wchar |
octet |
string/wstring |
short/unsigned short |
long/unsigned long |
long long/unsigned long long |
float |
double |
boolean |
char |
byte |
java.lang.String |
short |
int |
long |
float |
double |
IDL Type |
Java Type |
module |
interface |
enum |
struct |
union |
sequence/array |
any |
exception |
typedef |
package |
interface with an additional helper |
final class with enum values |
final class with the same name |
final class with the same name |
array |
class CORBA.any |
class extends CORBA.UserException |
Use original name |
IDL Type |
Java Type |
module HelloApp |
{ |
interface hello; |
{ |
string sayHello(); |
}; |
}; |
To use idltojava to compile the "hello" example IDL code as |
idltojava -fclient -fserver hello.idl |
Two sets of Java codes will be generated:
|
The example server consists of two classes, the servant and the server. |
The servant, HelloServant, is the implementation of the Hello IDL interface. |
Each Hello instance is implemented by a HelloServant instance. |
The servant is a subclass of _HelloImplBase, which is generated by the idltojava compiler from the example IDL. |
The servant contains one method for each IDL operation. |
import HelloApp.*; |
import org.omg.CosNaming.*; |
import org.omg.CosNaming.NamingContextPackage.*; |
import org.omg.CORBA.*; |
class HelloServant extends _HelloImplBase |
{ |
public String sayHello() |
{ |
return "\nHello world !!\n"; |
} |
} |
Creates an ORB instance |
Creates a servant instance (the implementation of one CORBA Hello object) and tells the ORB about it |
Gets a CORBA object reference for a naming context in which to register the new CORBA object |
Registers the new object in the naming context under the name "Hello" |
Waits for invocations of the new object |
public class HelloServer { |
public static void main(String args[]) { |
try{ |
// create and initialize the ORB |
ORB orb = ORB.init(args, null); |
// create servant and register it with the ORB |
HelloServant HelloRef = new HelloServant(); orb.connect(HelloRef); |
// get the root naming context |
org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService"); |
NamingContext ncRef = NamingContextHelper.narrow(objRef); |
// bind the Object Reference in Naming |
NameComponent nc = new NameComponent("Hello", ""); |
NameComponent path[] = {nc}; ncRef.rebind(path, HelloRef); |
// wait for invocations from clients |
java.lang.Object sync = new java.lang.Object(); |
synchronized (sync) { |
sync.wait(); |
} |
} catch (Exception e) { |
System.err.println("ERROR: " + e); |
e.printStackTrace(System.out); |
} |
} |
} |
The example application client that follows: |
Creates an ORB |
Obtains a reference to the naming context |
Looks up "Hello" in the naming context and receives a reference to that CORBA object |
Invokes the object's sayHello() operation and prints the result |
import HelloApp.*; |
import org.omg.CosNaming.*; |
import org.omg.CORBA.*; |
public class HelloClient { |
public static void main(String args[]) { |
try{ // create and initialize the ORB |
ORB orb = ORB.init(args, null); |
// get the root naming context |
org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService"); |
NamingContext ncRef = NamingContextHelper.narrow(objRef); |
// resolve the Object Reference in Naming |
NameComponent nc = new NameComponent("Hello", ""); |
NameComponent path[] = {nc}; |
Hello HelloRef = HelloHelper.narrow(ncRef.resolve(path)); |
// call the Hello server object and print results |
String Hello = HelloRef.sayHello(); |
System.out.println(Hello); |
} catch (Exception e) { |
System.out.println("ERROR : " + e) ; |
e.printStackTrace(System.out); |
} |
} |
} |
The server exports two methods InitSum and Increment methods simply initialize varaible sum and increments it by one, respectively. Then return the value of sum to the client. |
The Client increments the sum to 1000 and keeps tracking of the elapsed time. The output the average time per increment. (Roughly, this can be treated as the average time for ping command on IIOP.) |
module Counter{ |
interface Count { |
attribute long sum; |
void initSum(in long value); |
long increment(); |
}; |
}; |
Note: This code is provided by developer and passed to idltojava pre-compiler |
idltojava generates a Java package <userIDL> containing |
Client-side Classes:
|
Server-side Class:
|
Client's classes:
|
See: http://osprey7.npac.syr.edu:3768/reference-docs/cwou/JavaIDL/Counter/ |
Server's Classes:
|
Count |
CountHelper |
CountHolder |
_CountStub |
_CountImplBase |
(Skeleton and |
Implementation) |
CounterClient |
CountServantImpl |
CounterServer |
idltojava compiler |
User implements |
Counter IDL |
ORB Core |
Client |
Server |
package Counter; |
public interface Count extends org.omg.CORBA.Object { |
int sum() throws org.omg.CORBA.SystemException; |
void sum(int arg) throws org.omg.CORBA.SystemException; |
void initSum(int value); |
int increment(); |
} |
Note: This code is created automatically by idltojava pre-compiler from the IDL spec. |
package Counter; |
public class _CountStub extends org.omg.CORBA.portable.ObjectImpl implements Counter.Count { |
...... |
public int sum() throws org.omg.CORBA.SystemException { |
long _n[] = new long[1]; |
java.lang.Object _o[] = new java.lang.Object[1]; |
_invoke(__ops[0], _n, _o); |
return (int) (_n[0] & 0xFFFFFFFFL); |
} .... |
Detail can be found at |
http://osprey7.npac.syr.edu:3768/reference-docs/cwou/JavaIDL/Counter/Counter/_CountStub.html |
package Counter; |
public final class CountHelper { |
// It is useless to have instances of this |
class private CountHelper() { } |
public static void __write(org.omg.CORBA.portable.OutputStream out, Counter.Count that) { |
out.write_Object(that); |
} |
..... |
Details can be found at |
http://osprey7.npac.syr.edu:3768/reference-docs/cwou/JavaIDL/Counter/Counter/CountHelper.html |
package Counter; |
public final class CountHolder implements org.omg.CORBA.portable.Streamable{ |
// instance variable |
public Counter.Count value; |
// constructors |
public CountHolder() { |
this(null); |
} |
public CountHolder(Counter.Count __arg) { .... |
Details can be found at |
http://osprey7.npac.syr.edu:3768/reference-docs/cwou/JavaIDL/Counter/Counter/CountHolder.html |
package Counter; |
public abstract class _CountImplBase |
extends org.omg.CORBA.portable.ObjectImpl |
implements Counter.Count, org.omg.CORBA.portable.Skeleton { |
static private org.omg.CORBA.portable.OperationDescriptor[][] _dispatch_table; |
static { |
_dispatch_table = new |
org.omg.CORBA.portable.OperationDescriptor[1][0]; |
......... |
Details can be found at |
http://osprey7.npac.syr.edu:3768/reference-docs/cwou/JavaIDL/Counter/Counter/_CountImplBase.html |
The following packages used in developing the Counter/Timer example for both client and server codes: |
import java.io.*; |
import java.net.*; |
import org.omg.CORBA.*; |
import com.sun.CORBA.iiop.*; |
import org.omg.CosNaming.*; |
import org.omg.CosNaming.NamingContextPackage.*; |
import Counter.*; |
public class CounterClient |
{ |
public static org.omg.CORBA.ORB orb; |
public static Counter.Count counter; |
public static void main (String args[]) { |
try { |
orb = org.omg.CORBA.ORB.init(args, null); |
org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService"); |
NamingContext ncRef = NamingContextHelper.narrow(objRef); |
NameComponent nc = new NameComponent("Counter", ""); |
NameComponent path[] = {nc}; |
counter = Counter.CountHelper.narrow(ncRef.resolve(path)); |
counter.initSum((int)0); |
long startTime = System.currentTimeMillis(); |
for (int i=0; i i++) { |
counter.increment(); |
} |
long stopTime = System.currentTimeMillis(); |
System.out.println("Avg Ping = " + ((stopTime-startTime)/1000f) + "msecs"); |
System.out.println("Sum = " + counter.sum()); |
} catch (Exception ex) { |
ex.printStackTrace(); |
} |
} |
} |
class CountServantImpl extends Counter._CountImplBase { |
private int sum_; |
public CountServantImpl() { |
System.out.println("Count Object Created"); |
sum_ = 0; |
} |
public int sum() { |
return this.sum_; |
} |
public void initSum(int value) { |
sum(value); |
} |
public int increment() { |
this.sum_++; |
return this.sum_; |
} |
} |
public class CounterServer { |
public static org.omg.CORBA.ORB theORB; |
static public void main(String[] args) { |
try { |
theORB = org.omg.CORBA.ORB.init(args, null); |
CountServantImpl servant = new CountServantImpl(); |
theORB.connect(servant); |
org.omg.CORBA.Object objRef = theORB.resolve_initial_references("NameService"); |
NamingContext ncRef = NamingContextHelper.narrow(objRef); |
NameComponent nc = new NameComponent("Counter", ""); |
NameComponent path[] = {nc}; |
ncRef.rebind(path, servant); |
java.lang.Object sync = new java.lang.Object(); |
synchronized (sync) { |
sync.wait(); |
} |
} catch (Exception ex) { |
ex.printStackTrace(); |
} |
} |
} |