Hibernate SessionFactory: how to configure JNDI in Tomcat? - java

that's how the session factory should be gotten:
protected SessionFactory getSessionFactory() {
try {
return (SessionFactory) new InitialContext()
.lookup("SessionFactory");
} catch (Exception e) {
}
}
Please provide a simple solution for Tomcat6 to be able to get SessionFactory
thru simple jndi lookup in Java code.
What should be written in what file on the side of Tomcat ?

Here's a link
http://community.jboss.org/wiki/UsingJNDI-boundSessionFactorywithTomcat41
But other answers are welcome as well.

Tomcat documentation says:
Tomcat provides a read-only InitialContext, while Hibernate requires
read-write in order to manage multiple session factories. Tomcat is
apparently following the specification for unmanaged containers. If
you want to bind the session factory to a JNDI object, you'll either
have to move to a managed server (Glassfish, JBoss, etc.), or search
on the Internet for some posted work-arounds.
The recommendation from the Hibernate documentation is to just leave
out the hibernate.session_factory_name property when working with
Tomcat to not try binding to JNDI.
And Hibernate documentation says the same:
It is very useful to bind your SessionFactory to JDNI namespace. In
most cases, this is possible to use hibernate.session_factory_name
property in your configuration. But, with Tomcat you cann't use
hibernate.session_factory_name property, because Tomcat provide
read-only JNDI implementation. To use JNDI-bound SessionFactory with
Tomcat, you should write custom resource factory class for
SessionFactory and setup it Tomcat's configuration.
So you need to make custom SessionFactory like that:
package myutil.hibernate;
import java.util.Hashtable;
import java.util.Enumeration;
import javax.naming.Name;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.RefAddr;
import javax.naming.spi.ObjectFactory
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateSessionFactoryTomcatFactory implements ObjectFactory{
public Object getObjectInstance(Object obj, Name name, Context cntx, Hashtable env)
throws NamingException{
SessionFactory sessionFactory = null;
RefAddr addr = null;
try{
Enumeration addrs = ((Reference)(obj)).getAll();
while(addrs.hasMoreElements()){
addr = (RefAddr) addrs.nextElement();
if("configuration".equals((String)(addr.getType()))){
sessionFactory = (new Configuration())
.configure((String)addr.getContent()).buildSessionFactory();
}
}
}catch(Exception ex){
throw new javax.naming.NamingException(ex.getMessage());
}
return sessionFactory;
}
}

Related

How to debug a call to an EJB from a Netbeans platform module

Using GlassFish 3.1.2, I try to call a Session Bean from a Netbeans platform module, and I get a null pointer exception. My problem is that I have no trace explaining how / where the NPE is generated.
The code in my Module is simply:
import ejb.MySessionRemote;
import javax.ejb.EJB;
public class TestServer {
#EJB
private static MySessionRemote mySession;
public boolean execute() {
System.out.println("result = " + mySession.getString()); //NPE here: mySession is null
return true;
}
}
The Session bean "My Session", the remote interface and the application deployed on the server side are just the ones from this tutorial: https://netbeans.org/kb/docs/javaee/entappclient.html
Any help greatly appreciated.
Note: I've checked this tutorial, without solving my issue.
If mySession is null, it was probably not injected. You can inject into managed beans (EJBs for example), because these instances are managed (created/removed) by a container, and the container does the injection for you.
You can possibly inject into a POJO, if you use CDI.
If TestServer is part of a stand-alone application for example, try to lookup the EJB using JNDI. This is what your tutorial does as well. It involves setting up the properties to get an InitialContext, and the lookup of the EJB using JNDI.

#EJB annotation does not work for initialize bean within the EJB application

