EJB injection - JNDI lookup fails - java

So I'm starting to develop a Java EE Enterprise Application with Netbeans 8.2. It's about a shop, where you have a shopping cart and you have to store each client's session correctly.
In NetBeans I have: Shop-ejb and Shop-war.
Shop-ejb contains the following classes:
CartLocal.java
package cart;
#Local
public interface CartLocal{
}
CartBean.java
package cart;
#Stateful
#StatefulTimeout(unit = TimeUnit.MINUTES, value = 20)
public class CartBean implements CartLocal{
}
Then, Shop-war contains the following servlet:
Servlet.java
import cart.CartLocal;
import java.io.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
#WebServlet(name = "Servlet", urlPatterns = {"/Servlet"})
public class Servlet extends HttpServlet {
private static final String CARRITO_SESSION_KEY = "shoppingCart";
public Servlet() {
super();
}
#Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
CartLocal carrito = (CartLocal) request.getSession().getAttribute(CARRITO_SESSION_KEY);
try {
if (carrito == null) {
InitialContext ic = new InitialContext();
carrito = (CartLocal) ic.lookup("java:global/Shop/Shop-ejb/CartBean!cart.CartLocal");
request.getSession().setAttribute(CARRITO_SESSION_KEY, carrito);
}
} catch (NamingException ex) {
Logger.getLogger(Servlet.class.getName()).log(Level.SEVERE, null, ex);
}
}
I'm using GlasshFish, and when I access to http://localhost:8080/Shop-war/Servlet I get the following error on the NetBeans console:
Grave: javax.naming.NamingException: Lookup failed for 'java:global/Shop/Shop-ejb/CartBean!cart.CartLocal' in SerialContext[myEnv={java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFactory, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming} [Root exception is javax.naming.NameNotFoundException: Shop]
I know the lookup is failing but I tried multiple things, without result. Hope you can help me.

You need to setup an <ejb-local-ref> tag on your web.xml:
For example:
<ejb-local-ref>
<ejb-ref-name>CartLocal</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<local>cat.CartLocal</local>
<ejb-link>CartLocal</ejb-link>
</ejb-local-ref>
And access via lookup:
try {
if (carrito == null) {
InitialContext ic = new InitialContext();
carrito = (CartLocal) ic.lookup("java:comp/env/CartLocal");
request.getSession().setAttribute(CARRITO_SESSION_KEY, carrito);
}
} catch (NamingException ex) {
Logger.getLogger(Servlet.class.getName()).log(Level.SEVERE, null, ex);
}

Related

AttributeNotFoundException through JMX in Startup bean on Wildfly

Hello everyone!
I'm trying to load wildfly server's system properties through JMX in Startup bean's #PostConstruct method. It works fine on the already started server instance when deployment starts, but fails while starting with server instance bootstrapping.
Wildfly 11.0.0.CR1
Startup bean code:
package ru.wildfly.test.ejb.wildflyconsulregistrar.startup;
import ru.wildfly.test.ejb.wildflyconsulregistrar.api.ConsulRegistrar;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.inject.Inject;
#Startup
#Singleton
public class WildflyConsulRegistrarStartupBean {
#Inject
private ConsulRegistrar consulRegistrar;
#PostConstruct
public void initialize() {
registerServices();
}
private void registerServices() {
consulRegistrar.registerService("WildflyTestCluster");
}
.............
}
ConsulRegistrar code:
package ru.wildfly.test.ejb.wildflyconsulregistrar.impl;
import com.ecwid.consul.v1.ConsulClient;
import com.ecwid.consul.v1.agent.model.NewService;
import ru.test.ejb.wildflyconsulregistrar.api.ConsulRegistrar;
import ru.wildfly.test.ejb.wildflyconsulregistrar.serversettings.api.CurrentServerNodeSettings;
import javax.annotation.PostConstruct;
import javax.enterprise.context.Dependent;
import javax.inject.Inject;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
#Dependent
public class ConsulRegistrarImpl implements ConsulRegistrar {
...............
#Inject
private CurrentServerNodeSettings currentServerNodeSettings;
.............
#Override
public void registerService(String serviceName) {
String currentNodeName = currentServerNodeSettings.getCurrentNodeName();
........................
}
.......................
}
CurrentServerNodeSettings code:
package ru.wildfly.test.ejb.wildflyconsulregistrar.serversettings.impl;
import ru.wildfly.test.ejb.wildflyconsulregistrar.serversettings.api.CurrentServerNodeSettings;
import javax.enterprise.context.Dependent;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import java.lang.management.ManagementFactory;
#Dependent
public class CurrentServerNodeSettingsWildflyImpl implements CurrentServerNodeSettings {
....................
#Override
public String getCurrentNodeName() {
String currentNodeName = getPlatformMBeanServerAttributeValue(String.class, "jboss.as:system-property=server.name", "value");
return currentNodeName;
}
private <T> T getPlatformMBeanServerAttributeValue(Class<T> valueType, String objectName, String attributeName) {
T attributeValue = null;
try {
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
Object attributeObject = mBeanServer.getAttribute(new ObjectName(objectName), attributeName);
attributeValue = attributeObject != null ? (valueType.cast(attributeObject)) : null;
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
return attributeValue;
}
}
Error message:
Caused by: java.lang.IllegalStateException:
javax.management.AttributeNotFoundException:
"WFLYCTL0216: Management resource '[(\"system-property\" => \"server.name\")]' not found"
at ru.wildfly.test.ejb.wildflyconsulregistrar.serversettings.impl.CurrentServerNodeSettingsWildflyImpl
.getPlatformMBeanServerAttributeValue(CurrentServerNodeSettingsWildflyImpl.java:41)
I have found the same issue on jboss forum https://developer.jboss.org/message/971717#971717 , but it was unanswered.
Any suggestions?
This is a dependency problem during startup, i.e. the server name is set after your #PostConstruct method gets executed. Try to load the server name lazy when it is accessed from the application for the first time.
In Wildfly there is no generic way to enforce the sequence of deployments from the application despite the definition of module dependencies. But this won't help in your case.

DataSource without servlet not working - NoInitialContextException

This is the actual error I'm getting:
NoInitialContextException: Need to specify class name in environment or system property
I'm trying to have a datasource connection working on a project without servlet but just a main to launch.
This is the main class:
package pacchetto;
import java.sql.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class testIt {
public static void main(String[] args) throws SQLException, NamingException {
Context ctx = new InitialContext();
javax.sql.DataSource ds = (javax.sql.DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
Connection con = ds.getConnection();
try {
con = ds.getConnection();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (con != null)
System.out.println("Connessione riuscita");
}
}
}
In the same project I also have a servlet file and using it everything works fine. This led me to thinking that the problem must be in this class and not in the servlet.xml or any other configuration file. Should I be wrong and should you need the whole scene I'll be happy to paste them here along with the main.
What am I doing wrong?

NameAlreadyBoundException using JNDI

I created a session bean with this code:
package ejb2;
import javax.annotation.Resource;
import javax.ejb.SessionContext;
import javax.ejb.Stateless;
#Stateless(name = "TestEJB", mappedName = "EJB2-Project1-TestEJB")
public class TestEJBBean implements TestEJB, TestEJBLocal {
#Resource
SessionContext sessionContext;
public TestEJBBean() {
}
public String getHello(String who_welcome) {
return "Hello " + who_welcome;
}
}
As you can see, it's almost a default code (except getHello method). Besides this bean I have a client:
package ejb2;
import java.util.Hashtable;
import javax.naming.CommunicationException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class TestEJBClient {
public static void main(String[] args) {
try {
final Context context = getInitialContext();
TestEJB testEJB = (TestEJB) context.lookup("EJB2-Project1-TestEJB#ejb2.TestEJB");
System.out.println(testEJB.getHello("Student"));
} catch (CommunicationException ex) {
System.out.println(ex.getClass().getName());
System.out.println(ex.getRootCause().getLocalizedMessage());
System.out.println("\n*** A CommunicationException was raised. This typically\n*** occurs when the target WebLogic server is not running.\n");
} catch (Exception ex) {
ex.printStackTrace();
}
}
private static Context getInitialContext() throws NamingException {
Hashtable env = new Hashtable();
// WebLogic Server 10.x/12.x connection details
env.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
env.put(Context.PROVIDER_URL, "t3://localhost:7101");
return new InitialContext(env);
}
}
First time it worked like a charm. But then I created another bean:
package ejb2;
import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.ejb.SessionContext;
import javax.naming.Context;
import javax.naming.InitialContext;
#Stateless(name = "ClientEJB", mappedName = "EJB2-Project1-ClientEJB")
public class ClientEJBBean implements ClientEJB, ClientEJBLocal {
#Resource
SessionContext sessionContext;
TestEJB testEJB;
public ClientEJBBean() {
try {
final Context context = new InitialContext();
testEJB = (TestEJB) context.lookup("EJB2-Project1-TestEJB#ejb2.TestEJB");
} catch (Exception ex) {
ex.printStackTrace();
}
}
public String getHelloFromBean(String who) {
return testEJB.getHello(who);
}
}
And now beans aren't working. I get an error like this:
weblogic.application.ModuleException: Unable to bind Business Interface to the JNDI name: EJB2Project1WebApp_warClientEJB_Home, throw exception javax.naming.NameAlreadyBoundException: [EJB:011224]Unable to bind the interface ejb2.ClientEJB to ClientEJB. Another EJB has already bound an interface to that name.; remaining name 'EJB2-Project1-ClientEJB#ejb2'. NestedException Message is :[EJB:011224]Unable to bind the interface ejb2.ClientEJB to ClientEJB. Another EJB has already bound an interface to that name.
What's the problem with these codes?
As far as i can see you try to deploy two stateless EJBs with the same JNDI name
Try to undeploy the current application , check the JNDI tree from Admin Console
and make sure the tree does not have the JNDI name you see as duplicate.

How to achieve separation of concerns without using any framework but Tomcat + Servlets?

I have a code that works fine. The important parts are as follows:
My model class:
package biz.tugay.sakila.model;
/* User: koray#tugay.biz Date: 25/06/15 Time: 12:48 */
public class Actor {
private long id;
private String firstName;
private String lastName;
// Getters, setters...
}
My dao class:
package biz.tugay.sakila.dao;
/* User: koray#tugay.biz Date: 25/06/15 Time: 12:12 */
import biz.tugay.sakila.model.Actor;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class ActorDao {
protected static final Connection connection = DBConnector.getConnection();
public List<Actor> getAllActors() throws SQLException {
List<Actor> allActors = new ArrayList<Actor>();
Statement stmt = connection.createStatement();
String sql = "SELECT * FROM Actor";
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
Actor actor = new Actor();
actor.setFirstName(rs.getString("first_name"));
// You get the idea... Setters again..
allActors.add(actor);
}
rs.close();
stmt.close();
return allActors;
}
}
and the DBConnector
package biz.tugay.sakila.dao;
/* User: koray#tugay.biz Date: 25/06/15 Time: 12:35 */
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DBConnector {
static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
static final String DB_URL = "jdbc:mysql://localhost/sakila";
static final String USER = "root";
static final String PASS = "";
private static Connection connection = null;
public static final Connection getConnection() {
if (connection != null) {
return connection;
} else {
try {
Class.forName(JDBC_DRIVER);
connection = DriverManager.getConnection(DB_URL, USER, PASS);
return connection;
} catch (ClassNotFoundException e) {
} catch (SQLException e) {
}
throw new UnsupportedOperationException();
}
}
}
My Servlet class:
package biz.tugay.sakila.servlet;
/* User: koray#tugay.biz Date: 26/06/15 Time: 14:31 */
import biz.tugay.sakila.dao.ActorDao;
import biz.tugay.sakila.model.Actor;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
#WebServlet(urlPatterns = "/actors")
public class ActorServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
ActorDao actorDao = new ActorDao();
List<Actor> allActors = null;
try {
allActors = actorDao.getAllActors();
req.setAttribute("allActors",allActors);
req.getRequestDispatcher("/actors.jsp").forward(req, resp);
} catch (SQLException e) {
}
}
}
And /actors.jsp will show an HTML table to the user.
I have made this exercise myself with the sakila sample database MySQL provides.
My question is, without using any framework such as Spring or Struts, how can I achieve a better separation? For example, currently ActorServlet depends on ActorDao concretely, can I fix this, if so how? Also ActorDao depends heavily on DBConnector. For example, I want to be able to create a NoSQL connector and use it, but currently I can not I guess?
First step is to abstract out some interfaces. For example, make ActorDao an interface, move the implementation to ActorDaoImpl or whatever. Create an ActorDaoFactory that hands you an ActorDao which is, under the covers, an ActorDaoImpl, but the servlet doesn't need to know that.
Second step is more complex... if you want to only use Tomcat, then injection and the like is out, but you can configure Tomcat to create these new interfaces and put them in JNDI. This process is probably too complex to put in an answer here, but the Tomcat documentation on JNDI is really nice. The process basically involves creating a factory, like I advocated above, and then having Tomcat invoke that factory through configuration.
Once you do this, looking them up from JNDI is as simple as
// Obtain our environment naming context
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
// Look up our DAO
ActorDao ad = (ActorDao)envCtx.lookup("dao/actor");
Good luck!

