How to set up Eclipselink cache coordination with Wildfly - caching

I have set up a persistancce caching with Eclipselink on Wildfly 8. It works, but I also want to do cache coordination. I have the following setup for Eclipselink cache coordination in my persistance.xml:
<property name="eclipselink.cache.coordination.protocol" value="jms" />
<property name="eclipselink.cache.coordination.jms.topic" value="jms/MemberTopic" />
<property name="eclipselink.cache.coordination.jms.factory" value="jms/MemberConnectionFactory" />
However, when my entity is merged, no messages are sent by Eclipselink. I have logging set to "ALL", but nothing appears in the console.
I tried adding coordinationType=CacheCoordinationType.SEND_NEW_OBJECTS_WITH_CHANGES to entity's #Cache annotation, but it doesn't change anything. Also tried using an MDB as suggested for WebSphere (http://www.eclipse.org/eclipselink/documentation/2.4/concepts/cache011.htm#CDECEHFH).
The JMS topic and connectionfactory exist and Wildfly startup / application deployment shows no errors. For server clustering I run Wildfly in domain mode.

The problem ironically was in my Wildfly configuration instead - I didn't have my messaging cluster set up. I used the default messaging cluster settings from full-ha profile and set Eclipselink's cache coordination host accordingly:
<property name="eclipselink.cache.coordination.jms.host" value="231.7.7.7:9876" />

Related

Connecting ActiveMQ Web-Console to an existing broker (instead of starting a new one)

Having deployed the activemq-web-console war into a Tomcat embedded application how can one make it connect to an existing broker rather than create a new one?
The war comes with a set of predefined configurations, in particular, the WEB-INF/activemq.xml contains a configuration for the BrokerService
<broker brokerName="web-console" useJmx="true" xmlns="http://activemq.apache.org/schema/core">
<persistenceAdapter><kahaDB directory="target/kahadb"/></persistenceAdapter>
<transportConnectors>
<transportConnector uri="tcp://localhost:12345"/>
</transportConnectors>
</broker>
used from webconsole-embedded.xml in the following manner:
<bean id="brokerService" class="org.apache.activemq.xbean.BrokerFactoryBean">
<property name="config" value="/WEB-INF/activemq.xml"/>
</bean>
This configuration creates a new instance of BrokerService and tries to start the broker.
It is reported that the web console can be used to monitor an existing broker service rather than creating a new one. For this one should set the following properties somewhere:
webconsole.type=properties
webconsole.jms.url=tcp://localhost:61616
webconsole.jmx.url=service:jmx:rmi:///jndi/rmi://localhost:1099/karaf-trun
The questions is, where does one have to set these properties within the Tomcat embedded app and which XML changes in the above have to be performed for them to be used. I cannot find any sensible explanation how to configure it, and a BrokerService instance seems to be required by the remaining spring config.
Any ideas?
Please do not suggest to use hawtio instead!
I had the same problem today. You can start the webconsole in "properties" mode which gives you the oppertunity to connect over jmx.
I added following java arguments to our Jboss 6.1 and it worked immediatley. I didn't change any of the xmls (works out of the box)...
Example:
-Dwebconsole.type=properties -Dwebconsole.jms.url=tcp://<hostname>:61616 -Dwebconsole.jmx.url=service:jmx:rmi:///jndi/rmi://<hostname>:1090/jmxrmi -Dwebconsole.jmx.user=admin -Dwebconsole.jmx.password=123456
Also discussed here: https://svn.apache.org/repos/infra/websites/production/activemq/content/5.7.0/web-console.html

What's the differences between this Infinispan cache factories for Hibernate second level cache?

I'm trying to figure out the difference between this factories, used in hibernate.cache.region.factory_class property.
Example:
<property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.infinispan.JndiInfinispanRegionFactory" />
<property name="hibernate.cache.infinispan.cachemanager" value="java:jboss/infinispan/container/hibernate" />
There are 4 possible options.
The 2 options that I know something about is:
org.hibernate.cache.infinispan.InfinispanRegionFactory: for standalone aplications (not in a cluster, I think).
org.hibernate.cache.infinispan.JndiInfinispanRegionFactory: this is bounded to a JNDI in the property hibernate.cache.infinispan.cachemanager.
And I don't have any idea about these 2:
org.jboss.as.jpa.hibernate5.infinispan.SharedInfinispanRegionFactory: ?
org.jboss.as.jpa.hibernate5.infinispan.InfinispanRegionFactory: ?
We have a cluster configured on Wildfly 10.1.0 using domain mode. We want to share the entity cache among the nodes and we are having some doubts about how to do that.
If you're using Wildfly, you don't have to worry about setting the region factory class because Wildfly uses Infinispan as second-level cache provider by default. It's all explained here.
All you have to do is enable hibernate.cache.use_second_level_cache and you're good to go. See examples in the docu.
I agree with Galder, +1!
Regarding the purpose of [org.jboss.as.jpa.hibernate5.infinispan.SharedInfinispanRegionFactory][1] + [org.jboss.as.jpa.hibernate5.infinispan.InfinispanRegionFactory][2], these classes extend the Hibernate ORM [hibernate-infinispan][3] implementation classes, the purpose being to start the internal WildFly Infinispan cache services used for the JPA second level caching. They also deal with configuration as well. The below links may become outdated over time, as I think we [3] code might move to the Infinispan project (eventually).
A little more of the related code is at [HibernateSecondLevelCache.java][4], which backs up what Galder said. You can see that the WildFly JPA container automatically is setting the region factory class for you (if caching is enabled via [HibernatePersistenceProviderAdaptor.java][5].
I'm not sure if the code links are helpful to you, I thought they might be. :)
As a stackoverflow newbie, I am not allowed to post with more than 2 links, which is why [3] - [5] are invalid links.
Scott
[1] https://github.com/wildfly/wildfly/blob/master/jpa/hibernate5/src/main/java/org/jboss/as/jpa/hibernate5/infinispan/SharedInfinispanRegionFactory.java
[2] https://github.com/wildfly/wildfly/blob/master/jpa/hibernate5/src/main/java/org/jboss/as/jpa/hibernate5/infinispan/InfinispanRegionFactory.java
[3] github.com/hibernate/hibernate-orm/tree/master/hibernate-infinispan
[4] github.com/wildfly/wildfly/blob/master/jpa/hibernate5/src/main/java/org/jboss/as/jpa/hibernate5/HibernateSecondLevelCache.java
[5] github.com/wildfly/wildfly/blob/master/jpa/hibernate5/src/main/java/org/jboss/as/jpa/hibernate5/HibernatePersistenceProviderAdaptor.java#L91
The configuration envolves Infinispan, Hibernate and JGroups.
Using domain-mode on Wildfly10 you'll need this configuration on your application EAR:
<property name="hibernate.cache.use_second_level_cache" value="true"/>
Your server group need to use a profile that has the ha resources(high availability) such as full-ha or ha profiles. These profiles have the Infinispan and JGroups default configuration.
Then, you need to have the private 'Network Interfaces' on ALL Hosts' configuration that share the cache. JGroups uses the private Edit the domain/configuration/host.xml or use the wildfly console admin to add this configuration (200.0.0.171 needs to be replaced by the server's IP):
<interfaces>
...
<interface name="private">
<inet-address value="${jboss.bind.address.private:200.0.0.171}"/>
</interface>
<!-- .... -->
</interfaces>
For example, supposing you have a HostController HC1(with server-1 and server-2) and HC2(with server-3 and server-4)
Starting all the servers and Host Controllers, you'll see on your server.log:
INFO [org.infinispan.remoting.transport.jgroups.JGroupsTransport] (MSC service thread 1-4) ISPN000078: Starting JGroups channel hibernate
....
....
Received new cluster view for channel hibernate: [HC1:server-1, HC2-server-2, HC2-server-3, HC2-server-4]

Programatically set v$session program property

I found some answers on the problem but none that i could make work in my case. My problem is that I load a datasource from my JBoss configuration with spring:
<xa-datasource jndi-name="java:jboss/jdbc/oracleDatasource" pool-name="jdbc/oracleDatasource" enabled="true">
<xa-datasource-property name="URL">
jdbc:oracle:thin:#URL:1522:SID
</xa-datasource-property>
<xa-datasource-property name="connectionProperties">
v$session.program=MyAPP
</xa-datasource-property>
<driver>oracle-jdbc</driver>
The spring loading is made as follows:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:jboss/jdbc/oracleDatasource"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="dataSource"/>
</bean>
As you can see, I have set the v$session.program property in JBoss, it works well.
The problem is that i have several applications (war) that can be deployed on the same JBoss server, using this configuration. What I want to do in this case is to have each of my application to have its own name written in the v$session.program property.
So basically, i would like to be able to load the same datasource on each app but to have each of them using its own name to log the program property in oracle DB. Is it possible or do I have to have one datasource for each application hosted?
The only thing you need it to intercept each call of getConnection from connection pool.
You must obtain a real Oracle connection - not a proxy - and call the setClientInfo on 12c or setEndToEndMetrics in older versions to set the action / client / module identification.
An example see here.
Also note that the use of dbms_application_info for this same purpose works as well, but this produces a one server roundtrip too much. The setClientInfo doesn't produce server call, but stores this information for the next statement execution (which is the preformance saving approach).
Also note that to use this feature, your driver must match perfectly with your database - the strange exeptions you can see while setting teh client info are in most cases caused by the incompatibility of teh JDBC driver and the RDBMS.
If putting this information into v$session.module or v$session.client_info is an option, you can do using Java code.
All you need to do is call dbms_application_info.set_module() or dbms_application_info.set_client_info() after your Java code obtained the connection from the datasource.
Something like this:
Connection conn = ... // get connection from the DataSource
CallableStatement cstmt = conn.prepareCall("{call dbms_application_info.set_client_info(?)}");
cstmt.setString(1, "Some interesting information");
cstmt.execute();

quartz jboss spring multiple webapps

I have been successfully using quartz in my application.
Basically I have quartz bundled inside the webapp1 which is running inside the Jboss.
But we have got another webapp2 running in the jboss which needs to have quartz job as well
Now what I need to do is to have quartz scheduler running in the jboss as some kind of service and both the webapps should be able
to register their jobs on the single quartz scheduler.
below is my related spring configuration for webapp1 which has beenworking till now.
<bean id="qtzScheduler"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="dataSource">
<ref bean="jndiDataSource" />
</property>
<property name="applicationContextSchedulerContextKey">
<value>applicationContext</value>
</property>
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="schedulerName" value="webapp1" />
</bean>
<bean id="wrapperScheduler" class="uk.fa.quartz.schedule.ServiceScheduler">
<property name="scheduler">
<ref bean="qtzScheduler" />
</property>
</bean>
<bean id="jndiDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:/FmManagerDS</value>
</property>
</bean>
when I have to schedule the job,code is like below:
WrapperScheduler scheduler = (WrapperScheduler) ctx.getBean("wrapperScheduler");
scheduler.scheduleCronJob(job, jobName + "CronTrigger", WrapperScheduler.TRIGGER_GROUP, cronExpression);
Now I dont want to define the same scheduler again in webapp2 which will cause 2 quartz scheduler running in the jboss.
Can someone has any idea how to do it ?
I saw one example on the internet like below Link which I think is doing what I want.
But I dont understand how I can integrate this with my system using the datasource defined in my spring source.
If anybody can share the configuration or point me to the right resource on internet,I would be highly thankful.
The link you refer to explains how to access Quartz scheduler services built into JBoss. I have never used such approach but basically you let JBoss handle your scheduler, data source and everything around it. This makes it very easy to take advantage of job scheduling without all the configuration hustle - but is not very flexible and your application is no longer self-contained.
In your case I see two options worth investigating:
Clustered Quartz scheduler
Configure both of your web applications to run in a cluster. Both applications will share the same database and will run jobs defined in each other. This might not be an option for you due to several reasons:
both applications must be able to run jobs defined by each other - e.g. job classes must be available on CLASSPATH
you still need to define Quartz configuration in both applications (you can easily share configuration though, e.g. by extracting the XML configuration into a separate file)
both applications will maintain separate thread pool
Clustering is more suited for homogeneous applications running on several machines, not heterogeneous ones on single node.
Remote scheduler
Quartz has a built-in support for remote schedulers via rmi. Basically one application hosts full-blown Quartz server whilst the other connects to that server. This seems like a better approach for you (let's call it "master-slave") as only one application manages the scheduler while the other uses existing one.
See: RemoteScheduler.
Finally I got time to write it all down for all others who might have to use Quartz as a service running in jboss.
But other options as mentioned in his answer by #Tomasz can also be tried.
Please note that you will get a null reference back if you try to retrieve it from outside the JBoss server in which it was bound. In case you have such a requirement you might want to consider using Quartz's RMI support instead.
1)First of all ensure that you remove any existing versions of the quartz in the jboss/[profile]/lib or the quartz.rar which is comes up with the jboss distribution.
2)Please your quartz.1.8.3.jar & quartz-jboss.1.8.jar into the acccesmanager/[profile]/lib
3)Below is the code for quartz-service.xml which needs to be placed in the jboss deploy folder which will start the Quartz scheduler:
<server>
<mbean code="org.quartz.ee.jmx.jboss.QuartzService"
name="user:service=QuartzService,name=QuartzService">
<attribute name="JndiName">Quartz</attribute>
<attribute name="Properties">
org.quartz.scheduler.instanceName = BGSScheduler
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false
org.quartz.scheduler.xaTransacted = false
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 5
org.quartz.threadPool.threadPriority = 4
org.quartz.scheduler.threadsInheritContextClassLoaderOfInitializer = true
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreCMT
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.dataSource = QUARTZ
org.quartz.dataSource.QUARTZ.jndiURL = java:FmManagerDS
org.quartz.jobStore.nonManagedTXDataSource = QUARTZ_NO_TX
org.quartz.dataSource.QUARTZ_NO_TX.jndiURL = java:FmManagerDS
</attribute>
<depends>jboss.jca:service=DataSourceBinding,name=FmManagerDS</depends>
</mbean>
</server>
]
Most of things are self explanatory or you can get more details on this at Quartz Configuration
The key thing is to note that quartz requires 2 datasources.One is the container managed datasource-same one as one defined in jboss *-ds.xml(java:FmManagerDS in my case).
If your 'org.quartz.jobStore.dataSource' is XA, then set 'org.quartz.jobStore.nonManagedTXDataSource' to a non-XA datasource (for the same DB). Otherwise, you can set them to be the same.
Then in spring applicationContext,I had to get the handle of quartz so that I could inject into the wrapperScheduler.Code for that is below
<bean id="quartzScheduler" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>Quartz</value>
</property>
</bean>
<bean id="wrapperScheduler" class="k.fa.quartz.schedule.ServiceScheduler">
<property name="scheduler">
<ref bean="quartzScheduler" />
</property>
</bean>
Then we can schedule the jobs using below
Timestamp t = new Timestamp (System.currentTimeMillis());
ScheduleJob job = new ScheduleJob(EmailJob.class.getCanonicalName() +t.toString(), EmailJob.class);
Below is the code to pass the spring applicationContext to the EmailJob so that we can access beans and other things.
To achieve that we need to implement the ApplicationContextAware interface so that applicationContext is available and same is then
pushed into the schedulerContext.Please ensure that we dont put applicationContext into the JobdataMap incase you are using JDBC store as it gives serialization issues.
serviceScheduler.getScheduler().getContext().put("applicationContext", ctx);
serviceScheduler.scheduleCronJob(job, "test" + t.toString(), ServiceScheduler.DEFAULT_TRIGGER_GROUP, cronExpression);
Others who are not using wrapperscheduler can similarly get the handle of the quartz directly into their code using below
InitialContext ctx = new InitialContext();
Scheduler scheduler = (Scheduler) ctx.lookup("Quartz");
ScheduleJob job = new ScheduleJob(EmailJob.class.getCanonicalName() +t.toString(), Executor.class);
scheduler.scheduleJob(job, trigger);
In the Email job class you can use below to get the applicationContext
applicationContext = (ApplicationContext) context.getScheduler().getContext().get(APPLICATION_CONTEXT_KEY);
//get spring bean and do the necessary stuff
Another important thing is that as the quartz schedler is running outside the webapplication,quartz wont be able to fire the jobclass if it is inside the war.It needs to be in the shared jar in the jboss/[profile]/lib.

Unable to proxy a JBossMQ queue in Spring

Spring JMS going against a JBoss 4.x JBossMQ queue (I know, old JBoss, JBossMQ superseded by JBoss Messaging, but I can't change the stack). Everything works when the Spring JMS configuration is loaded at startup, but when I make the JNDI lookups lazy, so that they are first loaded when I want to send a JMS message, I get the following exception:
org.springframework.jms.InvalidDestinationException: Destination is not an instance of SpyDestination QUEUE.myQueueName; nested exception is javax.jms.InvalidDestinationException: Destination is not an instance of SpyDestination QUEUE.myQueueName
at org.springframework.jms.support.JmsUtils.convertJmsAccessException(JmsUtils.java:285)
My config:
<jee:jndi-lookup id="beanNameForMyQueue"
jndi-name="queue/myQueueName"
resource-ref="true" environment-ref="jndiEnvironment"
lookup-on-startup="false" cache="true" proxy-interface="javax.jms.Queue" />
I found a JBoss JIRA on this, and this similar HornetQ post, but so far no dice.
Am I just out of luck with the lazy init, or is there a workaround?

Resources