I have a Maven project with this structure:
-myproject
-myproject-ear
-myproject-service
-webservice
-myproject-ejb
In the myproject-ejb I have this java packages:
-src/main/java/
-src/test/java/
I have an EJB and the corresponding bean implementation in
-src/main/java/org/mypackage/MyBean.java
-src/main/java/org/mypackage/MyBeanImpl.java
In src/test/java/ I have a test called MyBeanTest.java with the following code:
import javax.ejb.EJB;
import org.mypackage.MyBean;
import org.junit.*;
public class MyBeanTest {
#EJB
private MyBean myBean;
#Test
public void testBean() {
System.out.println("myBean: "+myBean); // prints null
myBean.writeToDB("Hello", "World"); // fails since myBean is null
}
}
When I run the unit test, the myBean is null. I am wondering why the #EJB annotation does not work. The test package is in the same application as the bean, so #EJB should work.
Any ideas?
EDIT 1
I found this link with the same problem as I have, but the solution there doesn´t seem to work for me. Am I doing anything wrong?
package org.myproject.ejb;
import java.util.Hashtable;
import java.util.Properties;
import javax.ejb.EJB;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import org.myproject.ejb.MyBean;
import org.jboss.ejb.client.ContextSelector;
import org.jboss.ejb.client.EJBClientConfiguration;
import org.jboss.ejb.client.EJBClientContext;
import org.jboss.ejb.client.PropertiesBasedEJBClientConfiguration;
import org.jboss.ejb.client.remoting.ConfigBasedEJBClientContextSelector;
import org.junit.*;
public class MyBeanTest {
private MyBean myBean;
#Before
public void init() {
try {
Properties clientProp = new Properties();
clientProp.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "false");
clientProp.put("remote.connections", "default");
clientProp.put("remote.connection.default.port", "4447");
clientProp.put("remote.connection.default.host", "localhost");
clientProp.put("remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS", "false");
EJBClientConfiguration cc = new PropertiesBasedEJBClientConfiguration(clientProp);
ContextSelector<EJBClientContext> selector = new ConfigBasedEJBClientContextSelector(cc);
EJBClientContext.setSelector(selector);
Properties env = new Properties();
env.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
env.put(Context.SECURITY_PRINCIPAL, "admin");
env.put(Context.SECURITY_CREDENTIALS, "testing");
InitialContext ctx = new InitialContext(env);
myBean = (MyBean) ctx.lookup("java:app/myproject-ejb-1.0-SNAPSHOT/MyBeanImpl");
}
catch(NamingException ex) {
ex.printStackTrace();
}
}
#Test
public void testBean() {
System.out.println("ejb: "+myBean); // prints null
}
}
The error I get with the above configuration is:
WARN: Unsupported message received with header 0xffffffff
javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:662)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:307)
at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:344)
Container resource injection, such as #EJB, requires a populated JNDI directory and only works within Java EE managed components executing in a Java EE container. Is a challenge for unit testing. See JSR318 Java EE 6 Platform Spec, section EE.5 Resources, Naming, and Injection.
You're now attempting JNDI lookup - Java SE unit test app remotely connecting its JNDI Context. Disadvantages: must deploy full Java EE 6 app as precondition to run test; test-bugfix-build-deploy-retest lifecycle can slow things.
Some issues:
Your username/password properties are different than JBoss doc;
From doc it appears JNDI lookup name needs to be "ejb:..." rather than "java:app/..." because the JBoss EJB-client-project code uses this to intercept the lookup. Also from Java EE 6 platform spec EE.5.2.2: Names in java:app namespace are shared by all components in all modules in a single Java EE app. If your test is a separate JSE app using java:app, I suspect JBoss treats it as separate to the single Java EE application, and lookup will fail.
Make sure you lookup the interface, not the implementation class (i.e. the EJB no interface view) for remote access
You're refering to an unusual reference showing direct use of EJBClientConfiguration & EJBClientContext. It seems this is not required/preferred.
Try these actions:
Include these properties:
clientProp.put("remote.connection.default.username", "admin");
clientProp.put("remote.connection.default.password", "testing");
Change client reference:
java:app/myproject-ejb-1.0-SNAPSHOT/MyBeanImpl to
ejb:<app-ear-name>/<module-jar-name>/<jboss-optional-distinct-name>/<bean-name>!<fully-qualified-classname-of-the-remote-interface>
E.g. if MyBean is a stateless EJB deployed in myproject-ejb-1.0-SNAPSHOT.jar (without any ear). Then:
ejb:/myproject-ejb-1.0-SNAPSHOT//MyBeanImpl!org.mypackage.MyBean
If it's a stateful EJB, then add "?stateful" to string.
Setup ejb-client.properties directly (via file or program) and apply directly to JNDI Context. See https://docs.jboss.org/author/display/AS72/EJB+invocations+from+a+remote+client+using+JNDI and https://docs.jboss.org/author/display/AS72/Scoped+EJB+client+contexts and http://middlewaremagic.com/jboss/?p=1177
In future: use CDI for injection; JUnit + CDI #Mock for "POJO" unit testing; Arquillian for "Java EE" unit/module testing in containers. Then you could avoid/reduce tests like (2) above (JSE client -> EJB).
CDI supports:
Java EE resource injection into POJOs (including #EJB annotation). This still requires a deployed Java EE app/component and populated JNDI directory to lookup.
Managed beans as POJOs or Java EE components (incl. EJBs) - inject "any" to "any" with superior #Inject annotation. Works without JNDI directory, is typesafe & bean scope-aware.
Supports unit testing via simple mocking. Use #Mock & #Specializes to declare replacement version for any bean. Test EJB clients without EJBs. Test EJBs as POJOs.
To enable CDI, include a beans.xml file (can be empty, if all config via annotation).
To declare a managed bean:
optional scope above class e.g. #SessionScoped
no-arg constructor / #Inject on constructor
Use this to inject a reference:
#Inject (optional #MyDeclaredQualifier) private MyBean myBean;
Arquillian ("JUnit for Java EE 6") runs test code itself on a Java EE server. It dynamically deploys test code to configured container(s) and runs tests. It supports #EJB annotation, JNDI connection becomes simple and you can include Java EE classes in unit tests without mocking, or refactoring to abstract away from them.
1) Annotation injection is done by container. So the class which is not managed(container managed) will not be able to do annotation injection.
2) Now, in this scenarios, you will have to make a manual call to JNDI and retrieve EJB instance:
ie:
InitialContext ctx = new InitialContext();
MyBean bean = (MyBeanRemote) ctx.lookup("java:global/<portable jndi name of your bean>");
Note: The use of no arg constructor InitialContext(). Because your java class is deployed in a server I presume. Or else you may need to specify context factory class if your class is a standalone java class, depending on the vendor.
Note: You will need Bean Remote interface if you are making a call to EJB from a different application (ie: different war, ear ...) or else Local interface is enough.
This exception is thrown when no initial context implementation can be created. The policy of how an initial context implementation is selected is described in the documentation of the InitialContext class.
This exception can be thrown during any interaction with the InitialContext, not only when the InitialContext is constructed. For example, the implementation of the initial context might lazily retrieve the context only when actual methods are invoked on it. The application should not have any dependency on when the existence of an initial context is determined.

