I would like to call an ejb3 at runtime. The name of the ejb and the method name will only be available at runtime, so I cannot include any remote interfaces at compile time.
String bean = 'some/Bean';
String meth = 'doStuff';
//lookup the bean
Object remoteInterface = (Object) new InitialContext().lookup(bean);
//search the method ..
// foreach (methods)
// if method == meth, method.invoke(bean);
the beans should be distributed accross multiple application servers, and all beans are to be called remotely.
Any hints? specifically i do not want:
dependency injection
inclusion of appliation specific ejb interfaces in the dispatcher (above)
webservices, thats like throwing out processing power for nothing, all the xml crap
Is it possible to load an ejb3 remote interface over the network (if yes, how?), so I could cache the interface in some hashmap or something.
I have a solution with a remote dispatcher bean, which I can include in the above main dispatcher, which does essentially the same, but just relays the call to a local ejb (which I can lookup how? naming lookup fails). Given the remote dispatcher bean, I can use dependency injection.
thanks for any help
(netbeans and glassfish btw)
ejb3 calls use RMI. RMI supports remote class loading, so i'd suggest looking into that.
also, JMX mbeans support fully untyped, remote invocations. so, if you could use mbeans instead of session beans, that could work. (JBoss, for instance, supports ejb3-like mbeans with some custom annotations).
lastly, many app servers support CORBA invocations, and CORBA supports untyped method invocations.
You might be able to use java.rmi.server.RMIClassLoader for the remote class loading. You'll also need to load any classes that the remote service returns or throws.
It cannot be done. You will always get a "class not found" exception. That is in my opinion the biggest disadvantage of EJB/Java. You loose some of the dynamcis, because the meta-language features are limited.
EJB3 supports RMI/IIOP, but not RMI/JRMP (standard RMI) so dynamic class loading is not supported.You loose some Java generality, but gain other features like being able to communicate about transactions and security.
You need to use reflection for this, and it is very simple to do. Assuming that you're looking for a void method called meth:
Object ejb = ctx.lookup(bean);
for (Method m : ejb.getClass().getMethods()) {
if (m.getName().equals(meth) && m.getParameterTypes().length == 0) {
m.invoke(service);
}
}
If you're looking for a specific method signature just modify the m.getParameterTypes() test accordingly, e.g. for a method with a single String parameter you can try:
Arrays.equals(m.getParameterTypes(), new Class[]{String.class})
And then pass an Object[] array with the actual arguments to the m.invoke() call:
m.invoke(service, new Object[]{"arg0"})
Related
We have several legacy java-services with RMI-api, implemented by the old JRMP approach requiring 'rmic' pre-compilation.
As part of migrating everything to latest JDK,
I am also trying to rewrite the RMI stuff to the more current approach, where the implementation-classes extend from UnicastRemoteObject, thus getting rid of the rmic pre-compilation step.
Following a simple example, like here:
https://www.mkyong.com/java/java-rmi-hello-world-example/
but I have not been able to find such example with commit/rollback transaction-logic.
In the current legacy-code, all transaction-logic is handled in a single, common method invokeObject() in the JRMP container-code that will intercept all RMI api-calls in one place,
and will simply commit if the RMI-call is successful, or rollback if an Exception was thrown.
I haven't been able to figure out how to do this in the new approach with no JRMP container present.
Obviously, I do not want to code commit/rollback-logic into every single api-method (there are many dozens of them),
but still keep that uniform logic in one place.
Any advice, hints, references, etc, how to intercept all RMI-calls in a single point to implement the transaction-logic?
To begin with, I agree with #df778899 the solution he provides is a robust solution. Although,I will give you an alternative choice if you don't want to work with spring framework and you want to dig it further.
Interceptors provide a powerful and flexible design include invocation monitoring, logging, and message routing. In some sense, the key value you are looking is a kind of RMI-level AOP (aspect-oriented programming) support
Generally speaking:
it is not fair to ask RMI to directly support such capabilities as it
is only a basic remote method invocation primitive, while CORBA ORB is
at a layer close to what the J2EE EJB (Enterprise JavaBean) container
offers. In the CORBA specification, service context is directly
supported at the IIOP level (GIOP, or General Inter-Orb Protocol) and
integrated with the ORB runtime. However, for RMI/IIOP, it is not easy
for applications to utilize the underlying IIOP service-context
support, even when the protocol layer does have such support. At the
same time, such support is not available when RMI/JRMP (Java Remote
Method Protocol) is used. As a result, for RMI-based distributed
applications that do not use, or do not have to use, an ORB or EJB
container environment, the lack of such capabilities limits the
available design choices, especially when existing applications must
be extended to support new infrastructure-level functions. Modifying
existing RMI interfaces often proves undesirable due to the
dependencies between components and the huge impact to client-side
applications. The observation of this RMI limitation leads to the
generic solution that I describe in this article
Despite all the above
The solution is based on Java reflection techniques and some common
methods for implementing interceptors. More importantly, it defines an
architecture that can be easily integrated into any RMI-based
distributed application design.
The solution below is demonstrated through an example implementation that supports the transparent passing of transaction-context data, such as a transaction ID (xid), with RMI. The solution contains the following three important components:
RMI remote interface naming-function encapsulation and interceptor plug-in
Service-context propagation mechanism and server-side interface support
Service-context data structure and transaction-context propagation support
The implementation assumes that RMI/IIOP is used. However, it by no
means implies that this solution is only for RMI/IIOP. In fact, either
RMI/JRMP or RMI/IIOP can be used as the underlying RMI environments,
or even a hybrid of the two environments if the naming service
supports both
Naming-function encapsulation
First we encapsulate the naming function that provides the RMI remote
interface lookup, allowing interceptors to be transparently plugged
in. Such an encapsulation is always desirable and can always be found
in most RMI-based applications. The underlying naming resolution
mechanism is not a concern here; it can be anything that supports JNDI
(Java Naming and Directory Interface). In this example, to make the
code more illustrative, we assume all server-side remote RMI
interfaces inherit from a mark remote interface ServiceInterface,
which itself inherits from the Java RMI Remote interface. Figure
shows the class diagram, which is followed by code snippets that I
will describe further
RMI invocation interceptor
To enable the invocation interceptor, the original RMI stub reference
acquired from the RMI naming service must be wrapped by a local proxy.
To provide a generic implementation, such a proxy is realized using a
Java dynamic proxy API. In the runtime, a proxy instance is created;
it implements the same ServiceInterface RMI interface as the wrapped
stub reference. Any invocation will be delegated to the stub
eventually after first being processed by the interceptor. A simple
implementation of an RMI interceptor factory follows the class diagram
shown in Figure
package rmicontext.interceptor;
public interface ServiceInterfaceInterceptorFactoryInterface {
ServiceInterface newInterceptor(ServiceInterface serviceStub, Class serviceInterfaceClass) throws Exception;
}
package rmicontext.interceptor;
public class ServiceInterfaceInterceptorFactory
implements ServiceInterfaceInterceptorFactoryInterface {
public ServiceInterface newInterceptor(ServiceInterface serviceStub, Class serviceInterfaceClass)
throws Exception {
ServiceInterface interceptor = (ServiceInterface)
Proxy.newProxyInstance(serviceInterfaceClass.getClassLoader(),
new Class[]{serviceInterfaceClass},
new ServiceContextPropagationInterceptor(serviceStub)); // ClassCastException
return interceptor;
}
}
package rmicontext.interceptor;
public class ServiceContextPropagationInterceptor
implements InvocationHandler {
/**
* The delegation stub reference of the original service interface.
*/
private ServiceInterface serviceStub;
/**
* The delegation stub reference of the service interceptor remote interface.
*/
private ServiceInterceptorRemoteInterface interceptorRemote;
/**
* Constructor.
*
* #param serviceStub The delegation target RMI reference
* #throws ClassCastException as a specified uncaught exception
*/
public ServiceContextPropagationInterceptor(ServiceInterface serviceStub)
throws ClassCastException {
this.serviceStub = serviceStub;
interceptorRemote = (ServiceInterceptorRemoteInterface)
PortableRemoteObject.narrow(serviceStub, ServiceInterceptorRemoteInterface.class);
}
public Object invoke(Object proxy, Method m, Object[] args)
throws Throwable {
// Skip it for now ...
}
}
To complete the ServiceManager class, a simple interface proxy cache is implemented:
package rmicontext.service;
public class ServiceManager
implements ServiceManagerInterface {
/**
* The interceptor stub reference cache.
* <br><br>
* The key is the specific serviceInterface sub-class and the value is the interceptor stub reference.
*/
private transient HashMap serviceInterfaceInterceptorMap = new HashMap();
/**
* Gets a reference to a service interface.
*
* #param serviceInterfaceClassName The full class name of the requested interface
* #return selected service interface
*/
public ServiceInterface getServiceInterface(String serviceInterfaceClassName) {
// The actual naming lookup is skipped here.
ServiceInterface serviceInterface = ...;
synchronized (serviceInterfaceInterceptorMap) {
if (serviceInterfaceInterceptorMap.containsKey(serviceInterfaceClassName)) {
WeakReference ref = (WeakReference) serviceInterfaceInterceptorMap.get(serviceInterfaceClassName);
if (ref.get() != null) {
return (ServiceInterface) ref.get();
}
}
try {
Class serviceInterfaceClass = Class.forName(serviceInterfaceClassName);
ServiceInterface serviceStub =
(ServiceInterface) PortableRemoteObject.narrow(serviceInterface, serviceInterfaceClass);
ServiceInterfaceInterceptorFactoryInterface factory = ServiceInterfaceInterceptorFactory.getInstance();
ServiceInterface serviceInterceptor =
factory.newInterceptor(serviceStub, serviceInterfaceClass);
WeakReference ref = new WeakReference(serviceInterceptor);
serviceInterfaceInterceptorMap.put(serviceInterfaceClassName, ref);
return serviceInterceptor;
} catch (Exception ex) {
return serviceInterface; // no interceptor
}
}
}
}
You can find more details in the following guideline here. It is important to understand all this above if you desire to make it from scratch, in contrast with Spring-AOP Framework robust solution.In addition,I think you will find very interesting the Spring Framework plain source code for implementing an RmiClientInterceptor. Take another look here also.
You might consider using Spring with RMI. It offers a simplified way to use transactions. You just set some persistence settings from the #EnableTransactionManagement annotation and it manages transactions for you at a point defined by #Transactional. It can be a class or methods of a class.
example code here
The explanation is in the project README.
I don't know if you've already considered this, one possibility that would fit well with the dual requirement of RMI and transactional boundaries is clearly Spring. An example of Spring Remoting is here.
The #Transactional annotation is very widely used for declarative transaction management - Spring will automatically wrap your bean in an AOP transaction advisor.
These two would then fit together well, for example with a single transactional bean that could be exported as a remote service.
The Spring Remoting link above is based around Spring Boot, which is an easy way to get started. By default Boot would want to bring in an embedded server to the environment, though this can be disabled. Equally there are other options like a standalone AnnotationConfigApplicationContext, or a WebXmlApplicationContext within an existing web application.
Naturally with a question asking for recommendations, there will an element of opinion in any reply - I would be disappointed not to see some other suggestions shortly.
At a project I am working on, we have the need to add some additional parameters to our ejb calls.
We don't put those parameters as regular ejb interface parameters because we already have lots of interfaces and changing most of them would be a pain (plus it's not related to the logic, these are some additional parameters being saved in the database, call it a side effect).
So to the point, we use weblogic as our application server (10.3.4, Java 6, JavaEE 5) and the solution we found for this problem was to make a wrapper ejb that will accept the real method target, its arguments and of course the additional parameters.
The wrapper will then store the additional parameters on the transaction, create a new initial context and lookup the target ejb.
The wrapper ejb function looks like this:
public Object invokeWithAdditionalParameters (MethodSignature methodSignature, Object[] args, SomeAdditionalParameter p) {
transaction.putResource("additionalParam", p);
InitialContext ctx = new InitialContext();
Object service = ctx.lookup(methodSignature.buildLookupName());
return methodSignature.getMethod().invoke(service, args);
}
MethodSignature holds the targeted ejb method we would like to invoke.
I don't know if this solution is acceptable and if we should cache our InitialContexts, as we are already in the server and don't need to make expensive network calls to the jndi tree, but maybe I'm wrong...
Thank you,
Aviad.
I have a collection of stateless scala/Java APIs, which might look like:
class UserService {
def get(id: UserIDType): User { ... }
def update( user:User): User { ... }
...
}
where User has a set of inspectable bean properties. I'd like to make these same APIs not only available over HTTP (which I know how to do), but also other, more performant non-HTTP protocols (ideally also running in the same process as the HTTP server). And more importantly, automate as much as possible including generation of client APIs that match the original Java API, and the dispatching of method calls following network requests.
I've found Spring's guide on remoting
However, this looks limited to HTTP (text not binary). What I'd really love is a library/other method that:
lets me scan for registered/annotated services and describes methods and parameters as data
lets me easily dispatch method calls (so that I'm in control of the sockets, communication protocols and whatnot and can chose a more performant one than HTTP).
i.e. the kinds of things that Spring's DispatcherServlet does internally, but without the HTTP limitations.
Ideas?
Background
I'd like to make a set of stateless service API calls available as network services with the following goals:
Some of the APIs should be available as REST calls from web pages/mobile clients
A superset of these APIs should be available internally within our company (e.g. from C++ libraries, python libraries) in a way that is as high-performance (read low-latency) as possible, particularly when the service and client are:
co-located in the same process, or
co-located on the same machine.
automate wrapper code for the client and server. If I add a method a service API, or and an attribute to a class, no-one should have to write additional code in client or server. (e.g. I hit a button and a new client API that matches the original Java/scala service is auto-generated).
(1) is easily achievable with Spring MVC. Without duplication of classes I can simply markup the service: (i.e. service is also a controller)
#Controller
#Service
#RequestMapping(...)
class UserService {
#RequestMapping(...)
def get(#PathVariable("id") id: UserIDType): User { ... }
#RequestMapping(...)
def update( #RequestBody user:User): User { ... }
...
}
With tools like Swagger (3) is easily achievable (I can trivially read the Swagger-generated JSON spec and can auto-generate C++ or Python code that mimics the original service class, it's methods, parameter names and the POJO parameter types).
However, HTTP is not particularly performant, so I'd like to use a different (binary) protocol here. Trivially, I can use the this same spec to generate a thrift .idl or even directly generate client code to talk Thrift/ProtocolBuffers (or any other binary protocol) while also providing to the client an API that looks just like the original Java/scala one.
Really -- the only tricky part is getting a description of the service method and then actually dispatching a method calls. So -- are there libraries to help me do that?
Notes:
I'm aware that mixing service and controller annotations disgusts some Spring MVC purists. However, my goal really is to have a logical API, and automate all of the service embodiments of it (i.e. the controller part is redundant boilerplate that should be auto-generated). I'd REALLY rather not spend my life writing boilerplate code.
Essentially, I have a MessageBodyWriter that writes objects as JSON, and I'd like to be able to control some aspects of the output based on which resource method handled the request. However, the default lifecycle of #Provider classes is singleton (one per JVM), so I can't inject an instance of some configuration object. This leaves me with 2 obvious workarounds:
Use custom annotations: Each call to writeTo(...) includes the list of annotations on the method that was invoked, so I could check for the existence of some annotation. However, JAX-RS methods are already pretty laden with metaprogramming.
Use a ThreadLocal property map: Assuming one request per thread, but this approach breaks encapsulation a bit. The resource methods needs to be aware that there is some other class out there, looking for this map.
Is there a way to change the lifecycle of the Provider itself? I am using Jersey.
Not sure why you need a MessageBodyWriter Provider with per-request basis. If you just want to distinguish which methods are with JSON ouput and which are not, then jersey-json does already support.
And although the #Provider is singleton. You still can use per-request object within it like below.
#Provider
public class StViewProcessor implements ViewProcessor<ST> {
......
#Context
HttpServletRequest request;
public void writeTo(ST st, Viewable viewable, OutputStream out)
throws IOException {
System.out.println(request.getRequestURI());
...
}
}
And if you want to inject your instance per request, you can have a look at PerRequestTypeInjectableProvider. Here is a link about it.
The JAX-RS 1.1 spec requires that implementations support singleton providers and allows support for other lifecycles but doesn't suggest anything else along those lines. As far as I'm aware, pure Jersey doesn't support anything beyond singletons. With the jersey-spring contrib module, you get support for using Spring as Jersey's IoC container (where it gets its resource and provider instances from). I know Spring supports multiple lifecycles, including request, but I'm not sure if support for that is built into jersey-spring.
This is not a simple question its just because i'm rethinking our architecture for securing our EJB 3.0 service by a login and security.
We have a EJB3.0 application on JBoss 5.1 that offers various services to a SWT client to read and write data. To use a service, the client must login with a valid user and password which is looked up by SpringSecurity in a LDAP server. SpringSecurity generates a session id which is passed back to the client to be resused in any further service call.
client server
| |
|-> login(user/password)-------->|
| |
| <------- sessionId ------------|
| |
|-->serviceXy(sessionId,param1)->|
The situation seems clear. We store the sessionId in our own context object which is the first parameter of each service method. There is an interceptor on each service method which reads the sessionId from the given context object and checks if the session is still valid. The client needs to call the login service first to get a context object filled with the sessionId and reusue this context object in further service calls.
public class OurContext {
private String sessionId;
}
#Stateless
#Interceptors(SecurityInterceptor.class)
public OurServiceImpl implements OurService {
public void doSomething(OurContext context, String param1) {
[...]
}
}
The thing i don't like at this solution is the polution of each service method with the context parameter.
Isn't there a similar mechanism like a http session in rmi calls? I'm thinking of putting our context object in some kind of session that is created in the client(?) right after the login and is passed to the server on each service call so that the SecurityInterceptor can read the sessionId from this "magic context".
Something like this:
OurContext ctx = service.login("user","password");
Magical(Jboss)Session.put("securContext", ctx);
service.doSomething("just the string param");
Since you are already using an app server, it seems that you should be using the built-in EJB security mechanisms, generally provided through JAAS. On the 4.x jboss line, if you implemented your own JAAS plugin for jboss, you could get access to a "special" context map (similar to what you describe) which is passed along on remote requests (by the jboss remote invocation framework). I haven't used jboss in a while, so not sure how this maps to the 5.1 product, but i have to imagine it has similar facilities. This assumes, of course, that you are willing to implement something jboss specific.
There are some kinds of session mechanisms in EJB, but they all start when the remote call starts, and ends when that ends. On old one is the transaction context ( Adam Bien wrote about this some time ago), and a newer one the CDI Session Scope.
Contrary to popular belief, this scope doesn't just mirror the http session scope, but in absence of an http session (like for remote calls), it represents a single call chain or message delivery (for mdbs).
With such a session, your remote SWT client still has to pass the sessionId to the remote service, but any local beans called from there can pick it up from this "cdi" session.
The other option is kinda like what jtahlborn says: with your own login module you can return a custom principal, instead of the default one. Your code can first request the normal principal and then try to cast it.
The problem is that this stuff is container specific and JBoss always forgets about it. It pretty much breaks after every update, and users have to kick and scream to get it fixed in some next version (only to see it break again in the version after that). Without JBoss really supporting this it's an endless battle.
Yet another option is to let the user login with the sessionId as name. The login module behind that could be a simple module that accepts everything and just puts a principal in the security context with the sessionId as 'name'. It's a little weird, but we've used this succesfully to get any data that can be expressed by a string into the security context. Of course, you would need to let your client do a regular container authentication here, which kinda defeats using Spring security in the first place.
We went for another approach which is portable and does not rely on a specific app server. In addition our security implementation frees us from the restrictions of the EJB approach (which by the way I thought were closed 2 decades ago ... but came up again).
Looking top down:
There is a server providing classes with methods to work on same data.
The client(s) provide the data and invoke specific methods.
Our approach is to put all data (and therefore communication between client and server) into a "Business Object". Every BO extends a superclass. This superclass contains a session id. The login method provides and returns that id. Every client only has to ensure to copy the id received in one BO into the next one it sends to the server. Every method which can be remotely (or locally) invoked, first obtains the session object with the received id. The method to return the session object also checks security constraints (which are based on permissions and not on roles like in the EKB approach).