I am using Weblogic server to host the EJB application.
Now I have written code to lookup Datasource on server side which works fine
and search the Datasource if code look for specific name. See the line no 2 in below code.
dataSource = (DataSource) ic.lookup("jdbc/irisuatDS");
But my problem is I have 4 different environment let say Local, Dev, Stage and production. Is there any way where code can we written for generic DataSource. something like below lines without pointing to specific name.
When I use below piece of code it gives me error.
dataSource = (DataSource)ic.lookup("java:comp/env");
InitialContext ic = new InitialContext();
dataSource = (DataSource) ic.lookup("jdbc/irisuatDS");
dataSource = (DataSource)ic.lookup("java:comp/env");
Please let me know how can I resolve the issue.
Related
I'm trying to understand establishing a database-connection with a DataSource Object and the JNDI API.
I'm working with Intellij UE and have a local Tomcat-8- and Postgres-Server running.
I proceed as mentioned in the Oracle Java Documentation:
Creating Instance of DataSource Class and Setting its Properties
org.postgresql.ds.PGSimpleDataSource dataSource = new org.postgresql.ds.PGSimpleDataSource();
dataSource.setServerName("localhost");
dataSource.setDatabaseName("db01");
dataSource.setUser("jwi");
dataSource.setPassword("password");
Registering DataSource Object with Naming Service That Uses JNDI API
Context ctx = null;
try {
ctx = new InitialContext();
ctx.bind("jdbc/localDB", dataSource);
} catch (NamingException e) {
e.printStackTrace();
}
The Oracle Documentation says:
With the properties set, the system administrator can register the BasicDataSource object with a JNDI (Java Naming and Directory Interface) naming service.
So my first Question is: What means to register a DataSource? Is my code obove already the registration of an DataSource Object to JNDI?
Using Deployed DataSource Object
try {
Context ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("jdbc/localDB");
dbCon = ds.getConnection();
...
In this code cutting IntelliJ always claims, that it can't resolve the method getConnection().
The Oracle Documentation says:
After a basic DataSource implementation is deployed by a system administrator, it is ready for a programmer to use.
So my second Question is: What exactly means deployed in this case? Creating a DataSource Instance and execute the registration with JDNI? Or does deployed mean the Tomcat context.xml and web.xml configuration (Tomcat 8 JNDI How-To)?
I'd really appreciate if anybody has a good step by step instruction for this issue, in fact that the Oracle Documentation isn't really clear about some points imho.
for the second question, deployed means that your datasource is declared in the context.xml in tomcat.
Here is an example of an oracle database (you have to change the driver for postgres) :
<Resource name="jdbc/myoracle" auth="Container"
type="javax.sql.DataSource" driverClassName="oracle.jdbc.OracleDriver"
url="jdbc:oracle:thin:#127.0.0.1:1521:mysid"
username="scott" password="tiger" maxTotal="20" maxIdle="10"
maxWaitMillis="-1"/>
After that, you can code the java part, for that you can watch this link http://www.javapractices.com/topic/TopicAction.do?Id=127
For a complete example, there's a good tutorial here http://alvinalexander.com/blog/post/java/how-configure-tomcat-dbcp-connection-pool-pooling-postgres.
Hope this help
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.
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.
I want to test some new functionality which is part of an internal web app. This new code uses a database connection normally provided by an app server (tomcat).
I do not want to recreate the entire web app on my local machine to test the new code, since I only need to run one function.
Does anyone know how I can 'spoof' a Context, or Datasource, to retrieve the database config, without actually creating a web app instance on a server?
With the help of Spring SimpleNamingContextBuilder and Apache BasicDataSource, you can do something like this (I usually have this in a static block in test classes that need JNDI):
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(db_driver_name);
dataSource.setUrl(db_connection_url);
dataSource.setUsername(db_username);
dataSource.setPassword(db_password);
SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
builder.bind(jndi_name, dataSource);
builder.activate();
The value of jndi_name might look like this: java:comp/env/jdbc/my-db
Once this is set up, code that normally looks up the database connection via JNDI should work. The code above would for example work with this Spring config:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/my-db"/>
</bean>
The solutions listed here look a bit simpler than what I came up with about a year ago when I had to do the same thing. I basically made my own very simple DataSource implementation and adding it to a new Initial Context.
http://penguindreams.org/blog/running-beans-that-use-application-server-datasources-locally/
With TomcatJNDI you can access every JNDI resource you configured within Tomcat as used to do in your web application. The code to achieve it is simple and looks like
TomcatJNDI tomcatJNDI = new TomcatJNDI();
tomcatJNDI.processContextXml(contextXmlFile);
tomcatJNDI.start();
DataSource ds = (DataSource) InitialContext.doLookup("java:comp/env/path/to/datasource")
Go here to read more about it.
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