Bob Swart (aka Dr.Bob - www.drbob42.com) is an independent consultant, trainer, author & Webmaster for Bob Swart Training & Consultancy (eBob42) using Delphi (for .NET), C#Builder, Kylix, and C++Builder, and has spoken at Delphi and Borland Developer Conferences since 1993. Bob is a trainer who has presented all over the world (USA, BeNeLux, Germany, Italy, Singapore and for UK-BUG in London, Manchester, Reading and Edinburgh). He has written his own training material, including the Delphi 8 for .NET Essentials and Delphi 8 for .NET ASP.NET courseware material licensed by Borland. Bob is co-author of the Revolutionary Guide to Delphi 2, Delphi 4 Unleashed, C++Builder 4 Unleashed, C++Builder 5 Developer's Guide, Kylix Developer's Guide, Delphi 6 Developer's Guide, and the upcoming C++Builder 6 Developer's Guide, as well as author for a number of computer magazines, including The Delphi Magazine, Delphi Developer, UK-BUG Developer's Magazine, SDGN Magazine and Blaise, as well as the TechRepublic (CNET), DevX, Borland-IBM DB2 Web portal and the Borland Developer Network Web site, and his own Dr.Bob's Delphi Clinic at http://www.drbob42.com. Together with Marco Cantu, Bob received the Spirit of Delphi award in 1999 from Borland at BorCon.
Using Janeva to Connect CORBA, Java, and .NET
In this session, you learn how Microsoft .NET Framework developers can use Borland Janeva to connect to CORBA servers that run on different platforms (like Win32, Linux and others).
Janeva is Borland's "middle-ware" (or glue) technology to connect "legacy" J2EE (Enterprise JavaBeans) or CORA objects to .NET clients.
There are several examples using J2EE available already, but with my Delphi and C++Builder experience, I rather start with a CORBA example.
Micha Somers will show the JBuilder J2EE example for this session.
So, I'll start by building a Delphi CORBA server (using Borland Delphi 7 Enterprise and the VisiBroker ORB) and will connect that CORBA server to C# clients written in C#Builder using Borland's Janeva as "glue".
CORBA to .NET
CORBA is the acronym for Common Object Request Broker Architecture and is a widely used architecture to build distributed (multi-tier) applications with both cross-platform and cross-language in mind.
Like J2EE, CORBA is not easily connected to the .NET world, where ASP.NET Web Services and .NET Remoting are the generic ways to build distributed applications.
However, using Borland's Janeva, we can connect CORBA or J2EE objects to the .NET world.
Delphi CORBA Server
Let's start with the CORBA server, built in Borland Delphi 7 Enterprise.
The CORBA server that I want to use is based on an existing application to maintain a personal agenda with appointments that can be used to schedule meetings electronically.
I will not spend a lot of time to discuss the actual scheduling implementation details, but rather focus on the way to build and distribute the CORBA server interface specification (that will be used at the client side).
To build the CORBA server, start Delphi 7 Enterprise (or C++Builder 6 Enterprise), do File | New - Other and go to the Multitier tab of the Object Repository:
There are a number of icons here related to CORBA.
To start a new CORBA server project from scratch, double-click on the CORBA Server icon, which will bring up the CORBA Server Wizard to specify the options for our new project.
You can create a Console Application (with or without using Borland's Visual Component Library) or a Windows Application.
I've selected the latter, since I want the server to display some visual (debug) information during development.
You can set some options in the Options tab of the dialog.
CORBA servers can contain one or more CORBA objects, and the interface specification of these CORBA objects are usually stored in IDL (Interface Definition Language) files.
When you start a new CORBA server project, you can either add a number of existing IDL files, or start with an empty IDL file and add your own CORBA object definitions.
For this example, I've decided to use a simplified version of the actual IDL file, which is as follows::
When you click on OK in the CORBA Server Wizard, the new project is generated, including a number of generated files.
Do File | Save All to save the project files, placing the main form in MainForm.pas and the project main file itself in D7CorbaServer.dpr.
The other four (generated) files that are part of your project have already been saved in the current directory, and are (in alphabetical order) BirthdayReminder_c.pas (for the stub classes), BirthdayReminder_i.pas (for the interface definition), BirthdayReminder_impl.pas (for the implementation), and BirthdayReminder_s.pas (for the skeleton classes).
Of all the generated files, only the BirthdayReminder_impl.pas should be edited and modified by us.
This is the place to write the implementation of the actual CORBA server object, which I've kept simple but you can make it as sophisticated as you wish.
unit BirthdayReminder_impl;
interface
uses
SysUtils,
CORBA,
BirthdayReminder_i,
BirthdayReminder_c;
type
TIBirthday = class;
TIBirthday = class(TInterfacedObject, BirthdayReminder_i.IBirthday)
protected
public
constructor Create;
procedure RememberBirthday ( const Name : AnsiString;
const Date : BirthdayReminder_i.TDate);
function NumberOfBirthdaysOnDate ( const Date : BirthdayReminder_i.TDate): SmallInt;
function BirthdayOnDate ( const Date : BirthdayReminder_i.TDate;
const index : SmallInt): AnsiString;
end;
implementation
uses
IniFiles;
const
IniFileName = 'c:usrbirthday.ini';
constructor TIBirthday.Create;
begin
inherited;
end;
procedure TIBirthday.RememberBirthday ( const Name : AnsiString;
const Date : BirthdayReminder_i.TDate);
var
DateStr: String;
Count: integer;
begin
try
DateStr := Format('%.4d-%.2d-%.2d',[Date.Year,Date.Month,Date.Day]);
with TIniFile.Create(IniFileName) do
try
Count := ReadInteger(DateStr, 'count', 0) + 1;
WriteInteger(DateStr, 'count', Count);
WriteString(DateStr,IntToStr(Count),Name)
finally
Free
end
except
on E: Exception do
raise EIBirthday_InvalidBirthday.Create(E.ClassName + ': ' + E.Message)
end
end;
function TIBirthday.NumberOfBirthdaysOnDate ( const Date : BirthdayReminder_i.TDate): SmallInt;
var
DateStr: String;
begin
Result := 0;
DateStr := Format('%.4d-%.2d-%.2d',[Date.Year,Date.Month,Date.Day]);
with TIniFile.Create(IniFileName) do
try
Result := ReadInteger(DateStr, 'count', 0)
finally
Free
end
end;
function TIBirthday.BirthdayOnDate ( const Date : BirthdayReminder_i.TDate;
const index : SmallInt): AnsiString;
var
DateStr: String;
Count: integer;
begin
DateStr := Format('%.4d-%.2d-%.2d',[Date.Year,Date.Month,Date.Day]);
with TIniFile.Create(IniFileName) do
try
Count := ReadInteger(DateStr, 'count', 0);
if index > Count then
raise EIndexOutOfRange.Create
else
Result := ReadString(DateStr, IntToStr(index), '');
finally
Free
end
end;
initialization
end.
Apart from the implementation of the TIBirthday class, we must also go to the MainForm unit and make sure the CORBA Server Object is actually created.
In the TForm1 declaration, add a field called Birthday of type TIBirthday.
unit MainForm;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Corba, BirthdayReminder_c, BirthdayReminder_i, BirthdayReminder_impl, BirthdayReminder_s,
StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
protected
Birthday: IBirthday;
procedure InitCorba;
public
end;
var
Form1: TForm1;
implementation
procedure TForm1.InitCorba;
begin
CorbaInitialize;
Birthday := TIBirthdaySkeleton.Create('Happy Birthday', TIBirthday.Create);
BOA.ObjIsReady(Birthday as _Object);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
InitCorba;
Sender.Free // remove button from TForm1
end;
end.
If you wanted to create a Delphi 7 CORBA Console Server instead (also using the Basic Object Adapter - BOA - by default), then the implementation of the main project file must be as follows:
program D7CorbaConsoleServer;
{$APPTYPE CONSOLE}
uses
SysUtils, CORBA, BirthdayReminder_c, BirthdayReminder_i, BirthdayReminder_impl, BirthdayReminder_s;
var
Birthday: IBirthday;
begin
CorbaInitialize;
Birthday := TIBirthdaySkeleton.Create('Happy Birthday', TIBirthday.Create);
Writeln('Birthday Server Object Created...');
Writeln;
BOA.ObjIsReady(Birthday as _Object);
Writeln('Server is ready...');
BOA.ImplIsReady;
end.
Before you can run the CORBA Server, you must make sure the VisiBroker Smart Agent is also running (either normal or as NT service), so you can then run the server itself:
Now you can use the Borland VisiBroker Console to run OS Find and see the resulting Corba Server as one of the manually started objects, with name "Happy Birthday".
C# CORBA Client
Start C#Builder Enterprise or Architect, and start a new C# Application.
In the New Application dialog you can specify the name as well as the location of the new project.
If you've installed Borland Janeva, then you can right-click on the main project file inside the Project Manager and add a J2EE or CORBA Reference.
Without Janeva, you can add only regular references (normal files) or Web references (Web Services) to the project.
Since our example project is a CORBA server, we should select the Add CORBA Reference... choice.
This will open a dialog were we can specify the IDL file that holds the CORBA server definition: Birthday.idl.
Note that we only import the definition to the CORBA server now, but we do not yet specify how to connect to that CORBA server; that will be done after we've imported the definition.
Once you've added the IDL file to the project, Janeva will import and compile the IDL file and generate a corresponding .cs file - in our case a Birthday.cs file.
If you've made changes to the IDL file, you can always right-click on the IDL file to recompile it (and regenerate the Birthday.cs file).
In order to use the Birthday.cs file, we must add the CORBA namespace as well as the generated BirthdayReminder namespaces to our using clause of the WinForm.cs file.
Inside the WinForm constructor, we must create an instance of the ORB - the Object Request Broker that connects our client to the CORBA server.
This is done by calling CORBA.ORB.Init with the -vbroker.agent.port, 14000 arguments.
string[] args = new string[] {"-vbroker.agent.port", "14000"};
orb = CORBA.ORB.Init(args);
After this, we can use a button to create an instance of the CORBA Birthday object and call the Meeting method.
This can be seen in the last method of the complete listing below:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using CORBA;
using BirthdayReminder;
namespace BDSCorbaClient
{
///
/// Summary description for WinForm.
///
public class WinForm : System.Windows.Forms.Form
{
///
/// Required designer variable.
///
private System.ComponentModel.Container components = null;
private CORBA.ORB orb = null;
private BirthdayReminder.IBirthday MyBirthdayServer = null;
private System.Windows.Forms.Button button1;
public WinForm()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
string[] args = new string[] {"-vbroker.agent.port", "14000"};
orb = CORBA.ORB.Init(args);
}
///
/// Clean up any resources being used.
///
protected override void Dispose (bool disposing)
{
if (disposing)
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
///
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
///
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(56, 56);
this.button1.Name = "button1";
this.button1.TabIndex = 0;
this.button1.Text = "button1";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// WinForm
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 266);
this.Controls.Add(this.button1);
this.Name = "WinForm";
this.Text = "WinForm";
this.ResumeLayout(false);
}
#endregion
///
/// The main entry point for the application.
///
[STAThread]
static void Main()
{
Application.Run(new WinForm());
}
private void button1_Click(object sender, System.EventArgs e)
{
MyCorbaBirthdayServer =
ICorbaBirthdayServerHelper.Bind("Happy Birthday");
TDate Date = new TDate();
Date.Day = 10;
Date.Month = 9;
Date.Year = 1967;
MyBirthdayServer.RememberBirthday("Mira Swart", Date);
}
}
}
The Bind statement uses the same name - "Happy Birthday" - that we specified in the Delphi 7 CORBA Server to create an instance of the server object.
Janeva 6.0
The above C# code works just fine when using Janeva 1.0 (which is included with C#Builder Enterprise or higher) or Janeva 2.5 (which can be downloaded from the Borland website).
However, the latest version Janeva 6.0 does no longer support the BOA (Basic Object Adapter) by default.
In fact, it doesn't even generate the Bind methods that we're calling in the code above.
Fortunately, you can still force it to generate the Bind methods and tell it to use the BOA.
In order to generate the Bind methods, you need to call idl2cs outside of the C#Builder IDE with the -bind argument, as follows:
idl2cs -o Birthday.cs -bind -root_dir . Birthday.idl
And in order to tell the resulting client application to let Janeva use the VisiBroker OSAgent, you need to add some property values in the janeva configuration section of your application's config file.
In our case, the .config file should be as follows:
<configuration>
<configSections>
<section name="janeva" type="Janeva.Settings, Borland.Janeva.Runtime"/>
</configSections>
<janeva>
<agent enabled="true" port="14000"/>
</janeva>
</configuration>
Where the (OS)agent is enabled and the port is set to the default value of 14000.
If you migrate from Janeva version 1.0 or 2.5 to Janeva 6.0, then you may want to check out the Janeva 6.0 Release Notes for some important compatibility details (including more information about BOA support).
J2EE to .NET
Using JBuilder X, we'll create a J2EE Enterprise JavaBean with roughly the same functionality as the CORBA birthday reminder server, and we'll import the J2EE object using Janeva in C#Builder in order to show how to bind it to a C# client application.
For more information on Enterprise JavaBeans (EJB), Sudhansu Pati has written a white paper entitled EJB Development using Borland JBuilder X and Borland Enterprise Server 6.0 which provides an overview of creating, deploying, debugging, optimizing, and testing Enterprise JavaBeans (EJB) using Borland JBuilder X Enterprise and Borland Enterprise Server 6.0.
Once you have the EJB, you can use Janeva to connect to it (just like we did with the CORBA object).
As another reference, you can watch the BDNtv episode about Using Janeva to communicate between .NET and J2EE/CORBA, which shows how you can communicate via IIOP directly to a J2EE or CORBA server from .NET with Borland Janeva. In this episode, C#Builder is used to show how easy it is to take advantage of J2EE and CORBA from any .NET application.
Delphi 8 for .NET
If we can get Janeva to work in combination with Delphi 8 for .NET, then we'll also demonstrate Delphi 8 for .NET clients that can connect to and work with CORBA as well as J2EE server objects.
Pawel Glowacki has already written an article about Building CORBA applications with Delphi 8 and Janeva - Part 1 for the Borland Developer Network, where he shows the necessary steps to build simple CORBA server and client applications with Borland Janeva 6.0 and Borland Delphi 8 for .NET. Note that in that case, both the server and client are .NET based (instead of the Delphi 7 Win32 based CORBA server from earlier in this paper).
Summary
In this session, I've shown how Microsoft .NET Framework developers can use Borland Janeva to connect to CORBA servers that run on different platforms (like Win32, Linux and others).
Janeva offers a significant speed benefit over the use of web services when connecting .NET clients to server applications.
However, there are deployment issues and license fees that you have to pay - contact your local Borland office for details.
Bob Swart (aka Dr.Bob - www.drbob42.com) is an independent consultant, trainer, author & webmaster for Bob Swart Training & Consultancy (eBob42) using Delphi (for .NET), C#Builder, Kylix, and C++Builder, and has spoken at Delphi and Borland Developer Conferences since 1993.
Bob is a trainer who has presented all over the world (USA, BeNeLux, Germany, Italy, Singapore and for UK-BUG in London, Manchester, Reading and Edinburgh).
Bob has written his own training material, including the Delphi 8 for .NET Essentials and Delphi 8 for .NET ASP.NET courseware material licensed by Borland.
Bob is co-author of the Revolutionary Guide to Delphi 2, Delphi 4 Unleashed, C++Builder 4 Unleashed, C++Builder 5 Developer's Guide, Kylix Developer's Guide, Delphi 6 Developer's Guide, and the upcoming C++Builder 6 Developer's Guide, as well as author for a number of computer magazines, including The Delphi Magazine, Delphi Developer, UK-BUG Developer's Magazine, SDGN Magazine and Blaise, as well as the TechRepublic (CNET), DevX, Borland-IBM DB2 web portal and the Borland Developer Network website, and his own Dr.Bob's Delphi Clinic at http://www.drbob42.com.
Together with Marco Cantù, Bob received the Spirit of Delphi award in 1999 from Borland at BorCon.