VisiBroker for .NET Developer’s Guide : Developing VisiBroker for .NET Remoting servers

Developing VisiBroker for .NET Remoting servers
This chapter explains the process for developing a VisiBroker for .NET Remoting server, and in particular it discusses how to implement a MarshalByRefObject object in VisiBroker for .NET.
Introduction
This section introduces the concepts of .NET Remoting server and a VisiBroker for .NET server.
About .NET Remoting
MarshalByRefObject objects are remote objects that run on the server and accept method calls from clients. .NET Remoting MarshalByRefObjects can be categorized into two groups:
SAOs can be marked as either Singleton or SingleCall. In the first case, one instance serves requests of all clients in a multi-threaded fashion. When using SAOs in SingleCall mode, a new object will be created for each request and destroyed afterwards. Both Singleton and SingleCall SAO modes are supported in VisiBroker for .NET. In addition to that, VisiBroker for .NET supports transient MarshalByRefObject objects that run either on a server, or on a client for server callback.
About VisiBroker for .NET Server
A VisiBroker for .NET server always starts from an IDL interface definition. An IDL interface defines the business logic that both the client and the server abide by. For example, the following example IDL file defines three interfaces:
an AccountManager interface that follows the factory design pattern with an open method for opening new bank accounts.
an Account interface that has operations to query the balance, as well as to do account debit and credit.
a Callback interface for banking event notification.
// Bank.idl
module Bank {
interface Callback {
void notify(in string message);
};
interface Account {
float balance();
void credit(in float amount);
void debit(in float amount);
};
interface AccountManager {
Account open(in float balance, in Callback callback);
};
};
A server will implement both the AccountManager interface and the Account interface. The client will provide the implementation for the Callback interface so that the bank server can call back to notify the client about all of the banking events.
The next two sections will walk through how to write the Bank server in .NET Remoting style, as well as how to add the callback implementation to the .NET Remoting style client.
Developing a server in .NET Remoting style
A server needs to implement the business logic. For the bank example, the bank server needs to provide implementation for both the AccountManager interface and the Account interface. The following code snippet shows the implementation of the AccountManager interface and the Account interface at the server side:
namespace Server {
public class AccountImpl : MarshalByRefObject, Bank.Account {
private float _balance;
private Callback _callback;
internal AccountImpl(float balance, Callback callback) {
_balance = balance;
_callback = callback;
_callback.Notify("Created account with $" + _balance);
}
public float Balance() {
_callback.Notify("Current balance is $" + _balance);
return _balance;
}
public void Credit(float amount) {
_callback.Notify("Crediting account with $" + amount);
_balance += amount;
}
public void Debit(float amount) {
if(amount <= _balance) {
_callback.Notify("Debiting account by $" + amount);
_balance -= amount;
}
else {
_callback.Notify("Insufficient funds to debit $" + amount);
}
}
}
public class AccountManagerImpl : MarshalByRefObject, Bank.AccountManager {
public AccountManagerImpl() {
Console.WriteLine("AccountManager created on : " +
System.DateTime.UtcNow.ToLongTimeString());
}
public Account Open(float balance, Callback callback) {
Console.WriteLine("Opening a new account with balance = $" + balance);
return new AccountImpl(balance, callback);
}
}
}
The Open() method of the AccountManagerImpl class takes in an initial balance and a Callback object reference that is passed in by the client, then creates a new instance of AccountImpl class.
The Balance() method of the AccountImpl class simply returns the balance to the client; the Credit() method credits the passed in amount to the account balance; the Debit() method debits the requested amount from the account balance. All of these three account operation events are notified to the client via the Callback object.
Now that the interface implementation is completed, the next step for the server is to register the AccountManagerImpl object either as a well known SingleCall service object or as a well known Singleton object to the .NET Remoting system. AccountImpl objects are transient as they do not outlive the process that created them.
Singleton object configuration
When a server implementation object is configured as a Singleton well known service type, only one instance of the server implementation object is created. It is this singleton instance that serves all requests coming from all clients. The configuration can be done either explicitly using .NET RemotingConfiguration APIs, or implicitly using a .NET Remoting configuration file.
Explicit registration
Singleton server implementation objects are explicitly registered to the Remoting system at the server side using the following statement:
RemotingConfiguration.RegisterWellKnownServiceType(
typeof(<TheServerImplClass>),
“<objectURI>”, WellKnownObjectMode.Singleton);
For the bank example, the following code snippet explicitly registers an instance of AccountManagerImpl class as a well known Singleton service type with AccountManager.iiop as its end point URI:
RemotingConfiguration.RegisterWellKnownServiceType(typeof(
Server.AccountManagerImpl),“AccountManager.iiop”,
WellKnownObjectMode.Singleton);
Implicit registration
Implicit registration of a server implementation object as a well known Singleton service type is done through the <service> property in the .NET Remoting configuration file as shown in the following example:
<configuration>
<system.runtime.remoting>
<application>
<service>
<wellknown mode="Singleton"
type="<namespace>.<implclassname>, <assembly>"
objectUri="<objectURI>"/>
</service>
</application>
</system.runtime.remoting>
</configuration>
and a call to .NET RemotingConfiguration to load in the configuration file:
RemotingConfiguration.Configure(“<configfile>”);
For the bank example, the complete configuration file of the server is shown below:
<configuration>
<configSections>
<section name="visinet" type="Janeva.Settings, Borland.Janeva.Runtime"/>
</configSections>
<visinet>
<agent port="24300" addr="localhost"/>
<server defaultPort=”10000”>
<remoting enabled="true"/>
</server>
</visinet>
<system.runtime.remoting>
<application name="Server">
<channels>
<channel type="Janeva.Remoting.IiopChannel,
Borland.Janeva.Runtime"/>
</channels>
<service>
<wellknown mode="Singleton"
type="Server.AccountManagerImpl, Server"
objectUri="AccountManager.iiop"/>
</service>
</application>
</system.runtime.remoting>
<janeva.runtime.remoting>
<wellknown objectUri="AccountManager.iiop" jndi="a/b/c"/>
</janeva.runtime.remoting>
</configuration>
For more information on Janeva.Remoting.IiopChannel type and its properties, see “Specifying the Remoting channel”.
SingleCall object configuration
When a server object is configured as a well known SingleCall object, the server will create one instance per each client invocation of a method, execute the method and then destroy the object again. Similar to the Singleton mode, the configuration can be done either explicitly using .NET RemotingConfiguration APIs, or implicitly using .NET Remoting configuration file.
Explicit registration
To register a SingleCall server implementation object explicitly, use the following codes:
RemotingConfiguration.RegisterWellKnownServiceType(typeof(<TheServerImplClass>),
“<objectURI>”, WellKnownObjectMode.SingleCall);
Implicit registration
To register a SingleCall server implementation object implicitly, change the <wellknown> property’s mode attribute to be SingleCall in the .NET Remoting configuration file:
<configuration>
<configSections>
<section name="visinet" type="Janeva.Settings, Borland.Janeva.Runtime"/>
</configSections>
<visinet>
<agent port="24300" addr="localhost"/>
<server defaultPort=”10000”>
<remoting enabled="true"/>
</server>
</visinet>
<system.runtime.remoting>
<application>
<service>
<wellknown mode="SingleCall"
type="<namespace>.<implclassname>, <assembly>"
objectUri="<objectURI>"/>
</service>
</application>
</system.runtime.remoting>
</configuration>
If you compare the output of the bank server example between Singleton and SingleCall mode, you’ll notice that in Singleton mode, the AccountManagerImpl class constructor is invoked only once no matter how many times a client tries to invoke the open method. While in SingleCall mode, the constructor is invoked once every time when the client invokes the open method.
Adding callbacks to a VisiBroker for .NET Remoting client
Adding callback objects to a VisiBroker for .NET remoting client is straight forward: implement the callback interface defined in the IDL file, then create an instance of the callback object and pass it as object reference to a server invocation method. Callback objects are transient objects in VisiBroker for .NET.
The following code listing shows a complete client implementation of the bank example:
using System;
using System.Runtime.Remoting;
using Bank;
namespace Client {
public class CallbackImpl : MarshalByRefObject, Callback {
public void Notify(string message) {
Console.WriteLine(" Callback: " + message);
}
}
public class Client {
static void Main(string[] args) {
try {
RemotingConfiguration.Configure("Client.config");
AccountManager manager = new AccountManagerRemotingProxy();
Callback callback = new CallbackImpl();
Account account = manager.Open(1000, callback);
Console.WriteLine("Balance = $" + account.Balance());
Console.WriteLine("Withdrawing $500");
account.Debit(500);
Console.WriteLine("balance = $" + account.Balance());
Console.WriteLine("Depositing $100");
account.Credit(100);
Console.WriteLine("Balance = $" + account.Balance());
Console.WriteLine("Withdrawing $700");
account.Debit(700);
Console.WriteLine("Balance = $" + account.Balance());
}
catch(Exception e) {
Console.WriteLine(e);
}
Console.WriteLine("Press enter key to stop the client...");
Console.ReadLine();
}
}
}
The .NET remoting configuration file Client.config used by the bank client is listed below:
<configuration>
<system.runtime.remoting>
<application name="Client">
<channels>
<channel type="Janeva.Remoting.IiopChannel,
Borland.Janeva.Runtime"/>
</channels>
<client>
<wellknown type="Bank.AccountManagerRemotingProxy, Client"
url="janeva:corbaloc::localhost:10000/AccountManager.iiop"/>
</client>
</application>
</system.runtime.remoting>
</configuration>
Refer to “.NET Remoting configuration” for details on how write the Remoting section of the VisiBroker for .NET Remoting configuration file. See “Configuring properties” for information about configuring VisiBroker for .NET properties in a configuration file.
Properties
By default, VisiBroker for .NET Remoting server and callback feature is turned off. You will need to enable it explicitly for developing a VisiBroker for .NET Remoting server and/or add callback objects into your Remoting client. This is done by setting the janeva.server.remoting property to true. See “Configuring properties” for information about configuring VisiBroker for .NET properties in a configuration file.