I have 2 projects. The first uses Spring 4 and the second uses jBoss 7.
I'm creating a dependency that given a Class name (like "com.foo.Bar") will get the instance from the injection context.
The classes will implement an interface (TransitionRule), so my method would be like:
public TransitionRule getRule(String className) {
//... Magic goes here!
//get the instance of "className" from any container that the imported project is using.
}
Can i do that with only one implementation or i will to create a different implementation to get from Spring and from Jboss context?
You can do a bean lookup by name or type in Spring if you have access to the relevant Spring Context.
You can perform a JNDI lookup in a running JBoss container if the object has been registered in JNDI, for example, an EJB is generally registered in JNDI for you.
Both of these methods follow the Lookup or Service-Locator pattern. These are NOT injections.
I have a Delegate that instanciate the corresponding Bean sending credentials (Josso Authentication) through InitialContext as shown here.
At Bean, I've tried to recover Josso Data with SessionContext, as shown below:
#Resource private SessionContext context;
The problem I'm facing is that I couldn't retrieve Josso Data at Bean scope. I've tried "context.getEnvironment()" but this method is deprecated and I didn't find any alternative.
In order to find a solution, I've tried:
context.lookup(JNDI_BEAN_NAME);
context.lookup("java:comp/env/JNDI_BEAN_NAME")
context.lookup("java:comp/env")
But the two first commands only return me the Bean itself and the last one only return me global variables.
What is the correct alternative to "context.getEnvironment()"?
java:comp/env finds container-managed resources only and is read-only at runtime. If you want, you can expose a local interface that gets Josso credentials from the delegate.
#Local
public interface AuthenticatorLocal {
void getJossoCredentials();
}
Otherwise, you can just use context.getCallerPrincipal().
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.
I want to inject an EJB3 into a java class which is not an EJB.
these classes are both on the same server and application.
Is that possible ...and if yes ..then how ?
Thanks,
Perhaps you should supply more information about your work environment. The usage of CDI changes the whole specturm. You can inject it when you use CDI, otherwise you can only inject it into other EJB's and servlets (if your application server supports it).
Otherwise you can do a lookup using
Context ctx = new InitialContext();
MyEjb ejb = (MyEjb) ctx.lookup("java:comp/env/myEjb");
You can supply a name in the #EJB annotation you supply together with your #Stateless/#Stateful annotation.
#Stateless
#EJB(name="myEjb", beanInterface=MyEjb.class)
public class myEjbImpl implements MyEjb{
// code goes here
}
You can't inject it, but you can make a lookup for that EJB:
Look here:
http://www.roseindia.net/ejb/ejb-lookup.shtml
During the deploymentprocess of your EJB you may see, the Name of your Bean.
I am getting following exception when a Local Interface is implemented by two Stateless beans, in which one having normal functionality and other having some enhanced functionality in it.
java.lang.RuntimeException: could not
resolve global JNDI name for #EJB for
container UserBean: reference class:
org.app.SecurityServiceLocal ejbLink:
duplicated in Some.jar
Finally I came to know why I am getting this exception
I have used #EJB annotation to inject a Stateless bean into another Stateless bean Name UserBean with following code
#Stateless(name="UserBean")
#EJB(name="app/SecurityService",
beanInterface=SecurityServiceLocal.class)
public class UserBean implements UserRemote{
}
If you check the injection details I was injecting SecurityServiceLocal, which was implemented by two Stateless bean classes name SercurityServiceBean and SecurityServiceEnhaBean. So, container is in ambiguity state to decide which bean to inject in as both are implementing same interface.
This can be resolved by specifying some more information like beanName property value in #EJB annotation. There you need to provide which stateless bean class needs to be injected by using bean name(declared at that bean level (or) in ejb-jar.xml). check the code to identify the change in the injection mapping
#Stateless(name="UserBean")
#EJB(name="app/SecurityService",
beanInterface=SecurityServiceLocal.class,
beanName="SecurityServiceEnha")
public class UserBean implements UserRemote{
}
It's hard to say for sure without seeing code. A good first step would be to use the optional mappedName="" attribute on your session beans' annotion to give each a unique JNDI name. You'll have to use an equivalent mappedName attribute in your client to make sure you are using the bean that you intent.