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
Related
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.
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.
This relates to this answer:
System.getProperty("catalina.base") There can be scenario where client may use any other server
another server-independent system
property yourself, you can set as a VM
argument.
-Dconfig.location=/path/to/folder
In case of Tomcat, you can set it as
JAVA_OPTS environment variable, or
edit the catalina.bat startup file or
edit the Windows Service settings
(when it's installed as Windows
Service), etc. Other servers supports
similar constructs as well.
Is this considered 'clean'? We've been doing this for years, just want to know if this is acceptable, or there is a better way to configure runtime environment.
It feels maybe dirty, but there are apart from putting it in the classpath really no better ways if the requirement is to untouch the WAR whenever you want to change the location of external configuration files.
If untouching the WAR is not a strict requirement and rebuilding the WAR is allowed (e.g. you're using an inhouse developed application with continuous integration and serveradmins are in the same line, etc), then you could also use a <context-param> in web.xml instead.
<context-param>
<param-name>config.location<param-name>
<param-value>/path/to/file</param-value>
</context-param>
It's then in any Servlet (or better, ServletContextListener) available by ServletContext#getInitParameter():
String configLocation = servletContext.getInitParameter("config.location");
File configFile = new File(configLocation, "config.properties");
// ...
My understanding is that "more clean" would be using either <servlet-param> <init-param> in web.xml or some kind of IoC solution, like Spring.
I feel this is not the cleanest of ways to attain what you want. You can use the web.xml init params or servlet params tags.
Another way is using properties file or an XML configuration file.
I just solved a similar problem in a slightly different way. Our customer wants to configure database connection details, integration server locations and ports etc. without rebuilding the war. Using environment property to point an external file containing the information may or may not be okay, but it felt a bit dirty trick. Anyway, here's a slightly more enterprisey way.
For database connections we use JNDI lookup and below is the current solution for integration server parametrization. The parameters can come from at least three different sources now:
properties-file, which is overridable with Maven profiles and requires single line of xml in spring configuration to be accessible. This is obviously inside the war file.
web.xml context-param. This is also, of course, inside the war file.
Tomcat server can override the init parameters with context.xml which can be outside the war. This happens to be the same file where JNDI context is defined, which is nice.
Below is the implementation for configuration accessor bean. It can run in servlet context and also without one (for some unit tests it makes little sense to kickstart a full-blown web server, but we nevertheless need to satisfy spring bean injections).
I don't mean this to be a perfect solution, but it is one. Didn't find anything like this with google.
#Service
public class IntegrationConfigurationImpl implements
IntegrationConfiguration, InitializingBean,
ServletContextAware, ApplicationContextAware {
private static final String SERVER_HOST_PROPERTY = "integration.server.host";
private static final String SERVER_PORT_PROPERTY = "integration.server.port";
private static final String PROPERTY_BEAN_NAME = "integrationProperties";
private ServletContext servletContext;
private ApplicationContext applicationContext;
private static final Logger log = LoggerFactory.getLogger(IntegrationConfigurationImpl.class);
private String serverHost = "foo";
private int serverPort = 42;
#Override
public String getServerHost() {
return serverHost;
}
#Override
public int getServerPort() {
return serverPort;
}
#Override
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
#Override
public void afterPropertiesSet() throws Exception {
// konfiguraation validointi..
if (servletContext == null) {
log.info("servlet context not set, not running as a web application. Trying to get properties from application context");
if (applicationContext.containsBean(PROPERTY_BEAN_NAME)) {
Properties p = (Properties)applicationContext.getBean(PROPERTY_BEAN_NAME);
serverHost = p.getProperty(SERVER_HOST_PROPERTY);
serverPort = Integer.valueOf(p.getProperty(SERVER_PORT_PROPERTY)).intValue();
} else {
log.info("Property bean not found :" + PROPERTY_BEAN_NAME);
}
} else {
serverHost = servletContext.getInitParameter(SERVER_HOST_PROPERTY);
serverPort = Integer.valueOf(servletContext.getInitParameter(SERVER_PORT_PROPERTY)).intValue();
}
log.info("Using integration server " + getServerHost() + ", port " + getServerPort());
}
}
The disadvantage with having system property is you need to restart the container to modify the system parameter.
Having it as init-param in web.xml, can allow you to modify by just restarting the web app.
Having in init-param is a better way.
Is there any way in the Servlet API to access properties specified in web.xml (such as initialization parameters) from within a Bean or Factory class that is not associated at all with the web container?
For example, I'm writing a Factory class, and I'd like to include some logic within the Factory to check a hierarchy of files and configuration locations to see which if any are available to determine which implementation class to instantiate - for example,
a properties file in the classpath,
a web.xml parameter,
a system property, or
some default logic if nothing else is available.
I'd like to be able to do this without injecting any reference to ServletConfig or anything similiar to my Factory - the code should be able to run ok outside of a Servlet Container.
This might sound a little bit uncommon, but I'd like for this component I'm working on to be able to be packaged with one of our webapps, and also be versatile enough to be packaged with some of our command-line tools without requiring a new properties file just for my component - so I was hoping to piggyback on top of other configuration files such as web.xml.
If I recall correctly, .NET has something like Request.GetCurrentRequest() to get a reference to the currently executing Request - but since this is a Java app I'm looking for something simliar that could be used to gain access to ServletConfig.
One way you could do this is:
public class FactoryInitialisingServletContextListener implements ServletContextListener {
public void contextDestroyed(ServletContextEvent event) {
}
public void contextInitialized(ServletContextEvent event) {
Properties properties = new Properties();
ServletContext servletContext = event.getServletContext();
Enumeration<?> keys = servletContext.getInitParameterNames();
while (keys.hasMoreElements()) {
String key = (String) keys.nextElement();
String value = servletContext.getInitParameter(key);
properties.setProperty(key, value);
}
Factory.setServletContextProperties(properties);
}
}
public class Factory {
static Properties _servletContextProperties = new Properties();
public static void setServletContextProperties(Properties servletContextProperties) {
_servletContextProperties = servletContextProperties;
}
}
And then have the following in your web.xml
<listener>
<listener-class>com.acme.FactoryInitialisingServletContextListener<listener-class>
</listener>
If your application is running in a web container, then the listener will be invoked by the container once the context has been created. In which case, the _servletContextProperties will be replaced with any context-params specified in the web.xml.
If your application is running outside a web container, then _servletContextProperties will be empty.
Have you considered using the Spring framework for this? That way, your beans don't get any extra cruft, and spring handles the configuration setup for you.
I think that you will have to add an associated bootstrap class which takes a reference to a ServletConfig (or ServletContext) and transcribes those values to the Factory class. At least this way you can package it separately.
#toolkit : Excellent, most humbled - This is something that I have been trying to do for a while