Rinse
Overview
Rinse is to Delphi as RMI is to Java -- in other words, Rinse is a remote method
call architecture (similar to DCOM, SOAP, CORBA, etc.) that is
specifically designed to work with Delphi's type system. The most
frustrating thing about using other distributed application frameworks is
that they require you to "dumb down" your interfaces. You cannot take advantage
of the rich type system offered by Delphi. This has many negative implications
on software development.
With Rinse, you can develop distributed applications that make full use of
Delphi's type system. You can use objects (via interfaces), arrays (static,
dynamic, and open), sets, enumerations, sub-ranges, records, and variants
(including variant arrays) in your distributed applications. Rinse offers
a host of other features -- for more information, see the
Rinse Feature List.
Advantages
Rinse offers superior code reuse, because Rinse services can be used by any
of the following types of consumers: 2-tier applications, 3-tier clients,
3-tier servers, and web applications. Furthermore, Rinse services use the
ideal parameter types for the task at hand.
Rinse features an extensible, layered architecture, making it easy to add new
functionality to the communication framework. Rinse supports TCP/IP and HTTP
protocols, and additional protocols may be defined. Also, various features,
such as encryption, compression, session management, etc., can be implemented
as separate layers. In total, Rinse comes with 11 transport layers. The full
version of Rinse includes complete source code for these layers, along with
the rest of the library code that is compiled into your client and/or server
applications.
One of the most attractive features of Rinse is its automatic context management.
For each request from a client, Rinse manages a context object that holds
transactional resources such as database connections. If the server method
completes normally, Rinse will automatically commit any objects in the context.
However, if an exception is being returned to the client, then Rinse will
roll back any objects in the context. In a nutshell, this allows you to
implement your server-side methods without coding the tedious exception-handling
block in every method. For example, in DCOM, you might see...
procedure TRemoteDataMod.DeleteAllOrders;
begin
Database.StartTransaction;
try
Database.ExecSQL('delete from order_detail');
Database.ExecSQL('delete from cust_order');
Database.Commit;
except
Database.Rollback;
raise;
end;
end;
However, with Rinse, the exception-handling block is implemented automatically.
So, the above example would become...
procedure TRemoteDataMod.DeleteAllOrders;
begin
Database.ExecSQL('delete from order_detail');
Database.ExecSQL('delete from cust_order');
end;
Of course, sometimes you want to roll back the transaction without raising
an exception. Also, it is sometimes handy to be able to raise an exception
yet still commit the transaction. In these cases, you may simply call the
SetRollback or IgnoreExceptions methods of the context object.
In practice, the vast majority of server methods do not need to worry about
the context. Just go to the database, run your queries, and Rinse takes
care of the rest!
Rinse has already been used to build a dozen production applications -- including
this very website! We defined a handful of Rinse services to take care of the
database access, credit card processing, etc. This keeps the web pages
(DSP pages) clean, and isolates the business logic from the presentation.
Down the road, we could easily split these into two separate physical tiers,
but for now they both reside in a single process (the web server application).
Download Rinse
You can download a fully-functional trial version of
Rinse.
On-Line Resources
You can learn more about Rinse online in the following documents,
which are also included in the trial and full versions.
- The Rinse Tutorial is a good
step-by-step introduction to programming in Rinse. Each step builds
on previous steps, to create fully functional client and server projects
that illustrate the functionality of Rinse.
- The Rinse Introduction
is a good reference guide that discusses the various features of
Rinse. It is more detailed than the Rinse Tutorial, but does not
provide any examples of complete Rinse projects.
Sizing Up the Competition
Because Rinse is designed to work with the Delphi type system, it offers many
features missing from most other middleware frameworks. The highlights include:
- Polymorphism -
Surprisingly, many remote object technologies do not
support polymorphism. For example, Rinse allows you to declare a remote
method GetEmployee that returns an IEmployee object. When this
method is called, it may return an IEmployee object or any
inherited type, such as IManager or IConsultant. Of course,
Rinse also supports heterogeneous collections. For example, consider a
remote method that passes an array of some base type. The array may actually
contain elements of various types, as long as each is derived from the base
type. Naturally, Rinse supports polymorphism for function resuts and for
all parameters (input, output, and in/out parameters).
In many other remote object frameworks, polymorphism is not supported,
and as objects are passed between processes, they are "truncated" to the
declared type. Polymorphism is a fundamental concept of Object-Oriented
Programming, so its omission from a remote object framework is severly
limiting.
- Object Networks -
A network of objects is a collection of objects
that refer to one another. Examples include binary trees, linked lists,
and graphs in general. A more concrete example would be a Customer
object that includes Order objects for the customer. Rinse
transmits networks of objects intact. Specifically, if the same object is
referenced more than once in an object network, Rinse detects this and ensures
that the network is reconstructed faithfully on the recieving end. For
example, imagine a remote method that returns a collection of
Departments, each Department containing the Employees
who work in that Department. If a given Employee works in
multiple Departments, then the same Employee object would be
referenced by multiple Departments. When this data structure is
returned from the remote method, Rinse streams the Department and
Employee objects over the network, but it also detects duplicate
Employees. Of course, Rinse avoids writing the same object twice, but
instead writes a special reference so that the recieiving process knows to
re-use a previously sent object. While this may be complicated to explain,
it works automatically, helping to ensure that remote methods work as much
like regular methods as possible.
- Typed Exceptions -
Most remote object frameworks do not support
typed exceptions. Typically, they turn any exception raised on the server
into a simple exception that only has an error description (just a string).
However, Rinse allows you to transmit any type of exception from the server
to the client (you just need to register your exception with the streaming
system). Also, Delphi's standard exception types (EAbort,
EOverflow, EListError, EStreamError, etc.) are all
supported automatically.
- Method Overloading -
Simply use the overload keyword as you
nomally would when defining methods.
- Parameter Passing Modes -
Rine supports all four of Delphi's parameter
passing modes: pass-by-value, pass-by-reference (i.e., the var
keyword), constant reference (i.e., the const keyword), and
output (i.e., the out keyword). These four modes determine the
direction of information flow. For example, a parameter with the const
keyword (or no keyword at all) is an input parameter, so Rinse sends data
from the client to the server. A parameter with the var keyword is
an input/output parameter, so Rinse passes data from the client to the server,
and then back again when the method finishes. Finally, a parameter with the
out keyword is an output parameter, so Rinse sends nothing from the
client to the server, but does send a value in the opposite direction when
the method finishes.
- Warning Directives -
Rinse supports Delphi's warning directives:
library, platform, and deprecated. Just use these
keywords as you normally would when defining a method, type, or constant.
- Calling Conventions -
Rinse supports all of Delphi's method
calling conventions: register, stdcall, safecall,
pascal, and cdecl. Of course, the default is register,
but if for some reason you want one of the others, just use the appropriate
keyword as you normally would.
The common theme in the above list is that Rinse attempts to make remote methods
work like normal methods (as much as possible, anyway). This is very important
because developers don't have to learn two different sets of rules, and
constantly shift from one to the other. It also allows applications to be
migrated to a distributed architecture more easily. Finally, Rinse fully
supports OOP principles (encapsulation, inheritance, polymorphism, exceptions,
etc.), allowing developers to design their distributed applications in a
familiar, object-oriented fashion.
|