I'm working on a Java EE application, primarily JAX-RS with a JSF admin console, that uses CDI/Weld for dependency injection with javax.enterprise.context.ApplicationScoped objects. Minor debugging issues aside, CDI has worked beautifully for this project.
Now I need some very coarse-grained control over CDI-injected object lifecycles. I need the ability to:
Remove an injected object from the application context, or
Destroy/delete/clear/reset/remove the entire application context, or
Define my own #ScopeType and implementing Context in which I could provide methods to perform one of the two above tasks.
I'm fully aware that this is across, if not against, the grain of CDI and dependency injection in general. I just want to know
Is this remotely possible?
If yes, what is the easiest/simplest/quickest/foolproofiest way to get the job done?
Weld Reference Documentation Section 2.1.2
Keep in mind that once a bean is bound
to a context, it remains in that
context until the context is
destroyed. There is no way to manually
remove a bean from a context. If you
don't want the bean to sit in the
session indefinitely, consider using
another scope with a shorted lifespan,
such as the request or conversation
scope.
Custom scope example Porting the veiwscoped jsf annonation to cdi
If you really don't want to take the path of the Custom scope type.. You can use a non-portable method by using BeanManager.getContext method and cast this context in a weld AbstractSharedContext to have access to the beanstore or the cleanUp() method of the context.
Check this thread on how to get a BeanManager instance for your environment
A custom scope which might fit your needs is available at https://github.com/openknowledge/openknowledge-cdi-extensions/tree/master/openknowledge-cdi-scope/src/main/java/de/openknowledge/cdi/scope Maybe you have to adjust the implementation a bit.
Out of the box there is only the Conversation scope that gives you total control on its lifecycle. But you can create your own scope if conversation doesn't suit your needs.
Creating a scope is a tough job, but you can go to weld code and look how conversation was implemented.
In CDI 1.1 there is a javax.enterprise.context.spi.AlterableContext interface, which allows you to individually destroy a bean instance. All normal scopes (request, conversation, session) are alterable.
AlterableContext ctxConversation = (AlterableContext) beanManager.getContext(ConversationScoped.class);
for (Bean<?> bean : beanManager.getBeans(Object.class)) {
Object instance = ctxConversation.get(bean);
if (instance != null) {
ctxConversation.destroy(instance);
}
}
The beanManager here is a javax.enterprise.inject.spi.BeanManager instance. You can get it via JNDI lookup:
InitialContext.doLookup("java:comp/BeanManager");
or via CDI static method:
CDI.current().getBeanManager();
, but be aware of the issues with the static method in some Weld versions:
javax.enterprise.inject.spi.CDI implementation does not support multiple deployments;
CDI.current().getBeanManager() returns a beanmanager from a different deployment.
Related
Well, i'm trying to use RequestedScoped beans inside a Quartz Job, see:
public class JobRoboFtp implements Job {
#Inject
private AcervoVideoService acervoVideoService;
#Inject
private ConfiguracaoService configuracaoService;
#Inject
private FtpManager ftpManager;
But i got always:
No active contexts for scope type javax.enterprise.context.RequestScoped
Well, If i change this Services to #Dependent scope everything works but i would like to use RequestedScope. There is any way ?
Since you didn't say much about versions, I am going to assume some of the latest versions of Weld 2.x (or even 3.x) - then there is a way. I also assume you are talking about SE environment, as otherwise request scope would auto-activate during requests.
If we are talking CDI 1.2 (Weld 2.x) then you need to add explicit dependency on Weld API and make use of it. The dependency is org.jboss.weld:weld-api and the functionality you are looking for is #ActivateRequestContext interceptor binding. If you are looking for a link to Weld docs, its here - note that this was added in Weld 2.4!
The principle is simple - it intercepts method calls and activated context when entering the method, then destroys it when you exit the method.
#ActivateRequestContext
public void myMethod() {
// any content in here will have request context ACTIVE
doAwesomeThings();
}
If we are talking about CDI 2.0/Weld 3.x - then the very same approach was adapted by CDI (Weld version works there as well). You can read about it here.
I'm working with the developer of PF4J(Plugin Framework for Java) to provide better plugin functionality for Wicket. There is already a pf4j-spring and a pf4j-wicket project to provide some basic integration. In order to allow the #SpringBean or #Inject annotations to have access to plugin beans in a child context we need to be able to lookup the ApplicationContext associated with a specific class.
So for example, say I have a MyService bean in a child(plugin) ApplicationContext and that plugin also provides a panel that needs that via a #SpringBean annotation. Spring doesn't allow the parent ApplicationContext to see beans in a child context and for good reason. So we would get an exception saying that bean could not be found since #SpringBean only looks up beans in the parent context. We have code that we have developed that look up the child context like so:
SpringPlugin plugin = (SpringPlugin)PluginManager.whichPlugin(MyService.class);
ApplicationContext pluginContext = plugin.getApplicationContext();
How could I modify or provide this functionality in a custom version of SpringComponentInjector? It uses a ISpringContextLocator but that context locator does not specify the class for which it needs the ApplicationContext.
Any ideas on how this could be achieved?
Thanks for your help!
I'm afraid current SpringComponentInjector is not prepared for such usage. You will have to create your own version.
The problem that I see is that you will have to have either as many IComponentInstantiationListeners as plugins there are. Or create a composite ICIL that delegates to SpringBeanLocators for each plugin. I think the composite would be better. Then you'll have to make sure that a Panel in pluginA cannot use a bean located by SpringBeanLocatorB.
If you manage to do it and you find something in wicket-spring that could be made more generic to help make your version simpler then please let us know and we will consider your suggestion(s)!
Take a look at sbp. It is built on top of pf4j to support Spring Boot, and also provides mechanism of sharing beans between main application and plugins. It looks like:
#Override
protected SpringBootstrap createSpringBootstrap() {
return new SharedDataSourceSpringBootstrap(this, MdSimplePluginStarter.class)
.addSharedBeanName("objectMapper")
.addSharedBeanName("cacheService");
}
Env:
Wildfly 8.2.0 Final
JDK 8
Java EE 7
Please note that by 'POJO' i am referring to the classes that serve the other classes i.e other than value objects, entities.
This question was on back of my head for some time. Just wanted to put it out.
Based on CDI and Managed Beans specs and various other books/articles, its pretty clear that CDI injection starts with a 'managed' bean instance. By 'managed' i mean servlet, EJBs etc. which are managed by a container. From there, it injects POJOs (kind of crawl through layers) till every bean gets its dependencies. This all makes very sense to me and i see very little reason why developers ever need to use "new" to create an instance of their dependent POJO's.
One scenario that comes to my mind is when developer would like to have logic similar to
if(something) {
use-heavy-weight-A-instance
} else {
use-heavy-weight-B-instance
}
But, that also can be achieved via #Produces.
Here is one scenario that i verified to be true in wildfly 8.2.0 Final i.e. CDI is not able to inject bean when the JSP has
<%!
#Inject
BeanIntf bean;
%>
But, the alternative to use a servlet works fine.
That said, would like to know if there is any scenario(s) where a developer has to use 'new'. As i understand, by using 'new', developer owns the responsibility of fulfilling dependencies into that bean and all its dependent beans, and their dependent beans etc..
Thanks in advance,
Rakesh
When using CDI or other container you don't use new, because you expect a bunch of service coming from the container.
For CDI these main services are:
Injection of dependent beans (get existing instance or create a new
instance)
Lifecycle callback management (#PostConstruct and
#PreDestroy)
Lifecycle management of your instance (a #RequestScoped bean will make container produce an instance leaving until the end of request)
Applying interceptors and decorators on your instance
Registering and managing observers methods
Registering and managing producers methods
Now, on some rare occasion, you may want to add a part of these services to a class you instantiate yourself (or that another framework like JPA instantiate for you).
BeanManager bm = CDI.current().getBeanManager();
AnnotatedType<MyClass> type = bm.createAnnotatedType(MyClass.class);
InjectionTarget<MyClass> it = bm.getInjectionTargetFactory(type).createInjectionTarget(null);
CreationalContext<MyClass> ctx = bm.createCreationalContext(null);
MyClass pojo = new MyClass();
injectionTarget.inject(instance, ctx); // will try to satisfied injection points
injectionTarget.postConstruct(instance); // will call #PostConstruct
With this code you can instantiate your own MyClass containing injection points (#Inject) and lifecycle callbacks (#PostConstruct) and having these two services honored by the container.
This feature is used by 3rd party frameworks needing a basic integration with CDI.
The Unmanaged class handle this for you, but still prevent you to do the instantiation ;).
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.
I've got a NullPointerException using EJB3 in a J2SE environment (without EJB3 container)
Briefly, I've got a stateless bean implementing an interface.
When I call it in another class like in a main, a NullPointerException is triggered.
Sample:
#stateless
#Local(IMyInterface.class)
public class myBean implements IMyInterface{...}
public class Main{
#EJB
IMyInterface myInterface;
public static void main(String[] args){
Result result = myInterface.myBeanMethod(); // Exception happens here
}
}
I guess I miss some initialization stuff because the EJB is null when I first try to use it...
Thanks for your help,
EJBs can't work without a container. The dependencies (#EJB) are injected if the beans are instantiated by the container. If you are the one instantiating them, it is your responsibility to set the dependencies.
Furthermore, you are trying to use a non-static variable from a a static method - this won't even compile.
While you can use JPA (which is part of EJB 3) "Entity Beans" (actually, POJOs) in a J2SE environment, you can't use Session Beans without a container and you can't benefit from injection of resources using the #Resource or the more specialized #EJB and #WebServiceRef annotations in a non-managed environment, i.e. a container. In other words, only managed components support injection (Servlets, JSF Managed beans, EJB components, etc).
So, in your case, you'll need to:
Deploy your Session Bean in a Java EE container (like JBoss, GlassFish, WebLogic, etc)
Lookup the remote EJB using explicitly its global JNDI name. The code will look like that:
Foo foo = (Foo) new InitialContext().lookup("FooEJB");
A few additional remarks:
With EJB 3.0, the global JNDI name is container dependent so I can't tell you what it will be exactly (EJB 3.1 finally introduced "portable global JNDI names").
You'll need to set up the JNDI environment (which is container dependent) for the lookup either by providing a jndi.properties on the class path or by using the InitialContext(Hashtable) constructor.
You'll need to provide the application server "client library" on the class path of the client (which is obviously specific to each product).
Search for previous questions or open a new one if you need more specific guidance.