Architecture
Callbacks, JMS, asynchronous communication
Communication
Architecture
JProxy allows manipulate Java objects located on remote host (server). The classes
that represent such objects can be any Java classes. They do not have to be
serializable. The only requirement is that the class has to implement an interface.
JProxy can dynamically create on remote host stub class that implements and
delegates any number of requested interfaces. The stub class then can be used
to create stub instance to invoke methods on certain remote objects that implement
same set of interfaces.
JProxy runtime can create remotely object instance of any class and, if requested,
create stub for any of interfaces of object class.
All references to server objects and theirs stub instances are stored on JProxy
Sever in Object Hash. It allows managing lifetime of the objects. Each such
server object and stub reference is wrapped in special object that attaches
some properties such as Object's Time-to-Live (TTL), Object ID, Session ID,
etc. There is a special Timeout Thread on JProxy Server that periodically checks
object expiration time.
Usually JProxy Client cannot explicitly send signal to destroy certain server
object: the client can be just killed, or connection can be suddenly broken.
In this situation Object TTL expiration is reliable indication of time to remove
object reference from JProxy Server.
Just to make clearer: JProxy does not destroy server objects by itself it just
frees objects reference that allows utilizing JVM Garbage Collector. For instance
JProxy Server keeps in Object Hash EJB stub, and the hash item is expired. JProxy
Server does not call EJB "remove" method, it just delete reference
to the EJB object from Object Hash.
There is also other way to control server objects reference lifetime for asynchronous
objects. The method is based on validating client polling requests suspended
by JProxy Server.
So the described above JProxy functionality is very similar to such Distributed
Object Systems (DOS) as CORBA or RMI.
The functionality does not make JProxy very unique.
The real idea of JProxy is that a set of customizable logic automates implicit
stub creation and stub delivery.
The logic input is object request Java parameters, Java result returned and
method stack of methods invoked on the stub.
When method invoked on server object returns result to JProxy Server the returned
Java object is serialized with JProxy serializer before passing it to the network.
The serializer checks types of serialized objects if its instance of one from
the list of interfaces specified in customizable property. If match found then
JProxy Runtime substitute Java objects to generate JProxy stubs. Any interfaces
that implement one of interfaces enumerated in the property are considered as
remote. So, for instance, if class implements interface ICustomer which implements
java.rmi.Remote and Remote is mentioned in the property then ICustomer considered
as remote interface.
A reverse object substitution performed during object deserialization.
During object analysis JProxy Runtime also gets specifics of certain J2EE API
by examining objects and method invocation stacks on both client and server.
It helps, for instance, JProxy to recognize callback objects passing as parameters.
The result of such object substitution is creation of thin presentation of
server objects regardless of its nature.
The server object can be any remote object: RMI, CORBA, SOAP or EJB. Or it can
be JMS topic, JNDI context or even local object. JProxy can bring any server
functionality to the client. Only one requirement has to be satisfied: the object
functionality must be described in an interface. So, for instance, JProxy can
remote JNDI InitialContext because its functionality is specified in Context
interface.
Because of such flexibility JProxy simplifies callback object functionality.
With JProxy any local interface class instance can be passed to remote call.
Developer does not need to wrap object functionality in special classes and
then export object. Any non-remote aware objects can be become a server objects
and receive remote calls.
By default JProxy creates stubs for any instances of classes implementing java.rmi.Remote
and org.omg.CORBA.Object and some other J2EE specific objects. The list can
be customized. New user interfaces can be included. Interfaces that implement
one of such interfaces become remote interfaces. And during runtime JProxy will
automatically recognize such objects and make them remotely accessible.
There are two properties in JProxy used to specify such interface list. One
is for synchronous calls and other for asynchronous. A property for synchronous
interfaces is used during analyzing of result object from method invocation
on server objects. A property for asynchronous (or callback) property is used
during analyzing of method arguments for method invocation or construct request.
If same interface is mentioned in both properties then there is no matter if
the object was found in result or in method argument list.
Below is more detailed explanation of JProxy functionality.
The JProxy communication is initiated by obtaining initial stub for server
object. In this way it is similar to most of Distributed Object Systems. Usually
it is made in JNDI way (for EJB, RMI or JMS) by obtaining naming initial context.
For instance:
env.put(Context.PROVIDER_URL, serverUrl);
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.jproxy.proxy.NamingContextFactory");
Context context = new InitialContext(env);
com.jproxy.proxy.NamingContextFactory - is a JProxy JNDI SPI implementation
that allows implicitly activate JProxy communication.
During construction of InitialContext JProxy Client request JProxy Server to
create instance of InitialContext on the server. JProxy creates instance of
InitialContext locally and passes serializer.
And because the JProxy property for synchronous interfaces contains "javax.naming.Context"
the serializer replaces object with class javax.naming.InitialContext to stub
that implements javax.naming.Context.
From this point client gets initial JProxy stub (reference). And all subsequently
requested by "lookup" remote objects will be replaced to JProxy stubs.
By using JProxy you do not need presence of any provider specific classes on
the client. And it does not matter what API or Application Servers are utilized.
With exactly same client you can connect to JBoss or WebLogic. There are no
needs in different libraries to work with EJB, JMS or CORBA. Just one JProxy
Client is used for all varieties of Java technologies and server providers.
JProxy Client runtime is just about 100Kbytes. So small footprint and ability
to run in standard sand-box security model opens great potential to use J2EE
or other Java technologies from Web Browsers as a thin client.
Callbacks, JMS, asynchronous communication
A callback can be set by passing in remote call the callback receiver object
as an argument. Any number of arguments can be used. JProxy Client Runtime recognizes
callbacks from analyzing method arguments passed to JProxy stub. Each argument
class is compared with classes enumerated in property "com.jproxy.proxy.callback.classes"
Default property value - java.rmi.Remote, javax.jms.MessageListener, javax.jms.ExceptionListener,
org.omg.CORBA.Object
It is a list of interfaces. The Callback Object could be any object that is
instance of the class implementing either interface from the list.
If matched argument is found then JProxy replaces the argument to stub descriptor
and performs remote call as regular JProxy call.
At same time JProxy Client makes remote request to create HttpCallbackServer
remote object on JProxy Server.
HttpCallbackServer is similar to JMS Queue. The object has 2 main methods: "push"
for sender and ?pop? for receiver.
JProxy Client also starts thread that calls method "pop". When method
is called JProxy Client wait for return from the method. But moment of return
from the method is controlled by HttpCallbackServer running on JProxy Server.
If sender calls "push" then "pop" can be unblocked. Method
"pop" cannot be blocked for long time in order to support HTTP timeouts,
no more than several minutes. And HttpCallbackServer periodically allows return
from "pop" without any result. After return from ?pop? client immediately
calls the method again.
JProxy Server during deserialization replaces stub descriptors to special callback
stubs and then invokes call on "real" object. So when in JMS case
"setMessageListener(listener)" invoked, JMS Server will receive JProxy
callback stub in place of "listener" argument.
JProxy Callbacks implementation that JProxy Client Runtime is very similar
to Server Runtime: it also has ability to host remote objects, it has GC and
session support. It is very similar to CORBA with its ORB or RMI. But to keep
client small and able to work with sand-box security mode, JProxy Runtime misses
some functionality.
A communication with Client Runtime is possible only asynchronously via CallbackTunnel
because luck of Web-container on the client. It is also impossible to utilize
client-side HTTP server because of firewall issues. And all reason why HTTP
tunneling is used is to go through firewalls.
During setting of callback, client treats actual callback listener (receiver)
as remote object (or servant in CORBA). Client Runtime cannot generate dynamically
stub because of lack of functionality and security and this JProxy Server is
doing it for client. Client just sends stub request.
HttpCallbackServer is destroyed if receiver is not active even if sender is
still running.
During collecting of the object JMSException is thrown to the sender.
There are other callback related properties:
com.jproxy.proxy.callback.validate.receiver
It is a server property. Default - false.
If set to "true" HttpCallbackServer returns from "push"
requested by the sender only if callback receiver is active. During max time
(com.jproxy.proxy.callback.receiver.timeout) sender waits till receiver invoke
"pop" call. Only if sender finds out that callback receiver is alive
it will leave "push".
If "false" receiver validation is based only on delay since last "pop"
request from the client
The delay or timeout is specified by property below:
com.jproxy.proxy.callback.receiver.timeout
It is a server property. Default - 30000 (30 seconds).
Just to remind that since JProxy 2.0 all properties can be set outside of proxyservlet.war
or proxyclient.jar: in $JAVA_HOME/lib/proxy.properties
In order to set javax.jms.ExceptionListener the class name has to be present
in server property: com.jproxy.proxy.callback.classes.
If application server and JMS server (JBoss) was restarted it will not be able
to restore connection with callback clients. The only way to restore connection
is to do it explicitly from the client when it discovers that connection is
down. The server cannot restore connection with clients after start up because
all client-server communication is session-based, also each JProxy remote object
has unique time-based ID.
Communication
Currently JProxy utilizes HTTP/HTTPS for its communication with remote objects.
It makes JProxy very usable as generic HTTP Tunneling for different J2EE APIs
and server providers.
JProxy provides timeout functionality for HTTP communication.
According to Java API, java.net.URLConnection does not expose the underlying
socket. As result, you cannot explicitly set timeout for the socket.
Timeout capabilities in JProxy implemented in two ways:
First - based on overriding sun.net.www.protocol.http.HttpURLConnection, sun.net.www.protocol.http.Handler
and sun.net.www.http.HttpClient.
Second - using threads. Calling thread executes each remote call in separate
communication thread. Then calling thread waits for communication thread. And
if communication thread is still busy calling thread discards it and resume
working: starts new communication thread or throws exception. Later on discarder
communication threads will timeout and recycled by JVM Garbage Collector.
JProxy automatically selects which one must be used based on the Java Security
Model. If an applet does not have enough security privileges it selects threading
to support timeouts.
You may set default timeout in proxy.properties file in proxyclient.jar, or
specify different timeout for each remote object at runtime.
JProxy Runtime automatically attempts to avoid networking if it detects that
remote objects located in same instance of JVM. It greatly increases performance.
During all networking JProxy runtime measures performance of communication
and if detected performance is lower then specified in threshold property (com.jproxy.proxy.network.performance.threshold)
then JProxy uses data compression for current call. Later on if network resumes
working faster compression dynamically is turned off.
JProxy Tunnel supports simple failover mechanism.
Whenever a connection link is broken and from within your Applet you make a
remote call on and EJB interface JProxy Tunnel client runtime will detect that
there has been a failure and will try to reestablish the connection up to the
number of times that you specify in JProxy Tunnel client runtime configuration
file located in proxyclient.jar/com/jproxy/proxy/proxy.properties.
If it fails to do so, then JProxy tries to switch to a different App server
using comma separated values of com.jproxy.proxy.provider.url client property.
The switching is possible only during obtaining JNDI InitialContext and not
after.
JProxy Tunnel tries to reestablish the connection to your servers with no coding
involved on your part.
|