VisiBroker for .NET Developer’s Guide : Developing VisiBroker for .NET client applications

Developing VisiBroker for .NET client applications
This chapter introduces the development process for creating .NET client applications that can access J2EE and CORBA server objects using the VisiBroker for .NET runtime. Simple examples are provided to illustrate the three different methods for making calls on remote objects.
VisiBroker for .NET provides you with three methods for developing client applications that communicate with distributed objects: .NET Remoting, CORBA, and J2EE. These three technologies each define a standard way of doing essentially the same steps: bootstrap the middleware, locate and instantiate remote objects, and invoke methods on them.
The syntax, APIs, and programming models are slightly different for each of the three technologies, but the following examples will prove that whichever way you write it you can accomplish the same result with each of them.
Where do I go from here?
If you are a Microsoft developer, already comfortable with .NET Remoting, or new to distributed technologies, start with “A simple .NET Remoting example”. Developers familiar with J2EE should start with “A simple J2EE example”, and those familiar with CORBA should start with “A simple CORBA example”.
Some simple examples
The following sections show you some simple examples of the three methods you can use to bootstrap the middleware, locate and instantiate remote objects, and invoke methods on them.
A simple .NET Remoting example
If you are a Microsoft developer, already comfortable with .NET Remoting, or new to distributed technologies, you will be pleased to learn that you can develop .NET applications that interoperate with objects on both J2EE and CORBA servers using the .NET Remoting programming model.
The following three lines of code show how easily you can instantiate the remote object MyServer and call a Method() on it.
static void Main(string[] args) {
RemotingConfiguration.Configure (“MyApplication.exe.config”);
MyServerHome myServerHome = new MyServerHomeRemotingProxy();
MyServer myServer = myServerHome.Create();
myServer.Method();
}
The information for establishing a connection with the server and locating the remote object are contained in an XML configuration file, as shown in “.NET Remoting configuration”.
Let’s walk through the example line by line:
The first line specifies the configuration file where the .NET Remoting is configured.
RemotingConfiguration.Configure (“MyApplication.exe.config”);
The next line of code instantiates the factory object MyServerHome.
MyServerHome myServerHome = new MyServerHomeRemotingProxy();
A factory object is a lookup mechanism for locating and creating a remote object. You look it up first in order to locate and create an instance of the actual object you want to invoke methods on.
There is no concept of narrowing an object’s type in .NET. You locate the object and cast it to its specific type all in one step.
The next line creates an instance of myServer.
MyServer myServer = myServerHome.Create();
You can now call methods on your instance of myServer.
myServer.Method();
It’s that simple! If you want more information on configuring .NET Remoting using the VisiBroker for .NET protocol, see “.NET Remoting configuration”.
A simple J2EE example
VisiBroker for .NET provides a method for allowing developers familiar with writing calls to EJBs to do so in the .NET application.
Consider the following example.
static void Main(string[] args) {
J2EE.Naming.Context root = new J2EE.Naming.InitialContext(args);
string serverName = "location/of/my/server";
object myServerHomeObject = root.Lookup(serverName);
MyServerHome myServerHome = (MyServerHome)
J2EE.Rmi.PortableRemoteObject.Narrow(myServerHomeObject,
typeof(MyServerHome));
MyServer myServer = myServerHome.Create();
myServer.Method();
}
As you can see this is somewhat more complex than the .NET Remoting example. There is no configuration file in which to hide the details required for locating the objects.
Let’s walk through the example line by line:
In the first line we establish the root context for the J2EE naming service.
J2EE.Naming.Context root = new J2EE.Naming.InitialContext(args);
The next two lines declare a variable to contain the location of the EJBHome object (myServerHomeObject) on the server, and look it up.
string serverName = "location/of/my/server";
object myServerHomeObject = root.Lookup(serverName);
The next line narrows myServerHomeObject to its type, MyServerHome.
MyServerHome myServerHome = (MyServerHome)
J2EE.Rmi.PortableRemoteObject.Narrow(myServerHomeObject,
typeof(MyServerHome));
The next line creates an instance of myServer.
MyServer myServer = myServerHome.Create();
Finally we can invoke a method on MyServer:
myServer.Method();
A simple CORBA example
VisiBroker for .NET provides a method for allowing developers familiar with writing calls to CORBA objects to do so in the .NET application.
The following example shows the calls you might make.
static void Main(string[] args) {
CORBA.ORB orb = CORBA.ORB.Init(args);
CORBA.Object rootObject = orb.ResolveInitialReferences("NameService");
CosNaming.NamingContextExt root =
CosNaming.NamingContextExtHelper.Narrow(rootObject);
string serverName = "location/of/my/server";
CORBA.Object myServerHomeObject = root.ResolveStr(serverName);
MyServerHome myServerHome = MyServerHomeHelper.Narrow(myServerHomeObject);
MyServer myServer = myServerHome.Create();
myServer.Method();
}
As you can see this is somewhat more complex than the .NET Remoting example. There is no configuration file in which to hide the details required for locating the objects.
Let’s walk through the example line by line:
In the first line we initialize the ORB.
CORBA.ORB orb = CORBA.ORB.Init(args);
In the next two lines we obtain the root context for the CORBA naming service.
CORBA.Object rootObject = orb.ResolveInitialReferences("NameService");
CosNaming.NamingContextExt root =
CosNaming.NamingContextExtHelper.Narrow(rootObject);
The next two lines declare a variable to contain the location of the factory object (myServerHomeObject) on the server, and look it up.
string serverName = "location/of/my/server";
CORBA.Object myServerHomeObject = root.ResolveStr(serverName);
The next line narrows myServerHomeObject to its type, MyServerHome.
MyServerHome myServerHome = MyServerHomeHelper.Narrow(myServerHomeObject);
The next line creates an instance of myServer.
MyServer myServer = myServerHome.Create();
Finally we can invoke a method on MyServer.
myServer.Method();
.NET Remoting configuration
This section contains the details of the configuration file alluded to in the .NET example in “A simple .NET Remoting example”.
Let’s recall that .NET Remoting example:
static void Main(string[] args) {
RemotingConfiguration.Configure (“MyApplication.exe.config”);
MyServerHome myServerHome = new MyServerHomeRemotingProxy();
MyServer myServer = myServerHome.Create();
myServer.Method();
}
The information for establishing a connection with the server and locating the remote object are hidden away in an XML configuration file. This technique is known as declarative activation in .NET.
A configuration file for our example might look like the following:
<configuration>
<system.runtime.remoting>
<application name="MyApplication">
<client>
<wellknown type="MyServerHomeRemotingProxy, MyApplicationAssembly"
url="janeva:corbaname:rir:#location/of/my/server/object"/>
</client>
<channels>
<channel type="Janeva.Remoting.IiopChannel,
Borland.Janeva.Runtime"/>
</channels>
</application>
</system.runtime.remoting>
</configuration>
Specifying the object location
When we instantiated MyServerHome in the first line of the example, we used the new operator on MyServerHomeRemotingProxy(). In order to locate the object on which to make the call, the example configuration file uses the wellknown element,
<wellknown type="MyServerHomeRemotingProxy, MyApplication"
url="janeva:corbaname:rir:#location/of/my/server/object"/>
where MyServerHomeRemotingProxy is the type name and MyApplication is the name of the assembly where the type is defined.
Note:
MyServerHome is represented as a wellknown object (also known as Server-activated object or SAO). Any CORBA or EJB server object can be represented as an SAO. In addition, EJBs can be represented as Client Activated Objects (CAO). See “Client-activated objects vs. server-activated objects” for more information.
The .NET programming model requires that you locate the remote object with a URL. URLs are formed with two parts:
The janeva: protocol prefix tells the application to use the IIOP channel (Janeva.Remoting.IiopChannel), specified in the <channel> element of the configuration file.
Typically in .NET the first part of the URL contains the communication protocol. VisiBroker for .NET extends .NET Remoting with a new protocol: CORBA IIOP.
corbaname:rir:#location/of/my/server/object is one of several CORBA ORB string_to_object() compatible URL schemes. See the table in “URL schemes” for more examples and descriptions of the URL schemes.
URL schemes
To address the problem of bootstrapping and allow for more convenient exchange of human-readable object references, VisiBroker for .NET allows URLs in the formats listed in the following table to be converted into object references.
The corbaname URL scheme is most often used to resolve EJBs. It allows URLs to denote entries in a Naming Service. The host address is the location and listening port of the Naming Service and it can be formatted as <NS_host_name>:<NS_port> or <NS_ip_address>:<NS_port>. More details about the corbaname URL scheme are available in the OMG CORBA specification.
The corbaloc URL scheme provides direct access to server objects by location and object key. It is not often used because of the limited amount of addressing power. More details about the corbaloc URL scheme are available in the OMG CORBA specification.
The osagent scheme is a private feature for using with VisiBroker CORBA server objects.
To avoid ambiguity, all colons (:) in the <interface_repository_id> must be prefixed with the backslash (\) character, as follows: janeva:osagent:repid:IDL\:com/semagroup/targys/servicelayer/corba/ServiceRootI\:1.0:SL_demo_server
The IOR URL scheme allows you to look up an object by stringified object reference (IOR).
Specifying the Remoting channel
To communicate with remote objects a .NET client application has to create and register a Remoting channel. The channel provides a conduit for communication between a client and a remote object.
Instead of using the .NET Framework Channels types, VisiBroker for .NET provides the Janeva.Remoting.IiopChannel type for creating a channel on IIOP.
<channel type="Janeva.Remoting.IiopChannel, Borland.Janeva.Runtime"/>
The second argument is the VisiBroker for .NET runtime assembly name.
Client-activated objects vs. server-activated objects
VisiBroker for .NET supports both types of activation for remotable objects:
Server activation. Server-activated objects (SAO) are created by the server only when they are needed. They are not created when the client proxy is created by calling new or Activator.GetObject, but rather when the client invokes the first method on that proxy. The previous sections in this chapter are examples of this object activation method.
Client activation. Use client-activated objects when the application needs to retain state between method calls and also needs to pair each client with a unique object instance. Client-activated objects (CAO) are created on the server when the client calls new or Activator.CreateInstance.
Any kind of remote object supported by VisiBroker for .NET can be used on the client-side as an SAO. In addition, a J2EE server object can also be represented as a CAO.
The client activation in VisiBroker for .NET is based on the fact that many J2EE components follow the factory design pattern. Namely, any remotely accessible EJB (that is, stateful or stateless session or entity bean) exposes a home interface which is used to create or resolve the bean instance. For EJBs configured as CAOs, VisiBroker for .NET allows you to skip resolving the home interface and to create or resolve the bean instance simply by creating an instance of bean’s proxy class.
For example, let’s consider a simple EJB interface, SimpleSession, and its home interface, SimpleSessionHome:
public interface SimpleSession extends javax.ejb.EJBObject {
public void ping() throws java.rmi.RemoteException;
}
public interface SimpleSessionHome extends javax.ejb.EJBHome {
public SimpleSession create(String name);
}
The SimpleSession interface configured as an SAO can be accessed on the client side in C# as follows:
SimpleSessionHome home = new SimpleSessionHomeRemotingProxy();
SimpleSession session = home.Create("my name");
session.Method();
If the SimpleSession interface is represented as a CAO, the client code is a bit simpler:
SimpleSession session = new SimpleSessionRemotingProxy("my name");
session.Method();
Now, let’s explore in detail how VisiBroker for .NET supports the client activation model for J2EE components.
First, the java2cs compiler has extended knowledge of the EJB home interface. The compiler maps some methods defined on the EJB home interface to constructors of the bean’s Remoting Proxy class in the generated C# code. For the Session EJB home (stateful or stateless), these are any create() methods. For the Entity EJB home, this is the findByPrimaryKey() method. Also, the java2cs compiler preserves the parameters of the original home method in the generated proxy constructor. For example, the SimpleSessionHome.create(String name) method maps to the SimpleSessionRemotingProxy(string name) constructor in the generated C# code.
When a new instance of the CAO Remoting Proxy is created, the VisiBroker for .NET runtime does a few things under the covers. First, it resolves the bean’s home interface based on the VisiBroker for .NET URL specified in the Remoting object configuration. Then, depending on whether this is a Session bean or an Entity bean, the runtime remotely calls either the corresponding Session’s create() method, or the Entity’s findByPrimaryKey() method. Lastly, the Remoting Proxy of the EJB instance, resulted by this call, becomes an object returned by the new statement.
While the VisiBroker for .NET CAO usage model resembles the original .NET Remoting CAO model quite closely, it is worth noting a few peculiarities:
1
Creating an EJB Remoting Proxy, configured as a CAO, does not always imply that a new EJB instance is created on the server side (the EJB container). While this is true for the Session beans, the Entity beans behave differently. For Entities, the CAO constructor call translates into the findByPrimaryKey() call, therefore an existing instance with the corresponding primary key must already exist, otherwise an exception will be thrown. Thus, the CAO representation of the Entity bean can be used only to resolve a bean instance, not to create one. To create a new Entity instance use the SAO model.
2
A configuration file for a CAO example should look like the following:
<configuration>
<system.runtime.remoting>
<application name="MyApplication">
<client url=”janeva:corbaname:rir:#location/of/my/server/object”>
<activated type="SimpleSessionRemotingProxy,
MyApplicationAssembly"/>
</client>
<channels>
<channel type="Janeva.Remoting.IiopChannel,
Borland.Janeva.Runtime"/>
</channels>
</application>
</system.runtime.remoting>
</configuration>
Programmatic activation
An alternative to configuration files for writing your .NET calls to server side objects is to activate the Remoting channel and specify the location of the remote object directly in the code. The following code sample shows how this might look for an SAO.
static void Main(string[] args) {
Janeva.Remoting.IiopChannel channel = new Janeva.Remoting.IiopChannel
(args);
System.Runtime.Remoting.Channels.ChannelServices.RegisterChannel(channel);
string objectUrl = "janeva:corbaname:rir:#" +
"location/of/my/server/object";
MyServerHome myServerHome = (MyServerHome)
System.Activator.GetObject(typeof(MyServerHome), objectUrl);
MyServer myServer = myServerHome.Create();
myServer.Method();
}
The following code sample shows how this might look for a CAO.
static void Main(string[] args) {
Janeva.Remoting.IiopChannel channel = new Janeva.Remoting.IiopChannel
(args);
System.Runtime.Remoting.Channels.ChannelServices.RegisterChannel(channel);
string objectUrl = "janeva:corbaname:rir:#" +
"location/of/my/server/object";
MyServer myServer = (MyServer) System.Activator.CreateInstance(
typeof(MyServerRemotingProxy), new object[] {“my name”});
myServer.Method();
}
The first two lines in each example deal with setting up the VisiBroker for .NET Remoting channel on IIOP.
Janeva.Remoting.IiopChannel channel = new Janeva.Remoting.IiopChannel(args);
System.Runtime.Remoting.Channels.ChannelServices.RegisterChannel(channel);
The third line declares a variable to contain the location of the factory object (myServerHomeObject) on the server, and look it up similar to the way it was done in the J2EE and CORBA examples in the previous sections, except that there is no narrowing in .NET.