How to define a different connection pool by deployed application in glassfish - java

I am using glassfish 4 and java EE 7. I would need to define a connection pool that is different for each application I will deploy in glassfish.
I have one application (.war file) per client, and each client has its own user/password/schema in my mysql db, so the data is not shared between the clients.
I know how to define a connection pool in glassfish, but then all my applications can only use the same settings (I am using bonecp btw).
I would like to be able to change the user/password/schema for each application deployed. Is it possible to define entirely the connection pool in persistence.xml and not in glassfish, so I could have a different one within my different .war files?
With 10 .war files deployed (10 clients), I would like to have 10 different connection pools (different user/password/schema defined).

If you create the data source programmatically, then you can inject it to JPA without a need to declare it in your persistence.xml. Here's an example
Define the persistence-xml:
<persistence-unit name="foo-PU" transaction-type="RESOURCE_LOCAL">
<!-- the provider: Hibernate, EclipseLink or another -->
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<!-- No need to define any connection parameter nor the data source -->
<!-- class definitions here -->
</persistence-unit>
Defining a .properties file to store the configuration for the data source:
db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/foo_db
db.user=user
db.password=s3cr3t
db.bonecp.idleConnectionTestPeriod=60
db.bonecp.idleMaxAge=240
db.bonecp.maxConnections=10
# more properties...
Defining a class that will generate the data source
public class DataSourceGenerator {
public static DataSource getDataSource(String properties) {
Properties conf = new Properties();
try {
conf.load(
DataSourceFactory.class
.getClassLoader().getResourceAsStream(
properties));
} catch (IOException e) {
//handle the error
//naive handling shown here
e.printStacktrace();
}
BoneCPDataSource dataSource = new BoneCPDataSource();
//set the properties from the .properties file
dataSource.setDriverClass(conf.getProperty("db.driver"));
dataSource.setJdbcUrl(conf.getProperty("db.url"));
dataSource.setUsername(conf.getProperty("db.user"));
dataSource.setPassword(conf.getProperty("db.password"));
dataSource.setIdleConnectionTestPeriodInMinutes(
Long.parseLong(
conf.getProperty("db.bonecp.idleConnectionTestPeriod")));
dataSource.setIdleMaxAgeInSeconds(
Long.parseLong(
conf.getProperty("db.bonecp.idleMaxAge")));
dataSource.setMaxConnectionsPerPartition(
Integer.parseInt(
conf.getProperty("db.bonecp.maxConnections")));
//more properties to load...
return dataSource;
}
}
Create your EntityManagerFactory programmatically as well:
public class EntityManagerFactoryGenerator {
public static EntityManagerFactory createEMF() {
Map<String, Object> properties = new HashMap<>();
String dataSourceKey = "";
//uncomment here depending on your needs...
//using Hibernate
//dataSourceKey = org.hibernate.cfg.AvailableSettings.DATASOURCE;
//using EclipseLink
//dataSourceKey = org.eclipse.persistence
// .config.PersistenceUnitProperties.NON_JTA_DATASOURCE;
properties.put(
dataSourceKey,
DataSourceGenerator.getDataSource("mysql-con.properties"));
return Persistence.createEntityManagerFactory("foo-PU", properties);
}
}

Step 1. Go to Glassfish admin console to configure the JDBC connection details.
Inside Resources - JDBC create one pool for each set of connection details, then create a JDBC data source to each created pool.
Step 2. Go to your persistence file of each application and point to the right data source.
Don't specify the provider if you don't need anything special as Glassfish comes with EclipseLink already, which works fine.

Related

Dynamic Database property changes in Springboot

