Let me start by pointing out that while I've been using Java SE for a while now this is my first foray into Java EE territory. I'm using Netbeans 6.9 and the Netbeans code generator to do most of the heavy lifting (more on this further down). The version of GlassFish is 3 - the bog standard one that ships when you download Netbeans.
I have created a stateless Session Bean to return a simple String as follows:
#Stateless
public class SDBSStatelessSessionBean implements SDBSStatelessSessionBeanRemote {
#Override
public String sayHello() {
return "This seems to be working just fine.";
}
}
with the interface definition as:
#Remote
public interface SDBSStatelessSessionBeanRemote {
String sayHello();
}
The class and the interface were both created by using the 'Insert Code' feature that Netbeans provides. I figure this way I avoid making any stupid newbie errors (oh the irony).
My problem is that when I try to call the Enterprise bean from a servlet (the call was added using the 'Call Enterprise Bean' option from the Netbeans code generator) I get the following error:
javax.ejb.EJBException: javax.ejb.CreateException: Could not create stateless EJB
the exception was caused by:
NoClassDefFoundError
This is how the servlet makes the call:
#EJB
private SDBSStatelessSessionBeanRemote sDBSStatelessSessionBean;
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
out.println("<html>");
out.println("<head>");
out.println("<title>Test Servlet</title>");
out.println("</head>");
out.println("<body>");
out.println("<p>" + sDBSStatelessSessionBean.sayHello() +"</p>");
out.println("</body>");
out.println("</html>");
} catch (Exception e) {
out.println("<p>" + e.getMessage() + "</p>");
out.println("</body>");
out.println("</html>");
} finally {
out.close();
}
}
I'm afraid that I have not been able to find a solution to this problem after extensive Googling (mostly because the few forum posts that seem to come near this problem contain too much jargon for me to follow the solution).
I'd greatly appreciate any advice/help pointing me in the right direction.
If this is a local EJB (in the same JVM / EE container as your servlet) you could try declaring your EJB as a #LocalBean (under the #Stateless annotation). You could also remove the #Remote interface (and make your EJB no loger implement it).
So your EJB would become
#Stateless
#LocalBean
public class SDBSStatelessSessionBean
{
public String sayHello()
{
return "This seems to be working just fine.";
}
}
Related
First of all I want to say I'm pretty new in programming with ejb and jsf, and I'm trying to complete a project started by a friend of mine.
I'm getting a NullPointerException caused by the invoke of the method utenteSessionBean.CheckUtentebyId(username) of the session bean object called utenteSessionBean, declared inside the managed bean called Neo4jMBean.
I learned that it's not necessary creating and initializing a session bean (as you must do with a normal java object) in managed bean, but it's enough declaring it.
Here is the code of the session bean, which retrieves data from a DB
#Stateless
#LocalBean
public class UtenteSessionBean {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("EnterpriseApplication2-ejbPU");
public boolean CheckUtentebyId(String username){
EntityManager em = emf.createEntityManager();
Query query = em.createNamedQuery("Utente.findByUsername");
query.setParameter("username", username);
List<Utente> Res=query.getResultList();
//completare funzione ctrl+spazio
System.out.println("pre");
System.out.println("pre"+Res.isEmpty());
em.close();
System.out.println("post");
System.out.println("post"+Res.isEmpty());
if(Res.size()>=1)
{
return true;
}
else
{
return false;
}
}
}
Here's the code of the managed bean:
#ManagedBean
#ViewScoped
public class Neo4jMBean {
#EJB
private UtenteSessionBean utenteSessionBean;
static String SERVER_ROOT_URI = "http://localhost:7474/db/data/";
public Neo4jMBean() {
}
public boolean getUser(String username) {
return utenteSessionBean.CheckUtentebyId(username);
}
}
I've searched on StackOverFlow many times a solution for fixing this problem, but I haven't found something that works for me yet.
I fixed it accessing the EJB Components using JNDI.
In few words, if i use an EJB in a managed bean method, i need to add the next lines of code:
InitialContext ic = new InitialContext();
SessionBeanName = (SessionBeanClass) ic.lookup("java:global/NameOfTheApplication/NameOfTheEJBpackage/NameOfTheSessionBean");
It must be surronded by a try-catch statement
Create empty beans.xml file in your WEB-INF folder to enable CDI
I need to get the ServletContext from inside a #ServerEndpoint in order to find Spring ApplicationContext and lookup for a Bean.
For the moment my best approach is to bind that bean in the JNDI naming context and lookup it in the Endpoint. Any better solution is welcome.
I'm also looking for a reasonable way to sync servlet's HttpSession with websocket's Session.
The servlet HttpSession is in JSR-356 available by HandshakeRequest#getHttpSession() which is in turn available when a handshake request is made right before #OnOpen of a #ServerEndpoint. The ServletContext is in turn just available via HttpSession#getServletContext(). That's two birds with one stone.
In order to capture the handshake request, implement a ServerEndpointConfig.Configurator and override the modifyHandshake() method. The HandshakeRequest is here available as method argument. You can put the HttpSession into EndpointConfig#getUserProperties(). The EndpointConfig is in turn available as method argument #OnOpen.
Here's a kickoff example of the ServerEndpointConfig.Configurator implementation:
public class ServletAwareConfig extends ServerEndpointConfig.Configurator {
#Override
public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) {
HttpSession httpSession = (HttpSession) request.getHttpSession();
config.getUserProperties().put("httpSession", httpSession);
}
}
Here's how you can use it, note the configurator attribute of the #ServerEndpoint:
#ServerEndpoint(value="/your_socket", configurator=ServletAwareConfig.class)
public class YourSocket {
private EndpointConfig config;
#OnOpen
public void onOpen(Session websocketSession, EndpointConfig config) {
this.config = config;
}
#OnMessage
public void onMessage(String message) {
HttpSession httpSession = (HttpSession) config.getUserProperties().get("httpSession");
ServletContext servletContext = httpSession.getServletContext();
// ...
}
}
As a design hint, it's the best to keep your #ServerEndpoint fully free of servlet API dependencies. You'd in the modifyHandshake() implementation better immediately extract exactly that information (usually a mutable Javabean) you need from the servlet session or context and put them in the user properties map instead. If you don't do that, then you should keep in mind that a websocket session can live longer than the HTTP session. So when you still carry around HttpSession into the endpoint, then you may run into IllegalStateException when you try to access it while it's being expired.
In case you happen to have CDI (and perhaps JSF) at hands, you may get inspiration from the source code of OmniFaces <o:socket> (links are at very bottom of showcase).
See also:
Real time updates from database using JSF/Java EE
Notify only specific user(s) through WebSockets, when something is modified in the database
Updated code for BalusC's answer, the onOpen method needs to be decorated with #OnOpen. Then there is no need anymore to extend the Endpoint class:
#ServerEndpoint(value="/your_socket", configurator=ServletAwareConfig.class)
public class YourSocket {
private EndpointConfig config;
#OnOpen
public void onOpen(Session websocketSession, EndpointConfig config) {
this.config = config;
}
#OnMessage
public void onMessage(String message) {
HttpSession httpSession = (HttpSession) config.getUserProperties().get("httpSession");
ServletContext servletContext = httpSession.getServletContext();
// ...
}
}
I tried out BalusC's answer on Tomcat (Versions 7.0.56 and 8.0.14). On both containers, the modifyHandshake's request parameter does not contain a HttpSession (and thus no servletContext).
As I needed the servlet context only to access "global" variables (web-application global, that is), I just stored these variables in an ordinary static field of a holder class. This is inelegant, but it worked.
That ooks like a bug in this specific tomcat versions - has anyone out there also seen this?
Somtimes we can't get session with above ServletAwareConfig of BalusC, this is because that the session is still not created. since we are not seek for session but servletContext, in tomcat we can do as below:
public static class ServletAwareConfig extends ServerEndpointConfig.Configurator {
#Override
public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) {
try {
Field reqfld = request.getClass().getDeclaredField("request");
reqfld.setAccessible(true);
HttpServletRequest req = (HttpServletRequest) reqfld.get(request);
ServletContext ctxt = req.getServletContext();
Map<String, Object> up = config.getUserProperties();
up.put("servletContext", ctxt);
} catch (NoSuchFieldException e) {
} catch (SecurityException e) {
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
}
}
}
if we want init session immediately, we can call request.getSession().
Ref: Websocket - httpSession returns null
I searched a lot about implementing WebSocket/XMPP on Spring MVC based server but couldn't reach to a concrete answer. So here is my requirement
Receive a message from a client (in my case it will be a android/iOS mobile) via WebSocket/XMPP on tomcat server and parse the actual message at server side
Send a message from server app to WebSocket/XMPP client
If somebody could help me to point on some good tutorial or demo code, it would be a great help.
run Tomee 1.5.2
http://openejb.apache.org/downloads.html
activate the ActiveMQ JMS Server. create an OpenEJB configuration.
http://www.mail-archive.com/users#openejb.apache.org/msg04327.html
setup an XMPP ActiveMQ server protocol listener (in the activemq.xml)
in your Spring services configuration, create a Spring JMS listener (Spring ListenerContainer) configuration on the Topic/Queue.
you can use the JmsTemplate to push a message out to the Queue/Topic via ActiveMQ, the XMPP client will receive the message.
Enjoy!
BTW: This is exactly what I am in the middle of setting up right now...still learning.
check this out: www.xchat.io. It was built based on Asynchronous Spring MVC (DefferredResult, you know), XMPP, and jQuery. it's promising.
I am not sure if this is just perfect way to achieve or not, but for now I have found a solution and it would be glad to share it here.
There are two steps that you have to done.
1. Instead of ordinary HTTPServlet sub class, create a sub class of WebSocketServlet and
2. Create a sub class of MessageInbound class and override its required methods.
P.S. : Only latest version of tomcat supports WebSocket (apache tomcat 7.0.42 or higher).
Here is a WebSocket class.
public class WsChatServlet extends WebSocketServlet {
private static final long serialVersionUID = 1456546233L;
#Override
protected StreamInbound createWebSocketInbound(String protocol,
HttpServletRequest request) {
return new IncomingMessageHandler();
}
}
And this is a simple class which can send/receive message (String/binary).
public class IncomingMessageHandler extends MessageInbound {
#Override
public void onOpen(WsOutbound outbound) {
logger.info("Open Client.");
}
#Override
public void onClose(int status) {
logger.info("Close Client.");
}
#Override
public void onTextMessage(CharBuffer cb) throws IOException {
logger.info("Text Message received:" + cb.toString());
}
#Override
public void onBinaryMessage(ByteBuffer bb) throws IOException {
}
public synchronized void sendTextMessage(String message) {
try {
CharBuffer buffer = CharBuffer.wrap(message);
this.getMyoutbound().writeTextMessage(buffer);
this.getMyoutbound().flush();
} catch (IOException e) {
// Handle Exception
}
}
}
I basically am trying to inject a #Stateless bean with a local interface into a class annotated with #Named! My understanding is that injection is only possible when the injection point is managed (makes perfect sense), so for example it wouldn't be possible to inject into a POJO but you could inject into a Servlet, a JSF managed or another EJB.
I would have thought that it would have been possible to subsequently use it with #Named! However I get a NullPointerException that specifically seems to imply that this in fact doesn't seem possible!?
My classes look like this (stripped for clarity);
#Named
public class EmailUtil {
// Logger-------------------------------------------------------------------
private static final Logger LOG = Logger.getLogger(EmailUtil.class.getName());
// Constructor--------------------------------------------------------------
public EmailUtil() {
}
// EJB----------------------------------------------------------------------
#EJB AuditDAO audit;
// Methods------------------------------------------------------------------
public void sendEmail(
String emailSender,
String emailRecipient,
String emailSubject,
String emailHtmlBody,
String emailTextBody) throws FailedEmailException {
... code removed for clarity ...
// Call Amazon SES to send the message
try {
new SES().getClient().sendEmail(request);
// Create an audit log of the event
audit.create("Email sent to " + emailSender);
} catch (AmazonClientException ace) {
LOG.log(Level.SEVERE, ace.getMessage(), ace);
throw new FailedEmailException();
} catch (Exception e) {
LOG.log(Level.SEVERE, e.getMessage(), e);
}
}
}
#Stateless
public class AuditDAOImpl implements AuditDAO {
// Logger-------------------------------------------------------------------
private static final Logger LOG = Logger.getLogger(AuditDAOImpl.class.getName());
// EntityManager------------------------------------------------------------
#PersistenceContext(unitName = "iConsultPU")
private EntityManager em;
#Override
public void create(String event) {
String subject;
try {
/*
* If the current subject has authenticated and created a session we
* want to register their ID. However it is possible that a subject
* does not have an ID so we want to set it to unknown.
*/
subject = SecurityUtils
.getSubject()
.getPrincipals()
.asList()
.get(1)
.toString();
} catch (Exception e) {
subject = "UNKNOWN";
}
Audit audit = new Audit();
audit.setUserId(subject);
audit.setEventTime(Calendar.getInstance());
audit.setEvent(event);
em.persist(audit);
}
}
#Local
public interface AuditDAO {
public void create(String event);
}
I've tried using #Inject as well but that doesn't seem to work either. Have I misunderstood the specification or just poorly implemented it?
You should be injecting your dependencies. So if your EmailUtil is being manually constructed, injection won't work. It needs to be container managed. So if you use a servlet, or any managed bean, you can #Inject it. CDI injection only works for managed objects.
You can do some additional work arounds, such as manually invoking it against a constructed instance. Take a look at this question for an example like that: Parallel webservices access in a Weld CDI environment
Do you have the beans.xml in the correct location? Injection for #Named (and other CDI beans) is handled by CDI, which isn't started unless you have the beans.xml file in the correct location (WEB-INF for war and META-INF for jar).
using ejb 3.1, servlet 3.0 (glassfish server v3)
Scenario:
I have MDB that listen to jms messages and give processing to some other session bean (Stateless).
Servelet injecting jms resource.
Question 1: Why servlet can`t inject jms resources when they use static declaration ?
#Resource(mappedName = "jms/Tarturus")
private static ConnectionFactory connectionFactory;
#Resource(mappedName = "jms/StyxMDB")
private static Queue queue;
private Connection connection;
and
#PostConstruct
public void postConstruct() {
try {
connection = connectionFactory.createConnection();
} catch (JMSException e) {
e.printStackTrace();
}
}
#PreDestroy
public void preDestroy() {
try {
connection.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
The error that I get is :
[#|2010-05-03T15:18:17.118+0300|WARNING|glassfish3.0|javax.enterprise.system.container.web.com.sun.enterprise.web|_ThreadID=35;_ThreadName=Thread-1;|StandardWrapperValve[WorkerServlet]:
PWC1382: Allocate exception for
servlet WorkerServlet
com.sun.enterprise.container.common.spi.util.InjectionException:
Error creating managed object for
class
ua.co.rufous.server.services.WorkerServiceImpl
at
com.sun.enterprise.container.common.impl.util.InjectionManagerImpl.createManagedObject(InjectionManagerImpl.java:312)
at
com.sun.enterprise.web.WebContainer.createServletInstance(WebContainer.java:709)
at
com.sun.enterprise.web.WebModule.createServletInstance(WebModule.java:1937)
at
org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1252)
Caused by:
com.sun.enterprise.container.common.spi.util.InjectionException:
Exception attempting to inject
Unresolved Message-Destination-Ref
ua.co.rufous.server.services.WorkerServiceImpl/queue#java.lang.String#null
into class
ua.co.rufous.server.services.WorkerServiceImpl
at
com.sun.enterprise.container.common.impl.util.InjectionManagerImpl._inject(InjectionManagerImpl.java:614) at
com.sun.enterprise.container.common.impl.util.InjectionManagerImpl.inject(InjectionManagerImpl.java:384)
at
com.sun.enterprise.container.common.impl.util.InjectionManagerImpl.injectInstance(InjectionManagerImpl.java:141)
at
com.sun.enterprise.container.common.impl.util.InjectionManagerImpl.injectInstance(InjectionManagerImpl.java:127)
at
com.sun.enterprise.container.common.impl.util.InjectionManagerImpl.createManagedObject(InjectionManagerImpl.java:306)
... 27 more Caused by:
com.sun.enterprise.container.common.spi.util.InjectionException:
Illegal use of static field private
static javax.jms.Queue
ua.co.rufous.server.services.WorkerServiceImpl.queue
on class that only supports
instance-based injection at
com.sun.enterprise.container.common.impl.util.InjectionManagerImpl._inject(InjectionManagerImpl.java:532) ... 31 more |#]
my MDB :
/**
* asadmin commands
* asadmin create-jms-resource --restype javax.jms.ConnectionFactory jms/Tarturus
* asadmin create-jms-resource --restype javax.jms.Queue jms/StyxMDB
* asadmin list-jms-resources
*/
#MessageDriven(mappedName = "jms/StyxMDB", activationConfig =
{
#ActivationConfigProperty(propertyName = "connectionFactoryJndiName", propertyValue = "jms/Tarturus"),
#ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
})
public class StyxMDB implements MessageListener {
#EJB
private ActivationProcessingLocal aProcessing;
public StyxMDB() {
}
public void onMessage(Message message) {
try {
TextMessage msg = (TextMessage) message;
String hash = msg.getText();
GluttonyLogger.getInstance().writeInfoLog("geted jms message hash = " + hash);
} catch (JMSException e) {
}
}
}
everything work good without static declaration:
#Resource(mappedName = "jms/Tarturus")
private ConnectionFactory connectionFactory;
#Resource(mappedName = "jms/StyxMDB")
private Queue queue;
private Connection connection;
Question 2:
what is the best practice for working with MDB : processing full request in onMessage() or calling another bean(Stateless bean in my case) in onMessage() method that would process it.
Processing including few calls to soap services, so the full processing time could be for a 3 seconds.
Thank you.
Answers:
1. You cannot inject a resource into a static field. Injection into member fields occurs during object construction, static fields are not part of the object (only part of the class). In addition EJBs and servlets are threaded objects so this could possibly be dangerous to do.
2. If splitting the processing up into multiple EJB(s) makes sense do it that way, otherwise processing in onMessage() is perfectly valid.
One additional suggestion that I can give, is that you should take a look at CDI which is a new addition to the EE 6 specification and provides rich dependency injection.
Are you using an MDB to perform asynchronous operations, Servlet 3.0 has some neat asynchronous capabilities. I suggest you watch the entire presentation if you are not familiar with Servlet 3.0.