Adding datasource programmatically to JNDI context in embedded tomcat 7 - java

I'm trying to register a new datasource before the server starts but on lookup execution I'm getting
javax.naming.NameNotFoundException: Name [jdbc/db] is not bound in this Context. Unable to find [jdbc].
This is how I start tomcat:
Tomcat tomcat = new Tomcat();
//...
ContextResource resource = new ContextResource();
resource.setName("jdbc/db");
resource.setAuth("Container");
resource.setType("javax.sql.DataSource");
resource.setScope("Sharable");
resource.setProperty("driverClassName", "org.hsqldb.jdbc.JDBCDriver");
resource.setProperty("url", "jdbc:hsqldb:hsql://localhost:1234/mydb1");
tomcat.getServer().getGlobalNamingResources().addResource(resource);
tomcat.start();
tomcat.getServer().await();
The lookup:
Connection conn = null;
try {
Context initContext = new InitialContext();
Context envContext = (Context) initContext.lookup("java:/comp/env");
DataSource ds = (DataSource) envContext.lookup("jdbc/db");
conn = ds.getConnection();
conn.createStatement()....
} catch (Exception e) {
e.printStackTrace();
}
What am I missing here?

Oh well i figured it out! Instead of adding it in the GlobalNamingResources
tomcat.getServer().getGlobalNamingResources().addResource(resource);
I added it in the NamingResources
Context rootCtx = tomcat.addContext("", base.getAbsolutePath());
//...
rootCtx.getNamingResources().addResource(resource);
and it works!
If someone can tell me the difference between globalNamingResources and (local)NamingResources and how to lookup a globalNamingResource then please leave me a comment!

You don't show us how you look up the JNDI resource. However, in any case the full JNDI name to your resource is java:comp/env/jdbc/db i.e. that's what you need for lookup.
There's further reading here: https://stackoverflow.com/a/4099163/131929

Related

how to create single common class for jdbc connection pool

I am using jdbc connection pooling and i am getting the connection more than 100 place in the web application. how can i write the common code in single class and call, where required.
Context initContext = new InitialContext();
Context envContext = (Context)initContext.lookup("java:/comp/env");
DataSource ds = (DataSource)envContext.lookup("jdbc/UserDB");
Connection con = ds.getConnection();

Not able to use Callable statement from Connection Pool from WLS 12.1.3