I have mysql database and i have configured database properties in application.properties file .
Now if i do change db connection properties , i want reflect that changes into my application on the fly , means with out restarting the server
Is this possible using with spring cloud config server and actuator?
I have tested this quite a bit and here are my findings.
Spring config server works pretty well for simple key value pairs.
It also works for Database properties provided that you are creating datasource objects yourself and you are using #RefreshScope.
For example, if you have a config server with these properties.
mongodb.feed.database=kiran
mongodb.feed.host=localhost
mongodb.feed.port=27017
And you are configuring MongoTemplate in your application like this.
#Configuration
#ConfigurationProperties(prefix = "mongodb.feed")
#EnableMongoRepositories(basePackages = "in.phani.springboot.repository", mongoTemplateRef = "feedMongoTemplate")
#Setter
class FeedMongoConfig {
private String host;
private int port;
private String database;
#Primary
#Bean(name = "feedMongoTemplate")
#RefreshScope // this is the key
public MongoTemplate feedMongoTemplate() throws Exception {
final Mongo mongoClient = createMongoClient(new ServerAddress(host, port));
return new MongoTemplate(mongoClient, database);
}
Mongo createMongoClient(ServerAddress serverAddress) {
return new MongoClient(serverAddress);
}
}
And if you change the database name in your config properties and then refresh the scope with /refresh endpoint. It works pretty well.
With springboot you need not do manual configuration like this. Spring boot has Autoconfiguration for most of the stuff. Continuing with the same example above, if you were to put in config properties something like this
spring.data.mongodb.uri=mongodb://localhost:27017/phani
spring-boot will configure MongoTemplate for you(you don't need to create yourself as in 2nd point).
Here comes the hiccup.
Now if you change the database name, and refresh the scope, it doesn't work. Because in this case, MongoTemplate was configured by spring-boot Autoconfiguration(MongoAutoConfiguration)
So in conclusion, it needs extensive testing to be done, before using it on production(especially for complex beans like datasources, MongoTemplates), since there is not enough documentation on this.. But I would say, it is worth trying.

JPA schema file for two databases

I have two datasources (JPA) in my project. Both are on hsql server. I need to recreate the schema each time. For the first datasource I have schema-hsql.sql and import.sql files. Where to put initial HSQL script for second datasource?
My datasources configuration is based on http://www.baeldung.com/spring-data-jpa-multiple-databases
Is it even possible?
In this since it is a special case where two DataSources are available you can not use the default way of creating tables and inserting initial data using schema-hsql.sql and import.sql.
In this case you need to do some programming using DatabasePopulatorUtils
DataSource dataSource1() { ... }
DataSource dataSource2() { ... }
DatabasePopulatorUtils.execute(new ResourceDatabasePopulater(new ClasspathResource("schema-datasource1.sql"), new ClasspathResource("import-datasource1.sql")), dataSource1());
DatabasePopulatorUtils.execute(new ResourceDatabasePopulater(new ClasspathResource("schema-datasource2.sql"), new ClasspathResource("import-datasource2.sql")), dataSource2());

Database connection setup across all modules of a big java project

In a very large project where do we set up the database connection so that it is available across all the modules?
Suppose the requirement is like this:
LoginPage.html -> LoginServlet.java -> LoginService.java ==> Takes DB help to check the credentials.
Now, since the actual credentials are stored in DB, where do we set up the database so that the connection is available to all the modules?
In big projects, is database connection made as and when needed or database connections setup at the time when application is run and made available across all the modules.
If DB connections are made available to all the modules (which need DB connectivity), how is this achieved?
Thanks for your help and inputs.
Since you're not using an IoC approach (Spring), the alternative would be to have a static class (or a singleton) that has a reference to the DataSource. Whenever you need a Connection you only have to get it from that class:
public class JdbcUtils{
private static DataSource dataSource;
static{
dataSource = new DB2SimpleDataSource();
dataSource.setDatabaseName("DBNAME");
dataSource.setServerName("xxx.xxx.xxx.xxx");
dataSource.setPortNumber(447);
dataSource.setUser("USER");
dataSource.setPassword("PASS");
dataSource.setDriverType(4);
dataSource.setCurrentSchema("SCHEMA");
//OR even better get the DataSource through JNDI lookup if defined on server
}
public static Connection getConnection() throws SQLException{
return dataSource.getConnection()
}
}

How to connect junit and tomcat in java?

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.

ActiveMQInitialContextFactory vs. NamingContextFactory

I'm creating a java enterprise application which uses activemq to send messages to a standalone queue broker.
I currently maintain access to long lived resources through jndi lookup which works quite nicely. I'd like to continue this pattern with the ActiveMQ connection factories and queue connection factories, however in the amq documentation it specifies that my jndi.properties should have:
java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory
while the default jndi.properties (which works with my simple object and facade lookups has:
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
Can I use one with the other? Can I have two jndi.properties files or two initial contexts somehow?
This question shows how to configure ONLY activemq through jndi. I want them to play nicely together.
You can create any number of InitialContext objects you want. You just have to pass environment to its constructor to properly initialize it.
So you can still safely use jndi.properties and initialize initial context for activemq with the code which may look like this:
public void setUpActiveMQResources() throws IOException, NamingException {
InitialContext context = createInitialContext("/activemq.jndi.properties");
// do what you want
}
public InitialContext createInitialContext(String resource) throws IOException, NamingException {
InputStream is = getClass().getResourceAsStream(resource);
Properties props = new Properties();
try {
props.load(is);
} finally {
is.close();
}
return new InitialContext(props);
}
activemq.jndi.properties in that case is the classpath resource with content like here

Categories

Resources