I want to define a jms ConnectionFactory as global resource in tomcat server.xml to connect my webapps to standalone Artemis server.
Unfortunately I couldn't find any official or clean manual for such a common use case that describes required libraries and configurations.
Can somebody show me an example?
I couldn't find any native Artemis based solution. Artemis server is ActiveMQ client compatible. So we can follow ActiveMQ manual for this purpose.
Add ActiveMQ client libraries to $CATALINA_HOME/lib
geronimo-jms_2.0_spec-1.0-alpha-2.jar
activemq-client-5.14.3.jar
geronimo-j2ee-management_1.1_spec-1.0.1.jar
hawtbuf-1.11.jar
slf4j-api-1.7.6.jar
Add global resource to $CATALINA_HOME/conf/server.xml
<Resource auth="Container"
name="jms/ConnectionFactory"
type="org.apache.activemq.ActiveMQConnectionFactory"
factory="org.apache.activemq.jndi.JNDIReferenceFactory"
brokerURL="tcp://127.0.0.1:61616"
brokerName="MyActiveMQBroker"/>
Add resource link to $CATALINA_HOME/conf/context.xml
<ResourceLink name="/ConnectionFactory"
global="jms/ConnectionFactory"
type="javax.jms.ConnectionFactory"/>
Look up connection factory in app context
<bean id="jmsConnectionFactory"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/ConnectionFactory" />
<property name="proxyInterface" value="javax.jms.ConnectionFactory"/>
</bean>
Related
I'm trying to deploy my project to AWS Elastic Beanstalk, using Docker with preconfigured Glassfish.
Since the project uses JPA, and EJB to create a transactional persistence unit; I create a database connection pool in the Glassfish admin console, then supply the JNDI string to persistence.xml.
All good in my local machine, Amazon won't allow you to use the admin console. I've read this post, which discusses generally how to configure Glassfish with asadmin, but I've found it very hard to follow and sounds very invasive.
Is there a one-size-fits-all solution to create a database connection pool that is automatically allocated on any server I deploy my application to?
Yes. Although this is unfortunately under-documented.
You can create an application scoped connection pool, that Glassfish creates on the fly, when you depoly your war file to it. It will destroy it when undeployed. Though, it is only available to this application on the server.
Here's what you should do. Create a file named glassfish-resources.xml like this (for MySql):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN" "http://glassfish.org/dtds/glassfish-resources_1_5.dtd">
<resources>
<jdbc-connection-pool datasource-classname="com.mysql.jdbc.jdbc2.optional.MysqlDataSource" name="MySQLPool" res-type="javax.sql.DataSource">
<property name="user" value="someUser"></property>
<property name="password" value="aPassword"></property>
<property name="databaseName" value="aDatabase"></property>
<property name="serverName" value="some.string.you got.from.amazon.rds.amazonaws.com"></property>
<property name="portNumber" value="3306"></property>
</jdbc-connection-pool>
<jdbc-resource pool-name="MySQLPool" jndi-name="jdbc/MySQLPool"></jdbc-resource>
</resources>
And drop it into your WEB-INF directory. You should also place the database connection dependency jar in the lib directory.
Now since this isn't a global JNDI reference, as it is only available to this application, you should access it in persistence.xml with java:app prefix, like this:
<jta-data-source>java:app/jdbc/MySQLPool</jta-data-source>
I would like to configure a series of environment-dependant settings as an external resource, so that the same WAR artifact can be configured in any application server.
In Glassfish I rememeber that I just created a .properties file using the built-in Properties Resource JNDI Factory, and it worked like a charm, but there's no such thing in Tomcat.
I tried defining a java.net.URL and a java.lang.String to define just the path that this file is held in, but I get the following error:
Caused by: java.io.FileNotFoundException: Could not open ServletContext resource [/c://app.properties]
So what would be a good way to create an environment-agnostic set of properties for my application?
PS: this is how I define my properties in Spring:
<jee:jndi-lookup id="appProperties" jndi-name="java:comp/env/url/urlAppProperties" />
<bean id="application-properties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="locations">
<list>
<value>#{ appProperties }</value>
</list>
</property>
</bean>
You can add external configuration values to the JNDI context using Tomcat's resource configuration elements. As described in the Tomcat documentation, you can define a <GlobalNamingResources> element in your server.xml listing a set of configuration values which are available to all contexts (web applications) on that server:
Example taken from the Tomcat docs:
<GlobalNamingResources ...>
...
<Environment name="maxExemptions" value="10"
type="java.lang.Integer" override="false"/>
...
</GlobalNamingResources>
These environment variables are then available via JDNI in the java:comp/env context. In order to use such variables in a web application, you have to link to them in the individual context.xml configuration files using the <ResourceLink> element.
<Context>
<ResourceLink name="maxExemptions" global="maxExemptions" type="java.lang.Integer"/>
</Context>
With this set up, you can access these values through the standard JNDI API.
I got an exception at System.setProperty in Java when I've tried to deploy the application in GAE. Any ideas what can be wrong?
You can set Java system properties or environment variables for App Engine applications in the respective appengine-web.xml configuration file.
<system-properties>
<property name="property1" value="value1" />
<property name="property2" value="value2" />
</system-properties>
You can find more details in App Engine documentation.
I am facing a very bizarre problem where my App Engine server can't load its Cloud SQL's GoogleDriver, here's the error (It happens right after I run "mvn appengine:update").
org.springframework.transaction.CannotCreateTransactionException: Could not open Hibernate Session for transaction; nested exception is org.hibernate.exception.GenericJDBCException: Cannot open connection
at org.springframework.orm.hibernate3.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:596)
...
Caused by: org.apache.commons.dbcp.SQLNestedException: Cannot load JDBC driver class 'com.mysql.jdbc.GoogleDriver'
at org.apache.commons.dbcp.BasicDataSource.createConnectionFactory(BasicDataSource.java:1429)
at org.apache.commons.dbcp.BasicDataSource.createDataSource(BasicDataSource.java:1371)
at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044)
at org.springframework.orm.hibernate3.LocalDataSourceConnectionProvider.getConnection(LocalDataSourceConnectionProvider.java:81)
at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:446)
... 48 more
Caused by: java.lang.ClassNotFoundException: com.mysql.jdbc.GoogleDriver
appengine.properties
################### MySQL Configuration - Google Cloud App Engine ##########################
jdbc.driverClassName=com.mysql.jdbc.GoogleDriver
jdbc.url=jdbc:google:mysql://mytestapp:testdb?user=someuser
jdbc.username=someuser
jdbc.password=******
jdbc.dialect=org.hibernate.dialect.MySQLDialect
In my Spring context file I have:
<context:property-placeholder location="classpath:appengine.properties" />
<bean
id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close" >
<property
name="driverClassName"
value="${jdbc.driverClassName}" />
<property
name="url"
value="${jdbc.url}" />
...
Any ideas?
==
Just to confirm, I had already configured my appengine-web.xml and it doesn't help at all:
<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<application>mytestapp</application>
<version>1</version>
<threadsafe>true</threadsafe>
<sessions-enabled>true</sessions-enabled>
<system-properties>
<property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/>
</system-properties>
<use-google-connector-j>true</use-google-connector-j>
</appengine-web-app>
--
I couldn't move forward due to some incompatibility between hibernate jar versions so I kept trying through the actual release pipeline (Jenkins + Maven + build + test + deploy), I had to add the Compute Engine VM's IP address to the list of authorized IPs of the Cloud SQL Instance in order to run my unit tests and deploy it to the application (but, if I keep this approach, I can only use the MySQL driver and URL instead of the GoogleDriver and URL. So this is getting tricky...).
I have these properties in a Production.properties file that is loaded by my Spring MVC config file:
################### MySQL Configuration - Google Cloud App Engine ##########################
jdbc.driverClassName=com.mysql.jdbc.GoogleDriver
jdbc.url=jdbc:google:mysql://*******testapp:testsqldb?user=root
jdbc.username=root
jdbc.password=*****
jdbc.dialect=org.hibernate.dialect.MySQLDialect
Is there an easy way to dynamically switch between external and GAE Cloud SQL connection details without using this approach?
if (SystemProperty.environment.value() ==
SystemProperty.Environment.Value.Production) {
// Connecting from App Engine.
Any ideas?
The class is not automatically available in the App Engine runtime. You must enable it by adding <use-google-connector-j>true</use-google-connector-j> to your appengine-web.xml. This is documented at: https://cloud.google.com/appengine/docs/java/cloud-sql/#enable_connector_j
Edited to add (from comments below):
Also, when connecting to Cloud SQL from GAE you should leave the password field empty.
You should also make sure that if your code is running outside GAE (e.g. on your workstation, on GCE, on a Jenkins build) it uses stock MySQL connector as the Google connector is only available on GAE.
You might also want too look into using the stock MySQL driver, which works both from GAE and other connections. There is a demo of this at https://github.com/GoogleCloudPlatform/appengine-cloudsql-native-mysql-hibernate-jpa-demo-java
I am trying to use nested beans with a profile to setup an embedded jms broker when I am in dev mode. Here is my xml:
<beans ...>
...
other bean definition
...
<beans profile="embeddedBroker">
<!-- Configure an embedded ActiveMQ Broker with a TCP connector.
This broker is never set to start automatically by default, it is the broker service wrapper that
will take care to start it if configured to do so.
-->
<amq:broker id="jmsBroker" brokerId="EmbeddedBroker" brokerName="EmbeddedBroker"
persistent="false" useJmx="true" start="false">
<amq:plugins>
<!-- lets enable detailed logging in the broker but ignore ConnectionEvents -->
<amq:loggingBrokerPlugin logMessageEvents="true" logConnectionEvents="false"/>
<amq:timeStampingBrokerPlugin zeroExpirationOverride="1000" ttlCeiling="60000" futureOnly="true"/>
<amq:traceBrokerPathPlugin />
</amq:plugins>
<!-- Create a connector to give an external remote access to this broker. -->
<amq:transportConnectors>
<amq:transportConnector uri="tcp://127.0.0.1:35000" />
</amq:transportConnectors>
</amq:broker>
<!-- This broker service (wrapper) control the lifecycle of the jms broker defined above.
By default the internal broker will be initialized, but not started. It will usually be started only for
internal integration and unit tests.
-->
<bean id="jmsBrokerService" class="com.imetrik.global.common.jms.AMQBrokerService"
init-method="start"
destroy-method="stop">
<property name="broker" ref="jmsBroker" />
<property name="enabled" value="true" />
</bean>
</beans>
</beans>
But when I run my application with the correct profile, spring complain that the jmsBroker reference cannot be found!
Error creating bean with name 'jmsBrokerService' defined in class path resource [jms-beans.xml]: Cannot resolve reference to bean 'jmsBroker' while setting bean property 'broker';
Is there a way to fix that? Is it because the reference bean is not in the same namespace?
I know that if I put it out of the nested beans, it is working fine.
I am using Spring 4.1