I have created Datasource and try to get connection object using the below code,
Hashtable ht = new Hashtable();
ht.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
ht.put(Context.PROVIDER_URL, "t3://localhost:7001");
java.sql.Connection vendorConn = null;
try {
ctx = new InitialContext(ht);
javax.sql.DataSource ds
= (javax.sql.DataSource) ctx.lookup("jdbc/myDataSource");
conn = ds.getConnection();
} catch (SQLException e) {
LOGGER.error(e.getMessage());
}
Below I have mentioned connection object and callable object,
weblogic.jdbc.rmi.SerialConnection_weblogic_jdbc_rmi_internal_ConnectionImpl_weblogic_jdbc_wrapper_JTAConnection_weblogic_jdbc_wrapper_XAConnection_oracle_jdbc_driver_LogicalConnection_12130_WLStub#d4
cstmt = (weblogic.jdbc.rmi.SerialCallableStatement_weblogic_jdbc_rmi_internal_CallableStatementStub_weblogic_jdbc_rmi_internal_CallableStatementImpl_weblogic_jdbc_wrapper_CallableStatement_oracle_jdbc_driver_OracleCallableStatementWrapper_12130_WLStub) weblogic.jdbc.rmi.SerialCallableStatement_weblogic_jdbc_rmi_internal_CallableStatementStub_weblogic_jdbc_rmi_internal_CallableStatementImpl_weblogic_jdbc_wrapper_CallableStatement_oracle_jdbc_driver_OracleCallableStatementWrapper_12130_WLStub#145
I am getting the below exception when i called a store procedure using callable
java.sql.SQLException: weblogic.rmi.extensions.RemoteRuntimeException:
Unexpected Exception
at weblogic.jdbc.rmi.SerialStatement.close(SerialStatement.java:126)
at weblogic.jdbc.rmi.SerialStatement.close(SerialStatement.java:110)
at weblogic.ejb.container.internal.MDListener.execute(MDListener.java:451)
at weblogic.ejb.container.internal.MDListener.transactionalOnMessage(MDListener.java:375)
at weblogic.ejb.container.internal.MDListener.onMessage(MDListener.java:310)
at weblogic.jms.client.JMSSession.onMessage(JMSSession.java:4855)
at weblogic.jms.client.JMSSession.execute(JMSSession.java:4529)
at weblogic.jms.client.JMSSession.executeMessage(JMSSession.java:3976)
at weblogic.jms.client.JMSSession.access$000(JMSSession.java:120)
at weblogic.jms.client.JMSSession$UseForRunnable.run(JMSSession.java:5375)
at weblogic.work.SelfTuningWorkManagerImpl$WorkAdapterImpl.run(SelfTuningWorkManagerImpl.java:548)
at weblogic.work.ExecuteThread.execute(ExecuteThread.java:311)
at weblogic.work.ExecuteThread.run(ExecuteThread.java:263)
java.sql.SQLException: prepareStatement, Exception = Unexpected Exception
at weblogic.jdbc.rmi.RMIWrapperImpl.invocationExceptionHandler(RMIWrapperImpl.java:102)
at weblogic.jdbc.rmi.RMIStubWrapperImpl.invocationExceptionHandler(RMIStubWrapperImpl.java:34)
at weblogic.jdbc.rmi.SerialConnection.prepareStatement(SerialConnection.java:236)
at weblogic.ejb.container.internal.MDListener.execute(MDListener.java:451)
Please suggest is this the right way to use Datasource connection where all my sql statements are working but procedure is not getting called and also I need Is it required to typecast the SerialConnection to sql.Connection.
CallableStatement cst = null;
try {
cst = conn
.prepareCall("{call myProc(?,?,?,?,?,?,?,?)}");
final String typeTableName = "studentdetails";
cst.setInt(1, student.getEmpid());
cst.setInt(2, student.getOrgid());
cst.setInt(3, student.getYearid());
cst.setString(4, student.getClassType());
cst.setInt(5, student.getStudentid());
cst.registerOutParameter(6, Types.ARRAY, typeTableName);
cst.registerOutParameter(7, java.sql.Types.VARCHAR);
cst.registerOutParameter(8, java.sql.Types.VARCHAR);
long startTime=System.currentTimeMillis();
cst.execute();
String dat=cst.getString(7);
//Array arr = cst.getArray(6);
long endTime=System.currentTimeMillis();
if (null != cst.getObject(6)) {
data = (Object[]) ((Array) cst.getObject(6)).getArray();
}
If I use datasource, I am getting cst.getObject(6) as null, but if use normal jdbc connection it is working fine by providing the object.
If you are using Weblogic you must add the following element to your weblogic.xml
<resource-description>
<res-ref-name>datasource_ref</res-ref-name>
<jndi-name>jdbc/myDataSource</jndi-name>
</resource-description>
Then you must reference it from your deployment descriptor web.xml by adding following element
<resource-ref>
<res-ref-name>datasource_ref</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
Then you can reference your Data Src from your Java code like follows,
Context cntxt= (Context)new InitialContext().lookup("java:comp/env");
DataSource ds= (DataSource)cntxt.lookup("datasource_ref");
Or by using resource injection like follows,
#ApplicationScoped
public class DBHandler{
#Resource(name="datasource_ref")
private javax.sql.DataSource myDB;
public Connection getConnection(){
return myDB.getConnection();
}
}
And you can use it on demand anywhere using CDI
DBHandler handler = CDI.current().select(DBHandler.class).get();
Or by field injection
#Inject
javax.enterprise.inject.Instance<DBHandler> instance;
....
void persist(){
DBHandler handler=instance.get();
Connection con= handler.getConnection();
}

Tomcat 8.0.15 Oracle 11 Database and jdbc javax.naming.NamingException

I have an application that i use for buiding reports, now I need to move this application to Web environment.
For that I am using Tomcat 8.0.15 and an Oracle Database 11g Enterprise Edition.
In my TOMCAT_HOME\conf\server.xml i have the following code:
<Resource auth="Container"
driverClassName="oracle.jdbc.OracleDriver"
maxIdle="10"
maxTotal="20"
maxWaitMillis="-1"
name="jdbc/reportDataSource"
username="some_username"
password="some_pass"
type="javax.sql.DataSource"
url="jdbc:oracle:thin:#(DESCRIPTION =(ADDRESS_LIST =(ADDRESS = (PROTOCOL = TCP)(HOST = some.host)(PORT = some.port)))(CONNECT_DATA =(SID = SOME_SID)(SERVICE_NAME = SOME_SERVICE)))"/>
Therefore in my PROJECT_HOME\WebContent\WEB-INF\web.xml I have the following:
<resource-ref>
<description>Oracle Datasource definition</description>
<res-ref-name>jdbc/reportDataSource</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
Finally in my code I have a Java class with the following:
private void init() throws NamingException, SQLException {
try {
InitialContext initialContext = new InitialContext(); // JNDI initial context
Context eventContext = (Context) initialContext.lookup("java:comp/env/jdbc/reportDataSource"); // Event context
dataSource = (DataSource) eventContext.lookup("jdbc/reportDataSource"); // JNDI lookup
databaseConnection = dataSource.getConnection(); // database connection through data source
} catch (SQLException se) {
throw new SQLException("Connection object was not created. Rejected by host or not found.");
} catch (NamingException ne) {
throw new NamingException(ne.getMessage());
}
}
Finally in my project root I have have the following test setup:
#Before
public void setUp() throws Exception {
dbConnectorManager = new DatabaseConnectorManager();
assertNotNull(dbConnectorManager);
}
When I call the DatabaseConnectorManager() it calls the init() method shown in this question. However when I execute my test I got the following error related with line:
entContext eventContext = (Context) initialContext.lookup("java:comp/env/jdbc/reportDataSource"); // Event context
Hence, it is not possible to setup JNDI due the following error:
javax.naming.NamingException: 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
Can you please advise if I can create these JUnit tests for testing the connectivity, or if I can only test through a servlet?
Is there anything wrong with my configuration?
Update
I made the desiganted changes but now I get the following error:
javax.naming.NamingException: Name [jdbc/reportDataSource] is not bound in this Context. Unable to find [jdbc].
My data source now looks like the following:
InitialContext initialContext = new InitialContext(); // JNDI initial context
Context eventContext = (Context) initialContext.lookup("java:comp/env"); // Event context
dataSource = (DataSource) eventContext.lookup("jdbc/reportDataSource"); // JNDI lookup
databaseConnection = dataSource.getConnection(); // database connection through data source
'not sure this is the error, but you probably have a typo here:
Context eventContext =
(Context) initialContext.lookup("java:comp/env/jdbc/reportDataSource"); // Event context
// ^^^^^^^^^^^^^^^^^^^^^^
dataSource = (DataSource) eventContext.lookup("jdbc/reportDataSource"); // JNDI lookup
// ^^^^^^^^^^^^^^^^^^^^^^
Either you want to do a direct lookup:
dataSource =
(DataSource) initialContext.lookup("java:comp/env/jdbc/reportDataSource");
Or you want to get the context first, but in that case, you only requests java:comp/env:
Context eventContext =
(Context) initialContext.lookup("java:comp/env");
dataSource = (DataSource) eventContext.lookup("jdbc/reportDataSource");
In Server.xml, provide a name to your resource and do the lookup based on that name. Another point is, you can add a resource as a new context.xml under META-INF folder under webapps. This is done if you don't want to change your server.xml
<Resource name="tomcat/JDBCdatasource" auth="Container" ... />
Context ctx;
ctx = new InitialContext();
Context envContext = (Context) ctx.lookup("java:/comp/env");
// Look up a data source
javax.sql.DataSource ds
= (javax.sql.DataSource) envContext.lookup ("tomcat/JDBCdatasource");

Websphere Network deployment datasource

I have installed Websphere Network deployment server 7.0.0.0
I have configured a cluster on it.
I have configured a data source on it say ORA_DS this data source using "JAAS - J2C authentication data"
When i test the ORA_DS by clicking on "Test connection" button, the test connection is success.
The issue comes when i try to access this data source using my java code.
Here is my code to access data source and create a connection:
public class DSTester
{
/**
* Return the data source.
* #return the data source
*/
private DataSource getDataSource()
{
DataSource dataSource = null;
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.ibm.websphere.naming.WsnInitialContextFactory");
env.put(Context.PROVIDER_URL, "iiop://localhost:9811");
// Retrieve datasource name
String dataSourceName = "EPLA1";
if (dataSource == null)
{
try
{
Context initialContext = new InitialContext(env);
dataSource = (DataSource) initialContext.lookup(dataSourceName);
}
catch (NamingException e1)
{
e1.printStackTrace();
return null;
}
}
return dataSource;
}
public static void main(String[] args)
throws Exception
{
DSTester dsTester = new DSTester();
DataSource ds = dsTester.getDataSource();
System.out.println(ds);
System.out.println(ds.getConnection());
}
}
Here is the output:
com.ibm.ws.rsadapter.jdbc.WSJdbcDataSource#17e40be6
Exception in thread "P=792041:O=0:CT" java.sql.SQLException: ORA-01017: invalid username/password; logon denied
DSRA0010E: SQL State = 72000, Error Code = 1,017
at oracle.jdbc.driver.SQLStateMapping.newSQLException(SQLStateMapping.java:70)
at oracle.jdbc.driver.DatabaseError.newSQLException(DatabaseError.java:133)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:206)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:455)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:406)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:399)
at oracle.jdbc.driver.T4CTTIoauthenticate.receiveOauth(T4CTTIoauthenticate.java:799)
at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:368)
at oracle.jdbc.driver.PhysicalConnection.<init>(PhysicalConnection.java:508)
at oracle.jdbc.driver.T4CConnection.<init>(T4CConnection.java:203)
at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:33)
at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:510)
at oracle.jdbc.pool.OracleDataSource.getPhysicalConnection(OracleDataSource.java:275)
at oracle.jdbc.pool.OracleDataSource.getConnection(OracleDataSource.java:206)
at oracle.jdbc.pool.OracleConnectionPoolDataSource.getPhysicalConnection(OracleConnectionPoolDataSource.java:139)
at oracle.jdbc.pool.OracleConnectionPoolDataSource.getPooledConnection(OracleConnectionPoolDataSource.java:88)
at oracle.jdbc.pool.OracleConnectionPoolDataSource.getPooledConnection(OracleConnectionPoolDataSource.java:70)
at com.ibm.ws.rsadapter.spi.InternalGenericDataStoreHelper$1.run(InternalGenericDataStoreHelper.java:1175)
at com.ibm.ws.security.util.AccessController.doPrivileged(AccessController.java:118)
at com.ibm.ws.rsadapter.spi.InternalGenericDataStoreHelper.getPooledConnection(InternalGenericDataStoreHelper.java:1212)
at com.ibm.ws.rsadapter.spi.WSRdbDataSource.getPooledConnection(WSRdbDataSource.java:2019)
at com.ibm.ws.rsadapter.spi.WSManagedConnectionFactoryImpl.createManagedConnection(WSManagedConnectionFactoryImpl.java:1422)
at com.ibm.ws.rsadapter.spi.WSDefaultConnectionManagerImpl.allocateConnection(WSDefaultConnectionManagerImpl.java:81)
at com.ibm.ws.rsadapter.jdbc.WSJdbcDataSource.getConnection(WSJdbcDataSource.java:646)
at com.ibm.ws.rsadapter.jdbc.WSJdbcDataSource.getConnection(WSJdbcDataSource.java:613)
at com.test.DSTester.main(DSTester.java:70)
The code works fine if i replace
ds.getConnection()
with
ds.getConnection("ora_user", "ora_password")
My issue is i need to get the connection without specifying login details for Oracle.
Please help me on this issue.
Any clue will be appreciated.
Thanks
I'd guess it would work if you retrieved the datasource from an application running on the WAS.
Try creating a servlet.
Context initialContext = new InitialContext();
DataSource dataSource = (DataSource) initialContext.lookup("EPLA1");
Connection con = dataSource.getConnection();
As within a servlet it is running within WAS it should be fine, if the "Test Connection" works. Running it outside is probably a different context.
I think you need to check all your configuration:
1) Is it application deplyed on cluster or into only one of cluster member?
2) JAAS - J2C authentication data - what is the scope?
Sometimes you need restar all your WAS environment. It depends on resource configuration scope
I'd recomend to you add resource refences for better configuration options.
SeeIBM Tech note