JNDI InitialContext not working in simple netbeans project

Warning: New to Java
I have a simple Netbeans project - I wanted to just learn about interacting with DB's coming from php I thought I would have a go with a local one running on my computer.
Lots of the examples out there say to use the InitialContext() object to refer to the database resource.
After following the examples I get the following exception - Lots of Google stuff points to some .xml file - which I have no idea about or even where it exists in the Netbeans project? I'm not using a Webserver at this time so not Tomcat or anything like that, just local Java program to do this, I suspect this might be the problem. Could anyone shed some light on this?
Exception thrown javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.
package learningjava;
import com.mysql.jdbc.jdbc2.optional.*;
import com.mysql.jdbc.Driver;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.*;
public class LearningJava {
public static void main(String[] args) {
MysqlDataSource test_db = new MysqlDataSource();
test_db.setServerName("localhost");
test_db.setDatabaseName("dev");
try {
InitialContext test_db_context = new InitialContext();
test_db_context.bind("jcdb/testdb", test_db);
MysqlDataSource test_db_datasource = (MysqlDataSource)test_db_context.lookup("testdb");
} catch (NamingException e) {
System.out.println("Exception thrown " + e);
}
try {
test_db.getConnection("root","password");
} catch (SQLException e) {
System.out.println("Exception thrown " + e);
}
}
}
could you try to add this before the InitialContext test_db_context = new InitialContext();:
System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.naming.java.javaURLContextFactory");
System.setProperty(Context.URL_PKG_PREFIXES, "org.apache.naming");
You should include the jar naming-common-4.1.34 and mysql-connector-java-5.1.6 in your classpath
This example works for me (not optimized but works!)
public static void main(String[] args) throws NamingException {
// Create initial context
System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.naming.java.javaURLContextFactory");
System.setProperty(Context.URL_PKG_PREFIXES, "org.apache.naming");
InitialContext ic = new InitialContext();
ic.createSubcontext("java:");
ic.createSubcontext("java:comp");
ic.createSubcontext("java:comp/env");
ic.createSubcontext("java:comp/env/jdbc");
MysqlConnectionPoolDataSource mysqlConnectionPoolDataSource = new MysqlConnectionPoolDataSource();
mysqlConnectionPoolDataSource.setUser("root");
mysqlConnectionPoolDataSource.setPassword("root");
mysqlConnectionPoolDataSource.setURL("jdbc:mysql://localhost:3306/test_my_database");
ic.bind("java:comp/env/jdbc/test", mysqlConnectionPoolDataSource);
}
In general you should understand that JNDI should have a server. In a code snippet you've provided you're using a _CLIENT_SIDE_ part of JNDI technology when you're doing your lookup. There should be a JNDI server that should be accessible from your local client connection.
Once configured properly, the call to lookup should issue a connection with JNDI server and provide a way to obtain/bind resources to that server.
How to configure JNDI properly?
Usually you should supply a properties file that will contain a host name of this server, a port + some implementation specific information.
JNDI server is usually already provided when you're using application server (like JBoss or Web Sphere).
I think this is the root of misunderstanding here.
Hope, this helps
Usually JNDI is used inside an application server which is not your case.
For your needs you may use the following code:
Class.forName("com.mysql.jdbc.Driver")
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost/dbname", "user", "password");
Also you need to download MySQL driver here and add corresponding JAR file (mysql-connector-java-5.1.21-bin.jar) to your application's class path here is described how to do it.

