vinayc 2003/08/28 11:47:24
Added: xdocs client-usage.xml credits.xml facades.xml faq.fml
generating-proxies.xml index.xml monitors.xml
navigation.xml otherfeatures.xml pingers.xml
publishing.xml site.xml transports.xml
Log:
Refactorize (includes modularize,mavenize & rest of the nice's)
Revision Changes Path
1.1 incubator-altrmi/xdocs/client-usage.xml
Index: client-usage.xml
===================================================================
<?xml version="1.0"?>
<document>
<properties>
<author email="[EMAIL PROTECTED]">Paul Hammant</author>
<title>Client Usage</title>
</properties>
<body>
<section name="Introduction">
<p>
On the client you can choose to use JNDI or AltRMI's own clases to
lookup a
remote interface.
</p>
</section>
<section name="JNDI">
<p>
If you are using Ant for builds, then you can use the 'altrmiproxies'
taskdef
to make proxies in advance of use.
</p>
<source>
<![CDATA[
Hashtable env = new Hashtable();
env.put(
Context.INITIAL_CONTEXT_FACTORY,
"org.apache.altrmi.client.impl.naming.DefaultInitialContextFactory");
env.put(Context.PROVIDER_URL, "altrmi://somehost:1235/SocketCustomStream");
Context ctx = new InitialContext(env);
TestInterface ti = (TestInterface) ctx.lookup("Hello");
]]>
</source>
</section>
<section name="Custom AltRMI lookup">
<p>
Directly using AltRMI classes, you can lookup the same interface.
</p>
<source>
<![CDATA[
Factory factory = new ClientSideClassFactory(false);
factory.setHostContext(new SocketCustomStreamHostContext("somehost", 1235));
TestInterface ti = (TestInterface) af.lookup("Hello");
]]>
</source>
</section>
</body>
</document>
1.1 incubator-altrmi/xdocs/credits.xml
Index: credits.xml
===================================================================
<?xml version="1.0"?>
<document>
<properties>
<author email="[EMAIL PROTECTED]">Paul Hammant</author>
<title>Credits</title>
</properties>
<body>
<section name="Coders who've worked on AltRMI">
<p>
A broad group of people have contributed at various stages. Here
listed in alphabetical order:
</p>
<ol>
<li>Benjamin David Hall (patch)</li>
<li>Berin Loritsch</li>
<li>Mauro Talevi (pairing)</li>
<li>Mike Miller (patch submission)</li>
<li>Paul Hammant</li>
<li>Peter Royal</li>
<li>Thomas Kiesgen (patch submission)</li>
<li>Vinay Chandrasekharan</li>
</ol>
</section>
<section name="Forked code from other Apache projects">
<p>
We've borrowed code from elsewhere at Apache. Thus there are
accidental authors:
</p>
<ol>
<li>Anil K. Vijendran - JavaCompiler</li>
<li>Costin Manolache - JavaCompiler</li>
<li>Peter Donald - Dynamic Proxy</li>
<li>Sam Ruby - JavaCompiler</li>
</ol>
</section>
</body>
</document>
1.1 incubator-altrmi/xdocs/facades.xml
Index: facades.xml
===================================================================
<?xml version="1.0"?>
<document>
<properties>
<author email="[EMAIL PROTECTED]">Paul Hammant</author>
<title>Facade Design</title>
</properties>
<body>
<section name="Introduction">
<p>
AltRMI publishes an object via its interface. It does not replicate
the object
on the client side, it generates proxies for it defined as facades.
</p>
</section>
<section name="Facades">
<p>
Consider a system that models weather stations (fixed and mobile) and
the meterologists that staff the stations.....
</p>
<image src="images/facades.gif" alt="Picture of Facades"/>
<p>
The interfaces and the class on the right of the green line are
'interface'
or API, and we want them to exist as is on the client side for
general use. Things on the
left are the implementation classes and they exist on the server side
only. Though not
shown here, it would be easiest to have them in a separate package.
Representing those
objects on the client side are generated proxies. Proxies are
pass-by-reference
boundaries but are castable to any of the interfaces they represent.
There is one
pass-by-value object and that is Coordinate. It should be
serializable and final
(Immutable pattern).
</p>
<p>
The principle point of entry into the system from the client point of
view is
'WeatherSystem'. The mechanism of entry is a lookup on an agreed
name. We recommend
'WeatherSystem' or 'WeatherSystem_1.0' etc.
</p>
<p>
Once the client has a handle on the WeatherSystem normal Java
tarversals are possible
</p>
<source>
WeatherSystem ws = getWeatherSystem(); // some thing that does the JNDI
lookup.
// yes we know the following could throw NPEs or Array Index issues.
String aName =
ws.getWeatherStation("ArcticOne").getMeteorologists()[0].getName();
</source>
<p>
To generate the correct proxies for the above, you would want to have
the interface as
'WeatherSystem' and additional-facades of 'Meteorologist' and
'WeatherStation'
</p>
</section>
</body>
</document>
1.1 incubator-altrmi/xdocs/faq.fml
Index: faq.fml
===================================================================
<?xml version="1.0" encoding="UTF-8"?>
<faqs title="Frequently Asked Questions">
<part id="build">
<title>Building AltRMI</title>
<faq id="howto">
<question>
HowTo build AltRMI?
</question>
<answer>
<p>
AltRMI project comes with both <link href="ext:ant">Ant</link> as
well as <link href="ext:maven">Apache Maven</link> to
build the source+documentation.
</p>
</answer>
</faq>
</part>
</faqs>
1.1 incubator-altrmi/xdocs/generating-proxies.xml
Index: generating-proxies.xml
===================================================================
<?xml version="1.0"?>
<document>
<properties>
<author email="[EMAIL PROTECTED]">Paul Hammant</author>
<title>Generating Proxies</title>
</properties>
<body>
<section name="Introduction">
<p>
You can choose to generate your proxies in advance of use, or to
defer generation
until runtime. As the generation requires javac in tools.jar (multi
megabyte), you
have to decide whether your runtime environment or distribution can
support or
legally distribute it.
</p>
</section>
<section name="Generation in advance">
<p>
If you are using Ant for builds, then you can use the 'altrmiproxies'
taskdef to make
proxies in advance of use.
</p>
<source>
<![CDATA[
<altrmiproxies genname="Hello" srcgendir="${build.home}/genjava"
classgendir="${build.home}/classesection" verbose="true"
interfaces="org.apache.altrmi.test.TestInterface"
additionalfacades="org.apache.altrmi.test.TestInterface2">
<classpath>
<pathelement location="${build.home}/classes"/>
</classpath>
</altrmiproxies>
]]>
</source>
<p>
All you have to do after that is place them in a jar for later use.
That jar could be
client or server-side, thus classes can be retrieved from the server
for use on the client
or preexist in clients environment.
</p>
</section>
<section name="Generation at runtime">
<p>
If you are using Ant for builds, then you can use the 'altrmiproxies'
taskdef to make
proxies in advance of use.
</p>
<source>
<![CDATA[
DynamicGeneratorClassRetriever dgcr = new
DynamicGeneratorClassRetriever(mGenJarURL);
PublicationDescription pd = new PublicationDescription(TestInterface.class,
new Class[] { TestInterface2 });
dgcr.generate("Hello", pd, this.getClass().getClassLoader());
]]>
</source>
<p>
This by implication means server-side classes, so the above is code in
the server. It also
has a performance hit at time of first retrieval.
</p>
</section>
</body>
</document>
1.1 incubator-altrmi/xdocs/index.xml
Index: index.xml
===================================================================
<?xml version="1.0"?>
<document>
<properties>
<author email="[EMAIL PROTECTED]">Paul Hammant</author>
<title>Overview</title>
</properties>
<body>
<section name="Introduction">
<p>
AltRMI is a from-scratch replacement for RMI. It has a number of
different features
that make it easier to use. It tries as far as possible to be
transparent in use. It
is also inspired by the remoting facility in .NET. This does not
mean that it has SOAP
capabilty (yet), as it is more like the proprietary RPC transport for
the .NET framework.
</p>
<p>
The name AltRMI is inspired by the 'alt' usenet newsgroup hierarchy.
We have thought about
renaming it especially as alt means old in German. DRMI (Distributed
RMI), PMI (Proxied
Method Invocation), ARC (Apache Remote Control) and JRemoting were
all considered as
replacements, but for now we stick with AltRMI.
</p>
<p>
The mail list for this project is 'projects at incubator.apache.org'.
Subscribe
<link href="mailto:[EMAIL PROTECTED]">here</link>. Please mark your
emails with a subject of [altrmi] + your normal subject choice.
</p>
</section>
<section name="Feature Differences">
<p>
Some good, some bad:
</p>
<ul>
<li>It transports normal Java interfaces (no need to extend
java.rmi.Remote)</li>
<li>None of the remote capable methods have to throw
java.rmi.RemoteException.</li>
<li>Compared to RMI in use for EJB, it does not transport over CORBA
(yet).</li>
</ul>
</section>
<section name="Connection Robustness">
<p>
Given that there are <link
href="http://java.sun.com/people/jag/Fallacies.html">eight
fallacies of distributed computing</link>, we feel it important to
show that AltRMI
is not ignoring these issues.<br/>
The principal benefit for a developer making beans or an application
server is
that RemoteException is missing. That does not mean that
communications failure
is ignored. AltRMI still illustrates communication failure via
InvocationException which a subclass of RuntimeException. This
basically
allows the exception to be thrown, but not specified on each method
(like
RemoteException does). Many feel that allowing the bean developer to
ignore the robustness issues is a mistake. We think not given the
following.
</p>
<ol>
<li>The container could be programmed to know about
InvocationException.</li>
<li>AltRMI has configurable policies that can help re-establish
connection whilst in use.</li>
<li>Standard handling of RemoteException sucks.</li>
<li>It is difficult in EJB, in terms of coverage, to test your huge
amounts of
RemoteException handling code.</li>
<li>Most web-app uses of beans have a single "handler" place where
pertinent
exceptions are already caught.</li>
</ol>
<subsection name="1. The container could be programmed to know about
InvocationException">
<p>
A lot of beans coding is 'bean invokes method in bean which invokes
method in bean'. In
this case there are several places in the invocation stack where
the container's logic
is delegating between beans. Container could easily handle failing
connections and take
multiple actions: re-establish report, redirect, abend services or
server. If there is
a configurable policy for such events that may include the invoking
of methods in,
say, 'contingency' beans.
</p>
</subsection>
<subsection name="2. AltRMI has configurable policies that can help
reestablish connection whilst in use.">
<p>
AltRMI has a pluggable architecture for re-establishing connections
(and reporting timings
etc). Whilst in the middle of an invocation, if the connection is
lost, AltRMI can try to
re-establish the connection and complete the method invocation
normally. A delay would of
course be encountered, but if administrators are watching the logs,
then they can determine
where failures are happening and what to do long term about it.
Programmed policies
(configured in the container) could be "try perpetually to
reconnect", "try five times only,
one a second", "fail immediately".
</p>
</subsection>
<subsection name="3. Standard handling of RemoteException sucks.">
<p>
Referring to the various ways EJB teams handle RemoteException, in
the thousands of places
in a typical J2EE solution where it is thrown, different solutions
are...<br/>
</p>
<subsection name="3.1. Declare throws RemoteException on every
applicable method">
<p>
That means that it can often arrive back at the container. The
container always reports
it verbosely.<br/>
</p>
</subsection>
<subsection name="3.2. Have a standard catch block and pass the
RemoteException to a standard handle
method that does something with it.">
<p>
That something can often by turn it into a custom derivative of
RuntimeException as well
as reporting it. This strategy makes you wonder why it was not
a derivative of
RuntimeException in the first place.<br/>
</p>
</subsection>
<subsection name="3.3. Try the failing method call again, or n
times.">
<p>
Clutters your code with reams of retry logic. What if it still
fails? Combine this
with (1) or (2) as well?
</p>
</subsection>
</subsection>
<subsection name="4. It is difficult in EJB, in terms of coverage, to
test your huge amounts of
RemoteException handling code">
<p>
Your EJB team has developed a huge amount of code for the business
logic, and consequentually
loads of code concerning RemoteException. Question how do they
test the "connection failing"
logic? Do they rip out cables while the machine is in use? No
that does not yield good
coverage. Do they have test cases and mock beans that throw
RemoteException? Yes probably,
but that is an artificial connection outage. However most teams do
not test more than a
single case, and are happy for the same RemoteException handler
block to be used all over
the place.
</p>
</subsection>
<subsection name="5. Most web-app uses of beans have a single 'handler'
place where pertinent
exceptions are already caught.">
<p>
Webapps that use multiple beans (assuming a decent MVC separation
or a framework like
Velocity) already have a place where central exception handling is
going on. With
AltRMI, you can catch InvocationException where you feel is fit.
EJB teams that
choose to have throws RemoteException on all methods (percolating
it up the stack) probably
also choose to finally handle it centrally. Like so ...
</p>
<source>
public Template handleRequest(HttpServletRequest req, HttpServletResponse
resp, Context ctx) {
Template template = null;
String templateName = null;
HttpSession sess = req.getSession();
sess.setAttribute(ERR_MSG_TAG, "all ok");
try {
try {
// Process the command
templateName = processRequest(req, resp, ctx);
// Get the template
template = getTemplate(templateName);
} catch (InvocationException aie) {
template = getTemplate("commfailure.vm");
}
} catch (ResourceNotFoundException rnfe) {
// blah blah
} catch (ParseErrorException pee) {
// blah blah
} catch (Exception e) {
// blah blah
}
return template;
}
</source>
</subsection>
</section>
</body>
</document>
1.1 incubator-altrmi/xdocs/monitors.xml
Index: monitors.xml
===================================================================
<?xml version="1.0"?>
<document>
<properties>
<author email="[EMAIL PROTECTED]">Paul Hammant</author>
<title>Monitors</title>
</properties>
<body>
<section name="Introduction">
<p>
Both the server and client sides of AltRMI can be monitored. After
instantiation, the Server or Factory have a setMonitor() methods.
</p>
</section>
<section name="Server Monitor">
<p>
The interface for the ServerMonitor is :
</p>
<source>
<![CDATA[
public interface ServerMonitor {
void closeError(Class clazz, String s, IOException e);
void badConnection(Class clazz, String s, BadConnectionException bce);
void classNotFound(Class clazz, ClassNotFoundException e);
void unexpectedException(Class clazz, String s, Exception e);
void stopServerError(Class clazz, String s, Exception e);
}
]]>
</source>
<p>
You get to choose from a number of implementations. NullServerMonitor
consumes all monitored events. LogEnabledServerMonitor,
CommonsLoggingServerMonitor and Log4JServerMonitor route through to
the
appropriate logging framework. You do not have to tie the
application
you develop (that needs to use AltRMI) to any particular logging
framework. If you so desire, you do not need any logging jar in
your classpath (or classloader tree for more complex deployments).
</p>
</section>
<section name="Client Monitor">
<p>
The interface for the ClientMonitor is :
</p>
<source>
<![CDATA[
public interface ClientMonitor
{
void methodCalled(Class clazz, String methodSignature, long duration,
String annotation );
boolean methodLogging();
void serviceSuspended(Class clazz, Request altrmiRequest, int attempt,
int suggestedWaitMillis );
void serviceAbend(Class clazz, int attempt, IOException cause);
void invocationFailure(Class clazz, String name, InvocationException ie);
void unexpectedClosedConnection(Class clazz, String name,
ConnectionClosedException cce);
void unexpectedInterruption(Class clazz, String name,
InterruptedException ie);
}
]]>
</source>
<p>
The ClientMonitor has a couple of novel feautes over ServerMonitor
(which just listens).
The first is that timings for method calls can be reported on. As
timing costs time, the
ClientMonitor reports whether it wants timing at all. The second is
that
serviceSuspend() and serviceAbend() encourages the implementor to
join in
with whether the pending request will fail or try again. It does
this by throwing
InvocationException. Different strategies (fail-fast, retry-forever)
are possible, but
clearly they affect the way client code works.
</p>
<p>
As with the ServerMonitor, you get to choose from a number of
implementations.
DumbClientMonitor consumes all monitored events without logging
anything and
fails-fast for the two abend() and suspend() methods.
DefaultClientMonitor,
still logs nothing, but tries for a few attempts to reestablish a
connection.
</p>
</section>
</body>
</document>
1.1 incubator-altrmi/xdocs/navigation.xml
Index: navigation.xml
===================================================================
<?xml version="1.0" encoding="UTF-8"?>
<project>
<title>AltRMI</title>
<body>
<links>
<item name="Home" href="http://incubator.apache.org/projects/altrmi"/>
<item name="Apache" href="http://www.apache.org/"/>
</links>
<menu name="About">
<item name="Index" href="/index.html"/>
<item name="Other Features" href="/otherfeatures.html"/>
<item name="Transports" href="/transports.html"/>
<item name="FAQ" href="/faq.html"/>
<!-- <item name="Changes" href="changes.html"/> -->
<item name="Credits" href="/credits.html"/>
<!-- <item name="Todo" href=""/> -->
</menu>
<menu name="Modules">
<item name="Client" href="/client/index.html"/>
<item name="Server" href="/server/index.html"/>
<item name="Tools" href="/tools/index.html"/>
</menu>
<menu name="Tests">
<item name="Integration Tests"
href="/integrationtests/index.html"/>
</menu>
<menu name="Using">
<item name="Facade Design" href="/facades.html"/>
<item name="Generating Proxies" href="/generating-proxies.html"/>
<item name="Publishing" href="publishing.html"/>
<item name="Client Usage" href="client-usage.html"/>
<item name="Pingers" href="pingers.html"/>
<item name="Monitors" href="monitors.html"/>
<!-- <item name="Tests" href="tests.html"/> -->
</menu>
</body>
</project>
1.1 incubator-altrmi/xdocs/otherfeatures.xml
Index: otherfeatures.xml
===================================================================
<?xml version="1.0"?>
<document>
<properties>
<author email="[EMAIL PROTECTED]">Paul Hammant</author>
<title>Other Features</title>
</properties>
<body>
<section name="Features">
<p>
There are various features of AltRMI that are either different to RMI
or are configurable.
</p>
<subsection name="Choice of location of generated Proxy class">
<p>
Classes providing client side implementation of the transported
interface(s) can be either on the client side or the server side (and
duly transported) at the time of lookup. On the server side, the
proxy classes
can be generated in advance (Ant Task) or at runtime - javac is
invoked.
</p>
</subsection>
<subsection name="Choice of castability of generated proxy class.">
<p>
To suit remote facilities that are happy with refection and do
not need to cast to an interface to use a bean (I am thinking of
BeanShell) the proxy class can be generated without specifying
that it implements the interface(s).
</p>
</subsection>
<subsection name="Suspendable/Resumable service.">
<p>
The Server supports suspend() and resume(). With the current
implementation this
replies in a timely fashion to the client that the client should try
later. The client waits for the notified amount of time and
seamlessly
tries the request again. A server could cycle through suspended and
back
to resumed will not affect the client except for the a delay.
</p>
</subsection>
<subsection name="Recovering transport">
<p>
AltRMI tries to recover its transports should they fail. The
recovery
is pluggable in that the developer can choose when/how/if the
connection
handler tries to recover the connection. Any inprogress, but
disconnected method invocation will attempt to be recoved and just
return
as normal, albeit after a longer than normal delay.
</p>
</subsection>
<subsection name="Event API">
<p>
For suspensions, abnormal ends of connection etc, there is a
listener
that can be set that will allow actions to be taken. Abnormally
terminated connections will by default try to be reconnected, the
listener can decide if, how many, and how often the retries occur.
</p>
</subsection>
<subsection name="Pluggable Transport indenpendant keep-alive concept">
<p>
On the client side, there is an API for a pluggable pinger. While
the server
may support timeouts for client connections, the client could choose
to
overcome that default policy with a ping concept.
</p>
</subsection>
<subsection name="Unpublishable and republishable API">
<p>
The server is able to unpublish a service. In conjuction with
suspend()/resume() a service can be republished, upgraded etc
whilst in use, or just offlined.
</p>
</subsection>
<subsection name="Startable API for Server">
<p>
The server implements and acts upon start() and stop() methods.
</p>
</subsection>
<subsection name="Not just pass by value.">
<p>
AltRMI started life as 'pass by value' only. In now supports
return
types and parameters wrapped in another AltRMI Facade.
</p>
</subsection>
<subsection name="No duplicate instances.">
<p>
For Facades, if you call Person p = getPerson("Fred") twice you
will get
the same instance on the client side if it is the same instance on the
server side.
</p>
</subsection>
<subsection name="Load balancing server grouping">
<p>
In some configurations, the client side can have multiple servers
it
will forward calls to (TODO).
</p>
</subsection>
</section>
</body>
</document>
1.1 incubator-altrmi/xdocs/pingers.xml
Index: pingers.xml
===================================================================
<?xml version="1.0"?>
<document>
<properties>
<author email="[EMAIL PROTECTED]">Paul Hammant</author>
<title>Pingers</title>
</properties>
<body>
<section name="Introduction">
<p>
Although it may not be necessary for all types of transport,
there is a mechanism called a pinger that can be used to keep
the connection alive. Pingers run on the client side.
</p>
</section>
<section name="Pinger Interface">
<p>
It is possible to write your own or extend the exiting
ones if there are different requirements. The interface for bespoke
pingers
is 'ConnectionPinger'
</p>
<source>
<![CDATA[
public interface ConnectionPinger
{
void setInvocationHandler( ClientInvocationHandler
altrmiInvocationHandler );
void start();
void stop();
}
]]>
</source>
</section>
<section name="Pinger types">
<p>
Here are the types of pinger implemented so far
</p>
<subsection name="DefaultConnectionPinger">
<p>
This pinger pings every ten seconds, but stops one hundred seconds
after the last real request. The 10 & 100 are configurable of
course.
</p>
<p>
This pinger is the default and will be used if no other is
specified.
</p>
</subsection>
<subsection name="PerpetualPinger">
<p>
This pinger pings every ten seconds until the connection is closed.
</p>
</subsection>
<subsection name="NeverConnectionPinger">
<p>
This pinger never pings the server.
</p>
</subsection>
</section>
</body>
</document>
1.1 incubator-altrmi/xdocs/publishing.xml
Index: publishing.xml
===================================================================
<?xml version="1.0"?>
<document>
<properties>
<author email="[EMAIL PROTECTED]">Paul Hammant</author>
<title>Publishing</title>
</properties>
<body>
<section name="Introduction">
<p>
Publishing is a server responsibility obviously, it is quite straight
forward.
</p>
</section>
<section name="Publishing">
<p>
You have to choose your server, publish the implimentation
(reiterating the interfaces that will
be pass-by-reference boundaries), then start the server.....
</p>
<source>
<![CDATA[
AbstractServer as = new CompleteSocketCustomStreamServer(1235);
TestInterfaceImpl ti = new TestInterfaceImpl();
as.publish(ti, "Hello", new
PublicationDescription(TestInterface.class, TestInterface2.class));
as.start();
]]>
</source>
<p>
After starting the server client connections will be accepted.
</p>
</section>
</body>
</document>
1.1 incubator-altrmi/xdocs/site.xml
Index: site.xml
===================================================================
<?xml version="1.0"?>
<site label="AltRMI" href="" xmlns="http://apache.org/forrest/linkmap/1.0">
<about label="About">
<index label="Index" href="index.html"/>
<item href="otherfeatures.html" label="Other Features"/>
<item href="transports.html" label="Transports"/>
<faq label="FAQ" href="faq.html"/>
<changes label="Changes" href="changes.html"/>
<todo label="Credits" href="credits.html"/>
<todo label="Todo" href="todo.html"/>
</about>
<about label="Using">
<item href="facades.html" label="Facade Design"/>
<item href="generating-proxies.html" label="Generating proxies"/>
<item href="publishing.html" label="Publishing"/>
<item href="client-usage.html" label="Client usage"/>
<item href="pingers.html" label="Pingers"/>
<item href="monitors.html" label="Monitors"/>
<item href="tests.html" label="Tests"/>
</about>
<external-refs>
<xml.apache.org href="http://xml.apache.org/">
<forrest href="forrest/">
<validation href="validation.html"/>
<webapp href="your-project.html#webapp"/>
</forrest>
<cocoon href="cocoon/"/>
</xml.apache.org>
</external-refs>
</site>
1.1 incubator-altrmi/xdocs/transports.xml
Index: transports.xml
===================================================================
<?xml version="1.0"?>
<document>
<properties>
<author email="[EMAIL PROTECTED]">Paul Hammant</author>
<title>Transports</title>
</properties>
<body>
<section name="Introduction">
<p>
AltRMI has pluggable and reimplementable transports. They differ in
terms of speed and layers of transport.
Some are in VM, others between VMs using sockets and various Java
concepts.
</p>
</section>
<section name="Supplied Request/Response Transports">
<p>
The supplied transports fall into two categories - Intra-JVM and
Inter-JVM. The Inter-JVM types are for
bridging a network divide over TCP/IP. This can also mean two JVMs
in the same physical machine, using
local-loop TCP/IP. The Intra-JVM types are for situations where
normal dynamic proxy will not work. For
example when the client and the server both have a definition of the
same interface in different
classloaders. Most Java projects do not involve trees of
classloaders, but writing frameworks like
Avalon-Phoenix or or an implementation of the EJB specification will.
</p>
<p>
All of these transports are synchronous too. That means that an
invocation across their connection
will wait until it is completed server side before the next
invocation is allowed through.
</p>
<subsection name="Plain Sockets / ObjectStream & CustomStream
varients">
<p>
This transport is a streaming type that uses serialization of
objects over a TCP/IP connection. There
are two variations. The first uses java.io.ObjectInputStream &
java.io.ObjectOutputStream (AKA
'ObjectStream', the second uses what we call 'CustomStream'.
CustomStream came into being because of this
bug <link
href="http://developer.java.sun.com/developer/bugParade/bugs/4499841.html">
http://developer.java.sun.com/developer/bugParade/bugs/4499841.html</link>
which seriously restricts the usefulness of ObjectStream as a
transport
(and the same java.io classes for other uses). Custom Stream is
slower by 20%, but we recommend it's use
over ObjectStream. At least until the bug at Sun is fixed (please
vote for it).
</p>
</subsection>
<subsection name="Over RMI">
<p>
This is another transport that bridges two different JVMs using
TCP/IP. It is actually the fastest of all the
TCP/IP using transports. and takes advantage of RMI as it's
transport while hiding RMI from the AltRMI
client and server.
</p>
</subsection>
<subsection name="Piped with same VM / ObjectStream & CustomStream
varients">
<p>
In a similar way to the ObjectStream and CustomStream
implementations of the plain sockets transport, these
offer transport using a pipe inside the JVM. Not needed for most
users of AltRMI these prove useful for
developers making complex trees of classloaders with high
separation from each other. As a Pipe is being
used there is is some opportunity for buffering of invocations.
This might slow the throughput down but
this may relieve other parts of a particular design.
</p>
</subsection>
<subsection name="Direct within same VM">
<p>
There are 'Direct' and 'DirectMarshalled' transports. These are
use useful in the same scenarios as
the Piped one, but with some small differences. Principally, there
is no pipe - the invocation is
immediately handled on the server side. With Direct there is also
the fact that all mutually visible
classes and interfaces would have to be in a commonly visible
classloader. With DirectMarshalled,
there can be duplicate interfaces and class definitions as in the
streamed types of transport.
</p>
</subsection>
<subsection name="JNDI">
<p>
Many of the basic transport types are accessible client side
through JNDI. This makes the client side usage
more standards compliant, but these is no need to choose it over
the bespoke AltRMI client usage at all.
</p>
</subsection>
</section>
<section name="Supplied Callback capable Transports">
<p>
All of these transports are asynchronous. Thais means that an
invocation across the connection
does not wait until the reply is ready before it allows another
request though. This allows
two things - excpetionally lengthy requests (that might ordinarily
affect timeouts) to be performed and
callbacks (server invoking requests on the client). There is a small
(15%) cost to using this transport for
simple cases, but its benefits outweigh its deficiencies.
</p>
<p>
Whilst the Callback enabled transports are better from the point of
view of asynchronous behaviour
</p>
</section>
<section name="Future Transports">
<p>
</p>
<ul>
<li>SOAP - Might require additional undynamic "toWSDL()" step.</li>
<li>CORBA - Might require additional undynamic "toIDL()" step.</li>
<li>JMS</li>
<li>UDP</li>
<li>Over RMI over IIOP</li>
<li>Over JMS</li>
<li>Over RMI over HTTP</li>
<li>Over HTTP (custom impl)</li>
<li>TLS enabled versions of many of the above.</li>
</ul>
</section>
<section name="Speed">
<p>
Counting the number of 'void testSpeed()' invocations in 10 seconds,
we can guage the differences (Paul's Athlon900/Win2K machine)
</p>
<subsection name="AltRMI types over TCP/IP">
<p>
For remote publication<br/>
<br/>
Speed Test type Count Relative<br/>
------------------------------- ------- --------<br/>
a) ObjectStream over sockets #2 2702 1.00<br/>
b) Over RMI 4359 1.61<br/>
c) CustomStream over sockets 6069 2.25<br/>
d) ObjectStream over sockets #1 10088 3.73<br/>
</p>
</subsection>
<subsection name="AltRMI types in the same VM">
<p>
These are useful for complete classloader separation of interface
& implementation using
different classloaders. The implementation and 'remote' proxy do
not need to see the same
interfaces etc..<br/>
<br/>
Speed Test type Count Relative<br/>
------------------------------- ------- --------<br/>
e) ObjectStream over Pipe #2 12095 4.48<br/>
f) Direct Marshalled #3 20759 7.68<br/>
g) ObjectStream over Pipe #1 61166 22.64<br/>
h) Direct Unmarshalled #4 2391498 885.08<br/>
#1 Without calling reset() as workaround to the ObjectStream bug
#2 With calling reset() as workaround to the ObjectStream bug
#3 Completely separates classloaders of client and server. Requires
a thread for each though.
#4 Good as DynamicProxy for separation. Does not separate
classloaders
of client and server.
</p>
</subsection>
<subsection name="Non AltRMI types">
<p>
- In VM, without using AltRMI - for comparison.
- The inteface, implementation and proxy cannot be separated in
terms of
branches of classloader for these three. The same interfaces
etc must be visible to both implementation and proxy.
<br/>
Speed Test type Count Relative<br/>
------------------------------- ------- --------<br/>
i) DyanmicProxy #5<br/>
(copied from Excalibur) 20282070 7506.32<br/>
j) Hand-coded proxy #5 41214422 15253.30<br/>
k) No Proxy #5 42384804 15686.46<br/>
<br/>
#4 - For all of these three, the actual timing may slow down the
test.<br/>
</p>
</subsection>
</section>
<section name="Secrets of classloading">
<p>
There is a feature of classloading that affects the way that the an
AltRMI using client and server interoperte
when it comes to resolving classes and interfaces for a given object.
As is widely known, the JVM resolves
depended on classes for a being-instantiated object at runtime. The
issue concerns a class definition existing
twice in a tree of classloaders and whther the JVM considers an
instance of each to be of the same type.
</p>
<p>
Consider a tree of three classloaders - A, B and C. Consider that A
is the parent classloader of B & C.
This means that B can access all the classes mounted by itself and by
A. Similarly C can access all the
classes mounted by itself and A. Now if A had a singleton that
stored a single object via
<strong>void setObject(object o);</strong> and <strong>Object
getObject();</strong>, and clases in
B amp; C could invoke those methods freely, the you might consider
that B has a way of taking to C. if B
called (essentially) <strong>A.setObject("Hello")</strong>, then C
could indeed call <strong>String
s = A.getObject()</strong> without any problem. Say a class being
passed were called 'Thing' and was in the
classloader of B and duplicated in the classloader of C, but not in A
at all, then it would not be passable
by the setter/getter mechanism outlined above. Why? The JVM
considers then different classes because they
are mounted in different classloaders (even though from the same
source). That is a secret
of classloading (at least as it pertains to RPC in one VM).
</p>
<p>
The issue is relevent to AltRMI mostly if it is being used to connect
two nodes of a single classloader tree.
If the transport chosen is 'Direct' then you will get
ClassCastExceptions thrown by the JVM if you had been
passed an Object you wanted to cast up to something, and that
something were represented by a class definition
in both the server and client nodes of the classloader tree. If the
something class were in a mutualy
visible parent class loader then no issue would be apparent. IF the
client and server were in separate VMs,
then no issue would be apparent, principally because the marchalling
to serialized form neatly hides the
two class definitions from the JVM. This is the clue to the solving
of the issue for a particular
client/server (in one JVM) configuration you may be cooking up. If
you choose Piped or DirectMarshalled as
trasnports, then you can have the same class definition in multiple
classloader nodes. Of couse, both Piped
and DirectMarshalled are slower than Direct as transports.
Configuration choices for the developer/deployer.
</p>
</section>
</body>
</document>
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]