I have the following class for obtaining a JDBC connection:
package util;
import java.sql.Connection;
import java.sql.SQLException;
import javax.annotation.Resource;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
public class OracleConnection implements AutoCloseable{
private final String oracle_DS_CTX = "java:jboss/oracleDS";
// #Resource(name="java:jboss/oracleDS")
// private DataSource ds; //doesn't work
private Connection _conn;
public OracleConnection() throws SQLException, NamingException{
Context ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup(oracle_DS_CTX);
_conn = ds.getConnection();
}
#Override
public void close() throws Exception {
if(_conn != null){
_conn.close();
}
}
public Connection getConnection() throws SQLException {
return _conn;
}
}
I have a problem using the #Resource annotation. Datasource obtained via InitialContext works without any problems but I am not sure what string should I put into resource name (commented out in my code).
I have tried:
#Resource(name="java:jboss/oracleDS")
#Resource(name="oracleDS")
AS is JBOSS AS7
What name did you define in your standalone.xml?
That is the name you need to define in your #Resource
But there's a little trick, you need to set it in the lookup property instead of name.
Here's an example, let's assume my DS jndi is java:jboss/ExampleDS.
#Resource(lookup = "java:jboss/ExampleDS")
private DataSource dataSource;
Related
I have a ConnectionFactory class in order to use in my Jdbc Appender to save logs in a mysql database, but, I want to use properties in ConnectionFactory class to avoid leaving sensitive data exposed in the code, but, it is a singleton class, so its never get the values of my properties, the properties are always null. Can someone help me, is there any way to bring the application.properties properties into the ConnectionFactory?
I have this ConnectionFactory class:
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.DriverManagerConnectionFactory;
import org.apache.commons.dbcp.PoolableConnection;
import org.apache.commons.dbcp.PoolableConnectionFactory;
import org.apache.commons.dbcp.PoolingDataSource;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.springframework.beans.factory.annotation.Value;
public class ConnectionFactory {
private static interface Singleton {
final ConnectionFactory INSTANCE = new ConnectionFactory();
}
private final DataSource dataSource;
#Value("${spring.datasource.user}")
private String user;
#Value("${spring.datasource.password}")
private String password;
#Value("${spring.datasource.url}")
private String url;
private ConnectionFactory() {
Properties properties = new Properties();
properties.setProperty("user", user);
properties.setProperty("password", password); // or get properties from some configuration file
GenericObjectPool<PoolableConnection> pool = new GenericObjectPool<PoolableConnection>();
DriverManagerConnectionFactory connectionFactory = new DriverManagerConnectionFactory(
url, properties
);
new PoolableConnectionFactory(
connectionFactory, pool, null, "SELECT 1", 3, false, false, Connection.TRANSACTION_READ_COMMITTED
);
this.dataSource = new PoolingDataSource(pool);
}
public static Connection getDatabaseConnection() throws SQLException {
return Singleton.INSTANCE.dataSource.getConnection();
}
And, my application.properties:
spring.cloud.compatibility-verifier.enabled=false
# database configs
spring.datasource.url=jdbc:mysql://localhost:3306/myDatabase
spring.datasource.username=root
spring.datasource.password=
spring.datasource.testWhileIdle=true
spring.datasource.validationQuery=SELECT 1
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
Is there any way to bring the properties into the ConnectionFactory class?
I found a response, you can add the environment variables in a singleton class using this code:
System.getenv("MY_ENV_VARIABLE");
This way, you get the environment variables.
If you really need to get the properties of applications.properties, you need to create a Properties properties variable, and then you can use this code:
try (InputStream input = YourSingletonClass.class.getClassLoader().getResourceAsStream("application.properties")) {
properties.load(input);
} catch (IOException e) {
e.printStackTrace();
}
To get the value of any propertie, use properties.getProperty(key); where the 'key' is the name of your propertie.
I am trying to connect to Oracle AQ using JMS template to publish and subscribe.
However, I am unable to get it working. I might be lacking basic understanding of connecting to Oracle AQ in general. Any advice would be appreciated
Following is my code
import java.sql.SQLException;
import javax.jms.QueueConnectionFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.support.converter.MappingJackson2MessageConverter;
import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.jms.support.converter.MessageType;
import oracle.jdbc.pool.OracleDataSource;
import oracle.jms.AQjmsFactory;
#EnableJms
public class DataSourceConfig {
#Value("${spring.datasource.username}")
String username;
#Value("${spring.datasource.password}")
String password;
#Value("${spring.datasource.url}")
String url;
#Bean
private OracleDataSource dataSource() throws SQLException {
OracleDataSource dataSource = new OracleDataSource();
dataSource.setUser(username);
dataSource.setPassword(password);
dataSource.setURL(url);
dataSource.setImplicitCachingEnabled(true);
dataSource.setFastConnectionFailoverEnabled(true);
return dataSource;
}
#Bean
public QueueConnectionFactory connectionFactory() throws Exception {
return AQjmsFactory.getQueueConnectionFactory(dataSource());
}
#Bean
public JmsTemplate jmsTemplate() throws Exception {
JmsTemplate jmsTemplate = new JmsTemplate();
jmsTemplate.setConnectionFactory(connectionFactory());
return jmsTemplate;
}
}
Driver class
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Primary;
import org.springframework.jms.core.JmsTemplate;
#SpringBootApplication
public class AQProcessorApplication implements CommandLineRunner {
#Autowired
#Qualifier("jmsTemplate")
JmsTemplate template;
public static void main(String[] args) {
SpringApplication.run(AQProcessorApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
template.convertAndSend("QUEUE_NAME", "test");
System.out.println("------------- MESSAGE SENT--------------------------");
}
I get MESSAGE SENT in console but I do not see anything in Oracle DB
I tried to testing my Dao class but it return this error for the class DbConnection:
javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or in an application resource file: java.naming.factory.initial
at java.naming/javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:691)
at java.naming/javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:305)
at java.naming/javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:342)
at java.naming/javax.naming.InitialContext.lookup(InitialContext.java:409)
at model.DbConnection.(DbConnection.java:16)
at model.DbConnection.getInstance(DbConnection.java:30)
at model.ProfileManager.ReturnPatientByKey(ProfileManager.java:27)
at model.ProfileManagerTest.testReturnPatientByKey(ProfileManagerTest.java:32)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
....
my DbConnection class:
package model;
import java.sql.Connection;
import java.sql.SQLException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
public class DbConnection {
private DbConnection() {
Context ctx;
try {
ctx = new InitialContext();
ds = (DataSource)ctx.lookup("java:comp/env/jdbc/CheckUpDb");
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public Connection getConnection() throws SQLException {
return ds.getConnection();
}
public static DbConnection getInstance () {
if(db==null) {
return new DbConnection();
}
else {
return db;
}
}
private static DataSource ds;
private static DbConnection db;
}
Database connection works in the web application, only the testing return this error.
I don't think the problem si my class ProfileManager because it is only a testing example:
import static org.junit.Assert.assertTrue;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.*;
import model.Bean.PatientBean;
class ProfileManagerTest{
private ProfileManager pm;
String fiscal_code;
String user_password;
PatientBean patient;
#BeforeEach
void setUp() throws Exception {
this.pm = new ProfileManager();
fiscal_code = "aaa";
user_password = "bbb";
patient = mock(PatientBean.class);
}
#AfterEach
void tearDown() throws Exception {
}
#Test
void testReturnPatientByKey() {
patient = (PatientBean) pm.ReturnPatientByKey(fiscal_code, user_password);
assertTrue(true);
}
}
Database connection works in the web application, only the testing return this error.
That's most likely because you have the datasource declared in the server configuration and the server is providing your web app with one, but you don't have the same done in your test.
Do a search in your server files an you will probably discover something like this, or similar, depending on what server you use:
<Resource name="jdbc/CheckUpDb"
driverClassName="..."
type="..."
url="..."
username="..."
password="..."
/>
This is a way to configure a datasource using JNDI. When your web application runs, the server will provide you with this resource by name. This is what ctx.lookup("java:comp/env/jdbc/CheckUpDb"); does. It asks the server to give it that resource.
But when you run your unit tests, you run outside the server environment. That means that any resource you defined in the server (using context.xml for example) doesn't exist when you run your tests. In your tests you have to provide a datasource and make it available to your JNDI context so that this line of code then works:
ds = (DataSource)ctx.lookup("java:comp/env/jdbc/CheckUpDb");
The following post should give you the necessary details to set up your JNDI data source for your test: Setting up JNDI Datasource in jUnit
You will see that the examples there make use of a library called Simple-Jndi that they use to provide a JNDI context and configure it to include the datasource that the tests then try to retrieve by name. You can use any JNDI provider, but you must set up the datasource for your test yourself (inside #BeforeEach or #BeforeAll) because when running unit tests, you don't have the tomcat server doing this for you.
I am using Apache Derby and have the following code:
DBConnectionFactory.java
package edu.unsw.comp9321.jdbc;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.logging.Logger;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import edu.unsw.comp9321.common.DataSourceException;
import edu.unsw.comp9321.common.ServiceLocatorException;
// This class looks up the database via JNDI and returns a connection to the DAO Implementation class
public class DBConnectionFactory {
static Logger logger = Logger.getLogger(DBConnectionFactory.class.getName());
private static DBConnectionFactory factory = null;
private DataSource ds = null;
private InitialContext ctx;
private Context subctx;
private DBConnectionFactory() throws ServiceLocatorException{
try{
ctx = new InitialContext();
ds = (DataSource) ctx.lookup("java:comp/env/jdbc/cs9321");
logger.info("Database found:"+ds.toString());
}catch(NamingException e){
logger.severe("Cannot find context, throwing exception"+e.getMessage());
e.printStackTrace();
throw new ServiceLocatorException();
}
}
public DataSource getDataSource(){
return ds;
}
public static Connection getConnection() throws ServiceLocatorException, SQLException{
if(factory==null)
factory = new DBConnectionFactory();
Connection conn = factory.getDataSource().getConnection();
return conn;
}
}
The error seems to occur here:
ds = (DataSource) ctx.lookup("java:comp/env/jdbc/cs9321");
I read that this may occur if derbyclient.jar is not in the build path. However, I have already added this jar to the build path.
Would anyone have any suggestions as to what I can do?
Thanks.
You're missing a couple of jars, add this two and everything should be ok:
commons-dbcp-1.4.jar
commons-pool-1.6.jar
Hope that helps!
Cheers
Using this post I want to create JUnit test with datasource. I tested this code:
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.activation.DataSource;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.junit.BeforeClass;
public class NewEmptyJUnitTest
{
public NewEmptyJUnitTest()
{
}
#BeforeClass
public static void setUpClass() throws Exception
{
// rcarver - setup the jndi context and the datasource
try
{
// 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");
// Construct DataSource
OracleConnectionPoolDataSource ds = new OracleConnectionPoolDataSource();
ds.setURL("jdbc:oracle:thin:#host:port:db");
ds.setUser("MY_USER_NAME");
ds.setPassword("MY_USER_PASSWORD");
ic.bind("java:/comp/env/jdbc/nameofmyjdbcresource", ds);
}
catch (NamingException ex)
{
Logger.getLogger(MyDAOTest.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void inittest() throws NamingException
{
Context initContext = new InitialContext();
Context webContext = (Context) initContext.lookup("java:/comp/env");
DataSource ds = (DataSource) webContext.lookup("jdbc/nameofmyjdbcresource");
}
}
But Netbeans cannot find this class 'OracleConnectionPoolDataSource'. How I can solve this problem?
What is the package that I have to import in order to use this class?
As per ojdbc14.jar, OracleConnectionPoolDataSource can be found in oracle.jdbc.pool:
import oracle.jdbc.pool.OracleConnectionPoolDataSource;