Dynamic JPA Connection

I have a fairly standard Java EE6 web application using JPA 2 with dependency injection connecting to a MySQL database and everything is working fine. What I would like to do now is have this application interact with the databases of other applications we have installed at a clients site - essentially acting as a single point of control for our other application installs.
What I'm struggling with is how best to perform the interaction with the other databases. Ideally I would like to create an EntityManager for each install and interact using JPA but I can't see any way to set this up. I may, for example, have 5 installs (and therefore databases) of one application type and the master control application won't know about the other installs until runtime. This seems to preclude using dependency injection of an EntityManager and all the automatic transaction demacation etc etc. The alternative option is to just create a DataSource and do the interactions manually. While flexible this clearly requires a lot more effort.
So, my question really is how do I best tackle this problem?
I'm also looking into this, and so far I have found the following blog post that describes a way to do it
http://ayushsuman.blogspot.com/2010/06/configure-jpa-during-run-time-dynamic.html :
Removed all your database properties from persistance.xml
<persistence>
<persistence-unit name="jpablogPUnit" transaction-type="RESOURCE_LOCAL">
<class>com.suman.Company</class>
</persistence-unit>
</persistence>
Changed your java file where you are configuring entityManager, in our case TestApplication.java
package com.suman;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import org.apache.log4j.Logger;
/**
* #author Binod Suman
*/
public class TestApplication {
Logger log = Logger.getLogger(TestApplication.class);
public static void main(String[] args) {
TestApplication test = new TestApplication();
test.saveCompany();
}
public void saveCompany(){
log.info("Company data is going to save");
EntityManagerFactory emf;
Map properties = new HashMap();
properties.put("hibernate.connection.driver_class", "com.mysql.jdbc.Driver");
properties.put("hibernate.connection.url", "jdbc:mysql://localhost:3306/sumandb");
properties.put("hibernate.connection.username", "root");
properties.put("hibernate.connection.password", "mysql");
properties.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
properties.put("hibernate.show-sql", "true");
//emf = Persistence.createEntityManagerFactory("jpablogPUnit");
emf = Persistence.createEntityManagerFactory("jpablogPUnit",properties);
EntityManager entityManager = (EntityManager) emf.createEntityManager();
entityManager.getTransaction().begin();
Company company = new Company(120,"TecnoTree","Espoo, Finland");
entityManager.persist(company);
entityManager.getTransaction().commit();
log.info("Company data has been saved");
}
}

How to use JPA EclipseLink to connect to the DB in a multi layer environment (REST + EJB + Core)?