Can an EJB be called from a desktop application?

I am new in Java EJB 3.0. It is possible to call a (session) bean—deployed on JBoss—from a desktop application client?
Thanks in advance.
Yes you can. Some specifics are here (references EJB2 but it the same for EJB3 when it comes to remote clients): http://www.theserverside.com/discussions/thread.tss?thread_id=9197
Paraphrased:
Hashtable env = new Hashtable();
env.put("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
env.put("java.naming.provider.url", "jnp://localhost:1099");
env.put("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces");
Context ctx = new InitialContext(env);
// name is whatever JNDI name you gave it
Object o = ctx.lookup("home name");
EJBHome ejbHome = (EJBHome) PortableRemoteObject.narrow(o,EJBHome.class);
// This is userID should be the one passed.
EJB ejb = ejbHome.create(..);
Yes.
public static void main(String args[]) throws Exception {
InitialContext ctx = new InitialContext();
YourService yourService = (YourService) ctx.lookup("com.example.session.YourService");
String time = yourService.getTime();
System.out.println("Time is: " + time);
}
For client configuration you must provide jndi.properties file with contents
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost
If you are looking for working examples on JBoss try download source code of Enterprise JavaBeans 3.0, Fifth Edition
Let's assume you have the following remote interface:
#Remote
public interface HelloBeanRemote {
public String sayHello();
}
And a session bean implementing it:
#Stateless
public class HelloBean implements HelloBeanRemote {
...
}
And that this EJB is correctly packaged and deployed on JBoss.
On the client side, create a jndi.properties with the following content and put it on the classpath:
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost:1099
Then use the following code to call your EJB:
Context context;
try {
context = new InitialContext();
HelloBeanRemote beanRemote = (HelloBeanRemote)context.lookup("HelloBean/remote");
beanRemote.test();
} catch (NamingException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
Alternatively, if you don't want to provide a jndi.properties file, you can explicitly setup the JNDI environment in the code and create the context like this:
Properties properties = new Properties();
properties.put("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory");
properties.put("java.naming.factory.url.pkgs","=org.jboss.naming:org.jnp.interfaces");
properties.put("java.naming.provider.url","localhost:1099");
Context context = new InitialContext(properties);
But I'd recommend using the jndi.properties for the sake of portability.
You can also expose the bean as a web service. I believe this is available as of EJB 3. It is quite nice considering you can do it with annotations. You may wish to consider using this option to decrease coupling. Here is a link to a tutorial.

Categories

Resources