Indeed you seem to mix CDI Beans and JSF Beans and to be honest the example you are translating seems pretty strange I would just throw it out the window all together.
Because, JSF too has it's own dependency injection and you don't really extract stuff yourself from the scoped maps unless you have a very specific use case (say a ServletFilter).
To clarify CDI uses the http://en.wikipedia.org/wiki/Inversion_of_control principle and to "extract" stuff yourself is a anti pattern.
Further on CDI beans are created and managed by the CDI container (Weld or OWB in almost all cases) and you simply can't retrieve a CDI bean from externalContext because it's JSF's context and it's a completely separate thing.
Thus instances created by JSF are not injectable in CDI Beans and vice versa. Anyways as I said earlier extracting stuff yourself is bad practice. See #10 in this list: http://zeroturnaround.com/rebellabs/watch-out-for-these-10-common-pitfalls-of-experienced-java-developers-architects/
So whatever you want you simply use @Inject
(possibly with a qualifier).
Workaround For special cases when Inject will not work:
- CDI context is not available in the current thread.
- Current instance is not CDI managed
The first scenario happends when you have a ThreadLocal for example a QuartzJob. EJB containers might offer ways to get contextual threads but if you are on a plain servlet container (tomcat) or the thread is spawned with no CDI context for what ever reason you must attach this information yourself. To do this use Deltaspike CDI Control.
http://deltaspike.apache.org/container-control.html
That example is not updated, Today you should use DependentProvider to get a hold of ContextControl.
Example on my blog here: http://www.kildeen.com/blog/post/2013-10-11/Batch%20Jobs%20in%20EE/
The second scenario is when the ServletContainer created the instance and you are on a plain container (for example Tomcat), JSF created the instance, whatever.
Then, injection will not work. As workaround use BeanProvider from Deltaspike. http://deltaspike.apache.org/core.html It can force injection in your current instance and what's even more useful, it can extract a bean for you. If you do this and you still suffer from the first scenario you will get an exception, probably ContextNotActiveException
.
To get started properly with JSF and CDI I would recommend using TomEE. It's a apache project thus it's open source. The mailing list and irc channel is really active and it's really on the rise and even now it's really great.
Of course this is my opinion and others prefer other solutions such as WildFly, build it yourself with Tomcat / Jetty, Glassfish etc.
Now, all the usual rules of JSF applies (must use convention for getters / setters etc). To expose your bean to EL expressions (that JSF uses) you must mark it as @Named
. The default name will be myBean
if the class is named MyBean
.
Now comes the scopes. Always use @RequestScoped for every bean you have in your application. When you run into trouble because that scope is to short you should consider how long it should be, if the data you want to keep is interesting for other beans and if you want it available across all browser tabs.
If it's user information then chances are it's interesting for many beans. Thus we create a new class called WebUser
. The user probably expects his information to be kept for the full duration of his session (and you might need to track him with that object too). So we use @SessionScoped
from the correct package, must be import javax.enterprise.context.SessionScoped
. But all of the sudden some logic should not be shared across tabs so you need a more fine grained scope. CDI comes with @ViewScoped
(CDI 1.1, JSF 2.2) and @ConversationScoped
but chances are you want the scopes from Myfaces CODI sooner or later. Now, most of CODI is already in deltaspike but not the scopes. They have however been split off and how to import them is explained here: http://os890.blogspot.fr/2013/07/add-on-codi-scopes-for-deltaspike.html You will see them in Deltaspike instead sooner or later.
So now you can use a lot of different scopes and you choose this wisely. Stuff that should only be read once from the DB can be stored with @ApplicationScoped
.
For example you might want to read system settings from the database and store them in SettingManager that is a CDI bean annotated with @ApplicationScoped
.
WelcomeBean
is @RequestScoped
and @Model
and is responsible for logins and account creation. To find out if new accounts may be created it might look like this:
@ViewScoped
@Named
public class WelcomeBean {
@Inject
private SettingManager settingManager;
private boolean allowCreateAccount;
public boolean isAllowCreateAccount() {
return allowCreateAccount;
}
// login and create account here
@PostConstruct
private void init() {
allowCreateAccount = settingManager.getBooleanSetting("registrationOpen");
}
}
The Facelet create account button looks like this:
<h:commandButton action="#{welcomeBean.createAccount}" value="login" disabled="#{welcomeBean.allowCreateAccount}"/>
Now when the user performs the login you might want to signal this as an event. Read up on CDI events. Really the most advanced examples differs little from this simple one.