I am using Glassfish v3 server.
Usually the DB connection with EJB3 + JPA (Eclipselink) is done through injection, with #PersistenceUnit or #Persistencecontext.
However, there are 3 layers in my App :
Core (contains business logic, entities, exception handling etc)
an EJB on top of it, calling the right core objects and methods to do the job. This EJB is called by other internal modules of our ERP.
a REST layer on top of it for uses by frontend web sites.
I do not want to get the entityManager, nor the EMF (EM factory) in the EJB, because I want my middle layer to be unaware that there is a DB used under it. I could after all, later, decide to change my core implementation for a non-DB-using one.
I see only two bad solutions :
1) Add an EM parameter every time i call a method of the core layer that needs DB connection. Very ugly and goes againt what I said above.
2) In every method of core needing DB connection, I create a factory, an EM, use them, and then close them both.
I tried to cut things in the middle, having one factory per class of the Core level, and EMs are created and closed in every method. But I still have memory leaks like this :
javax.servlet.ServletException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.0.0.v20091127-r5931): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: Error in allocating a connection. Cause: In-use connections equal max-pool-size and expired max-wait-time. Cannot allocate more connections.
I guess it's because if one of my EJB methods uses 10 different objects, it creates 10 EM factories, and none of them is closed.
Example of typical use in a Core object:
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
// do some stuff with em; for example persist, etc
em.flush();
em.close();
Should I go for solution 2?
Is there a way to use a single EM factory at this core level ? I seems like the JPA spec assumes you're going to use the entities at the EJB level only, which is bad in a multi layers apps.
EDIT : here is the current status after trying #Inject :
Added an empty beans.xml file in the /META-INF directory on my CORE jar.
The parent DAO class is now like this :
public class ExampleBZL {
public EntityManagerFactory emf;
#Inject public Emf emfobject;
public ExampleBZL()
{
this.emf = emfobject.emf;
}
The Emf class is very simple, and Stateless.
#Stateless
public class Emf implements EmfAbstract {
#PersistenceUnit(unitName = Setup.persistenceUnitName)
public EntityManagerFactory emf;
public Emf()
{
}
}
I must be doing something wrong, but the injection doesn't work, altough in glassfish I see "[ejb, weld, web]" in the engines list, so the CDI is loaded.
Servlet.service() for servlet Jersey Web Application threw exception
java.lang.NullPointerException
at com.blablabla.core.bizlogic.ExampleBZL.<init>(ExampleBZL.java:40)
Am I missing other annotations ?? Is it really working to do an inection in a JAR with those two small annotations (Stateless on one side, Inject on the other) ?
With JavaEE 6 you can define your core level classes as Beans and inject resources there.
Please check Context and Dependency Injection (CDI) with JavaEE 6.
What if you had two session beans? One with the injected EntityManager that can leverage JTA, and the other is your current session bean.
I am currently putting together a series on my blog using a session bean as the REST service using EclipseLink & Glass Fish v3:
Part 1 - The Database Model
Part 2 - Mapping the Database Model to JPA Entities
Part 3 - Mapping JPA Entities to XML using JAXB
Part 4 - The RESTful Service
Below is how I inject the EntityManager on my session bean that is serving as my REST service:
package org.example.customer;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.ws.rs.Path;
import org.eclipse.persistence.rest.JPASingleKeyResource;
#Stateless
#LocalBean
#Path("/customers")
public class CustomerService {
#PersistenceContext(unitName="CustomerService", type=PersistenceContextType.TRANSACTION)
EntityManager entityManager;
}
You can link your session beans using the #EJB annotation:
package org.example;
import javax.ejb.EJB;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.naming.Context;
import javax.naming.InitialContext;
#Stateless
#LocalBean
#EJB(name = "someName", beanInterface = CustomerService.class)
public class OtherSessionBean {
public Customer read(long id) {
try {
Context ctx = new InitialContext();
CustomerService customerService = (CustomerService) ctx.lookup("java:comp/env/someName");
return customerService.read(id);
} catch(Exception e) {
throw new RuntimeException(e);
}
}
}
I am not sure it is a good answer, but I have found this :
link of forum saying :
it appears that interaction between
JPA and CDI was considered but not
made part of the spec for some unknown
reason. If I come to know of the
reason, I shall update this thread. In
the mean while, it has been sent as a
feedback to appropriate folks. So,
this one is definitely not a bug in
GlassFish.
So, does that explain why my #Inject (of a class containing an entity manager) in a java class is not working ?
Here is the final working code, thanks to Blaise :
The father class that "receives" the connection
import com.wiztivi.apps.wsp.billing.interfaces.bin.db.NewInterface;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.persistence.EntityManager;
#Stateless
#LocalBean
public class FatherService {
public EntityManager em;
public FatherService()
{
}
public EntityManager getGoodEm()
{
try {
Context ctx = new InitialContext();
NewInterface dp = (NewInterface) ctx.lookup("java:global/billing-ear/billing-connection/DataProvider");
em = dp.getEm();
} catch(Exception e) {
throw new RuntimeException(e);
}
return em;
}
}
The class who "provides" the connection (in a separate connection JAR, with the entities)
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
#Stateless
#LocalBean
public class DataProvider implements NewInterface
{
#PersistenceContext(unitName=Setup.persistenceUnitName, type=PersistenceContextType.TRANSACTION)
public EntityManager entityManager;
public DataProvider() {
}
#Override
public EntityManager getEm()
{
return entityManager;
}
}
Something important : You have to put #Stateless on any class of "higher level" layer" that will call the FatherService EJB (in my case, the REST classes).
The Core layer must be packaged as an EJB, and the connection too, both in an EAR

Categories

Resources