I try to use TJWS Embeddable Servlet Container to start RestEasy application using this userguide http://docs.jboss.org/resteasy/docs/2.3.3.Final/userguide/html/RESTEasy_Embedded_Container.html#d0e2640
Application work correct in JBOSS7-AS. I want to use TJWS for debuging and unit testing, but have problem with dependency injection.
I create resource class UserResource, which using CDI to inject utility class UserManager:
#Path("users")
#SessionScoped
class UserResource {
#Inject
UserManager userManager; // simple interface and imlementation
public UserResource() {} // constructor with no parameters for bean
#Path("list")
#GET
public List<User> list() {
List<User> userList = userManager.getList(); // NullPointerException
return userList;
}
}
Start TJWS in main:
public static void main(String[] args) throws IOException {
TJWSEmbeddedJaxrsServer tjws = new TJWSEmbeddedJaxrsServer();
tjws.setPort(9997);
tjws.start();
tjws.getDeployment().getRegistry().addPerRequestResource(User.class);
}
When i try to get http://localhost/users/list via browser, i get NullPointerException in UserResource.list() method, because userManager not injected and is null.
Is there any way to inject userManager?
TJWS is a standalone servlet container and web server that does not support EE annotations like #Inject. For the code to work you have to use EE container such as JBoss AS.
Related
I am using TomEE+ 1.7.1.
With JSF managed beans this code was working well:
#ManagedBean( eager = true )
#ApplicationScoped
public class AppBean {
#PostConstruct
public void init() {
ServletContext sc = (ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext();
if (GlobalSettings.TESTMODE) {
sc.getSessionCookieConfig().setDomain("." + GlobalSettings.APP_DOMAIN_TEST);
} else {
sc.getSessionCookieConfig().setDomain("." + GlobalSettings.APP_DOMAIN);
}
}
}
The init function ran at application startup and ServletContext was available.
I read everywhere that it's time to migrate to CDI beans instead of JSF beans. So I wanted to change #ManagedBean( eager = true ) to #Named #Eager (#Eager is from Omnifaces). Init function is running at application startup, but there is no FacesContext so I can't get ServletContext.
General question: How to get ServletContext in a non-request environment in CDI beans? (ServletContext is not a 'per request' object, so it should exist before the first request.)
Specific question: how to set the domain for the session cookies dynamically from code but before the first request occurs?
You should be using a ServletContextListener for the purpose of performing programmatic configuration on a servlet based application.
#WebListener
public class Config implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent event) {
ServletContext servletContext = event.getServletContext();
// ...
}
#Override
public void contextDestroyed(ServletContextEvent event) {
ServletContext servletContext = event.getServletContext();
// ...
}
}
A #WebListener is inherently also CDI managed and thus you can just use #Inject and friends in there.
An application scoped managed bean is intented for holding application scoped data/state which can be used/shared across requests/views/sessions.
Per the CDI spec, you can #Inject the ServletContext into a CDI bean. Just be sure to do it in a #PostConstruct, as injected fields are available only after construction:
#Inject ServletContext extCtxt;
#PostConstruct
public void doSomething(){
// do something with your injected field
}
I have a stateful, session scoped (CDI) EJB that holds the info about the user session.
#Stateful
#SessionScoped
public class GestorSesion implements IGestorSesionLocal, Serializable {
private final static long serialVersionUID = 1L;
private static final Logger log = Logger.getLogger(GestorSesion.class.getName());
#PostConstruct
private void init() {
log.info("Configurando información de usuario");
log.info("****************************************************************************");
}
#Override
public void cerrarSesion() {
}
#Override
public ISessionInfo getSesionInfo() {
return null;
}
}
Now, I want to call cerrarSesion() (closeSession()) from an HttpSessionListener
public class GestorSesionWeb implements HttpSessionListener {
private static final Logger log = Logger.getLogger(GestorSesionWeb.class.getName());
#Inject
private Instance<IGestorSesionLocal> gestorSesion;
#Override
public void sessionCreated(HttpSessionEvent se) {
if (log.isLoggable(Level.FINE)) {
log.fine("Iniciada sesión web");
}
gestorSesion.get().getSesionInfo();
}
#Override
public void sessionDestroyed(HttpSessionEvent se) {
if (log.isLoggable(Level.FINE)) {
log.fine("Limpiando sesión al salir");
}
try {
this.gestorSesion.get().cerrarSesion();
if (log.isLoggable(Level.FINE)) {
log.fine("Sesión limpiada sin problemas");
}
} catch (Exception e) {
log.log(Level.WARNING, "Excepción limpiando sesión", e);
}
}
}
And I access the EJB from the webapp, directly (injecting using #EJB) into the beans that I use for JSF (they are also CDI managed beans).
The issue that I face is that it seems that the HttpSessionListener seems to be in a different "session scope" than the JSF beans. Two instances of GestorSession are created; one instantiated from the JSF and other instantiated from the HttpSessionListener.
I have tried injecting the bean via #Inject Instance<IGestorSesionLocal>, #Inject IGestorSesionLocal and BeanManager, with identical results.
This bug report suggests that it should to work correctly (the bug is solved for my version), but I still cannot get around it. I have looked around, but what I find are Q&A relating to JSF managed beans (yes, I could try to wrap a reference to the EJB in a JSF managed bean, but I would like to try it "correctly" first).
Working with WilFly 8.1.0 and JDK 7
Any ideas?
I think your pb comes from here:
And I access the EJB from the webapp, directly (injecting using
#EJB) into the JSF beans.
When use CDI with EJB (by putting a #Sessionscoped on it for instance) you got an CDI bean that also has an EJB nature but not the other way around. In other word CDI is aware of the EJB nature but EJB is not aware of CDI.
So if you want to inject an EJB as a CDI bean in your code use #Inject and not #EJB. From Java EE 6 the admitted good practice is to always use #Inject except for EJB remote.
Also be sure to only use CDI managed bean and not a mix of CDI and JSF managed bean.
I'm writing Java SE application that uses CDI.
I have bean definition:
public class BeanA {
#PostConstruct
public void init() {
System.out.println("INIT");
}
public void receive(#Observes String test) {
System.out.println("received: " + test);
}
}
Requirements:
- I need to have many instances of BeanA in application
- I'd like to use Event CDI mechanism to communicate with that objects
When I use #Dependent scope, then #PostConstruct of BeanA is called everytime a new message is received. When I use #Singleton or #ApplicationScope then I can't have many objects of BeanA type.
What is solution to my problem?
I want to get a web application context url (ex.: http://myserver:8080/myApp) and store it in the database at startup.
I know how to hook a method call in the startup by using: #ApplicationScoped combined with #ManagedBean(eager=true) and #PostConstruct
And ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext().getRequestContextPath() will give me the context path.
However, since the method annotated with #PostConstruct is not being triggered by a request (since it's eager) getRequestContextPath() is giving me null.
As stated in your question, eager #ApplicationScoped bean cannot access to the context in #PostConstruct since there's no request-response cycle. Instead, use ServletContextListener to listen when the application is deployed/undeployed.
public class MyAppListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent sce) {
//here the application has been deployed
ServletContext servletContext = sce.getServletContext();
String contextPath = servletContext.getContextPath();
//do what you want/need with context path
//...
}
#Override
public void contextDestroyed(ServletContextEvent sce) {
//here the application is being undeployed
}
}
Then just configure the listener properly in web.xml
<listener>
<listener-class>the.package.of.your.MyAppListener</listener-class>
</listener>
This question already has an answer here:
Using special auto start servlet to initialize on startup and share application data
(1 answer)
Closed 7 years ago.
For university project I am developing a webapplication with JSF. My excercise is to do the frontend. A fellow studend is supposed to do backend stuff. Both parts are designed to be seerate applications. Both communicate through RMI. I want to open the connection once at deployment.
I am at the point to settle up the connection now. I tried to do that with a #ApplicationScoped ManagedBean:
//Constructor of ApplicationScoped ManagedBean
public Communication() {
this.connect();
}
Is that way possible? I tried it but the managedBean seems not to be called..
Can you advice a Best Practice?
#Brian: Unfortunately I don't use EJB at all -.-
#BalusC's pot:
I created a communicationbean:
#ManagedBean(name="communication")
#ApplicationScoped
public class Communication {
public static FrontendCommInterface server;
public Communication() {
this.connect();
}
Then I created the LoginBean:
#ManagedBean
#ViewScoped
public class Login {
#ManagedProperty(value="#{communication}")
private Communication communicationBean;
public FrontendCommInterface server;
private String username;
private String password;
public Login() {
server = communicationBean.getConnection();
}
public String login(){
HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(true);
String sessionId = session.getId();
try {
server.login(getUsername(), getPassword(), sessionId);
return "start.xhtml";
} catch (RemoteException e) {
e.printStackTrace();
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR,"Anmeldung nicht erfolgreich: ", getUsername()+", "+getPassword()+", "+sessionId));
return "login.xhtml";
}
}
But unfortunately it throws exceptions:
com.sun.faces.mgbean.ManagedBeanCreationException: Klasse org.dhbw.stg.wwi2008c.mopro.ui.managedBeans.Login can not be instanciated.
java.lang.NullPointerException
org.dhbw.stg.wwi2008c.mopro.ui.managedBeans.Login.<init>(Login.java:28)
After debuging I found out that my ManagedProperty is Null ! It hasn't been created! How to do that? I thought referencing via managedproperty would create it -.-
The managed bean is only auto-created whenever it's been referenced by EL #{managedBeanName}, which can happen by either accessing as-is in view, or by being injected as managed property of another bean, or being manually EL-resolved by e.g. Application#evaluateExpressionGet().
In your particular case, you actually want to intialize some stuff during webapp's startup. You rather want to use ServletContextListener for this.
#WebListener
public class Config implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
// Do stuff during webapp's startup.
}
public void contextDestroyed(ServletContextEvent event) {
// Do stuff during webapp's shutdown.
}
}
You could even pre-create an application scoped managed bean there whenever necessary (if your intent is to be able to access it from other beans by #ManagedProperty).
public void contextInitialized(ServletContextEvent event) {
event.getServletContext().setAttribute("bean", new Bean());
}
JSF stores application scoped beans as an attribute of the ServletContext and JSF won't auto-create another one when one is already present, so the one and the same as created by the above code example will be used by JSF as well.
If you can use EJB 3.1 lite {1} in your web app, then you can use a Singleton Session Bean, annotated with #Startup, and a #PostConstruct method. I have one that looks like:
#Singleton
#Startup
public class CachePrimer {
#PostConstruct
public void loadOpenRequests() {
...
}
}
{1}: EJB 3.1 lite is included in the Web Profile of JavEE 6, and is provided by web profile servers like Glassfish, JBoss 6, and Resin. When using such a web profile server, you simply include your EJBs in your .war file, no additional work is required.