Spring application using JNDI lookup to get datasource as following:
#Bean(name = "dataSource1", destroyMethod = StringUtils.EMPTY)
public DataSource dataSource() {
final JndiDataSourceLookup lookup = new JndiDataSourceLookup();
lookup.setResourceRef(true);
return lookup.getDataSource(this.environment.getProperty(Constants.DB_JNDI_NAME_ES));
}
and getting a connection from the datasource as follows :
#Autowired
#Qualifier("dataSource1")
private DataSource ds;
Connection conn = null;
conn = this.ds.getConnection();
But when i pass that connection to StructDescriptor it throws classCastException as follows:
StructDescriptor desc1 =
StructDescriptor.createDescriptor("MSAF_DBA.AMOUNT_DUE_OBJ",conn);
java.lang.ClassCastException: weblogic.jdbc.wrapper.PoolConnection_oracle_jdbc_driver_T4CConnection cannot be cast to oracle.jdbc.OracleConnection
at oracle.sql.StructDescriptor.createDescriptor(StructDescriptor.java:101)
at oracle.sql.StructDescriptor.createDescriptor(StructDescriptor.java:72)
at com.ceiwc.es.policyholder.dao.PolicyHolderDaoImpl.getAmountDue(PolicyHolderDaoImpl.java:290)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
My understanding is the getConnection() returns a T4CConnection where as OracleConnection is required. Tried couple of ways to get the oracleConnection but cant seem to get it. Any help would be appreciated.
I believe this has to do with the contents of your war/ear file. Do not package in the Oracle driver .jar file.
Specifically, if you have ojdbc6.jar in your war file (or the equivalent) it will cause conflicts. It is fine to use that jar for compilation but you won't want it in your classpath as it is already in the Weblogic classpath by default.
See these links for similar info: here and here
Related
I am attempting to set up various PostgreSQL JDBC driver properties to my HikariCP pool, but for some reason, it's stating that those properties don't exist. Why so? Am I using the wrong parameter names?
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource
import java.sql.Connection;
import java.sql.SQLException;
public class HikariTest {
public static void main(String[] args) throws SQLException {
HikariConfig config = new HikariConfig();
config.setDataSourceClassName("org.postgresql.ds.PGSimpleDataSource");
config.setUsername("[REDACTED]");
config.setPassword("[REDACTED]");
config.addDataSourceProperty("host", "[REDACTED");
config.addDataSourceProperty("database", "[REDACTED]");
config.addDataSourceProperty("ssl", true);
config.addDataSourceProperty("sslcert", "[REDACTED]");
HikariDataSource ds = new HikariDataSource(config);
Connection conn = ds.getConnection();
}
}
Output:
Exception in thread "main" java.lang.RuntimeException: Property database does not exist on target class org.postgresql.ds.PGSimpleDataSource
at com.zaxxer.hikari.util.PropertyElf.setProperty(PropertyElf.java:127)
at com.zaxxer.hikari.util.PropertyElf.lambda$setTargetFromProperties$0(PropertyElf.java:51)
at java.base/java.util.concurrent.ConcurrentHashMap.forEach(ConcurrentHashMap.java:1603)
at java.base/java.util.Properties.forEach(Properties.java:1422)
at com.zaxxer.hikari.util.PropertyElf.setTargetFromProperties(PropertyElf.java:46)
at com.zaxxer.hikari.pool.PoolBase.initializeDataSource(PoolBase.java:323)
at com.zaxxer.hikari.pool.PoolBase.<init>(PoolBase.java:112)
at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:93)
at com.zaxxer.hikari.HikariDataSource.<init>(HikariDataSource.java:81)
at HikariTest.main(HikariTest.java:21)
It gives that error because PGSimpleDataSource does not have a property database (i.e. it doesn't have a setDatabase(String) method). It does have a property databaseName (setDatabaseName defined in BaseDataSource). This property is specified in section 9.6.1 DataSource Properties of the JDBC 4.3 specification.
Reading the comments, it looks like you're confusing the documentation of the JDBC URL format (and connection properties) with the properties that are available on the data source implementations provided by the driver. To be clear, that documentation doesn't specify there is a property database, it only uses database as a placeholder in the JDBC URL syntax (as in jdbc:postgresql://host/database.
Running under a Tomcat 9 and JDK 1.8, using Spring 5, I am trying to configure a JNDI connection to get a DataSource.
If I configure Spring, through XML, I get my DataSource and everything seems to work fine. I configured the DataSource in my applicationContext.xml, in this way:
<jee: jndi-lookup id = "dataSource" jndi-name = "jdbc / yages"
resource-ref = "true" />
When I use the AbstractAnnotationConfigDispatcherServletInitializer class to initialize Spring, my DataSource is created but when I try to catch the connection it gives me the following error:
java.sql.SQLException: Data source is closed
at org.apache.tomcat.dbcp.dbcp2.BasicDataSource.createDataSource (BasicDataSource.java:2049)
I try to create the DataSource with this function:
#Bean (name = "dataSource")
public DataSource dataSource (Environment env) throws NamingException
{
DataSource datasource = null;
try {
JndiDataSourceLookup lookup = new JndiDataSourceLookup ();
datasource = lookup.getDataSource ("jdbc/yages");
datasource.getConnection ();
return datasource;
} catch (SQLException ex) {
ex.printStackTrace ();
}
return datasource;
}
It seems that the DataSource is created correctly, but the connection to the database seems to be closed.
However, if I use the DataSource, configure it through XML, it works well for me, which is why I assume that it is not a problem neither of the connection to the database nor of the configuration of Tomcat.
Any idea why the connection is closed?
Thank you.
I found the solution.
It is to create the Bean with this instruction
#Bean(name = "dataSource", destroyMethod = "")
The problem is that Spring to do an undeploy, destroy the Bean and close the connection. To avoid this, I have to change the default behavior of Spring.
I create a data source using standard below:
private DataSource ds;
Context envContext = (Context) initContext.lookup("java:/comp/env");
ds = (DataSource)envContext.lookup("jdbc/myDB");
I would want the connection url written to log file.
System.out.println(ds);
The above will not due. I thought about casting to BasicDataSource
(ds instanceof BasicDataSource);
to get information since BDS has getUrl() method. This goes against indirection, since not all connections will be BasicDataSource and should be avoided? How should one print the url used for a datasource, at least for debugging?
BasicDataSource and OracleDataSource (and probably other wrappers) are really the only ways to get URL information directly from the DataSource. But as gonzo described in the comments, you can get this information from your connection:
Connection conn = ds.getConnection();
String url = conn.getMetaData().getURL();
I am trying to set up a DataSource in liberty profile server, but I'm getting a NullPointerException (on my ds variable below) when my code tries to use it.
The relevant code, and server.xml entries are below.
Interestingly, if I change the jndiName to java:comp/env/jdbc/Oracle I get an IllegalArgumentException on server startup, but with the config below it doesn't even seem to try to activate the DataSource...
public abstract class DAOBase {
//#Resource(name = "jdbc/Oracle", type = javax.sql.DataSource.class, shareable = true, authenticationType = AuthenticationType.CONTAINER)
#Resource(lookup = "jdbc/Oracle")
private DataSource ds;
protected Connection getConnection() throws SQLException {
Connection conn = ds.getConnection();
return conn;
}
My server.xml config:
<featureManager>
<feature>jsp-2.2</feature>
<feature>jaxrs-1.1</feature>
<feature>localConnector-1.0</feature>
<feature>appSecurity-2.0</feature>
<feature>jpa-2.0</feature>
<feature>jdbc-4.0</feature>
<feature>jndi-1.0</feature>
</featureManager>
<library id="OracleJDBC_ID">
<fileset dir="C:\src\main\lib" includes="ojdbc6.jar"/>
</library>
<jdbcDriver id="OracleDriver" libraryRef="OracleJDBC_ID"/>
<dataSource jdbcDriverRef="OracleDriver" jndiName="jdbc/Oracle">
<properties.oracle URL="jdbc:oracle:thin:#ldap://oid:***/opl***,cn=OracleContext,dc=****,dc=com" password="****" user="*****"/>
</dataSource>
Error in the log:
[ERROR ] CWWKE0701E: [com.ibm.ws.jdbc.dataSource(200)] The modified method has
thrown an exception Bundle:com.ibm.ws.jdbc(id=82) java.lang.IllegalArgumentException:
J2CA8011E: Value java:comp/env/jdbc/Oracle is not supported for jndiName on dataSource
at com.ibm.ws.jdbc.DataSourceService.activate(DataSourceService.java:209)
at [internal classes]
EDIT:
The code is in the base class for our Data Access layer. We're calling this in a RESTful web service via a very plain initialization:
AuditDAO auditDAO = new AuditDAO();
The #Resource will not work in POJO unless you activate CDI. Try the following:
add beans.xml file to the WEB-INF folder, and add CDI feature
<feature>cdi-1.0</feature>
inject auditDAO to your web service using #Inject AuditDAO auditDAO
use the following reference in the dao
#Resource(name="jdbc/Oracle", lookup = "jdbc/Oracle")
private DataSource ds;
I'm trying to follow Sun's JDBC tutorial at http://java.sun.com/docs/books/tutorial/jdbc/basics/connecting.html
It gives the following example code:
DataSource ds = (DataSource) org.apache.derby.jdbc.ClientDataSource()
ds.setPort(1527);
ds.setHost("localhost");
ds.setUser("APP")
ds.setPassword("APP");
Connection con = ds.getConnection();
This code doesn't compile because the DataSource interface has none of these methods, except for the getConnection() method invoked last.
(Here's the javadoc: http://java.sun.com/javase/6/docs/api/javax/sql/DataSource.html)
What am I missing?
Edit:
I'm actually trying to connect to MySQL (com.mysql.jdbc) and I can't find the javadoc for that. I'll accept an answer that points me to either:
1) documentation for com.mysql.jdbc regarding a DataSource that I can understand, or
2) gives an example to follow for what the tutorial's code should be, for any database.
One thing you might want to look at is the Commons DBCP project. It provides a BasicDataSource that is configured fairly similarly to your example. To use that you need the database vendor's JDBC JAR in your classpath and you have to specify the vendor's driver class name and the database URL in the proper format.
Edit:
If you want to configure a BasicDataSource for MySQL, you would do something like this:
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUsername("username");
dataSource.setPassword("password");
dataSource.setUrl("jdbc:mysql://<host>:<port>/<database>");
dataSource.setMaxActive(10);
dataSource.setMaxIdle(5);
dataSource.setInitialSize(5);
dataSource.setValidationQuery("SELECT 1");
Code that needs a DataSource can then use that.
DataSource is vendor-specific, for MySql you could use MysqlDataSource which is provided in the MySql Java connector jar:
MysqlDataSource dataSource = new MysqlDataSource();
dataSource.setDatabaseName("xyz");
dataSource.setUser("xyz");
dataSource.setPassword("xyz");
dataSource.setServerName("xyz.yourdomain.com");
Basically in JDBC most of these properties are not configurable in the API like that, rather they depend on implementation. The way JDBC handles this is by allowing the connection URL to be different per vendor.
So what you do is register the driver so that the JDBC system can know what to do with the URL:
DriverManager.registerDriver((Driver) Class.forName("com.mysql.jdbc.Driver").newInstance());
Then you form the URL:
String url = "jdbc:mysql://[host][,failoverhost...][:port]/[database][?propertyName1][=propertyValue1][&propertyName2][=propertyValue2]"
And finally, use it to get a connection:
Connection c = DriverManager.getConnection(url);
In more sophisticated JDBC, you get involved with connection pools and the like, and application servers often have their own way of registering drivers in JNDI and you look up a DataSource from there, and call getConnection on it.
In terms of what properties MySQL supports, see here.
EDIT: One more thought, technically just having a line of code which does Class.forName("com.mysql.jdbc.Driver") should be enough, as the class should have its own static initializer which registers a version, but sometimes a JDBC driver doesn't, so if you aren't sure, there is little harm in registering a second one, it just creates a duplicate object in memeory.
use MYSQL as Example:
1) use database connection pools: for Example: Apache Commons DBCP , also, you need basicDataSource jar package in your classpath
#Bean
public BasicDataSource dataSource() {
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/gene");
ds.setUsername("root");
ds.setPassword("root");
return ds;
}
2)use JDBC-based Driver it is usually used if you don't consider connection pool:
#Bean
public DataSource dataSource(){
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/gene");
ds.setUsername("root");
ds.setPassword("root");
return ds;
}
I think the example is wrong - javax.sql.DataSource doesn't have these properties either. Your DataSource needs to be of the type org.apache.derby.jdbc.ClientDataSource, which should have those properties.
The javadoc for DataSource you refer to is of the wrong package. You should look at javax.sql.DataSource. As you can see this is an interface. The host and port name configuration depends on the implementation, i.e. the JDBC driver you are using.
I have not checked the Derby javadocs but I suppose the code should compile like this:
ClientDataSource ds = org.apache.derby.jdbc.ClientDataSource()
ds.setHost etc....
For postgres, the below works. I actually used it in integ tests. I guess there should be some more consideration for production usage.
PGSimpleDataSource ds = new PGSimpleDataSource() ;
ds.setServerName( "localhost" );
ds.setDatabaseName( "your_db_name_here" );
ds.setUser( "scott" );
ds.setPassword( "tiger" );
The class is bundled in the postgres jdbc driver.
The original stackoverflow post i followed: https://stackoverflow.com/a/45091982/3877642