I have an application which is part JavaEE (the server side) part JavaSE (the client side). As I want that client to be well architectured, I use Weld in it to inject various components. Some of these components should be server-side #EJB.
What I plan to do is to extend Weld architecture to provide the "component" allowing Weld to perform JNDI lookup to load instances of EJBs when client tries to reference them. But how do I do that ?
In other worrds, I want to have
on the client side
public class ClientCode {
public #Inject #EJB MyEJBInterface;
}
on the server-side
#Stateless
public class MyEJB implements MyEJBInterface {
}
With Weld "implicitely" performing the JNDI lookup when ClientCode objects are created. How can I do that ?
Basically, doing so requires write a so-called portable CDI extension.
But, as it is quite long and requires a few tweaks, let me explain it further.
Portable extension
Like weld doc explains, first step is to create a class that implements the Extension tagging interface, in which one will write code corresponding to interesting CDI events. In that precise case, the most interesting event is, to my mind, AfterBeanDiscovery. Indeed, this event occurs after all "local" beans have been found by CDI impl.
So, writing extension is, more opr less, writing a handler for that event :
public void loadJndiBeansFromServer(
#Observes AfterBeanDiscovery beanDiscovery, BeanManager beanManager)
throws NamingException, ClassNotFoundException, IOException {
// Due to my inability to navigate in server JNDI naming (a weird issue in Glassfish naming)
// This props maps interface class to JNDI name for its server-side
Properties interfacesToNames = extractInterfacesToNames();
// JNDI properties
Properties jndiProperties = new Properties();
Context context = new InitialContext();
for (Entry<?, ?> entry : interfacesToNames.entrySet()) {
String interfaceName = entry.getKey().toString();
Class<?> interfaceClass = Class.forName(interfaceName);
String jndiName = entry.getValue().toString();
Bean<?> jndiBean = createJndIBeanFor(beanManager, interfaceClass, jndiName, jndiProperties);
beanDiscovery.addBean(jndiBean);
}
}
Creating the bean is not a trivial operation : it requires transforming "basic" Java reflection objects into more advanced weld ones (well, in my case)
private <Type> Bean<Type> createJndIBeanFor(BeanManager beanManager, Class<Type> interfaceClass,
String jndiName, Properties p) {
AnnotatedType<Type> annotatedType = beanManager
.createAnnotatedType(interfaceClass);
// Creating injection target in a classical way will fail, as interfaceClass is the interface of an EJB
JndiBean<Type> beanToAdd = new JndiBean<Type>(interfaceClass, jndiName, p);
return beanToAdd;
}
Finally, one has to write the JndiBean class. But before, a small travel in annotations realm is required.
Defining the used annotation
At first, I used the #EJB one. A bad idea : Weld uses qualifier annotation method calls result to build hashcode of bean ! So, I created my very own #JndiClient annotation, which holds no methods, neither constants, in order for it to be as simple as possible.
Constructing a JNDI client bean
Two notions merge here.
On one side, the Bean interface seems (to me) to define what the bean is.
On the other side, the InjectionTarget defines, to a certain extend, the lifecycle of that very bean.
From the literature I was able to find, those two interfaces implementations often share at least some of their state. So I've decided to impelment them using a unique class : the JndiBean !
In that bean, most of the methods are left empty (or to a default value) excepted
Bean#getTypes, which must return the EJB remote interface and all extended #Remote interfaces (as methods from these interfaces can be called through this interface)
Bean#getQualifiers which returns a Set containing only one element : an AnnotationLiteral corresponding to #JndiClient interface.
Contextual#create (you forgot Bean extended Contextual, didn't you ?) which performs the lookup :
#Override
public T create(CreationalContext<T> arg0) {
// Some classloading confusion occurs here in my case, but I guess they're of no interest to you
try {
Hashtable contextProps = new Hashtable();
contextProps.putAll(jndiProperties);
Context context = new InitialContext(contextProps);
Object serverSide = context.lookup(jndiName);
return interfaceClass.cast(serverSide);
} catch (NamingException e) {
// An unchecked exception to go through weld and break the world appart
throw new LookupFailed(e);
}
}
And that's all
Usage ?
Well, now, in my glassfish java client code, I can write things such as
private #Inject #JndiClient MyRemoteEJB instance;
And it works without any problems
A future ?
Well, for now, user credentials are not managed, but I guess it could be totally possible using the C of CDI : Contexts ... oh no ! Not contexts : scopes !
Section 3.5 of the CDI spec should help out. You may want to use some of the properties on the EJB annotation as well. Also, (probably don't need to tell you this) make sure you have JNDI set up correctly on the client to reference the server, and pack any of the needed interfaces into your client jar.
Related
I am trying to understand what would be the correct usage of Spring prototype bean.
May be the following code sample will help in you understanding my dilemma:
List<ClassA> caList = new ArrayList<ClassA>();
for (String name : nameList) {
ClassA ca = new ClassA();
//or Shall I use protypebean, using method lookup I can inject the dependency of ClassA.
// ClassA ca = getPrototypeClassA();
ca.setName(name);
caList.add(ca);
}
So my exact point is in this scenario shall I go with method injection or new() operator.
Provide your view with justification.
You can make use of either of the ways, because ultimately client code is responsible for handling the life-cycle of the prototype bean rather than spring container.
According to Spring-docs,
In some respects, you can think of the Spring containers role when
talking about a prototype-scoped bean as somewhat of a replacement for
the Java 'new' operator. All lifecycle aspects past that point have to
be handled by the client.
Spring does not manage the complete lifecycle of a prototype bean: the
container instantiates, configures, decorates and otherwise assembles
a prototype object, hands it to the client and then has no further
knowledge of that prototype instance. It is the responsibility of the
client code to clean up prototype scoped objects and release any
expensive resources that the prototype bean(s) are holding onto.
If ClassA needs to have #Autowired references, then go for a prototype bean.
Otherwise a simple POJO (that the Spring container is unaware of) will do.
It seems that your instance need some runtime values in order to initialise properly. In such case ,it depends on if you need to use spring feature such as AOP for the ClassA instance. If yes , go with the method injection .If not , you can consider using factory pattern . Much more OO and cleaner to me :
Something like the following . You should get the idea.
#Component
public class FactoryForClassA {
#Autowired
private FooBean someDependencyForClassA;
public ClassA create(String name){
ClassA a = new ClassA(someDependencyForClassA);
a.setName(name);
return a;
}
}
And the client code:
#Autowired
private FactoryForClassA factoryForClassA;
List<ClassA> caList = new ArrayList<ClassA>();
for (String name : nameList) {
ClassA a = factoryForClassA.create(name);
caList.add(ca);
}
I know I can inject as an instance all the beans that match the interface and then choose between them programmatically :
#Inject #Any Instance<PaymentProcessor> paymentProcessorSource;
That means I have to put the selecting logic into the client.
Can I, as an alternative, cache the value of the ejb using lexical scoping with lambda expression? Will the container be able to correctly manage the lifecycle of the ejb in that case or is this practice to avoid?
For example, having PaymentProcessorImpl1 e PaymentProcessorImpl2 as two strategies of PaymentProcessor, something like that:
public class PaymentProcessorProducer {
#Inject
private PaymentProcessorImpl1 paymentProcessorImpl1;
#Inject
private PaymentProcessorImpl2 paymentProcessorImpl2;
#Produces
private Function<String, PaymentProcessor> produce() {
return (strategyValue) -> {
if ("strategy1".equals(strategyValue)) {
return paymentProcessorImpl1;
} else if ("strategy2".equals(strategyValue)) {
return paymentProcessorImpl2;
} else {
throw new IllegalStateException("Tipo non gestito: "
+ strategyValue);
}
};
}
}
and then into the client to something like that:
#Inject
Function<String, PaymentProcessor> paymentProcessor;
...
paymentProcessor.apply("strategy1")
Can I, as an alternative, cache the value of the ejb using lexical scoping with lambda expression?
Theoretically, you could do this. Whether it works is easy to try on our own.
Will the container be able to correctly manage the lifecycle of the ejb in that case or is this practice to avoid?
What exactly is an EJB here? The implementation of PaymentProcessor? Note that EJB beans are different from CDI beans. As in CDI container does not control lifecycle of EJB beans, it "only provides a wrapper for you to use them as if they were CDI beans".
That being said, the lifecycle is still the same - in your case the producer is creating #Dependent bean meaning every time you inject Function<String, PaymentProcessor>, the producer will be invoked.
What poses certain problem is that you create an assumption on two or more context being active at any given time. The moment you decide to actually apply() the function, the scope within which your implementation(s) exist may or may not be active. If they are both ApplicationScoped for instance, you should be alright. If, however, they are SessionScoped and you happen to timeout/invalidate session before applying function, then you get into a very weird state.
This is probably why I would rather avoid this approach and go with qualifiers. Or you can introduce a new bean which has both strategies in it and have a method with an argument which decides which strategy to use.
I looked for a clean CDI solution and not a WELD dependent one but so far nothing...
I need to test if every element of a list of objects that I get with #Inject #Any MyInterface beans is a proxy, and when true I need to get the real object to do introspection and get all the properties of the object.
My WELD implementation:
MyInterface interf = obj;
if (isProxy(interf )) {
interf = (Config) ((TargetInstanceProxy)interf ).getTargetInstance();
}
where isProxy is so defined (CDI solution?):
public boolean isProxy(Object obj) {
try{
return Class.forName("org.jboss.weld.bean.proxy.ProxyObject").isInstance(obj);
} catch (Exception e) {
LOGGER.error("Unable to check if object is proxy", e);
}
return false;
}
Any suggestions /Indications. In the official documentation I found no mention of introspection (here)
And then I would like to get all the properties of the bean with something like this:
Arrays.stream(interf.getClass().getDeclaredFields()).forEach(
field -> extractStuff(...)
);
We use Wildfly and WELD but don't want to bind us to an implementation of CDI.
Thanks in advance!
EDIT:
The question is, more precisely: Do you know a clean CDI solution that WELD is already implementing with TargetInstanceProxy? Not if I need to go back to school or if I understand what I'm writing.. Thanks for taking time to help!
CDI is intentionally hiding (or rather not exposing) the internals as they should be unimportant to end user when programming against interface.Furthermore messing with this can cause weird errors as you should always be invoking methods via proxy, not the actual instance.
So the short answer is - no, there is no pure CDI way to do this.
(At least not an intended one.)
However, seeing that you are using Weld already, there are other ways. Weld comes with pretty much any EE server excepting TomEE, so depending on Weld API should be pretty safe.
Now why am I saying this - in Weld 3.x (WildFly 12+), the API was extended to contain WeldConstruct and WeldClientProxy which are interfaces implemented by either Weld sublasses (interceptors/decorators) and/or client proxies - see javadocs of those classes for more information.
So if you must do this, then you could add a dependency on Weld API as such:
<dependency>
<groupId>org.jboss.weld</groupId>
<artifactId>weld-api</artifactId>
<version>x.y.z</version>
</dependency>
And then, in your code, you can check if injected object is a proxy by doing:
#Inject
Foo foo;
public void doSomething() {
if (foo instanceof WeldClientProxy) {
// foo is a proxy
} else {
// not a proxy
}
}
If you want to obtain actual instances, WeldClientProxy allows you to obtain Metadata from which you can the retrieve the underlying contextual instance. That's the closest I can get you to what you are after.
One common option is to:
get the Bean of the instance you want to unwrap
get its scope (bean.getScope())
from the bean manager (injectable) get the Context associated to the scope
do a context.get(bean) to get the unwrapped instance if available in CDI context (there are some cases you can't get it at all).
Now my colleagues work on logging subsystem and they want to bind separate operations, that was initiated from some business method. For example, if method from bean A calls to some method in bean B and then in bean C it will be great to know than business methods in bean B and bean C does some staff for method from bean A. Especially it will be great to know that methods from B and C done some unit of work for concrete call of bean A.
So, the question is how to tie this units of work into something total? Obviously, it is not beautiful to use method arguments for binding!
And also I think that it is time to ask another question, that is close enough to previous one. What if I want to propagate some context information from bean A to another beans, that are called from A? Something like security credentials and security principal? What can I do?
May be questions that I asked is some kind of bad practice?
Looks like a good use case for mdc, available in both Logback and Log4J. Essentially you are attaching some custom value to a thread and all logging messages comming from that thread can attach that value to the message.
I think the best way to implement this in EJB will be an interceptor:
public class MdcInterceptor {
#AroundInvoke
public Object addMdcValue(InvocationContext context) throws Exception {
MDC.put("cid", RandomStringUtils.randomAlphanumeric(16));
try {
return context.proceed();
} finaly {
MDC.remove("cid");
}
}
}
Now all you have to do is add:
%X{user}
to your logging pattern (logback.xml or log4j.xml).
See also
Logging user activity in web app
For general purpose context information you can use TransactionSynchronizationRegistry. It could look something like this:
#Stateless
public class MyBean {
#Resource
TransactionSynchronizationRegistry registry;
#AroundInvoke
public Object setEntryName(InvocationContext ic) throws Exception {
registry.putResource(NAME, "MyBean");
return ic.proceed();
}
}
#Stateless
public class MyBean2 {
#Resource
TransactionSynchronizationRegistry registry;
public void doJob() {
String entryName = (String)registry.getResource(NAME);
...
}
}
I believe it is usually implemented using ThreadLocal variables as normally each transaction maps to a sigle thread in application servers. So if TransactionSynchronizationRegistry is not implemented in your AS (like e.g. in JBoss 4.2.3) or you need lower level tool, you could use ThreadLocal variables directly.
BTW I guess that MDC utilities use the same thing under the covers.
I'm fairly new to EJBs and full blown application servers like JBoss, having written and worked with special purpose standalone Java applications for most of my career, with limited use of Java EE. I'm wondering about the best way to adapt a commonly used design pattern to EJB3 and JBoss: the static factory pattern. In fact this is Item #1 in Joshua Bloch's Effective Java book (2nd edition)
I'm currently working with the following factory:
public class CredentialsProcessorFactory {
private static final Log log = LogFactory.getLog(CredentialsProcessorFactory.class);
private static Map<CredentialsType, CredentialsProcessor> PROCESSORS =
new HashMap<CredentialsType, CredentialsProcessor>();
static {
PROCESSORS.put(CredentialsType.CSV, new CSVCredentialsProcessor());
}
private CredentialsProcessorFactory() {}
public static CredentialsProcessor getProcessor(CredentialsType type) {
CredentialsProcessor p = PROCESSORS.get(type);
if(p == null)
throw new IllegalArgumentException("No CredentialsProcessor registered for type " + type.toString());
return p;
}
However, in the implementation classes of CredentialsProcessor, I require injected resources such as a PersistenceContext, so I have made the CredentialsProcessor interface a #Local interface, and each of the impl's marked with #Stateless. Now I can look them up in JNDI and use the injected resources.
But now I have a disconnect because I am not using the factory anymore. My first thought was to change the getProcessor(CredentialsType) method to do a JNDI lookup and return the SLSB instance that is required, but then I need to configure and pass the proper qualified JNDI name. Before I go down that path, I wanted to do more research on accepted practices.
How is this design pattern treated in EJB3 / Java EE?-
When you start playing with factories and "real" Java POJO code, you basically need rely on JNDI.
The dependency injection only works on the managed components of an EJB server, and that's basically Servlets and EJBs.
When you're talking generic java code that wants to refer to EJBs, they need to lookup the resources themselves via JNDI.
The best thing to do, in that case, is simply write a wrapper lookup class filled with static functions to do your JNDI lookups, rather than calling JNDI directly in each implementation. And then use that in your implementations.
That's just a generic overall rule.
Now, for your specific case, consider this.
You have:
static {
PROCESSORS.put(CredentialsType.CSV, new CSVCredentialsProcessor());
}
That's no different from:
static {
PROCESSORS.put(CredentialsType.CSV, "java:comp/env/ejb/CSVCredentialProcessorSessionBean");
}
Then, in your getProcessor() code:
Context c = new InitialContext();
return (CredentialsProcessor) c.lookup(PROCESSORS.get(type));
See, basically, the code is identical, and your factory interface is the same to the clients.
You have to "hard code" the JNDI lookup key, but you're "hard coding" the class names now anyway, so how is this different?
There's some potential portability concerns across containers, in that everyone seems to like to use different JNDI identifiers for bean names. Most of that can be tweaked in the deployment, but if not, then you can pull these keys out in to a config file, or whatever.
In Java EE 6, there are guaranteed portable names. If you're not porting containers today, then don't worry about this at all.
So, basically, it's not really a disconnect at all.
With EJB3, you generally don't need to do JNDI lookups. EJB3 supports dependency injection of EJBs and several other types of resources. If your bean attribute is annotated with #EJB, the dependency will automatically be injected by the container.
Not having to do a JNDI lookup means you can test your EJB like a POJO for unit testing purposes. You can just manually inject mock implementations of dependencies and test them without having to deploy them in a container.