Check if InitialContext exist before NoInitialContextException occures - java

I am getting javax.naming.NoInitialContextException from Hibernate's SessionFactory.buildSessionFactory() method. This is because I am trying to run a testcase outside of container.
I have code in place to refer to local Datasource configured in applicationContext.xml. Problem is that I am not figure out where to implement local datasource code.
I can not put it inside a catch(NoInitialContextException) because SessionFactory class is deep in the code and as per the application design, throwing all exceptions not catching them.
Is there anyway to find out if InitialContext exist before hitting the buildSessionFactory method?

Maybe can you perform a lookup on the InitialContext to check if there is a SessionFactory, as described here: http://docs.jboss.org/jbossas/getting_started/v4/html/hibernate.html
try {
InitialContext ctx = new InitialContext();
ctx.lookup("java:/hibernate/SessionFactory");
catch (NamingException e) {
//here you can assume that buildSessionFactory won't work
...
}

Related

Create application specific tables in the existing database of WSO2

For this requirement we tried to create the datasource using the org.wso2.carbon.user.core.util.DatabaseUtil class by passing the realm, but we always get an exception saying error in looking up datasource.
We understand that during server startup, org.wso2.carbon.user.core.internal.Activator -> startDeploy(BundleContext bundleContext) is invoked and it creates a new RealmService instance where the realmconfiguration and datasource objects are successfully initialized. In the Activator class initialized realmservice instance is set to UserCoreUtil class(UserCoreUtil.setRealmService(realmService)). RealmService initialization invokes the DefaultRealmService, where the datasource instance is initialized and that object is added to the properties.
For any of user or tenant related DB operations below call is invoked, CarbonContext.getThreadLocalCarbonContext().getUserRealm() method is invoked which actually uses the datasource from the properties which was stored by DefaultRealmService during the server start up and it creates the userStoreManager instance and returns the userRealm through which all user related operations are performed.
For accessing the application specific table, we created our own JDBCCustomManager class and tried to perform JDBC operations. We need the datasource to do DB operations for that when we execute, “DatabaseUtil.getRealmDataSource(objRealmService.getBootstrapRealmConfiguration())”, we always get an exception "Error in looking up data source: jdbc/WSO2CarbonDB".
If we write methods to access our table in the JDBCUserStoreManager its working but which is not the proper way to do. Can you please suggest is there any other way to get hold of datasources object of WSO2 so that we can use it in the application.
Your description is not much clear. If your are trying to get an datasource object you can do it like this.
public static DataSource lookupDataSource(String dataSourceName, final Hashtable<Object, Object> jndiProperties) {
try {
if (jndiProperties == null || jndiProperties.isEmpty()) {
return (DataSource) InitialContext.doLookup(dataSourceName);
}
final InitialContext context = new InitialContext(jndiProperties);
return (DataSource) context.doLookup(dataSourceName);
} catch (Exception e) {
throw new RuntimeException("Error in looking up data source: " + e.getMessage(), e);
}
}
You can defind the datasource in master-datasource.xml and give it a JNDI name which is used for the lookup.

Inject stateful EJB beans in a maven project

I don't understand one thing that I hope someone of you could explain me. I have a maven enterprise project developed with glassfish.
I use the insert code netbeans function (right click) to call bean in a servlet and in particular the annotation
#EJB
I don't understand why when I call a stateful session bean through Insert Code function in netbeans the bean is called through JNDI. Here what I mean
private BookingBeanInterface lookupBookingBeanLocal() {
try {
Context c = new InitialContext();
return (BookingBeanInterface) c.lookup("java:global/it.volaconnoi_volaconnoi-webapp-ear_ear_1.0-SNAPSHOT/it.volaconnoi_volaconnoi-webapp-ejb_ejb_1.0-SNAPSHOT/BookingBean!it.volaconnoi.logic.BookingBeanInterface");
} catch (NamingException ne) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, "exception caught", ne);
throw new RuntimeException(ne);
}
}`
The above function hasn't been wrote by me
I can't inject a stateful session bean through EJB?
Here is the solution to the problem:
As you probably already know a single Servlet instance is used to handle multiple requests from multiple clients so the Stateful EJB should not be injected directly in the Servlet and kept as an instance property, or we will face obvious thread-safety related issues. In our case we are fetching it from JNDI inside doGet method and storing it in the HTTP session so each user will have it's own Sateful EJB instance.

JAX-WS & Tomcat: storing in InitialContext not possible?

Intro I'm writing a web service using JAX-WS, and deploying it in Tomcat. With a lot of difficulties I finally had some code written.
Problem Unfortunately, when trying to run it I get the following error:
Context is read only
Setting I'm writing a web service that queries multiple databases and returns a single result. For that purpose, in the init() method (marked with #PostConstruct), I create a series of DataSources that I add to the context.
This is how I create the pool (based on Tomcat documentation) and after its creation I add it to the context (based on this tutorial):
#PostConstruct
private void init(){
PoolProperties props = new PoolProperties();
props.setUrl("jdbc:postgresql://" + ...);
props.setUsername(...);
props.setPassword(...);
props.setJdbcInterceptors("org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;" +
"org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer");
DataSource dataSource = new DataSource();
dataSource.setPoolProperties(propos);
Context ctx = new InitialContext(env);
ctx.bind("java:/comp/env/dbpool", dataSource);
}
And later I use it:
#WebMethod
public Result performQuery(QueryParameters params){
Context ctx = new InitialContext(env);
(DataSource) source = (DataSource) ctx.lookup("java:/comp/env/dbpool");
}
I deploy the web service on a Tomcat 7 server.
Question I understand after Google-ing that I cannot write into the Context on Tomcat. But how else could I solve this? From what I understand about JAX-WS I cannot just have a private variable holding a DataSource, right? I have to pass that DataSource using a Context, right?
The InitialContext is writable from the Tomcat code only, not from your client code. You must add your DataSource to your context.xml and it'll work.

How to connect junit and tomcat in java?

I have configured MysqlDataSource in tomcat using this link.I have written junit test cases.when am i calling below connection from junit it throws following errors.
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
I have used following code
class DataConnection {
private static DataSource dataSource;
public DataConnection() {
try {
Context ctx = new InitialContext();
dataSource = (DataSource)ctx.lookup("java:comp/env/jdbc/test");
} catch (NamingException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
new DataConnection();
Connection con=dataSource.getConnection();
return con;
}
}
How to call tomcat from junit? How to achieve this?
The code you give gets the database connection from JNDI, e.g. when running in tomcat from the container. However, for Unit Tests (assuming that's what you use JUnit for) I'd rather suggest to use "dependency injection" - e.g. explicitly pass a database connection to the code under test or manually set it up before the test runs.
There's no need to rely on JNDI for executing your tests: That's not what you want to test, instead, you want to just verify that your actual code is running correctly.
You don't need any fancy library (e.g. spring) for dependency injection, just a slightly adjusted architecture. This will greatly enhance the testability of your application and lower the execution time of your tests.
(This is based on my assumptions of your situation based on the little bit of information that you give in your question)
Give TomcatJNDI a try. It is based on embedded Tomcat but initializes only Tomcat's JNDI environment without starting a server. So you can access all your resources as configured in Tomcat's configuration files in tests or from within any Java SE application. The API is simple. For instance to get a DataSource declared in context.xml:
TomcatJNDI tomcatJNDI = new TomcatJNDI();
tomcatJNDI.processContextXml(contextXmlFile);
tomcatJNDI.start();
Then you can lookup the DataSource as usual
DataSource ds = (DataSource) InitialContext.doLookup("java:comp/env/path/to/datasource")
More information about TomcatJNDI can be found here.

Spring & Hibernate SessionFactory - recovery from a down server

So pre spring, we used version of HibernateUtil that cached the SessionFactory instance if a successful raw JDBC connection was made, and threw SQLException otherwise. This allowed us to recover from initial setup of the SessionFactory being "bad" due to authentication or server connection issues.
We moved to Spring and wired things in a more or less classic way with the LocalSessionFactoryBean, the C3P0 datasource, and various dao classes which have the SessionFactory injected.
Now, if the SQL server appears to not be up when the web app runs, the web app never recovers. All access to the dao methods blow up because a null sessionfactory gets injected. (once the sessionfactory is made properly, the connection pool mostly handles the up/down status of the sql server fine, so recovery is possible)
Now, the dao methods are wired by default to be singletons, and we could change them to prototype. I don't think that will fix the matter though - I believe the LocalSessionFactoryBean is now "stuck" and caches the null reference (I haven't tested this yet, though, I'll shamefully admit).
This has to be an issue that concerns people.
Tried proxy as suggested below -- this failed
First of all I had to ignore the suggestion (which frankly seemed wrong from a decompile) to call LocalSessionFactory.buildSessionFactory - it isn't visible.
Instead I tried a modified version as follows:
override newSessionFactory. At end return proxy of SessionFactory pointing to an invocation handler listed below
This failed too.
org.hibernate.HibernateException: No local DataSource found for configuration - 'dataSource' property must be set on LocalSessionFactoryBean
Now, if newSessionfactory() is changed to simply
return config.buildSessionFactory() (instead of a proxy) it works, but of course no longer exhibits the desired proxy behavior.
public static class HibernateInvocationHandler implements InvocationHandler {
final private Configuration config;
private SessionFactory realSessionFactory;
public HibernateInvocationHandler(Configuration config) {
this.config=config;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if (false) proxy.hashCode();
System.out.println("Proxy for SessionFactory called");
synchronized(this) {
if (this.realSessionFactory == null){
SessionFactory sf =null;
try {
System.out.println("Gonna BUILD one or die trying");
sf=this.config.buildSessionFactory();
} catch (RuntimeException e) {
System.out.println(ErrorHandle.exceptionToString(e));
log.error("SessionFactoryProxy",e);
closeSessionFactory(sf);
System.out.println("FAILED to build");
sf=null;
}
if (sf==null) throw new RetainConfigDataAccessException("SessionFactory not available");
this.realSessionFactory=sf;
}
return method.invoke(this.realSessionFactory, args);
}
}
The proxy creation in newSessionFactory looks like this
SessionFactory sfProxy= (SessionFactory) Proxy.newProxyInstance(
SessionFactory.class.getClassLoader(),
new Class[] { SessionFactory.class },
new HibernateInvocationHandler(config));
and one can return this proxy (which fails) or config.buildSessionFactory() which works but doesn't solve the initial issue.
An alternate approach has been suggested by bozho, using getObject(). Note the fatal flaw in d), because buildSessionFactory is not visible.
a) if this.sessionfactory is nonnull, no need for a proxy, just return
b) if it is , build a proxy which...
c) should contain a private reference of sessionfactory, and each time it is called check if it is null. If so, you build a new factory and if successful assign to the private reference and return it from now on.
d) Now, state how you would build that factory from getObject(). Your answer should involve calling buildSessionFactory....but you CAN'T. One could create the factory by oneself, but you would end up risking breaking spring that way (look at buildSessionFactory code)
You shouldn't worry about this. Starting the app is something you will rarely do in production, and in development - well, you need the DB server anyway.
You should worry if the application doesn't recover if the db server stops while the app is running.
What you can do is extend LocalSessionFactoryBean and override the getObject() method, and make it return a proxy (via java.lang.reflect.Proxy or CGLIB / javassist), in case the sessionFactory is null. That way a SessionFactory will be injected. The proxy should hold a reference to a bare SessionFactory, which would initially be null. Whenever the proxy is asked to connect, if the sessionFacotry is still null, you call the buildSessionFactory() (of the LocalSessionFactoryBean) and delegate to it. Otherwise throw an exception. (Then of course map your new factory bean instead of the current)
Thus your app will be available even if the db isn't available on startup. But I myself wouldn't bother with this.

Categories

Resources