I have java web application using struts 2 and running on JBoss server. We don't use Spring. This application does not use any database right now. They have moved some hard coded data in the application to database and have asked me to start using the database. I'll have to connect to the database to start with.
I have two conditions that have to be met:
I am told we can't reconfigure the server since it is read only (which means I cannot create DataSource on the server[add *-ds.xml to server] - Does it have any other meaning ?) -
(This leaves me with an option to use DriverManager. Is there a better way ?)
. They have told me to keep the database connection properties file out of the ear file and in the config directory. (Does this mean that I have to place the config file somewhere inside the jboss server? What does this mean ? Will this eventually make me to "reconfigure" the server ?)
How do I place the database connection properties file outside the EAR and still have my DAO layer access the configuration properties ?
Related
I'm using TomEE 8.0.9. I should distribute a webapp in its .war format. In order to ensure an easy installation I want the database (specified in resources.xml) to be automatically created with all its tables and some initial records (By means of a .sql file).
I tried with a class that gets executed on startup but it gets problematic if the database isn't connected during the webapp's deploy. Isn't there a way to do an action when a JDBC connection gets created for the first time? Tomcat offers the initSQL parameter but it just works with one single statement.
In general, what it the best way to create a database on the app's first startup?
I am currently trying to implement a simple servlet that has to communicate with our database.
I have no real prior experience with databases, so I was wondering how I should I go about this? I have downloaded the mysql-connector-java-5.1.40 from dev.mysql.
Going over some of the directions on the web for setting up the connection, it seems to only be for local mysql, but what of remote? The remote's user and pass is demo/demo; of course I would also need to log into the the remote server with my credentials. How do I go about connecting to this remote db?
Edit: So I believe I successfully connected to the DB, at least I can see it in my eclipse under data sources and the tables are present (company and stock_prices), however my eclipse still says I have an unsuitable driver even though I do have one associated with it.
The proper way of consuming a database resources in a web container (or in an application server) is through the javax.sql.DataSource abstraction. So you should configure a data source in your container. For tomcat it's as simple as creating a file named context.xml in your war's META-INF folder with the following content (replace address and credentials with your own):
<Context>
<Resource name="jdbc/[YourDatabaseName]"
auth="Container"
type="javax.sql.DataSource"
username="[DatabaseUsername]"
password="[DatabasePassword]"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql:/[yourserver]:3306/[your-db]"
maxActive="20"
maxIdle="20"/>
</Context>
Then when you want to perform a DB operation:
you either look up the data source:
DataSource ds =(DataSource) new InitialContext().lookup("java:comp/env/jdbc[YourDatabaseName]");
or simply use dependency injection for managed components like servlets:
#Resource(name="jdbc/YourDataSource")
Datasource ds;
The you just get a connection from the datasource in order to execute statements to the database.
The DB driver can be put in one of two places:
the war's lib folder
tomcat's lib folder
It's recommended to put it in tomcat's lib, because drivers are singletons and if you have several apps with different versions of the driver in the same container bad things will happen.
How do I go about connecting to this remote db?
Connecting to a remote DB is the same as connecting to alocal DB. Just pass the correct DB address in the connection string.
For a long time in many IT services, I see some complex process to manage Java EE application configuration depending of the environments:
- custom tools, with Database or not, to manage replacement in the properties file (unzip war, replace, zip war...)
- Externalize properties file in obscure directory in the server (and some process to update it some time) and some time with a JNDI configuration...
- maven profile and lot of big properties files
But for database connection everybody use jndi datasource.
Why this is not generalized for all configurations that depend of environment ?
Update : I want deal with other variable than datasource, there is no question about datasource : it's in configured in JNDI for Java EE application. After if you want hack JNDI...
Setting up database connectivity (like user name, password, URL, driver etc.) somewhere in the application server has several advantages over doing it yourself in the WAR:
The app server can be a central point where the DB is configured, and you might have several WARs running on that server sharing a DB. So you need to set it up only once.
The DB settings, especially the credentials (username, password) are stored somewhere in the app server instead of somewhere in the WAR. That can have security implications (for instance, restricting access to that file is easier done than in a WAR archive).
You can set up one JNDI path to retrieve a DataSource instance pointing to the DB and do not need to worry about username and password anymore. If you have multiple app servers (one live system, one test system, several developer machines) with different DB URLs and credentials, then you can just configure that in each app server individually and deploy the WAR files without the need to change DB settings (see below).
The server might provide additional services, like connection pools, container managed transactions, etc. So again, you don't have to do it on your own in the WAR.
This is true for other services provided by the app server as well, for example JavaMail.
There are other cases where it you want to configure something that is specific to one web application and does not rely on the environment (the app server), like logging (although that may be set up in the app server, too). In those cases you might prefer using static config files, for instance log4j.properties.
I want to illustrate the third bullet point a bit further ...
Suppose you have one WAR in three app servers (developer machine, test server, live server).
Option 1 (DB setup in WAR)
Create a database.properties :
db.url=jdbc:mysql://localhost:3306/localdb
db.user=myusername
db.pass=mysecretpassword
#db.url=jdbc:mysql://10.1.2.3:3306/testdb
#db.user=myusername
#db.pass=mysecretpassword
#db.url=jdbc:mysql://10.2.3.4:3306/livedb
#db.user=myusername
#db.pass=mysecretpassword
Before you deploy it somewhere, you need to check if your settings are pointing to the right DB!
Also, if you check this file in to some version control system, then you might not want to publish your DB username/password to your local machine.
Option 2 (DB setup in App Server)
Imagine you have configured the three servers with their individual DB settings, and each of them registers the DB with the JNDI path java:database/mydb.
Then you can retrieve the DataSource like so:
Context context = new InitialContext();
DataSource dataSource = (DataSource) context.lookup("java:database/mydb");
This is working on every app server instance and you can deploy your WAR without the need to modify anything.
Conclusion
By moving the configuration to the app server you'll have the advantage of separating settings depending on the environment from your app code. I would prefer this whenever you have settings involving IP addresses, credentials, etc.
Using a static .properties file on the other hand is simpler to manage. I would prefer this option when dealing with settings that have no dependencies to the environment or are app specific.
Java webapps provide a convenient way to make them run: It’s suficcient to drop the jar file into tomcat‘s webapps folder or upload it using the tomcat manager. If the jar file is named foo123.jar, the web application is soon accessible under http://<host>:8080/foo123/. However, in the majority of cases, there is a problem with the configuration: It’s a good practice to store data in a database, but where can I store the database connection parameters? Usually you have to adapt some server.xml or web.xml or other configuration file to put it there, but this hinders making use of the automatic deployment for such an application.
A “simple to use” web application should request its required configuration on the first run, like a “setup” screen, and then keep it in some place where it survives a restart of the servlet container. Of course, for database connection parameters, storing them in the database is not an option.
Following the specs, the servlet container has to provide a directory that a web application has write access to. It can be determined using:
File tempDir =
(File) session.getServletContext().getAttribute("javax.servlet.context.tempdir");
The content of this directory is bound to the ‘servlet context lifecycle’, if I got it right this means it is empty after a server restart. If that is true, it cannot be used for my purpose.
Does anybody know some kind of best practice for that? I don’t want to reinvent the wheel.
In lack of a better solution, I would implement it this way: As I said, if you make use of the easy deployment means described above, the context path is derived from the jar file name. So I could imagine to make use of this for the database connection as well. In simple terms: If the web application foo123 finds a MySQL connection on localhost:3306 (the MySQL default port) and can connect to it with username foo123 and password foo123 and has permissions to access a schema called foo123 it always uses that on restart.
What do you think of that?
You could just use a context.xml file. That will let you store the config files on a server-by-server basis and that means that you'll never have to put that information in the code itself.
This example seems to sum it up rather nicely.
I have a Web application running on Oracle Weblogic Server 11g.
It uses a datasource defined in the application server to connect to the Oracle Database (11g too), its class is
oracle.jdbc.xa.client.OracleXADataSource
If for some reason the database becomes not present and then comes
backs, the application is running ok (it gets exceptions while trying
to access the db but this is fine and then can again get some new
connections when the db comes back)
However, if the database is down during weblogic server startup,
the datasource is not deployed on the server and the application
throws an exception because it has not any datasource available, the
deployment is marked as failed and of course nothing does repair this
automatically.
Is there a way to make the datasource be deployed even if the database is not present during server startup ? (such that the application becomes usable when the database is back)
Why do you want to deploy an application without a valid datasource?
You could possibly fake the datasource (create a dummy datasource with the same JNDI name) and assuming that the application does not validate datasource schema at startup you will get a semi-functional running application (which will fail with the first DB interaction).
When the real datasource is up and running you won't be able to switch to it. You will still have to restart the application server.
Update:
According to the J2EE spec (1.5 version) resources are binded during the deployment process. I believe that it is possible to implement a custom Factory that will return dummy / active datasource. Does it worth the effort to implement? ;)
EE.5.6.2 Deployer’s Responsibilities
Bind the resource manager connection factory reference to a resource manager connection factory that exists in the operational environment. The Deployer may use, for example, the JNDI LinkRef mechanism to create a symbolic link to the actual JNDI name of the resource manager connection factory. The re- source manager connection factory type must be compatible with the type de- clared in the res-type element.
The option you are looking for is "Connection Creation Retries", check this link
"If set and if the database is unavailable when the data source is created, WebLogic Server attempts to create connections in the pool again after the number of seconds you specify, and will continue to attempt to create the connections until it succeeds. This option applies to connections created when the data source is created at server startup ..."
set "Initial Capacity" http://docs.oracle.com/cd/E14571_01/web.1111/e13814/jdbc_tuning.htm#i1028616 to 0: weblogic on startup will not attempt to create any connection, and will not fail if the DB is not available.