How to run Application Client on the GlassFish Server 4 from command line

I just started to learn EJB and I wrote a simple bean and client application. Below is a code:
Interface:
package ejb;
import javax.ejb.Remote;
#Remote
public interface MySessionRemote {
String getResult();
}
Bean:
import javax.ejb.EJB;
import javax.ejb.Stateless;
#Stateless
public class MySession implements MySessionRemote {
// #EJB
//private static MySessionRemote mySession1;
#Override
public String getResult() {
return "Bean";
}
}
Client application:
package entappclient;
import javax.naming.*;
import ejb.MySessionRemote;
import java.util.Properties;
import javax.ejb.EJB;
public class Main {
// #EJB private static MySessionRemote mySession;
public static void main(String[] args) {
// TODO code application logic here
new Main().Save();
}
public Context getContext() throws javax.naming.NamingException {
Properties props = new Properties();
props.setProperty("java.naming.factory.initial",
"com.sun.enterprise.naming.SerialInitContextFactory");
props.setProperty("java.naming.factory.url.pkgs",
"com.sun.enterprise.naming");
props.setProperty("java.naming.factory.state",
"com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
props.setProperty("org.omg.CORBA.ORBInitialHost", "localhost");
return new InitialContext(props);
}
public void Save () {
//System.out.println(mySession1.getResult());
try {
Context jndiContext = getContext();
System.out.println("0");
MySessionRemote ref = ySessionRemote)jndiContext.lookup("java:global/EntAppEJB- ejb/MySession!ejb.MySessionRemote");
System.out.println("1");
System.out.println(ref.getResult());
} catch (Exception e ) {
System.out.println("Save"+e);
}
}
}
When I run it under NetBeans 8 everything works fine. The result is:
0
1
Bean
But when I try to run this from command line using : appclient - client path/EntAppClient.jar, it does not work. The result is:
0
Savejavax.naming.NamingException: Lookup failed for 'java:global/EntAppEJB-ejb/M
ySession!ejb.MySessionRemote' in SerialContext[myEnv={java.naming.factory.initia
l=com.sun.enterprise.naming.SerialInitContextFactory, org.omg.CORBA.ORBInitialHo
st=localhost, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.J
NDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming} [Ro
ot exception is javax.naming.NamingException: ejb ref resolution error for remot
e business interfaceejb.MySessionRemote [Root exception is java.lang.ClassNotFou
ndException: ejb.MySessionRemote]]
Can anybody help me to find out why I can run this under NetBeans but it does not work from command line.
Best regards
Marcin

Categories

Resources